CHROMIUM: coredump: sanitize the setting of signal->group_exit_code
authorOleg Nesterov <oleg@redhat.com>
Sun, 17 Feb 2013 19:19:05 +0000 (20:19 +0100)
committerChromeBot <chrome-bot@google.com>
Wed, 20 Feb 2013 19:58:21 +0000 (11:58 -0800)
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.

Under review upstream:

http://thread.gmane.org/gmane.linux.kernel/1442910

BUG=chrome-os-partner:16961
TEST=See "coredump: prevent crash pipe reader from blocking suspend."

Signed-off-by: Oleg Nesterov <oleg@redhat.com>
Signed-off-by: Mandeep Singh Baines <msb@chromium.org>
Change-Id: I96e81bfea6cb5e21e59f2500f502fe1e9c673b43
Reviewed-on: https://gerrit.chromium.org/gerrit/43580
Reviewed-by: Aaron Durbin <adurbin@chromium.org>
fs/exec.c

index ac9aa66..b27c74d 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -1952,12 +1952,14 @@ static int coredump_wait(int exit_code, struct core_state *core_state)
        return core_waiters;
 }
 
-static void coredump_finish(struct mm_struct *mm)
+static void coredump_finish(struct mm_struct *mm, bool core_dumped)
 {
        struct core_thread *curr, *next;
        struct task_struct *task;
 
        spin_lock_irq(&current->sighand->siglock);
+       if (core_dumped && !__fatal_signal_pending(current))
+               current->signal->group_exit_code |= 0x80;
        current->signal->group_exit_task = NULL;
        current->signal->flags = SIGNAL_GROUP_EXIT;
        spin_unlock_irq(&current->sighand->siglock);
@@ -2110,6 +2112,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
        int retval = 0;
        int flag = 0;
        int ispipe;
+       bool core_dumped = false;
        static atomic_t core_dump_count = ATOMIC_INIT(0);
        struct coredump_params cprm = {
                .signr = signr,
@@ -2245,9 +2248,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
                        goto close_fail;
        }
 
-       retval = binfmt->core_dump(&cprm);
-       if (retval)
-               current->signal->group_exit_code |= 0x80;
+       core_dumped = binfmt->core_dump(&cprm);
 
        if (ispipe && core_pipe_limit)
                wait_for_dump_helpers(cprm.file);
@@ -2260,7 +2261,7 @@ fail_dropcount:
 fail_unlock:
        kfree(cn.corename);
 fail_corename:
-       coredump_finish(mm);
+       coredump_finish(mm, core_dumped);
        revert_creds(old_cred);
 fail_creds:
        put_cred(cred);