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 ============