#include <security/_label.h>
#endif
+#include <IOKit/IOBSD.h>
+
void mach_kauth_cred_uthread_update( void );
#define CRED_DIAGNOSTIC 0
#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);
break;
/* woken because the resolver has died? */
if (kauth_resolver_identity == 0) {
- error = EIO;
+ RESOLVER_FAILED_MESSAGE("kauth external resolver died while while waiting for work to complete");
+ error = KAUTH_RESOLVER_FAILED_ERRCODE;
break;
}
/* an error? */
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.
*/
* 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);
}
* 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);
struct kauth_identity_extlookup extl;
struct kauth_resolver_work *workp;
struct kauth_resolver_work *killp;
- int error, result, request_flags;
+ int error, result, want_extend_data;
/*
* Copy in the mesage, including the extension field, since we are
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
/* 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:
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;
}
/* found it? */
if (workp->kr_seqno == extl.el_seqno) {
/*
- * Take a snapshot of the original request flags.
+ * Do we want extend_data?
*/
- request_flags = workp->kr_work.el_flags;
+ want_extend_data = (workp->kr_work.el_flags & (KAUTH_EXTLOOKUP_WANT_PWNAM|KAUTH_EXTLOOKUP_WANT_GRNAM));
/*
* Get the request of the submitted queue so
* part of a user's address space if they return
* flags that mismatch the original request's flags.
*/
- if ((extl.el_flags & request_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;
* 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) {
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 */
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
- mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
proc_ucred_unlock(p);
}
break;
p->p_ucred = my_new_cred;
/* update cred on proc */
PROC_UPDATE_CREDS_ONPROC(p);
- mac_proc_set_enforce(p, MAC_ALL_ENFORCE);
proc_ucred_unlock(p);
}
break;
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);
}
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);
}