diff options
author | Oleg Nesterov <oleg@redhat.com> | 2013-04-30 18:28:13 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2013-04-30 20:04:06 -0400 |
commit | acdedd99b0f3bff9b4bb2103a6b1268c03d1f963 (patch) | |
tree | bfacbb825c6024a0374db0a6a38a222581b15083 /fs/coredump.c | |
parent | 6cd8f0acae3420afce37bf51a9ff8c2c20342af5 (diff) |
coredump: sanitize the setting of signal->group_exit_code
Now that the coredumping process can be SIGKILL'ed, the setting of
->group_exit_code in do_coredump() can race with complete_signal() and
SIGKILL or 0x80 can be "lost", or wait(status) can report status ==
SIGKILL | 0x80.
But the main problem is that it is not clear to me what should we do if
binfmt->core_dump() succeeds but SIGKILL was sent, that is why this patch
comes as a separate change.
This patch adds 0x80 if ->core_dump() succeeds and the process was not
killed. But perhaps we can (should?) re-set ->group_exit_code changed by
SIGKILL back to "siginfo->si_signo |= 0x80" in case when core_dumped == T.
Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Tested-by: Mandeep Singh Baines <msb@chromium.org>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: Neil Horman <nhorman@redhat.com>
Cc: "Rafael J. Wysocki" <rjw@sisk.pl>
Cc: Roland McGrath <roland@hack.frob.com>
Cc: Tejun Heo <tj@kernel.org>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/coredump.c')
-rw-r--r-- | fs/coredump.c | 11 |
1 files changed, 6 insertions, 5 deletions
diff --git a/fs/coredump.c b/fs/coredump.c index 6fea59043532..acc4448c28e7 100644 --- a/fs/coredump.c +++ b/fs/coredump.c | |||
@@ -390,12 +390,14 @@ static int coredump_wait(int exit_code, struct core_state *core_state) | |||
390 | return core_waiters; | 390 | return core_waiters; |
391 | } | 391 | } |
392 | 392 | ||
393 | static void coredump_finish(struct mm_struct *mm) | 393 | static void coredump_finish(struct mm_struct *mm, bool core_dumped) |
394 | { | 394 | { |
395 | struct core_thread *curr, *next; | 395 | struct core_thread *curr, *next; |
396 | struct task_struct *task; | 396 | struct task_struct *task; |
397 | 397 | ||
398 | spin_lock_irq(¤t->sighand->siglock); | 398 | spin_lock_irq(¤t->sighand->siglock); |
399 | if (core_dumped && !__fatal_signal_pending(current)) | ||
400 | current->signal->group_exit_code |= 0x80; | ||
399 | current->signal->group_exit_task = NULL; | 401 | current->signal->group_exit_task = NULL; |
400 | current->signal->flags = SIGNAL_GROUP_EXIT; | 402 | current->signal->flags = SIGNAL_GROUP_EXIT; |
401 | spin_unlock_irq(¤t->sighand->siglock); | 403 | spin_unlock_irq(¤t->sighand->siglock); |
@@ -480,6 +482,7 @@ void do_coredump(siginfo_t *siginfo) | |||
480 | int ispipe; | 482 | int ispipe; |
481 | struct files_struct *displaced; | 483 | struct files_struct *displaced; |
482 | bool need_nonrelative = false; | 484 | bool need_nonrelative = false; |
485 | bool core_dumped = false; | ||
483 | static atomic_t core_dump_count = ATOMIC_INIT(0); | 486 | static atomic_t core_dump_count = ATOMIC_INIT(0); |
484 | struct coredump_params cprm = { | 487 | struct coredump_params cprm = { |
485 | .siginfo = siginfo, | 488 | .siginfo = siginfo, |
@@ -638,9 +641,7 @@ void do_coredump(siginfo_t *siginfo) | |||
638 | goto close_fail; | 641 | goto close_fail; |
639 | if (displaced) | 642 | if (displaced) |
640 | put_files_struct(displaced); | 643 | put_files_struct(displaced); |
641 | retval = binfmt->core_dump(&cprm); | 644 | core_dumped = binfmt->core_dump(&cprm); |
642 | if (retval) | ||
643 | current->signal->group_exit_code |= 0x80; | ||
644 | 645 | ||
645 | if (ispipe && core_pipe_limit) | 646 | if (ispipe && core_pipe_limit) |
646 | wait_for_dump_helpers(cprm.file); | 647 | wait_for_dump_helpers(cprm.file); |
@@ -653,7 +654,7 @@ fail_dropcount: | |||
653 | fail_unlock: | 654 | fail_unlock: |
654 | kfree(cn.corename); | 655 | kfree(cn.corename); |
655 | fail_corename: | 656 | fail_corename: |
656 | coredump_finish(mm); | 657 | coredump_finish(mm, core_dumped); |
657 | revert_creds(old_cred); | 658 | revert_creds(old_cred); |
658 | fail_creds: | 659 | fail_creds: |
659 | put_cred(cred); | 660 | put_cred(cred); |