X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/316670eb35587141e969394ae8537d66b9211e80..a39ff7e25e19b3a8c3020042a3872ca9ec9659f1:/bsd/kern/kern_credential.c?ds=inline diff --git a/bsd/kern/kern_credential.c b/bsd/kern/kern_credential.c index 7569cf5eb..c433affea 100644 --- a/bsd/kern/kern_credential.c +++ b/bsd/kern/kern_credential.c @@ -61,7 +61,7 @@ #include #include -#include +#include #ifdef MACH_ASSERT # undef MACH_ASSERT #endif @@ -74,12 +74,33 @@ #include #endif +#include + void mach_kauth_cred_uthread_update( void ); #define CRED_DIAGNOSTIC 0 # define NULLCRED_CHECK(_c) do {if (!IS_VALID_CRED(_c)) panic("%s: bad credential %p", __FUNCTION__,_c);} while(0) +/* Set to 1 to turn on KAUTH_DEBUG for kern_credential.c */ +#if 0 +#ifdef KAUTH_DEBUG +#undef KAUTH_DEBUG +#endif + +#ifdef K_UUID_FMT +#undef K_UUID_FMT +#endif + +#ifdef K_UUID_ARG +#undef K_UUID_ARG +#endif + +# define K_UUID_FMT "%08x:%08x:%08x:%08x" +# define K_UUID_ARG(_u) *(int *)&_u.g_guid[0],*(int *)&_u.g_guid[4],*(int *)&_u.g_guid[8],*(int *)&_u.g_guid[12] +# define KAUTH_DEBUG(fmt, args...) do { printf("%s:%d: " fmt "\n", __PRETTY_FUNCTION__, __LINE__ , ##args); } while (0) +#endif + /* * Credential debugging; we can track entry into a function that might * change a credential, and we can track actual credential changes that @@ -141,6 +162,7 @@ static lck_mtx_t *kauth_resolver_mtx; #define KAUTH_RESOLVER_UNLOCK() lck_mtx_unlock(kauth_resolver_mtx); static volatile pid_t kauth_resolver_identity; +static int kauth_identitysvc_has_registered; static int kauth_resolver_registered; static uint32_t kauth_resolver_sequence; static int kauth_resolver_timeout = 30; /* default: 30 seconds */ @@ -166,10 +188,28 @@ TAILQ_HEAD(kauth_resolver_done_head, kauth_resolver_work) kauth_resolver_done; #define KAUTH_COMPLAINT_INTERVAL 1000 int kauth_resolver_timeout_cnt = 0; +#if DEVELOPMENT || DEBUG +/* Internal builds get different (less ambiguous) breadcrumbs. */ +#define KAUTH_RESOLVER_FAILED_ERRCODE EOWNERDEAD +#else +/* But non-Internal builds get errors that are allowed by standards. */ +#define KAUTH_RESOLVER_FAILED_ERRCODE EIO +#endif /* DEVELOPMENT || DEBUG */ + +int kauth_resolver_failed_cnt = 0; +#define RESOLVER_FAILED_MESSAGE(fmt, args...) \ +do { \ + if (!(kauth_resolver_failed_cnt++ % 100)) { \ + printf("%s: " fmt "\n", __PRETTY_FUNCTION__, ##args); \ + } \ +} while (0) + static int kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data); static int kauth_resolver_complete(user_addr_t message); static int kauth_resolver_getwork(user_addr_t message); static int kauth_resolver_getwork2(user_addr_t message); +static __attribute__((noinline)) int __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__( + struct kauth_resolver_work *); #define KAUTH_CACHES_MAX_SIZE 10000 /* Max # entries for both groups and id caches */ @@ -178,6 +218,8 @@ struct kauth_identity { int ki_valid; uid_t ki_uid; gid_t ki_gid; + int ki_supgrpcnt; + gid_t ki_supgrps[NGROUPS]; guid_t ki_guid; ntsid_t ki_ntsid; const char *ki_name; /* string name from string cache */ @@ -188,6 +230,7 @@ struct kauth_identity { * not go to userland to resolve, just assume that there is no answer * available. */ + time_t ki_groups_expiry; time_t ki_guid_expiry; time_t ki_ntsid_expiry; }; @@ -201,7 +244,8 @@ static int kauth_identity_cachemax = KAUTH_IDENTITY_CACHEMAX_DEFAULT; static int kauth_identity_count; static struct kauth_identity *kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry, - ntsid_t *ntsidp, time_t ntsid_expiry, const char *name, int nametype); + ntsid_t *ntsidp, time_t ntsid_expiry, int supgrpcnt, gid_t *supgrps, time_t groups_expiry, + const char *name, int nametype); static void kauth_identity_register_and_free(struct kauth_identity *kip); static void kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_identity *kip, uint64_t extend_data); static void kauth_identity_trimcache(int newsize); @@ -238,9 +282,7 @@ static void kauth_groups_trimcache(int newsize); #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; @@ -248,11 +290,11 @@ static struct kauth_cred_entry_head * kauth_cred_table_anchor = NULL; #define KAUTH_CRED_HASH_DEBUG 0 static int kauth_cred_add(kauth_cred_t new_cred); -static void kauth_cred_remove(kauth_cred_t cred); +static boolean_t kauth_cred_remove(kauth_cred_t cred); static inline u_long kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key); static u_long kauth_cred_get_hashkey(kauth_cred_t cred); static kauth_cred_t kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t new_cred, boolean_t retain_auditinfo); -static void kauth_cred_unref_hashlocked(kauth_cred_t *credp); +static boolean_t kauth_cred_unref_hashlocked(kauth_cred_t *credp); #if KAUTH_CRED_HASH_DEBUG static int kauth_cred_count = 0; @@ -261,6 +303,51 @@ static void kauth_cred_print(kauth_cred_t cred); #endif #if CONFIG_EXT_RESOLVER + +/* + * __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__ + * + * Description: Waits for the user space daemon to respond to the request + * we made. Function declared non inline to be visible in + * stackshots and spindumps as well as debugging. + * + * Parameters: workp Work queue entry. + * + * Returns: 0 on Success. + * EIO if Resolver is dead. + * EINTR thread interrupted in msleep + * EWOULDBLOCK thread timed out in msleep + * ERESTART returned by msleep. + * + */ +static __attribute__((noinline)) int +__KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__( + struct kauth_resolver_work *workp) +{ + int error = 0; + struct timespec ts; + for (;;) { + /* we could compute a better timeout here */ + ts.tv_sec = kauth_resolver_timeout; + ts.tv_nsec = 0; + error = msleep(workp, kauth_resolver_mtx, PCATCH, "kr_submit", &ts); + /* request has been completed? */ + if ((error == 0) && (workp->kr_flags & KAUTH_REQUEST_DONE)) + break; + /* woken because the resolver has died? */ + if (kauth_resolver_identity == 0) { + RESOLVER_FAILED_MESSAGE("kauth external resolver died while while waiting for work to complete"); + error = KAUTH_RESOLVER_FAILED_ERRCODE; + break; + } + /* an error? */ + if (error != 0) + break; + } + return error; +} + + /* * kauth_resolver_init * @@ -398,23 +485,7 @@ kauth_resolver_submit(struct kauth_identity_extlookup *lkp, uint64_t extend_data * work. */ wakeup_one((caddr_t)&kauth_resolver_unsubmitted); - for (;;) { - /* we could compute a better timeout here */ - ts.tv_sec = kauth_resolver_timeout; - ts.tv_nsec = 0; - error = msleep(workp, kauth_resolver_mtx, PCATCH, "kr_submit", &ts); - /* request has been completed? */ - if ((error == 0) && (workp->kr_flags & KAUTH_REQUEST_DONE)) - break; - /* woken because the resolver has died? */ - if (kauth_resolver_identity == 0) { - error = EIO; - break; - } - /* an error? */ - if (error != 0) - break; - } + error = __KERNEL_IS_WAITING_ON_EXTERNAL_CREDENTIAL_RESOLVER__(workp); /* if the request was processed, copy the result */ if (error == 0) @@ -522,10 +593,15 @@ identitysvc(__unused struct proc *p, struct identitysvc_args *uap, __unused int3 int opcode = uap->opcode; user_addr_t message = uap->message; struct kauth_resolver_work *workp; - struct kauth_cache_sizes sz_arg; + struct kauth_cache_sizes sz_arg = {}; int error; pid_t new_id; + if (!IOTaskHasEntitlement(current_task(), IDENTITYSVC_ENTITLEMENT)) { + KAUTH_DEBUG("RESOLVER - pid %d not entitled to call identitysvc", current_proc()->p_pid); + return(EPERM); + } + /* * New server registering itself. */ @@ -557,6 +633,7 @@ identitysvc(__unused struct proc *p, struct identitysvc_args *uap, __unused int3 } kauth_resolver_identity = new_id; kauth_resolver_registered = 1; + kauth_identitysvc_has_registered = 1; wakeup(&kauth_resolver_unsubmitted); } KAUTH_RESOLVER_UNLOCK(); @@ -564,9 +641,10 @@ identitysvc(__unused struct proc *p, struct identitysvc_args *uap, __unused int3 } /* - * 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); } @@ -701,15 +779,17 @@ kauth_resolver_getwork_continue(int result) * If this is a wakeup from another thread in the resolver * deregistering it, error out the request-for-work thread */ - if (!kauth_resolver_identity) - error = EIO; + if (!kauth_resolver_identity) { + RESOLVER_FAILED_MESSAGE("external resolver died"); + error = KAUTH_RESOLVER_FAILED_ERRCODE; + } KAUTH_RESOLVER_UNLOCK(); return(error); } thread = current_thread(); ut = get_bsdthread_info(thread); - message = ut->uu_kauth.message; + message = ut->uu_kevent.uu_kauth.message; return(kauth_resolver_getwork2(message)); } @@ -836,15 +916,17 @@ kauth_resolver_getwork(user_addr_t message) thread_t thread = current_thread(); struct uthread *ut = get_bsdthread_info(thread); - ut->uu_kauth.message = message; + ut->uu_kevent.uu_kauth.message = message; error = msleep0(&kauth_resolver_unsubmitted, kauth_resolver_mtx, PCATCH, "GRGetWork", 0, kauth_resolver_getwork_continue); KAUTH_RESOLVER_UNLOCK(); /* * If this is a wakeup from another thread in the resolver * deregistering it, error out the request-for-work thread */ - if (!kauth_resolver_identity) - error = EIO; + if (!kauth_resolver_identity) { + printf("external resolver died"); + error = KAUTH_RESOLVER_FAILED_ERRCODE; + } return(error); } return kauth_resolver_getwork2(message); @@ -868,7 +950,7 @@ kauth_resolver_complete(user_addr_t message) struct kauth_identity_extlookup extl; struct kauth_resolver_work *workp; struct kauth_resolver_work *killp; - int error, result; + int error, result, want_extend_data; /* * Copy in the mesage, including the extension field, since we are @@ -902,6 +984,7 @@ kauth_resolver_complete(user_addr_t message) case KAUTH_EXTLOOKUP_FATAL: /* fatal error means the resolver is dead */ KAUTH_DEBUG("RESOLVER - resolver %d died, waiting for a new one", kauth_resolver_identity); + RESOLVER_FAILED_MESSAGE("resolver %d died, waiting for a new one", kauth_resolver_identity); /* * Terminate outstanding requests; without an authoritative * resolver, we are now back on our own authority. Tag the @@ -919,7 +1002,7 @@ kauth_resolver_complete(user_addr_t message) /* Cause all waiting-for-work threads to return EIO */ wakeup((caddr_t)&kauth_resolver_unsubmitted); /* and return EIO to the caller */ - error = EIO; + error = KAUTH_RESOLVER_FAILED_ERRCODE; break; case KAUTH_EXTLOOKUP_BADRQ: @@ -929,12 +1012,14 @@ kauth_resolver_complete(user_addr_t message) case KAUTH_EXTLOOKUP_FAILURE: KAUTH_DEBUG("RESOLVER - resolver reported transient failure for request %d", extl.el_seqno); - result = EIO; + RESOLVER_FAILED_MESSAGE("resolver reported transient failure for request %d", extl.el_seqno); + result = KAUTH_RESOLVER_FAILED_ERRCODE; break; default: KAUTH_DEBUG("RESOLVER - resolver returned unexpected status %d", extl.el_result); - result = EIO; + RESOLVER_FAILED_MESSAGE("resolver returned unexpected status %d", extl.el_result); + result = KAUTH_RESOLVER_FAILED_ERRCODE; break; } @@ -949,6 +1034,10 @@ kauth_resolver_complete(user_addr_t message) TAILQ_FOREACH(workp, &kauth_resolver_submitted, kr_link) { /* found it? */ if (workp->kr_seqno == extl.el_seqno) { + /* + * Do we want extend_data? + */ + want_extend_data = (workp->kr_work.el_flags & (KAUTH_EXTLOOKUP_WANT_PWNAM|KAUTH_EXTLOOKUP_WANT_GRNAM)); /* * Get the request of the submitted queue so @@ -986,13 +1075,23 @@ kauth_resolver_complete(user_addr_t message) * 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 (want_extend_data && (extl.el_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_DEBUG("RESOLVER - resolver got name :%*s: len = %d\n", (int)actual, + actual ? "null" : (char *)extl.el_extend, 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); } /* @@ -1026,6 +1125,7 @@ kauth_resolver_complete(user_addr_t message) #define KI_VALID_NTSID (1<<3) #define KI_VALID_PWNAM (1<<4) /* Used for translation */ #define KI_VALID_GRNAM (1<<5) /* Used for translation */ +#define KI_VALID_GROUPS (1<<6) #if CONFIG_EXT_RESOLVER /* @@ -1061,7 +1161,7 @@ kauth_identity_init(void) * Parameters: uid * * Returns: NULL Insufficient memory to satisfy - * the request + * the request or bad parameters * !NULL A pointer to the allocated * structure, filled in * @@ -1070,7 +1170,9 @@ kauth_identity_init(void) * and *either* a UID *or* a GID, but not both. */ static struct kauth_identity * -kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry, ntsid_t *ntsidp, time_t ntsid_expiry, const char *name, int nametype) +kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry, + ntsid_t *ntsidp, time_t ntsid_expiry, int supgrpcnt, gid_t *supgrps, time_t groups_expiry, + const char *name, int nametype) { struct kauth_identity *kip; @@ -1087,6 +1189,24 @@ kauth_identity_alloc(uid_t uid, gid_t gid, guid_t *guidp, time_t guid_expiry, nt kip->ki_uid = uid; 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; + memcpy(kip->ki_supgrps, supgrps, sizeof(supgrps[0]) * supgrpcnt); + kip->ki_valid |= KI_VALID_GROUPS; + } + kip->ki_groups_expiry = groups_expiry; if (guidp != NULL) { kip->ki_guid = *guidp; kip->ki_valid |= KI_VALID_GUID; @@ -1248,6 +1368,18 @@ kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_id TAILQ_FOREACH(kip, &kauth_identities, ki_link) { /* matching record */ if ((kip->ki_valid & KI_VALID_UID) && (kip->ki_uid == elp->el_uid)) { + if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) { + assert(elp->el_sup_grp_cnt <= NGROUPS); + if (elp->el_sup_grp_cnt > NGROUPS) { + KAUTH_DEBUG("CACHE - invalid sup_grp_cnt provided (%d), truncating to %d", + elp->el_sup_grp_cnt, NGROUPS); + elp->el_sup_grp_cnt = NGROUPS; + } + kip->ki_supgrpcnt = elp->el_sup_grp_cnt; + memcpy(kip->ki_supgrps, elp->el_sup_groups, sizeof(elp->el_sup_groups[0]) * kip->ki_supgrpcnt); + kip->ki_valid |= KI_VALID_GROUPS; + kip->ki_groups_expiry = (elp->el_member_valid) ? tv.tv_sec + elp->el_member_valid : 0; + } if (elp->el_flags & KAUTH_EXTLOOKUP_VALID_UGUID) { kip->ki_guid = elp->el_uguid; kip->ki_valid |= KI_VALID_GUID; @@ -1286,6 +1418,9 @@ kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_id (elp->el_uguid_valid) ? tv.tv_sec + elp->el_uguid_valid : 0, (elp->el_flags & KAUTH_EXTLOOKUP_VALID_USID) ? &elp->el_usid : NULL, (elp->el_usid_valid) ? tv.tv_sec + elp->el_usid_valid : 0, + (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_grp_cnt : 0, + (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_groups : NULL, + (elp->el_member_valid) ? tv.tv_sec + elp->el_member_valid : 0, (elp->el_flags & KAUTH_EXTLOOKUP_VALID_PWNAM) ? speculative_name : NULL, KI_VALID_PWNAM); if (kip != NULL) { @@ -1343,6 +1478,9 @@ kauth_identity_updatecache(struct kauth_identity_extlookup *elp, struct kauth_id (elp->el_gguid_valid) ? tv.tv_sec + elp->el_gguid_valid : 0, (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GSID) ? &elp->el_gsid : NULL, (elp->el_gsid_valid) ? tv.tv_sec + elp->el_gsid_valid : 0, + (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_grp_cnt : 0, + (elp->el_flags & KAUTH_EXTLOOKUP_VALID_SUPGRPS) ? elp->el_sup_groups : NULL, + (elp->el_member_valid) ? tv.tv_sec + elp->el_member_valid : 0, (elp->el_flags & KAUTH_EXTLOOKUP_VALID_GRNAM) ? speculative_name : NULL, KI_VALID_GRNAM); if (kip != NULL) { @@ -1432,7 +1570,7 @@ kauth_identity_guid_expired(struct kauth_identity *kip) return (0); microuptime(&tv); - KAUTH_DEBUG("CACHE - GUID expires @ %d now %d", kip->ki_guid_expiry, tv.tv_sec); + KAUTH_DEBUG("CACHE - GUID expires @ %ld now %ld", kip->ki_guid_expiry, tv.tv_sec); return((kip->ki_guid_expiry <= tv.tv_sec) ? 1 : 0); } @@ -1461,11 +1599,38 @@ kauth_identity_ntsid_expired(struct kauth_identity *kip) return (0); microuptime(&tv); - KAUTH_DEBUG("CACHE - NTSID expires @ %d now %d", kip->ki_ntsid_expiry, tv.tv_sec); + KAUTH_DEBUG("CACHE - NTSID expires @ %ld now %ld", kip->ki_ntsid_expiry, tv.tv_sec); return((kip->ki_ntsid_expiry <= tv.tv_sec) ? 1 : 0); } +/* + * kauth_identity_groups_expired + * + * Description: Handle lazy expiration of supplemental group translations. + * + * Parameters: kip kauth identity to check for + * groups expiration + * + * Returns: 1 Expired + * 0 Not expired + */ +static int +kauth_identity_groups_expired(struct kauth_identity *kip) +{ + struct timeval tv; + + /* + * Expiration time of 0 means this entry is persistent. + */ + if (kip->ki_groups_expiry == 0) + return (0); + + microuptime(&tv); + KAUTH_DEBUG("CACHE - GROUPS expires @ %ld now %ld\n", kip->ki_groups_expiry, tv.tv_sec); + + return((kip->ki_groups_expiry <= tv.tv_sec) ? 1 : 0); +} /* * kauth_identity_find_uid @@ -1946,14 +2111,108 @@ static int kauth_cred_cache_lookup(int from, int to, void *src, void *dst); #if CONFIG_EXT_RESOLVER == 0 /* - * If there's no resolver, short-circuit the kauth_cred_x2y() lookups. + * If there's no resolver, only support a subset of the kauth_cred_x2y() lookups. */ static __inline int -kauth_cred_cache_lookup(__unused int from, __unused int to, - __unused void *src, __unused void *dst) +kauth_cred_cache_lookup(int from, int to, void *src, void *dst) +{ + /* NB: These must match the definitions used by Libinfo's mbr_identifier_translate(). */ + static const uuid_t _user_compat_prefix = {0xff, 0xff, 0xee, 0xee, 0xdd, 0xdd, 0xcc, 0xcc, 0xbb, 0xbb, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00}; + static const uuid_t _group_compat_prefix = {0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0xab, 0xcd, 0xef, 0x00, 0x00, 0x00, 0x00}; +#define COMPAT_PREFIX_LEN (sizeof(uuid_t) - sizeof(id_t)) + + assert(from != to); + + switch (from) { + case KI_VALID_UID: { + id_t uid = htonl(*(id_t *)src); + + if (to == KI_VALID_GUID) { + uint8_t *uu = dst; + memcpy(uu, _user_compat_prefix, sizeof(_user_compat_prefix)); + memcpy(&uu[COMPAT_PREFIX_LEN], &uid, sizeof(uid)); + return (0); + } + break; + } + case KI_VALID_GID: { + id_t gid = htonl(*(id_t *)src); + + if (to == KI_VALID_GUID) { + uint8_t *uu = dst; + memcpy(uu, _group_compat_prefix, sizeof(_group_compat_prefix)); + memcpy(&uu[COMPAT_PREFIX_LEN], &gid, sizeof(gid)); + return (0); + } + break; + } + case KI_VALID_GUID: { + const uint8_t *uu = src; + + if (to == KI_VALID_UID) { + if (memcmp(uu, _user_compat_prefix, COMPAT_PREFIX_LEN) == 0) { + id_t uid; + memcpy(&uid, &uu[COMPAT_PREFIX_LEN], sizeof(uid)); + *(id_t *)dst = ntohl(uid); + return (0); + } + } else if (to == KI_VALID_GID) { + if (memcmp(uu, _group_compat_prefix, COMPAT_PREFIX_LEN) == 0) { + id_t gid; + memcpy(&gid, &uu[COMPAT_PREFIX_LEN], sizeof(gid)); + *(id_t *)dst = ntohl(gid); + return (0); + } + } + break; + } + default: + /* NOT IMPLEMENTED */ + break; + } + return (ENOENT); +} +#endif + +#if defined(CONFIG_EXT_RESOLVER) && (CONFIG_EXT_RESOLVER) +/* + * Structure to hold supplemental groups. Used for impedance matching with + * kauth_cred_cache_lookup below. + */ +struct supgroups { + int *count; + gid_t *groups; +}; + +/* + * kauth_cred_uid2groups + * + * Description: Fetch supplemental GROUPS from UID + * + * Parameters: uid UID to examine + * groups pointer to an array of gid_ts + * gcount pointer to the number of groups wanted/returned + * + * Returns: 0 Success + * kauth_cred_cache_lookup:EINVAL + * + * Implicit returns: + * *groups Modified, if successful + * *gcount Modified, if successful + * + */ +static int +kauth_cred_uid2groups(uid_t *uid, gid_t *groups, int *gcount) { - return (EWOULDBLOCK); + int rv; + struct supgroups supgroups; + supgroups.count = gcount; + supgroups.groups = groups; + + rv = kauth_cred_cache_lookup(KI_VALID_UID, KI_VALID_GROUPS, uid, &supgroups); + + return (rv); } #endif @@ -2092,6 +2351,45 @@ kauth_cred_guid2gid(guid_t *guidp, gid_t *gidp) return(kauth_cred_cache_lookup(KI_VALID_GUID, KI_VALID_GID, guidp, gidp)); } +/* + * kauth_cred_nfs4domain2dsnode + * + * Description: Fetch dsnode from nfs4domain + * + * Parameters: nfs4domain Pointer to a string nfs4 domain + * dsnode Pointer to buffer for dsnode + * + * Returns: 0 Success + * ENOENT For now just a stub that always fails + * + * Implicit returns: + * *dsnode Modified, if successuful + */ +int +kauth_cred_nfs4domain2dsnode(__unused char *nfs4domain, __unused char *dsnode) +{ + return(ENOENT); +} + +/* + * kauth_cred_dsnode2nfs4domain + * + * Description: Fetch nfs4domain from dsnode + * + * Parameters: nfs4domain Pointer to string dsnode + * dsnode Pointer to buffer for nfs4domain + * + * Returns: 0 Success + * ENOENT For now just a stub that always fails + * + * Implicit returns: + * *nfs4domain Modified, if successuful + */ +int +kauth_cred_dsnode2nfs4domain(__unused char *dsnode, __unused char *nfs4domain) +{ + return(ENOENT); +} /* * kauth_cred_ntsid2uid @@ -2343,7 +2641,10 @@ kauth_cred_cache_lookup(int from, int to, void *src, void *dst) * atomically. */ if (to == KI_VALID_PWNAM || to == KI_VALID_GRNAM) { + if (dst == NULL) + return (EINVAL); namebuf = dst; + *namebuf = '\0'; } ki.ki_valid = 0; switch(from) { @@ -2367,6 +2668,9 @@ kauth_cred_cache_lookup(int from, int to, void *src, void *dst) default: return(EINVAL); } + /* If we didn't get what we're asking for. Call the resolver */ + if (!error && !(to & ki.ki_valid)) + error = ENOENT; /* lookup failure or error */ if (error != 0) { /* any other error is fatal */ @@ -2384,6 +2688,9 @@ kauth_cred_cache_lookup(int from, int to, void *src, void *dst) case KI_VALID_NTSID: expired = kauth_identity_ntsid_expired; break; + case KI_VALID_GROUPS: + expired = kauth_identity_groups_expired; + break; default: switch(from) { case KI_VALID_GUID: @@ -2521,6 +2828,32 @@ kauth_cred_cache_lookup(int from, int to, void *src, void *dst) el.el_flags |= KAUTH_EXTLOOKUP_WANT_GRNAM; extend_data = CAST_USER_ADDR_T(dst); } + if (to == KI_VALID_GROUPS) { + /* Expensive and only useful for an NFS client not using kerberos */ + el.el_flags |= KAUTH_EXTLOOKUP_WANT_SUPGRPS; + if (ki.ki_valid & KI_VALID_GROUPS) { + /* + * Copy the current supplemental groups for the resolver. + * The resolver should check these groups first and if + * the user (uid) is still a member it should endeavor to + * keep them in the list. Otherwise NFS clients could get + * changing access to server file system objects on each + * expiration. + */ + if (ki.ki_supgrpcnt > NGROUPS) { + panic("kauth data structure corrupted. kauth identity 0x%p with %d groups, greater than max of %d", + &ki, ki.ki_supgrpcnt, NGROUPS); + } + + el.el_sup_grp_cnt = ki.ki_supgrpcnt; + + memcpy(el.el_sup_groups, ki.ki_supgrps, sizeof (el.el_sup_groups[0]) * ki.ki_supgrpcnt); + /* Let the resolver know these were the previous valid groups */ + el.el_flags |= KAUTH_EXTLOOKUP_VALID_SUPGRPS; + KAUTH_DEBUG("GROUPS: Sending previously valid GROUPS"); + } else + KAUTH_DEBUG("GROUPS: no valid groups to send"); + } /* Call resolver */ KAUTH_DEBUG("CACHE - calling resolver for %x", el.el_flags); @@ -2577,6 +2910,18 @@ found: case KI_VALID_NTSID: *(ntsid_t *)dst = ki.ki_ntsid; break; + case KI_VALID_GROUPS: { + struct supgroups *gp = (struct supgroups *)dst; + u_int32_t limit = ki.ki_supgrpcnt; + + if (gp->count) { + limit = MIN(ki.ki_supgrpcnt, *gp->count); + *gp->count = limit; + } + + memcpy(gp->groups, ki.ki_supgrps, sizeof(gid_t) * limit); + } + break; case KI_VALID_PWNAM: case KI_VALID_GRNAM: /* handled in kauth_resolver_complete() */ @@ -2954,11 +3299,11 @@ kauth_cred_ismember_guid(__unused kauth_cred_t cred, guid_t *guidp, int *resultp *resultp = 1; break; default: -#if CONFIG_EXT_RESOLVER { - struct kauth_identity ki; gid_t gid; -#if 6603280 +#if CONFIG_EXT_RESOLVER + struct kauth_identity ki; + /* * Grovel the identity cache looking for this GUID. * If we find it, and it is for a user record, return @@ -2985,7 +3330,7 @@ kauth_cred_ismember_guid(__unused kauth_cred_t cred, guid_t *guidp, int *resultp return (0); } } -#endif /* 6603280 */ +#endif /* CONFIG_EXT_RESOLVER */ /* * Attempt to translate the GUID to a GID. Even if * this fails, we will have primed the cache if it is @@ -3002,13 +3347,12 @@ kauth_cred_ismember_guid(__unused kauth_cred_t cred, guid_t *guidp, int *resultp error = 0; } } else { +#if CONFIG_EXT_RESOLVER do_check: +#endif /* CONFIG_EXT_RESOLVER */ error = kauth_cred_ismember_gid(cred, gid, resultp); } } -#else /* CONFIG_EXT_RESOLVER */ - error = ENOENT; -#endif /* CONFIG_EXT_RESOLVER */ break; } return(error); @@ -3157,15 +3501,14 @@ kauth_cred_init(void) 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]); } } @@ -3394,7 +3737,7 @@ kauth_cred_get_with_ref(void) * Returns: (kauth_cred_t) Pointer to the process's * newly referenced credential * - * Locks: PROC_LOCK is held before taking the reference and released + * Locks: PROC_UCRED_LOCK is held before taking the reference and released * after the refeence is taken to protect the p_ucred field of * the process referred to by procp. * @@ -3416,10 +3759,10 @@ kauth_cred_proc_ref(proc_t procp) { kauth_cred_t cred; - proc_lock(procp); + proc_ucred_lock(procp); cred = proc_ucred(procp); kauth_cred_ref(cred); - proc_unlock(procp); + proc_ucred_unlock(procp); return(cred); } @@ -3877,17 +4220,42 @@ kauth_cred_setgroups(kauth_cred_t cred, gid_t *groups, int groupcount, uid_t gmu } /* - * XXX temporary, for NFS support until we can come up with a better - * XXX enumeration/comparison mechanism - * * Notes: The return value exists to account for the possibility of a * kauth_cred_t without a POSIX label. This will be the case in * the future (see posix_cred_get() below, for more details). */ +#if CONFIG_EXT_RESOLVER +int kauth_external_supplementary_groups_supported = 1; + +SYSCTL_INT(_kern, OID_AUTO, ds_supgroups_supported, CTLFLAG_RW | CTLFLAG_LOCKED, &kauth_external_supplementary_groups_supported, 0, ""); +#endif + int kauth_cred_getgroups(kauth_cred_t cred, gid_t *grouplist, int *countp) { int limit = NGROUPS; + posix_cred_t pcred; + + pcred = posix_cred_get(cred); + +#if CONFIG_EXT_RESOLVER + /* + * If we've not opted out of using the resolver, then convert the cred to a list + * of supplemental groups. We do this only if there has been a resolver to talk to, + * since we may be too early in boot, or in an environment that isn't using DS. + */ + if (kauth_identitysvc_has_registered && kauth_external_supplementary_groups_supported && (pcred->cr_flags & CRF_NOMEMBERD) == 0) { + uid_t uid = kauth_cred_getuid(cred); + int err; + + err = kauth_cred_uid2groups(&uid, grouplist, countp); + if (!err) + return 0; + + /* On error just fall through */ + KAUTH_DEBUG("kauth_cred_getgroups failed %d\n", err); + } +#endif /* CONFIG_EXT_RESOLVER */ /* * If they just want a copy of the groups list, they may not care @@ -3896,11 +4264,11 @@ kauth_cred_getgroups(kauth_cred_t cred, gid_t *grouplist, int *countp) * and limit the returned list to that size. */ if (countp) { - limit = MIN(*countp, cred->cr_posix.cr_ngroups); + limit = MIN(*countp, pcred->cr_ngroups); *countp = limit; } - memcpy(grouplist, cred->cr_posix.cr_groups, sizeof(gid_t) * limit); + memcpy(grouplist, pcred->cr_groups, sizeof(gid_t) * limit); return 0; } @@ -4169,11 +4537,12 @@ kauth_cred_label_update(kauth_cred_t cred, struct label *label) * 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 label *scriptl, struct label *execl, - 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; @@ -4182,8 +4551,9 @@ kauth_cred_label_update_execve(kauth_cred_t cred, vfs_context_t ctx, mac_cred_label_init(&temp_cred); mac_cred_label_associate(cred, &temp_cred); - *disjointp = mac_cred_label_update_execve(ctx, &temp_cred, - vp, scriptl, execl); + 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); @@ -4225,7 +4595,7 @@ int kauth_proc_label_update(struct proc *p, struct label *label) DEBUG_CRED_CHANGE("kauth_proc_setlabel_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); - proc_lock(p); + proc_ucred_lock(p); /* * We need to protect for a race where another thread * also changed the credential after we took our @@ -4233,7 +4603,7 @@ int kauth_proc_label_update(struct proc *p, struct label *label) * restart this again with the new cred. */ if (p->p_ucred != my_cred) { - proc_unlock(p); + proc_ucred_unlock(p); kauth_cred_unref(&my_new_cred); my_cred = kauth_cred_proc_ref(p); /* try again */ @@ -4243,8 +4613,7 @@ int kauth_proc_label_update(struct proc *p, struct label *label) /* update cred on proc */ PROC_UPDATE_CREDS_ONPROC(p); - mac_proc_set_enforce(p, MAC_ALL_ENFORCE); - proc_unlock(p); + proc_ucred_unlock(p); } break; } @@ -4267,6 +4636,8 @@ int kauth_proc_label_update(struct proc *p, struct label *label) * 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 @@ -4277,13 +4648,13 @@ int kauth_proc_label_update(struct proc *p, struct label *label) * 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 label *scriptl, struct label *execl) + 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); @@ -4298,12 +4669,12 @@ kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx, * 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, scriptl, execl, &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); - proc_lock(p); + proc_ucred_lock(p); /* * We need to protect for a race where another thread * also changed the credential after we took our @@ -4311,7 +4682,7 @@ kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx, * restart this again with the new cred. */ if (p->p_ucred != my_cred) { - proc_unlock(p); + proc_ucred_unlock(p); kauth_cred_unref(&my_new_cred); my_cred = kauth_cred_proc_ref(p); /* try again */ @@ -4320,15 +4691,12 @@ kauth_proc_label_update_execve(struct proc *p, vfs_context_t ctx, p->p_ucred = my_new_cred; /* update cred on proc */ PROC_UPDATE_CREDS_ONPROC(p); - mac_proc_set_enforce(p, MAC_ALL_ENFORCE); - proc_unlock(p); + proc_ucred_unlock(p); } break; } /* Drop old proc reference or our extra reference */ kauth_cred_unref(&my_cred); - - return (disjoint); } #if 1 @@ -4442,7 +4810,8 @@ kauth_cred_ref(kauth_cred_t cred) * Parameters: credp Pointer to address containing * credential to be freed * - * Returns: (void) + * Returns: TRUE if the credential must be destroyed by the caller. + * FALSE otherwise. * * Implicit returns: * *credp Set to NOCRED @@ -4461,10 +4830,11 @@ kauth_cred_ref(kauth_cred_t cred) * intended effect, to take into account the reference held by * the credential hash, which is released at the same time. */ -static void +static boolean_t kauth_cred_unref_hashlocked(kauth_cred_t *credp) { int old_value; + boolean_t destroy_it = FALSE; KAUTH_CRED_HASH_LOCK_ASSERT(); NULLCRED_CHECK(*credp); @@ -4490,9 +4860,14 @@ kauth_cred_unref_hashlocked(kauth_cred_t *credp) */ if (old_value < 3) { /* The last absolute reference is our credential hash table */ - kauth_cred_remove(*credp); + destroy_it = kauth_cred_remove(*credp); + } + + if (destroy_it == FALSE) { + *credp = NOCRED; } - *credp = NOCRED; + + return (destroy_it); } @@ -4517,9 +4892,23 @@ kauth_cred_unref_hashlocked(kauth_cred_t *credp) void kauth_cred_unref(kauth_cred_t *credp) { + boolean_t destroy_it; + KAUTH_CRED_HASH_LOCK(); - kauth_cred_unref_hashlocked(credp); + destroy_it = kauth_cred_unref_hashlocked(credp); KAUTH_CRED_HASH_UNLOCK(); + + if (destroy_it == TRUE) { + assert(*credp != NOCRED); +#if CONFIG_MACF + mac_cred_label_destroy(*credp); +#endif + AUDIT_SESSION_UNREF(*credp); + + (*credp)->cr_ref = 0; + FREE_ZONE(*credp, sizeof(*(*credp)), M_CRED); + *credp = NOCRED; + } } @@ -4763,17 +5152,31 @@ kauth_cred_update(kauth_cred_t old_cred, kauth_cred_t model_cred, return(old_cred); } if (found_cred != NULL) { + boolean_t destroy_it; + DEBUG_CRED_CHANGE("kauth_cred_update(cache hit): %p -> %p\n", old_cred, found_cred); /* * Found a match so we bump reference count on new * one and decrement reference count on the old one. */ kauth_cred_ref(found_cred); - kauth_cred_unref_hashlocked(&old_cred); + destroy_it = kauth_cred_unref_hashlocked(&old_cred); KAUTH_CRED_HASH_UNLOCK(); + if (destroy_it == TRUE) { + assert(old_cred != NOCRED); +#if CONFIG_MACF + mac_cred_label_destroy(old_cred); +#endif + AUDIT_SESSION_UNREF(old_cred); + + old_cred->cr_ref = 0; + FREE_ZONE(old_cred, sizeof(*old_cred), M_CRED); + old_cred = NOCRED; + + } return(found_cred); } - + /* * Must allocate a new credential using the model. also * adds the new credential to the credential hash table. @@ -4826,7 +5229,7 @@ kauth_cred_add(kauth_cred_t new_cred) 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 @@ -4855,7 +5258,7 @@ kauth_cred_add(kauth_cred_t new_cred) * Parameters: cred Credential to remove from cred * hash cache * - * Returns: (void) + * Returns: TRUE if the cred was found & removed from the hash; FALSE if not. * * Locks: Caller is expected to hold KAUTH_CRED_HASH_LOCK * @@ -4864,43 +5267,36 @@ kauth_cred_add(kauth_cred_t new_cred) * following code occurs with the hash lock held; in theory, this * protects us from the 2->1 reference that gets us here. */ -static void +static boolean_t kauth_cred_remove(kauth_cred_t cred) { u_long hash_key; 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) panic("cred reference underflow"); if (cred->cr_ref > 1) - return; /* someone else got a ref */ + return (FALSE); /* someone else got a ref */ /* Find cred in the credential hash table */ TAILQ_FOREACH(found_cred, &kauth_cred_table_anchor[hash_key], cr_link) { if (found_cred == cred) { /* found a match, remove it from the hash table */ TAILQ_REMOVE(&kauth_cred_table_anchor[hash_key], found_cred, cr_link); -#if CONFIG_MACF - mac_cred_label_destroy(cred); -#endif - AUDIT_SESSION_UNREF(cred); - - cred->cr_ref = 0; - FREE_ZONE(cred, sizeof(*cred), M_CRED); #if KAUTH_CRED_HASH_DEBUG kauth_cred_count--; #endif - return; + return (TRUE); } } /* Did not find a match... this should not happen! XXX Make panic? */ printf("%s:%d - %s - %s - did not find a match for %p\n", __FILE__, __LINE__, __FUNCTION__, current_proc()->p_comm, cred); - return; + return (FALSE); } @@ -4938,7 +5334,7 @@ kauth_cred_find(kauth_cred_t cred) #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) { @@ -4952,12 +5348,13 @@ kauth_cred_find(kauth_cred_t cred) match = (bcmp(found_pcred, pcred, sizeof (*pcred)) == 0) ? TRUE : FALSE; match = match && ((bcmp(&found_cred->cr_audit, &cred->cr_audit, sizeof(cred->cr_audit)) == 0) ? TRUE : FALSE); +#if CONFIG_MACF if (((found_pcred->cr_flags & CRF_MAC_ENFORCE) != 0) || ((pcred->cr_flags & CRF_MAC_ENFORCE) != 0)) { match = match && mac_cred_label_compare(found_cred->cr_label, cred->cr_label); } - +#endif if (match) { /* found a match */ return(found_cred); @@ -5019,7 +5416,9 @@ kauth_cred_hash(const uint8_t *datap, int data_len, u_long start_key) static u_long kauth_cred_get_hashkey(kauth_cred_t cred) { +#if CONFIG_MACF posix_cred_t pcred = posix_cred_get(cred); +#endif u_long hash_key = 0; hash_key = kauth_cred_hash((uint8_t *)&cred->cr_posix, @@ -5028,12 +5427,13 @@ kauth_cred_get_hashkey(kauth_cred_t cred) hash_key = kauth_cred_hash((uint8_t *)&cred->cr_audit, sizeof(struct au_session), hash_key); - +#if CONFIG_MACF if (pcred->cr_flags & CRF_MAC_ENFORCE) { hash_key = kauth_cred_hash((uint8_t *)cred->cr_label, sizeof (struct label), hash_key); } +#endif return(hash_key); } @@ -5059,7 +5459,7 @@ kauth_cred_hash_print(void) 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) { @@ -5244,7 +5644,7 @@ sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1, __unus 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++; } @@ -5257,7 +5657,7 @@ sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1, __unus return 0; } - MALLOC( cred_listp, debug_ucred *, req->oldlen, M_TEMP, M_WAITOK ); + MALLOC( cred_listp, debug_ucred *, req->oldlen, M_TEMP, M_WAITOK | M_ZERO); if ( cred_listp == NULL ) { return (ENOMEM); } @@ -5265,7 +5665,7 @@ sysctl_dump_creds( __unused struct sysctl_oid *oidp, __unused void *arg1, __unus /* 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; @@ -5356,7 +5756,7 @@ sysctl_dump_cred_backtraces( __unused struct sysctl_oid *oidp, __unused void *ar return (ENOMEM); } - MALLOC( bt_bufp, cred_debug_buffer *, req->oldlen, M_TEMP, M_WAITOK ); + MALLOC( bt_bufp, cred_debug_buffer *, req->oldlen, M_TEMP, M_WAITOK | M_ZERO); if ( bt_bufp == NULL ) { return (ENOMEM); }