Synopsis: race between sugid-exec and ptrace(2)
NetBSD versions: 1.4, 1.4.1, 1.4.2, 1.4.3
Thanks to: Jason Thorpe <[email protected]>
Reported in NetBSD Security Advisory: NetBSD-SA2001-009

Index: sys/kern/exec_script.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/exec_script.c,v
retrieving revision 1.20.2.1
diff -p -p -c -r1.20.2.1 exec_script.c
*** sys/kern/exec_script.c      2000/02/01 23:11:20     1.20.2.1
--- sys/kern/exec_script.c      2001/07/16 09:06:10
*************** exec_script_makecmds(p, epp)
*** 146,153 ****
 check_shell:
 #ifdef SETUIDSCRIPTS
       /*
!        * MNT_NOSUID and STRC are already taken care of by check_exec,
!        * so we don't need to worry about them now or later.
        */
       script_sbits = epp->ep_vap->va_mode & (S_ISUID | S_ISGID);
       if (script_sbits != 0) {
--- 146,154 ----
 check_shell:
 #ifdef SETUIDSCRIPTS
       /*
!        * MNT_NOSUID has already taken care of by check_exec,
!        * so we don't need to worry about it now or later.  We
!        * will need to check P_TRACED later, however.
        */
       script_sbits = epp->ep_vap->va_mode & (S_ISUID | S_ISGID);
       if (script_sbits != 0) {
*************** check_shell:
*** 260,266 ****
 #ifdef SETUIDSCRIPTS
               /*
                * set thing up so that set-id scripts will be
!                * handled appropriately
                */
               epp->ep_vap->va_mode |= script_sbits;
               if (script_sbits & S_ISUID)
--- 261,269 ----
 #ifdef SETUIDSCRIPTS
               /*
                * set thing up so that set-id scripts will be
!                * handled appropriately.  P_TRACED will be
!                * checked later when the shell is actually
!                * exec'd.
                */
               epp->ep_vap->va_mode |= script_sbits;
               if (script_sbits & S_ISUID)
Index: sys/kern/kern_exec.c
===================================================================
RCS file: /cvsroot/syssrc/sys/kern/kern_exec.c,v
retrieving revision 1.100.2.3
diff -p -p -c -r1.100.2.3 kern_exec.c
*** sys/kern/kern_exec.c        2000/02/01 22:55:07     1.100.2.3
--- sys/kern/kern_exec.c        2001/07/16 09:06:11
*************** check_exec(p, epp)
*** 123,129 ****
               error = EACCES;
               goto bad1;
       }
!       if ((vp->v_mount->mnt_flag & MNT_NOSUID) || (p->p_flag & P_TRACED))
               epp->ep_vap->va_mode &= ~(S_ISUID | S_ISGID);

       /* try to open it */
--- 123,129 ----
               error = EACCES;
               goto bad1;
       }
!       if (vp->v_mount->mnt_flag & MNT_NOSUID)
               epp->ep_vap->va_mode &= ~(S_ISUID | S_ISGID);

       /* try to open it */
*************** sys_execve(p, v, retval)
*** 444,453 ****

       /*
        * deal with set[ug]id.
!        * MNT_NOEXEC and P_TRACED have already been used to disable s[ug]id.
        */
!       if (((attr.va_mode & S_ISUID) != 0 && p->p_ucred->cr_uid != attr.va_uid)
!        || ((attr.va_mode & S_ISGID) != 0 && p->p_ucred->cr_gid != attr.va_gid)){
               p->p_ucred = crcopy(cred);
 #ifdef KTRACE
               /*
--- 444,462 ----

       /*
        * deal with set[ug]id.
!        * MNT_NOSUID has already been used to disable s[ug]id.
        */
!       if ((p->p_flag & P_TRACED) == 0 &&
!           (((attr.va_mode & S_ISUID) != 0 &&
!             p->p_ucred->cr_uid != attr.va_uid) ||
!            ((attr.va_mode & S_ISGID) != 0 &&
!             p->p_ucred->cr_gid != attr.va_gid))) {
!               /*
!                * Mark the process as SUGID before we do
!                * anything that might block.
!                */
!               p->p_flag |= P_SUGID;
!
               p->p_ucred = crcopy(cred);
 #ifdef KTRACE
               /*
*************** sys_execve(p, v, retval)
*** 461,467 ****
                       p->p_ucred->cr_uid = attr.va_uid;
               if (attr.va_mode & S_ISGID)
                       p->p_ucred->cr_gid = attr.va_gid;
-               p->p_flag |= P_SUGID;
       } else
               p->p_flag &= ~P_SUGID;
       p->p_cred->p_svuid = p->p_ucred->cr_uid;
--- 470,475 ----