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 <thorpej@netbsd.org>
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 ----
