Subject: setuid processes can not be suspended with ^Z (#425)
Index:	sys/kern_sig.c 2.11BSD

Description:
	1. Setuid programs run by a user other than root can not be
	suspended even though the 'real userid' of those programs is
	that of the user.

	2. The SDETACH bit in the process table entry was unused but
	needlessly being set and propagated.

Repeat-By:
	1. The problem was spotted when running the new 'crontab' command.

	NOTE: the bug is not in crontab - it is a kernel bug.

	After 'crontab' would start up 'vi' to edit the crontab file
	use of ^Z to suspend the processes would only stop 'vi' and *not*
	the 'crontab' process.  It would appear that the terminal was
	"hung".  Hitting a ^C would interrupt and kill both processes
	leaving a file in /tmp.

	crontab -e
	^Z

	Unless you are running as "root" the terminal will appear to
	go dead on you.  If you are running as root the ^Z will behave
	as expected.

Fix:
	The problem is that the check for a process being able to post
	a signal to another process only looked at the "effective uid"
	of the two processes.  A "setuid" program however will have
	an "effective uid" _different_ (in almost all cases) than the
	"real uid".

	'crontab' is setuid to 'root' (uid 0).  When a user runs the
	command "crontab -e" to edit a cron file the chain of processes
	looks like this (using my user id as an example):

			csh   (euid=10, ruid=10)
			crontab (euid=0, ruid=10)
			vi     (euid=10, ruid=10)

	when a ^Z is typed the csh process sends a SIGTSTP signal to
	the process group (which contains 'crontab' and 'vi').   The
	OLD check for permission to send a signal used only the 'euid'
	so only the 'vi' process would be stopped.

	The fix was to borrow some more code from 4.4BSD to augment the
	signal posting permission check.  If _either_ the real _or_
	effective uids match permission is granted to send the signal.

	2.  The SDETACH ("detacted") flag bit was still being set and
	passed along during child process creation.  This bit was left
	over from the pre-4.2BSD era when the TTY driver relied on 
	the bit to detect background processes that were not permitted
	access to the tty.  In 4.3BSD the check was commented out and
	later on in 4.4BSD it was completely removed.  It is now gone
	from 2.11BSD as well.  The only thing in the entire system that
	referenced SDETACH (aside from the nonfunctional 2.9BSD 'crash'
	program) was the "ps" process.  That reference was removed.

	The 'spgrp()' routine in kern_proc.c is gone. Its purpose was
	to set SDETACH and clear pending signal bits for descendant 
	processes.   Since SDETACH no longer exists and the kernel has 
	changed sufficiently over time to remove the need to clear pending
	signal bits the entire 'spgrp()' routine (and the single use of it
	in kern_exit.c) was removed.

	To install this update cut where indicated and save to a file 
	(/tmp/425).  Then:

		patch -p0 < /tmp/425
		cd /sys/YOUR_KERNEL
		make clean
		make
		mv /unix /ounix
		mv /netnix /onetnix
		mv unix netnix /
		chmod 744 /unix /netnix
		reboot

	(omit the 'netnix' use if you do not have a networking kernel)

	After that you may wish to compile a 'GENERIC' kernel to keep 
	around for emergencies:

		cd /sys/GENERIC
		make clean
		make
		mv unix /genunix
		chmod 744 /genunix

	There is no need at this time to recompile 'ps' unless you
	want to.  The only change was to remove the use of 'SDETACH' in
	one place.  Since that bit will never be set 'ps' will behave
	as it always has because the proc structure has not changed in
	size or organization.

	As always this and previous updates to 2.11BSD are available via
	anonymous FTP to either FTP.GD-ISO.COM or MOE.2BSD.COM in the
	directory /pub/2.11BSD.
-----------------------------cut here-----------------------
*** /usr/src/sys/sys/kern_sig.c.old	Fri Nov 28 16:19:54 1997
--- /usr/src/sys/sys/kern_sig.c	Wed Aug 11 19:38:29 1999
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_sig.c	1.9 (2.11BSD GTE) 1997/11/28
   */
  
  #include "param.h"
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_sig.c	1.10 (2.11BSD) 1999/8/10
   */
  
  #include "param.h"
***************
*** 19,24 ****
--- 19,58 ----
  extern	char	sigprop[];	/* XXX - defined in kern_sig2.c */
  
  /*
+  * Can the current process send the signal `signum' to process `q'?
+  * This is complicated by the need to access the `real uid' of `q'.
+  * The 'real uid' is in the u area and `q' may be (but usually is not) swapped 
+  * out.  Use the routine `fill_from_u' which the sysctl() call uses.  See the
+  * notes in kern_sysctl.c
+  *
+  * The previous checks for a process to post a signal to another process
+  * checked _only_ the effective userid.  With the implementation of the
+  * 'saved id' feature and the ability of a setuid program to assume either
+  * uid that check was inadequate.
+  *
+  * The 'c'urrent process is allowed to send a signal to a 't'arget process if 
+  * 1) either the real or effective user ids match OR 2) if the signal is 
+  * SIGCONT and the target process is a descendant of the current process
+ */
+ cansignal(q,signum)
+ 	register struct proc *q;
+ 	int	signum;
+ 	{
+ 	register struct proc *curp = u.u_procp;
+ 	uid_t	ruid;
+ 
+ 	fill_from_u(q, &ruid, NULL, NULL);	/* XXX */
+ 	if	(curp->p_uid == 0 ||		/* c effective root */
+ 		 u.u_ruid == ruid ||		/* c real = t real */
+ 		 curp->p_uid == ruid ||		/* c effective = t real */
+ 		 u.u_ruid == q->p_uid ||	/* c real = t effective */
+ 		 curp->p_uid == q->p_uid ||	/* c effective = t effective */
+ 		 (signum == SIGCONT && inferior(q)))
+ 		return(1);
+ 	return(0);
+ 	}
+ 
+ /*
   * 4.3 Compatibility
   */
  sigvec()
***************
*** 195,207 ****
  			error = ESRCH;
  			goto out;
  		}
! 		/*
! 		 * Fix to allow a non-root process to send SIGCONT to
! 		 * one of its own decendants which happens to be running
! 		 * with a different uid.
! 		 */
! 		if (u.u_uid && u.u_uid != p->p_uid &&
! 		    (uap->signo != SIGCONT || !inferior(p)))
  			error = EPERM;
  		else if (uap->signo)
  			psignal(p, uap->signo);
--- 229,235 ----
  			error = ESRCH;
  			goto out;
  		}
! 		if (!cansignal(p))
  			error = EPERM;
  		else if (uap->signo)
  			psignal(p, uap->signo);
***************
*** 257,264 ****
  		if ((p->p_pgrp != pgrp && !all) || p->p_ppid == 0 ||
  		    (p->p_flag&SSYS) || (all && p == u.u_procp))
  			continue;
! 		if (u.u_uid != 0 && u.u_uid != p->p_uid &&
! 		    (signo != SIGCONT || !inferior(p))) {
  			if (!all)
  				error = EPERM;
  			continue;
--- 285,291 ----
  		if ((p->p_pgrp != pgrp && !all) || p->p_ppid == 0 ||
  		    (p->p_flag&SSYS) || (all && p == u.u_procp))
  			continue;
! 		if (!cansignal(p)) {
  			if (!all)
  				error = EPERM;
  			continue;
*** /usr/src/sys/sys/kern_sysctl.c.old	Thu Apr 29 20:18:27 1999
--- /usr/src/sys/sys/kern_sysctl.c	Wed Aug 11 19:40:36 1999
***************
*** 33,39 ****
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   *
!  *	@(#)kern_sysctl.c	8.4.10 (2.11BSD) 1999/4/29
   */
  
  /*
--- 33,39 ----
   * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   * SUCH DAMAGE.
   *
!  *	@(#)kern_sysctl.c	8.4.11 (2.11BSD) 1999/8/11
   */
  
  /*
***************
*** 979,988 ****
  
  	if	(p->p_stat == SZOMB)
  		{
! 		*rup = (uid_t)-2;
! 		*ttp = NULL;
! 		*tdp = NODEV;
! 		return;
  		}
  	if	(p->p_flag & SLOAD)
  		{
--- 979,988 ----
  
  	if	(p->p_stat == SZOMB)
  		{
! 		ruid = (uid_t)-2;
! 		ttyp = NULL;
! 		ttyd = NODEV;
! 		goto out;
  		}
  	if	(p->p_flag & SLOAD)
  		{
***************
*** 1021,1027 ****
  		brelse(bp);
  		u.u_error = 0;		/* XXX */
  		}
! 	*rup = ruid;
! 	*ttp = ttyp;
! 	*tdp = ttyd;
  	}
--- 1021,1031 ----
  		brelse(bp);
  		u.u_error = 0;		/* XXX */
  		}
! out:
! 	if	(rup)
! 		*rup = ruid;
! 	if	(ttp)
! 		*ttp = ttyp;
! 	if	(tdp)
! 		*tdp = ttyd;
  	}
*** /usr/src/sys/sys/kern_proc.c.old	Fri Mar 12 19:41:36 1993
--- /usr/src/sys/sys/kern_proc.c	Fri Aug 13 18:55:03 1999
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_proc.c	2.0 (2.11BSD GTE) 3/12/93
   */
  
  #include "param.h"
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_proc.c	2.1 (2.11BSD) 1999/8/11
   */
  
  #include "param.h"
***************
*** 10,45 ****
  #include "user.h"
  #include "proc.h"
  #include "systm.h"
- 
- #define bit(a)	(1L<<(a-1))
- 
- /*
-  * This version is not the 4.XBSD spgrp() for a couple of very good reasons.
-  * The 4.2 one didn't work and the 4.3 one requires the child pointers in
-  * the proc structure.  This one is pretty simple and loses *big* for several
-  * levels of processes since it recursively handles children of children.
-  * We don't bother to return the number of processes found as 4.X does since
-  * no one ever uses it.  Note, if you have enough processes and unlimited
-  * processes per user, someone can crash your system by running you out of
-  * kernel stack space.  An alternative method would be to run inferior
-  * against every process in the proc structure.  This method is probably
-  * faster for most systems.
-  */
- spgrp(top)
- 	register struct proc *top;
- {
- 	register struct proc *p;
- 
- 	top->p_sig &=
- 		~(sigmask(SIGTSTP)|sigmask(SIGTTIN)|sigmask(SIGTTOU));
- 	top->p_flag |= SDETACH;
- 	for (p = allproc; p; p = p->p_nxt)
- 		if (p->p_pptr == top)
- 			spgrp(p);
- 	for (p = zombproc; p; p = p->p_nxt)
- 		if (p->p_pptr == top)
- 			spgrp(p);
- }
  
  /*
   * Is p an inferior of the current process?
--- 10,15 ----
*** /usr/src/sys/sys/kern_exit.c.old	Tue Feb 23 22:06:16 1999
--- /usr/src/sys/sys/kern_exit.c	Fri Aug 13 18:55:30 1999
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_exit.c	2.3 (2.11BSD) 1999/2/23
   */
  
  #include "param.h"
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_exit.c	2.4 (2.11BSD) 1999/8/11
   */
  
  #include "param.h"
***************
*** 142,153 ****
  					psignal(q, SIGHUP);
  					psignal(q, SIGCONT);
  				}
- 				/*
- 				 * Protect this process from future
- 				 * tty signals, clear TSTP/TTIN/TTOU if pending.
- 				 * 2.11 also sets SDETACH bit.
- 				 */
- 				spgrp(q);
  			}
  		if (!doingzomb) {
  			doingzomb = 1;
--- 142,147 ----
*** /usr/src/sys/sys/kern_fork.c.old	Fri Nov 28 15:56:12 1997
--- /usr/src/sys/sys/kern_fork.c	Wed Aug 11 20:11:12 1999
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_fork.c	1.5 (2.11BSD GTE) 1997/11/28
   */
  
  #include "param.h"
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)kern_fork.c	1.6 (2.11BSD) 1999/8/11
   */
  
  #include "param.h"
***************
*** 163,169 ****
  #endif
  	rpp->p_stat = SIDL;
  	rpp->p_realtimer.it_value = 0;
! 	rpp->p_flag = SLOAD | (rip->p_flag & SDETACH);
  	rpp->p_uid = rip->p_uid;
  	rpp->p_pgrp = rip->p_pgrp;
  	rpp->p_nice = rip->p_nice;
--- 163,169 ----
  #endif
  	rpp->p_stat = SIDL;
  	rpp->p_realtimer.it_value = 0;
! 	rpp->p_flag = SLOAD;
  	rpp->p_uid = rip->p_uid;
  	rpp->p_pgrp = rip->p_pgrp;
  	rpp->p_nice = rip->p_nice;
*** /usr/src/sys/h/proc.h.old	Tue Sep  2 21:50:34 1997
--- /usr/src/sys/h/proc.h	Wed Aug 11 20:12:28 1999
***************
*** 3,9 ****
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)proc.h	1.3 (2.11BSD GTE) 1997/8/28
   */
  
  #ifndef	_SYS_PROC_H_
--- 3,9 ----
   * All rights reserved.  The Berkeley software License Agreement
   * specifies the terms and conditions for redistribution.
   *
!  *	@(#)proc.h	1.4 (2.11BSD) 1999/8/11
   */
  
  #ifndef	_SYS_PROC_H_
***************
*** 123,129 ****
  #define	SVFPRNT		0x0200	/* parent in vfork, waiting for child */
  #define	SVFDONE		0x0400	/* parent has released child in vfork */
  	/*		0x0800	/* unused */
! #define	SDETACH		0x1000	/* detached inherited by init */
  #define	P_NOCLDSTOP	0x2000	/* no SIGCHLD signal to parent */
  #define	SSEL		0x4000	/* selecting; wakeup/waiting danger */
  	/*		0x8000	/* unused */
--- 123,129 ----
  #define	SVFPRNT		0x0200	/* parent in vfork, waiting for child */
  #define	SVFDONE		0x0400	/* parent has released child in vfork */
  	/*		0x0800	/* unused */
! 	/*		0x1000	/* used to be SDETACH */
  #define	P_NOCLDSTOP	0x2000	/* no SIGCHLD signal to parent */
  #define	SSEL		0x4000	/* selecting; wakeup/waiting danger */
  	/*		0x8000	/* unused */
*** /usr/src/bin/ps.c.old	Tue Dec 16 20:37:03 1997
--- /usr/src/bin/ps.c	Wed Aug 11 20:30:45 1999
***************
*** 1,4 ****
--- 1,7 ----
  /*
+  *	1999/8/11 - Remove reference to SDETACH.  It was removed from the kernel
+  *		    (finally) because it was not needed.
+  *
   *	1997/12/16 - Fix coredump when processing -U.
   *
   *	1996/11/16 - Move 'psdatabase' in /var/run.
***************
*** 252,258 ****
  			if (procp->p_pgrp == 0 && xflg == 0)
  				continue;
  			/* skip group leaders on a tty unless -g, -x, or -t.. */
! 			if (!tptr && !gflg && !xflg && procp->p_ppid == 1 && (procp->p_flag & SDETACH) == 0)
  				continue;
  			/* -g also skips those where **argv is "-" - see savcom */
  			puid = procp->p_uid;
--- 255,261 ----
  			if (procp->p_pgrp == 0 && xflg == 0)
  				continue;
  			/* skip group leaders on a tty unless -g, -x, or -t.. */
! 			if (!tptr && !gflg && !xflg && procp->p_ppid == 1)
  				continue;
  			/* -g also skips those where **argv is "-" - see savcom */
  			puid = procp->p_uid;
*** /usr/src/new/crash/crashsubs.c.old	Tue Sep  2 21:57:00 1997
--- /usr/src/new/crash/crashsubs.c	Wed Aug 11 20:43:39 1999
***************
*** 1,6 ****
--- 1,9 ----
  /*
   *	U N I X   2 . 9 B S D   C R A S H   A N A L Y Z E R   S U B S
   *
+  * Another proc struct flag went away.  Program still doesn't run or
+  * compile ;-(  1999/8/11
+  *
   * The proc structure flags cleaned up.  This program still doesn't run
   * (or compile) under the current system.  1997/9/2
   *
***************
*** 575,581 ****
  procflg(flgs)
  int *flgs;
  {
! #define	PROC_FLAGS "\0\1SLOAD\2SSYS\3SLOCK\4SSWAP\5STRC\6SWTED\7SULOCK\11SVFORK\12SVFPRNT\13SVFDONE\15SDETACH\16P_NOCLDSTOP\17SSEL"
  	printb((u_long) *flgs, PROC_FLAGS);
  }
  
--- 578,584 ----
  procflg(flgs)
  int *flgs;
  {
! #define	PROC_FLAGS "\0\1SLOAD\2SSYS\3SLOCK\4SSWAP\5STRC\6SWTED\7SULOCK\11SVFORK\12SVFPRNT\13SVFDONE\16P_NOCLDSTOP\17SSEL"
  	printb((u_long) *flgs, PROC_FLAGS);
  }
  
*** /VERSION.old	Tue Aug 10 19:56:45 1999
--- /VERSION	Fri Aug 13 19:18:48 1999
***************
*** 1,5 ****
! Current Patch Level: 424
! Date: August 10, 1999
  
  2.11 BSD
  ============
--- 1,5 ----
! Current Patch Level: 425
! Date: August 13, 1999
  
  2.11 BSD
  ============
