]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/kern/kern_exec.c
xnu-1228.15.4.tar.gz
[apple/xnu.git] / bsd / kern / kern_exec.c
index 6b2702d7b63e0b9475ccd52f5b2d6b79ba6c394d..71dd14c128373537f1cbe708c4737ca36eb63f5d 100644 (file)
@@ -893,9 +893,6 @@ grade:
                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.
         */
@@ -919,8 +916,6 @@ grade:
         */
        error = exec_handle_sugid(imgp);
 
-       proc_knote(p, NOTE_EXEC);
-
        if (!vfexec && (p->p_lflag & P_LTRACED))
                psignal(p, SIGTRAP);
 
@@ -928,6 +923,13 @@ grade:
                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,
@@ -1127,6 +1129,8 @@ grade:
        }
 
 badtoolate:
+       proc_knote(p, NOTE_EXEC);
+
        if (vfexec) {
                task_deallocate(new_task);
                thread_deallocate(thread);
@@ -1196,6 +1200,7 @@ exec_activate_image(struct image_params *imgp)
        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)
@@ -1209,7 +1214,7 @@ exec_activate_image(struct image_params *imgp)
         */
        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);
@@ -1220,10 +1225,12 @@ exec_activate_image(struct image_params *imgp)
 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;
@@ -1292,6 +1299,7 @@ encapsulated_binary:
 
                        nd.ni_segflg = UIO_SYSSPACE32;
                        nd.ni_dirp = CAST_USER_ADDR_T(imgp->ip_interp_name);
+                       proc_transend(p, 0);
                        goto again;
 
                default:
@@ -1310,6 +1318,9 @@ encapsulated_binary:
        }
 
 bad:
+       proc_transend(p, 0);
+
+bad_notrans:
        if (imgp->ip_strings)
                execargs_free(imgp);
        if (imgp->ip_ndp)
@@ -1949,7 +1960,7 @@ __mac_execve(proc_t p, struct __mac_execve_args *uap, register_t *retval)
        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);
@@ -1974,9 +1985,7 @@ __mac_execve(proc_t p, struct __mac_execve_args *uap, register_t *retval)
        }
 #endif
 
-       proc_transstart(p, 0);
        error = exec_activate_image(imgp);
-       proc_transend(p, 0);
 
        kauth_cred_unref(&context.vc_ucred);
        
@@ -2534,24 +2543,33 @@ exec_handle_sugid(struct image_params *imgp)
        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
@@ -2565,13 +2583,15 @@ exec_handle_sugid(struct image_params *imgp)
         */
        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.
@@ -2597,28 +2617,36 @@ exec_handle_sugid(struct image_params *imgp)
 
 #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
@@ -2631,13 +2659,15 @@ exec_handle_sugid(struct image_params *imgp)
                }
 
                /*
-                * 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 */
@@ -2704,6 +2734,21 @@ exec_handle_sugid(struct image_params *imgp)
                        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
@@ -2711,7 +2756,8 @@ exec_handle_sugid(struct image_params *imgp)
         */
        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);