imgp->ip_csflags |= CS_KILL;
- /* load_machfile() maps the vnode */
- (void)ubc_map(imgp->ip_vp, PROT_READ | PROT_EXEC);
-
/*
* Set up the system reserved areas in the new address space.
*/
*/
error = exec_handle_sugid(imgp);
- proc_knote(p, NOTE_EXEC);
-
if (!vfexec && (p->p_lflag & P_LTRACED))
psignal(p, SIGTRAP);
goto badtoolate;
}
+#if CONFIG_MACF
+ /* Determine if the map will allow VM_PROT_COPY */
+ error = mac_proc_check_map_prot_copy_allow(p);
+ vm_map_set_prot_copy_allow(get_task_map(task),
+ error ? FALSE : TRUE);
+#endif
+
if (load_result.unixproc &&
create_unix_stack(get_task_map(task),
load_result.user_stack,
}
badtoolate:
+ proc_knote(p, NOTE_EXEC);
+
if (vfexec) {
task_deallocate(new_task);
thread_deallocate(thread);
int once = 1; /* save SGUID-ness for interpreted files */
int i;
int iterlimit = EAI_ITERLIMIT;
+ proc_t p = vfs_context_proc(imgp->ip_vfs_context);
error = execargs_alloc(imgp);
if (error)
*/
error = exec_save_path(imgp, imgp->ip_user_fname, imgp->ip_seg);
if (error) {
- goto bad;
+ goto bad_notrans;
}
DTRACE_PROC1(exec, uintptr_t, imgp->ip_strings);
again:
error = namei(&nd);
if (error)
- goto bad;
+ goto bad_notrans;
imgp->ip_ndp = &nd; /* successful namei(); call nameidone() later */
imgp->ip_vp = nd.ni_vp; /* if set, need to vnode_put() at some point */
+ proc_transstart(p, 0);
+
error = exec_check_permissions(imgp);
if (error)
goto bad;
nd.ni_segflg = UIO_SYSSPACE32;
nd.ni_dirp = CAST_USER_ADDR_T(imgp->ip_interp_name);
+ proc_transend(p, 0);
goto again;
default:
}
bad:
+ proc_transend(p, 0);
+
+bad_notrans:
if (imgp->ip_strings)
execargs_free(imgp);
if (imgp->ip_ndp)
if (!(uthread->uu_flag & UT_VFORK)) {
if (task != kernel_task) {
proc_lock(p);
- numthreads = get_task_numacts(task);
+ numthreads = get_task_numactivethreads(task);
if (numthreads <= 0 ) {
proc_unlock(p);
kauth_cred_unref(&context.vc_ucred);
}
#endif
- proc_transstart(p, 0);
error = exec_activate_image(imgp);
- proc_transend(p, 0);
kauth_cred_unref(&context.vc_ucred);
kauth_cred_t cred = vfs_context_ucred(imgp->ip_vfs_context);
proc_t p = vfs_context_proc(imgp->ip_vfs_context);
int i;
- int is_member = 0;
+ int leave_sugid_clear = 0;
int error = 0;
struct vnode *dev_null = NULLVP;
-#if CONFIG_MACF
- kauth_cred_t my_cred;
-#endif
-
#if CONFIG_MACF
int mac_transition;
- mac_transition = mac_cred_check_label_update_execve(imgp->ip_vfs_context, imgp->ip_vp,
- imgp->ip_scriptlabelp, imgp->ip_execlabelp, p);
+
+ /*
+ * Determine whether a call to update the MAC label will result in the
+ * credential changing.
+ *
+ * Note: MAC policies which do not actually end up modifying
+ * the label subsequently are strongly encouraged to
+ * return 0 for this check, since a non-zero answer will
+ * slow down the exec fast path for normal binaries.
+ */
+ mac_transition = mac_cred_check_label_update_execve(
+ imgp->ip_vfs_context,
+ imgp->ip_vp,
+ imgp->ip_scriptlabelp,
+ imgp->ip_execlabelp, p);
#endif
OSBitAndAtomic(~((uint32_t)P_SUGID), (UInt32 *)&p->p_flag);
/*
* Order of the following is important; group checks must go last,
- * as we use the success of the 'is_member' check combined with the
+ * as we use the success of the 'ismember' check combined with the
* failure of the explicit match to indicate that we will be setting
* the egid of the process even though the new process did not
* require VSUID/VSGID bits in order for it to set the new group as
*/
if (((imgp->ip_origvattr->va_mode & VSUID) != 0 &&
kauth_cred_getuid(cred) != imgp->ip_origvattr->va_uid) ||
-#if CONFIG_MACF
- mac_transition || /* A policy wants to transition */
-#endif
((imgp->ip_origvattr->va_mode & VSGID) != 0 &&
- ((kauth_cred_ismember_gid(cred, imgp->ip_origvattr->va_gid, &is_member) || !is_member) ||
+ ((kauth_cred_ismember_gid(cred, imgp->ip_origvattr->va_gid, &leave_sugid_clear) || !leave_sugid_clear) ||
(cred->cr_gid != imgp->ip_origvattr->va_gid)))) {
+#if CONFIG_MACF
+/* label for MAC transition and neither VSUID nor VSGID */
+handle_mac_transition:
+#endif
+
/*
* Replace the credential with a copy of itself if euid or
* egid change.
#if CONFIG_MACF
/*
- * XXXMAC: In FreeBSD, we set P_SUGID on a MAC transition
- * to protect against debuggers being attached by an
- * insufficiently privileged process onto the result of
- * a transition to a more privileged credential. This is
- * too conservative on FreeBSD, but we need to do
- * something similar here, or risk vulnerability.
- *
- * Before we make the call into the MAC policies, get a new
+ * If a policy has indicated that it will transition the label,
+ * before making the call into the MAC policies, get a new
* duplicate credential, so they can modify it without
* modifying any others sharing it.
*/
- if (mac_transition && !imgp->ip_no_trans) {
- kauth_proc_label_update_execve(p,
- imgp->ip_vfs_context,
- imgp->ip_vp,
- imgp->ip_scriptlabelp, imgp->ip_execlabelp);
+ if (mac_transition) {
+ kauth_cred_t my_cred;
+ if (kauth_proc_label_update_execve(p,
+ imgp->ip_vfs_context,
+ imgp->ip_vp,
+ imgp->ip_scriptlabelp,
+ imgp->ip_execlabelp)) {
+ /*
+ * If updating the MAC label resulted in a
+ * disjoint credential, flag that we need to
+ * set the P_SUGID bit. This protects
+ * against debuggers being attached by an
+ * insufficiently privileged process onto the
+ * result of a transition to a more privileged
+ * credential.
+ */
+ leave_sugid_clear = 0;
+ }
my_cred = kauth_cred_proc_ref(p);
mac_task_label_update_cred(my_cred, p->task);
kauth_cred_unref(&my_cred);
}
-#endif
+#endif /* CONFIG_MACF */
+
/*
* Have mach reset the task and thread ports.
* We don't want anyone who had the ports before
}
/*
- * If 'is_member' is non-zero, then we passed the VSUID and
- * MACF checks, and successfully determined that the previous
- * cred was a member of the VSGID group, but that it was not
- * the default at the time of the execve. So we don't set the
- * P_SUGID on the basis of simply running this code.
+ * If 'leave_sugid_clear' is non-zero, then we passed the
+ * VSUID and MACF checks, and successfully determined that
+ * the previous cred was a member of the VSGID group, but
+ * that it was not the default at the time of the execve,
+ * and that the post-labelling credential was not disjoint.
+ * So we don't set the P_SUGID on the basis of simply
+ * running this code.
*/
- if (!is_member)
+ if (!leave_sugid_clear)
OSBitOrAtomic(P_SUGID, (UInt32 *)&p->p_flag);
/* Cache the vnode for /dev/null the first time around */
dev_null = NULLVP;
}
}
+#if CONFIG_MACF
+ else {
+ /*
+ * We are here because we were told that the MAC label will
+ * be transitioned, and the binary is not VSUID or VSGID; to
+ * deal with this case, we could either duplicate a lot of
+ * code, or we can indicate we want to default the P_SUGID
+ * bit clear and jump back up.
+ */
+ if (mac_transition) {
+ leave_sugid_clear = 1;
+ goto handle_mac_transition;
+ }
+ }
+#endif /* CONFIG_MACF */
/*
* Implement the semantic where the effective user and group become
*/
p->p_ucred = kauth_cred_setsvuidgid(p->p_ucred, kauth_cred_getuid(p->p_ucred), p->p_ucred->cr_gid);
- /* XXX Obsolete; security token should not be separate from cred */
+ /* Update the process' identity version and set the security token */
+ p->p_idversion++;
set_security_token(p);
return(error);