Path: utzoo!utgpu!jarvis.csri.toronto.edu!torsqnt!sickkids!mark From: mark@sickkids.UUCP (Mark Bartelt) Newsgroups: comp.bugs.4bsd Subject: /bin/sh may loop if SIGSEGV is blocked at startup Message-ID: <393@sickkids.UUCP> Date: 28 Feb 90 20:11:56 GMT Reply-To: mark@sickkids.UUCP (Mark Bartelt) Organization: Hospital for Sick Children, Toronto Lines: 67 If a process with SIGSEGV blocked spawns /bin/sh as a subprocess, the shell may loop forever. The following is likely to exhibit the problem: (1) Create the following program called, say, "x": #include main() { sigblock(sigmask(SIGSEGV)); system("echo foo"); } (2) Define an environment variable with a gigantically long name, then run the program (in the background, so it's easier to kill things!): $ FOO='Some enormously long string of characters. I have no idea how long it needs to be. Several thousand is certainly sufficient; a couple hundred is probably adequate.' $ export FOO $ x & (3) Take a look at things with "ps". You should see something like: 16869 01 R 2:37 sh -c echo foo Watch the CPU time of the process accumulate without bound. What's happening is that if the environment is sufficiently large, then when the shell attempts to build an environment to pass to execve(), it eventually runs past the end of valid memory. Not a problem (it thinks), since it's catching SIGSEGV, so that it can just do an sbrk() and return from the signal catching routine. But if SIGSEGV is blocked (note that under 4.3bsd the signal mask is inherited across fork() and exec()), then when the kernel takes the fault and invokes trap(), sendsig() never gets called. So when the kernel returns from the trap, the instruction which caused the fault gets executed again, causing another fault, and the whole thing continues, forever. The fix is trivial. In fault.c, at the beginning of stdsigs(), add the following: sigsetmask(sigblock(0)&~sigmask(MEMF)); You also have to add "#include " so that the sigmask() macro is defined. Once you do this, though, the compiler is unhappy with another statement, complaining that ... operands of & have incompatible types ... so you have to make one other change: In ignsig(), change IF (s=signal(i=n,1)&01)==0 to IF (s=(int)signal(i=n,1)&01)==0 It may well be that the more sensible change might be to make the first statement in stdsigs() ... sigsetmask(sigblock(0)&~(sigmask(INTR)|sigmask(MEMF)|sigmask(ALARM))); ... but I haven't given any thought to what the implications of doing so might be. (And why is it catching SIGALRM anyway?) Mark Bartelt INTERNET: mark@sickkids.toronto.edu Hospital for Sick Children, Toronto mark@sickkids.utoronto.ca 416/598-6442 UUCP: {utzoo,decvax}!sickkids!mark