fred@nmtvax.UUCP (04/28/84)
Index: /sys/sys/kern_prot.c 4.2 BSD Vax Description: There is a bug with signals and setuid in 4.2 bsd. This may have existed in 4.1, but I am not sure since I don't have source readily available at the moment. What happens is when a process first starts up p_uid in the process structure is set to the effective uid. Then if you do a setuid (or setreuid), it sets p_uid to your REAL user id. If you them send a signal to yourself, the system searches for a process with the same pid as yours and has a uid equal to your effective uid to send the signal requested and fails. Repeat-By: The following is a small program to show the bug run it on your machine. It should be run by a normal(non-root) user and made set uid to someone else. The second kill will fail with no such process. #include <signal.h> #include <stdio.h> #include <errno.h> int tsig(); main() { int euid,uid; signal(SIGALRM,tsig); printf("uid: %d,euid: %d\n",getuid(),geteuid()); if(kill(0,SIGALRM) < 0) perror("kill"); setreuid(-1,-1); printf("uid: %d,euid: %d\n",getuid(),geteuid()); if(kill(0,SIGALRM) < 0) perror("kill"); } tsig() { printf("Caught signal.\n"); } Fix: The fix is very simple. Just change setreuid() in /sys/sys/kern_prot.c so that the p_uid is set to the effective uid rather than the real user id. The following is a diff of what needs to be corrected. *** kern_prot.c Fri Apr 27 19:34:16 1984 --- kern_prot.old Tue Feb 28 11:53:20 1984 *************** *** 133,139 qstart(getquota(ruid, 0, 0)); } #endif ! u.u_procp->p_uid = euid; u.u_ruid = ruid; u.u_uid = euid; } --- 133,139 ----- qstart(getquota(ruid, 0, 0)); } #endif ! u.u_procp->p_uid = ruid; u.u_ruid = ruid; u.u_uid = euid; } -- Fred Romelfanger Computer Science Department New Mexico Tech ..!ucbvax!unmvax!nmtvax!fred (uucp) ..!cmcl2!lanl-a!nmtvax!fred (uucp) fred.nmt@rand-relay (arpa) fred@nmt (CSnet)
matt@oddjob.UChicago.UUCP (Matt Crawford) (04/30/84)
While checking out nmtvax!fred's report, I found another... Subject: sending SIGCONT to child proc not *always* allowed Index: sys/kern_sig.c 4.2BSD Description: The manual for kill(2) states "...the signal SIGCONT ... may always be sent to any child or grandchild of the current process.", but this is true only if the signal is sent to the entire process group via kill(0, SIGCONT) or killpg(). Repeat-By: Compile the following programs and make "child" suid to some other user than "parent", then run parent (not as root). ------------parent.c----------- #include <stdio.h> #include <errno.h> #include <signal.h> main() { int pid; if ( pid = fork() ) { sleep(5); if ( kill(pid, SIGCONT) ) perror("CONT"); fprintf(stderr, "Parent exitting.\n"); } else { execv("child", 0); fprintf(stderr, "Can't exec.\n"); } } ------------child.c----------- #include <stdio.h> #include <signal.h> main() { fprintf(stderr, "Child started.\n"); kill(getpid(), SIGSTOP); fprintf(stderr, "Continued OK.\n"); } ------------------------------- Fix: This could be intended to allow suid processes to protect themselves from SIGCONT by using setpgrp(0, getpid()), but I don't see why... If this is not a "feature" then the following >>untested<< change to kill1() in sys/kern_sig.c should fix it. Change: ---------------------- if (who > 0 && !ispgrp) { p = pfind(who); if (p == 0) return (ESRCH); * if (u.u_uid && u.u_uid != p->p_uid) return (EPERM); ---------------------- to: ********************** if (who > 0 && !ispgrp) { p = pfind(who); if (p == 0) return (ESRCH); * if (u.u_uid && u.u_uid != p->p_uid && * (signo != SIGCONT || !inferior(p))) return (EPERM); *********************************