MAC policy credential labeling infinite loop in kauth_cred_update()
MAC policy credential labeling infinite loop in kauth_cred_update()
- Subject: MAC policy credential labeling infinite loop in kauth_cred_update()
- From: Phil Jordan <email@hidden>
- Date: Mon, 04 Feb 2013 12:27:29 +0100
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_credential.c
--
http://philjordan.eu/ - Phil Jordan, software development contractor
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Darwin-kernel mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden