MAC policy credential labeling infinite loop in kauth_cred_update()
Hi, In a custom MAC policy kext, I am making use of credential labeling to identify processes. I've discovered that kauth_cred_update() will go into an infinite loop and make the system unresponsive at the drop of a hat. It's possible to prevent the hang by implementing the mpo_cred_label_associate() callback in a very specific, restrictive way. However, the "default implementation" of zeroing out label slots does not satisfy this condition, so as soon as you deregister a MAC policy that labels credentials, the system comes crashing down. I've not found a way to avoid this, and I'd consider being unable to kextunload my kext a bug, but I wouldn't mind discussing it before filing a radar. In particular, would it help if I supplied a patch along with the radar issue? I couldn't find a policy for contributing to the kernel anywhere. Just to explain the problem in more detail: The issue is in kauth_cred_update()[1]. This function is supposed to perform a copy-and-update on an existing kauth_cred_t, based on a "model" kauth_cred_t which contains the new credential data. The complexity and the bug come from the need to maintain uniqueness of credentials via the global credential hash table. In pseudocode (leaving aside refcounting and locking), the function does this: inputs: old_cred, model_cred while (1) { found_cred = hash_lookup(model_cred) if (found_cred == old_cred) return old_cred // old and new are the same if (found_cred != NULL) // there already is another existing credential matching the model return found_cred // make copy of model credential on heap new_cred = kauth_cred_dup(model_cred) // attempt to insert new_cred into hash table if (kauth_cred_add(new_cred) == 0) return new_cred // inserting succeeds, we're done // inserting into hash table failed because a credential identical to new_cred already exists. Start over. mac_cred_label_destroy(new_cred) } Basically, the problem is this function assumes that the result of kauth_cred_dup() [new_cred] is identical to its argument [model_cred]. If a label slot's MAC policy has a callback registered for mpo_cred_label_associate, kauth_cred_dup() will call it. Otherwise, the label slot value ends up being 0. If any credential in the system has a nonzero label slot, deregistering the corresponding MAC policy means that kauth_cred_dup() changes the label slot from X to 0. This means new_cred is not identical to model_cred, violating the assumption. When the result of kauth_cred_dup() doesn't match its input, and there happens to be a credential that does match its result already in the hash table, we enter an infinite loop. This turns out to be extremely likely. What I don't get is why failure to insert new_cred is even treated as an error. If there already is a matching credential available, then great, just use that! There's no need for a loop here - much like the lookup of model_cred, it should look up new_cred, and if a matching entry in the table exists, it should throw new_cred away and return the found credential. Otherwise, insert new_cred and return that. I'd be happy to provide a patch that implements this corrected logic. Thanks, phil [1] lines 4740-4800 in http://opensource.apple.com/source/xnu/xnu-2050.18.24/bsd/kern/kern_credenti... -- http://philjordan.eu/ - Phil Jordan, software development contractor _______________________________________________ Do not post admin requests to the list. They will be ignored. Darwin-kernel mailing list (Darwin-kernel@lists.apple.com) Help/Unsubscribe/Update your Subscription: https://lists.apple.com/mailman/options/darwin-kernel/site_archiver%40lists.... This email sent to site_archiver@lists.apple.com
participants (1)
-
Phil Jordan