#include <libkern/OSAtomic.h>
#include <kern/task.h>
-#include <kern/lock.h>
+#include <kern/locks.h>
#ifdef MACH_ASSERT
# undef MACH_ASSERT
#endif
#endif /* CONFIG_EXT_RESOLVER */
-static const int kauth_cred_primes[KAUTH_CRED_PRIMES_COUNT] = KAUTH_CRED_PRIMES;
-static int kauth_cred_primes_index = 0;
-static int kauth_cred_table_size = 0;
+#define KAUTH_CRED_TABLE_SIZE 97
TAILQ_HEAD(kauth_cred_entry_head, ucred);
static struct kauth_cred_entry_head * kauth_cred_table_anchor = NULL;
}
/*
- * Beyond this point, we must be the resolver process.
+ * Beyond this point, we must be the resolver process. We verify this
+ * by confirming the resolver credential and pid.
*/
- if (current_proc()->p_pid != kauth_resolver_identity) {
+ if ((kauth_cred_getuid(kauth_cred_get()) != 0) || (current_proc()->p_pid != kauth_resolver_identity)) {
KAUTH_DEBUG("RESOLVER - call from bogus resolver %d\n", current_proc()->p_pid);
return(EPERM);
}
struct kauth_identity_extlookup extl;
struct kauth_resolver_work *workp;
struct kauth_resolver_work *killp;
- int error, result;
+ int error, result, request_flags;
/*
* Copy in the mesage, including the extension field, since we are
TAILQ_FOREACH(workp, &kauth_resolver_submitted, kr_link) {
/* found it? */
if (workp->kr_seqno == extl.el_seqno) {
+ /*
+ * Take a snapshot of the original request flags.
+ */
+ request_flags = workp->kr_work.el_flags;
/*
* Get the request of the submitted queue so
* issue and is easily detectable by comparing
* time to live on last response vs. time of
* next request in the resolver logs.
+ *
+ * A malicious/faulty resolver could overwrite
+ * part of a user's address space if they return
+ * flags that mismatch the original request's flags.
*/
- if (extl.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM|KAUTH_EXTLOOKUP_VALID_GRNAM)) {
+ if ((extl.el_flags & request_flags) & (KAUTH_EXTLOOKUP_VALID_PWNAM|KAUTH_EXTLOOKUP_VALID_GRNAM)) {
size_t actual; /* notused */
KAUTH_RESOLVER_UNLOCK();
error = copyinstr(extl.el_extend, CAST_DOWN(void *, workp->kr_extend), MAXPATHLEN, &actual);
KAUTH_RESOLVER_LOCK();
+ } else if (extl.el_flags & (KAUTH_EXTLOOKUP_VALID_PWNAM|KAUTH_EXTLOOKUP_VALID_GRNAM)) {
+ error = EFAULT;
+ KAUTH_DEBUG("RESOLVER - resolver returned mismatching extension flags (%d), request contained (%d)",
+ extl.el_flags, request_flags);
}
/*
* Parameters: uid
*
* Returns: NULL Insufficient memory to satisfy
- * the request
+ * the request or bad parameters
* !NULL A pointer to the allocated
* structure, filled in
*
kip->ki_valid = KI_VALID_UID;
}
if (supgrpcnt) {
+ /*
+ * A malicious/faulty resolver could return bad values
+ */
+ assert(supgrpcnt >= 0);
assert(supgrpcnt <= NGROUPS);
assert(supgrps != NULL);
+
+ if ((supgrpcnt < 0) || (supgrpcnt > NGROUPS) || (supgrps == NULL)) {
+ return NULL;
+ }
if (kip->ki_valid & KI_VALID_GID)
panic("can't allocate kauth identity with both gid and supplementary groups");
kip->ki_supgrpcnt = supgrpcnt;
int i;
kauth_cred_hash_mtx = lck_mtx_alloc_init(kauth_lck_grp, 0/*LCK_ATTR_NULL*/);
- kauth_cred_table_size = kauth_cred_primes[kauth_cred_primes_index];
/*allocate credential hash table */
MALLOC(kauth_cred_table_anchor, struct kauth_cred_entry_head *,
- (sizeof(struct kauth_cred_entry_head) * kauth_cred_table_size),
+ (sizeof(struct kauth_cred_entry_head) * KAUTH_CRED_TABLE_SIZE),
M_KAUTH, M_WAITOK | M_ZERO);
if (kauth_cred_table_anchor == NULL)
panic("startup: kauth_cred_init");
- for (i = 0; i < kauth_cred_table_size; i++) {
+ for (i = 0; i < KAUTH_CRED_TABLE_SIZE; i++) {
TAILQ_INIT(&kauth_cred_table_anchor[i]);
}
}
* that is returned to them, if it is not intended to be a
* persistent reference.
*/
+
static
kauth_cred_t
kauth_cred_label_update_execve(kauth_cred_t cred, vfs_context_t ctx,
- struct vnode *vp, struct vnode *scriptvp, struct label *scriptl,
- struct label *execl, void *macextensions, int *disjointp)
+ struct vnode *vp, off_t offset, struct vnode *scriptvp, struct label *scriptl,
+ struct label *execl, unsigned int *csflags, void *macextensions, int *disjointp, int *labelupdateerror)
{
kauth_cred_t newcred;
struct ucred temp_cred;
mac_cred_label_init(&temp_cred);
mac_cred_label_associate(cred, &temp_cred);
- *disjointp = mac_cred_label_update_execve(ctx, &temp_cred,
- vp, scriptvp, scriptl, execl,
- macextensions);
+ mac_cred_label_update_execve(ctx, &temp_cred,
+ vp, offset, scriptvp, scriptl, execl, csflags,
+ macextensions, disjointp, labelupdateerror);
newcred = kauth_cred_update(cred, &temp_cred, TRUE);
mac_cred_label_destroy(&temp_cred);
* vp The vnode being exec'ed
* scriptl The script MAC label
* execl The executable MAC label
+ * lupdateerror The error place holder for MAC label authority
+ * to update about possible termination
*
* Returns: 0 Label update did not make credential
* disjoint
* result of this call. The caller should not assume the process
* reference to the old credential still exists.
*/
-int
+
+void
kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx,
- struct vnode *vp, struct vnode *scriptvp, struct label *scriptl,
- struct label *execl, void *macextensions)
+ struct vnode *vp, off_t offset, struct vnode *scriptvp, struct label *scriptl,
+ struct label *execl, unsigned int *csflags, void *macextensions, int *disjoint, int *update_return)
{
kauth_cred_t my_cred, my_new_cred;
- int disjoint = 0;
-
my_cred = kauth_cred_proc_ref(p);
DEBUG_CRED_ENTER("kauth_proc_label_update_execve: %p\n", my_cred);
* passed in. The subsequent compare is safe, because it is
* a pointer compare rather than a contents compare.
*/
- my_new_cred = kauth_cred_label_update_execve(my_cred, ctx, vp, scriptvp, scriptl, execl, macextensions, &disjoint);
+ my_new_cred = kauth_cred_label_update_execve(my_cred, ctx, vp, offset, scriptvp, scriptl, execl, csflags, macextensions, disjoint, update_return);
if (my_cred != my_new_cred) {
DEBUG_CRED_CHANGE("kauth_proc_label_update_execve_unlocked CH(%d): %p/0x%08x -> %p/0x%08x\n", p->p_pid, my_cred, my_cred->cr_flags, my_new_cred, my_new_cred->cr_flags);
}
/* Drop old proc reference or our extra reference */
kauth_cred_unref(&my_cred);
-
- return (disjoint);
}
#if 1
KAUTH_CRED_HASH_LOCK_ASSERT();
hash_key = kauth_cred_get_hashkey(new_cred);
- hash_key %= kauth_cred_table_size;
+ hash_key %= KAUTH_CRED_TABLE_SIZE;
/* race fix - there is a window where another matching credential
* could have been inserted between the time this one was created and we
kauth_cred_t found_cred;
hash_key = kauth_cred_get_hashkey(cred);
- hash_key %= kauth_cred_table_size;
+ hash_key %= KAUTH_CRED_TABLE_SIZE;
/* Avoid race */
if (cred->cr_ref < 1)
#endif
hash_key = kauth_cred_get_hashkey(cred);
- hash_key %= kauth_cred_table_size;
+ hash_key %= KAUTH_CRED_TABLE_SIZE;
/* Find cred in the credential hash table */
TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) {
printf("\n\t kauth credential hash table statistics - current cred count %d \n", kauth_cred_count);
/* count slot hits, misses, collisions, and max depth */
- for (i = 0; i < kauth_cred_table_size; i++) {
+ for (i = 0; i < KAUTH_CRED_TABLE_SIZE; i++) {
printf("[%02d] ", i);
j = 0;
TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
return (EPERM);
/* calculate space needed */
- for (i = 0; i < kauth_cred_table_size; i++) {
+ for (i = 0; i < KAUTH_CRED_TABLE_SIZE; i++) {
TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
counter++;
}
/* fill in creds to send back */
nextp = cred_listp;
space = 0;
- for (i = 0; i < kauth_cred_table_size; i++) {
+ for (i = 0; i < KAUTH_CRED_TABLE_SIZE; i++) {
TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[i], cr_link) {
nextp->credp = found_cred;
nextp->cr_ref = found_cred->cr_ref;