aboutsummaryrefslogtreecommitdiffstats
path: root/fs/exec.c
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2009-09-23 18:56:58 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-24 10:21:00 -0400
commit61be228a06dc6e8662f30e89eda3c12083c1f379 (patch)
treebe481a4f2dcb2ab4fded8d72d42601e360fc89df /fs/exec.c
parenta293980c2e261bd5b0d2a77340dd04f684caff58 (diff)
exec: allow do_coredump() to wait for user space pipe readers to complete
Allow core_pattern pipes to wait for user space to complete One of the things that user space processes like to do is look at metadata for a crashing process in their /proc/<pid> directory. this is racy however, since do_coredump in the kernel doesn't wait for the user space process to complete before it reaps the crashing process. This patch corrects that. Allowing the kernel to wait for the user space process to complete before cleaning up the crashing process. This is a bit tricky to do for a few reasons: 1) The user space process isn't our child, so we can't sys_wait4 on it 2) We need to close the pipe before waiting for the user process to complete, since the user process may rely on an EOF condition I've discussed several solutions with Oleg Nesterov off-list about this, and this is the one we've come up with. We add ourselves as a pipe reader (to prevent premature cleanup of the pipe_inode_info), and remove ourselves as a writer (to provide an EOF condition to the writer in user space), then we iterate until the user space process exits (which we detect by pipe->readers == 1, hence the > 1 check in the loop). When we exit the loop, we restore the proper reader/writer values, then we return and let filp_close in do_coredump clean up the pipe data properly. Signed-off-by: Neil Horman <nhorman@tuxdriver.com> Reported-by: Earl Chew <earl_chew@agilent.com> Cc: Oleg Nesterov <oleg@tv-sign.ru> Cc: Andi Kleen <andi@firstfloor.org> Cc: Alan Cox <alan@lxorguk.ukuu.org.uk> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'fs/exec.c')
-rw-r--r--fs/exec.c26
1 files changed, 26 insertions, 0 deletions
diff --git a/fs/exec.c b/fs/exec.c
index dc022dd15d51..8efbdc606a1e 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -55,6 +55,7 @@
55#include <linux/kmod.h> 55#include <linux/kmod.h>
56#include <linux/fsnotify.h> 56#include <linux/fsnotify.h>
57#include <linux/fs_struct.h> 57#include <linux/fs_struct.h>
58#include <linux/pipe_fs_i.h>
58 59
59#include <asm/uaccess.h> 60#include <asm/uaccess.h>
60#include <asm/mmu_context.h> 61#include <asm/mmu_context.h>
@@ -1729,6 +1730,29 @@ int get_dumpable(struct mm_struct *mm)
1729 return (ret >= 2) ? 2 : ret; 1730 return (ret >= 2) ? 2 : ret;
1730} 1731}
1731 1732
1733static void wait_for_dump_helpers(struct file *file)
1734{
1735 struct pipe_inode_info *pipe;
1736
1737 pipe = file->f_path.dentry->d_inode->i_pipe;
1738
1739 pipe_lock(pipe);
1740 pipe->readers++;
1741 pipe->writers--;
1742
1743 while ((pipe->readers > 1) && (!signal_pending(current))) {
1744 wake_up_interruptible_sync(&pipe->wait);
1745 kill_fasync(&pipe->fasync_readers, SIGIO, POLL_IN);
1746 pipe_wait(pipe);
1747 }
1748
1749 pipe->readers--;
1750 pipe->writers++;
1751 pipe_unlock(pipe);
1752
1753}
1754
1755
1732void do_coredump(long signr, int exit_code, struct pt_regs *regs) 1756void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1733{ 1757{
1734 struct core_state core_state; 1758 struct core_state core_state;
@@ -1886,6 +1910,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1886 if (retval) 1910 if (retval)
1887 current->signal->group_exit_code |= 0x80; 1911 current->signal->group_exit_code |= 0x80;
1888close_fail: 1912close_fail:
1913 if (ispipe && core_pipe_limit)
1914 wait_for_dump_helpers(file);
1889 filp_close(file, NULL); 1915 filp_close(file, NULL);
1890fail_dropcount: 1916fail_dropcount:
1891 if (dump_count) 1917 if (dump_count)