aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWilly Tarreau <w@1wt.eu>2009-06-07 11:48:19 +0200
committerWilly Tarreau <w@1wt.eu>2009-06-07 21:37:00 +0200
commitbdf30ce4294bb5fc6d5e6e8001557ac1b0fc7968 (patch)
treeb74a47b4d81295dc79ed6b1b6911c46f70e2fe37
parent4871441ddf930f5e5651af50f6b42645fbbf9638 (diff)
downloadlinux-2.4-bdf30ce4294bb5fc6d5e6e8001557ac1b0fc7968.tar.gz
exit_notify: fix regression uncovered by the CAP_KILL fix
Patch 3551c6a671cd7aa17ef6254276000ab8f3171708 silently uncovered a bug waiting to strike. The problem is that request_module() does not set the modprobe task's exit_signal and does not expect it to send a signal when it dies, as it does a waitpid(pid, NULL, __WCLONE). During exit_notify(), exit signal 0 was not changed when modprobe exited because modprobe had CAP_KILL set ! Since we removed that test, modprobe sees its exit_signal assigned to SIGCHLD, which does not please its parent and leaves modprobe zombies everywhere. The correct fix consists in not setting exit_signal to SIGCHLD if exit_signal was not previously set. This simple reproducer easily triggers the bug, with CONFIG_IPV6=m : #include <stdio.h> #include <sys/socket.h> #include <netinet/in.h> main() { socket(PF_INET6, SOCK_STREAM, IPPROTO_TCP); getchar(); } It causes the following line to be displayed in kernel logs : request_module[net-pf-10]: waitpid(371,...) failed, errno 1 A modprobe zombie lies around until the reproducer dies. Special thanks to Michael Niehren for reporting the issue and helping in quickly narrowing the problem down by testing patches. Signed-off-by: Willy Tarreau <w@1wt.eu>
-rw-r--r--kernel/exit.c2
1 files changed, 1 insertions, 1 deletions
diff --git a/kernel/exit.c b/kernel/exit.c
index ed2b1898f22ad..3cf239461a3d5 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -369,7 +369,7 @@ static void exit_notify(void)
*
*/
- if(current->exit_signal != SIGCHLD &&
+ if (current->exit_signal && current->exit_signal != SIGCHLD &&
( current->parent_exec_id != t->self_exec_id ||
current->self_exec_id != current->parent_exec_id))
current->exit_signal = SIGCHLD;