diff options
author | Willy Tarreau <w@1wt.eu> | 2009-06-07 11:48:19 +0200 |
---|---|---|
committer | Willy Tarreau <w@1wt.eu> | 2009-06-07 21:37:00 +0200 |
commit | bdf30ce4294bb5fc6d5e6e8001557ac1b0fc7968 (patch) | |
tree | b74a47b4d81295dc79ed6b1b6911c46f70e2fe37 | |
parent | 4871441ddf930f5e5651af50f6b42645fbbf9638 (diff) | |
download | linux-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.c | 2 |
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; |