Commit 7dc0b22e authored by Neil Horman's avatar Neil Horman Committed by Linus Torvalds

core_pattern: ignore RLIMIT_CORE if core_pattern is a pipe

For some time /proc/sys/kernel/core_pattern has been able to set its output
destination as a pipe, allowing a user space helper to receive and
intellegently process a core.  This infrastructure however has some
shortcommings which can be enhanced.  Specifically:

1) The coredump code in the kernel should ignore RLIMIT_CORE limitation
   when core_pattern is a pipe, since file system resources are not being
   consumed in this case, unless the user application wishes to save the core,
   at which point the app is restricted by usual file system limits and
   restrictions.

2) The core_pattern code should be able to parse and pass options to the
   user space helper as an argv array.  The real core limit of the uid of the
   crashing proces should also be passable to the user space helper (since it
   is overridden to zero when called).

3) Some miscellaneous bugs need to be cleaned up (specifically the
   recognition of a recursive core dump, should the user mode helper itself
   crash.  Also, the core dump code in the kernel should not wait for the user
   mode helper to exit, since the same context is responsible for writing to
   the pipe, and a read of the pipe by the user mode helper will result in a
   deadlock.

This patch:

Remove the check of RLIMIT_CORE if core_pattern is a pipe.  In the event that
core_pattern is a pipe, the entire core will be fed to the user mode helper.
Signed-off-by: default avatarNeil Horman <nhorman@tuxdriver.com>
Cc: <martin.pitt@ubuntu.com>
Cc: <wwoods@redhat.com>
Cc: Jeremy Fitzhardinge <jeremy@goop.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 8e2b7056
...@@ -44,7 +44,7 @@ ...@@ -44,7 +44,7 @@
static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs); static int load_irix_binary(struct linux_binprm * bprm, struct pt_regs * regs);
static int load_irix_library(struct file *); static int load_irix_library(struct file *);
static int irix_core_dump(long signr, struct pt_regs * regs, static int irix_core_dump(long signr, struct pt_regs * regs,
struct file *file); struct file *file, unsigned long limit);
static struct linux_binfmt irix_format = { static struct linux_binfmt irix_format = {
.module = THIS_MODULE, .module = THIS_MODULE,
...@@ -1091,7 +1091,7 @@ static int writenote(struct memelfnote *men, struct file *file) ...@@ -1091,7 +1091,7 @@ static int writenote(struct memelfnote *men, struct file *file)
* and then they are actually written out. If we run out of core limit * and then they are actually written out. If we run out of core limit
* we just truncate. * we just truncate.
*/ */
static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) static int irix_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
{ {
int has_dumped = 0; int has_dumped = 0;
mm_segment_t fs; mm_segment_t fs;
...@@ -1101,7 +1101,6 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file) ...@@ -1101,7 +1101,6 @@ static int irix_core_dump(long signr, struct pt_regs * regs, struct file *file)
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct elfhdr elf; struct elfhdr elf;
off_t offset = 0, dataoff; off_t offset = 0, dataoff;
int limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
int numnote = 3; int numnote = 3;
struct memelfnote notes[3]; struct memelfnote notes[3];
struct elf_prstatus prstatus; /* NT_PRSTATUS */ struct elf_prstatus prstatus; /* NT_PRSTATUS */
......
...@@ -35,7 +35,7 @@ ...@@ -35,7 +35,7 @@
static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout32_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout32_library(struct file*); static int load_aout32_library(struct file*);
static int aout32_core_dump(long signr, struct pt_regs * regs, struct file *file); static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
static struct linux_binfmt aout32_format = { static struct linux_binfmt aout32_format = {
.module = THIS_MODULE, .module = THIS_MODULE,
...@@ -86,7 +86,7 @@ if (file->f_op->llseek) { \ ...@@ -86,7 +86,7 @@ if (file->f_op->llseek) { \
* dumping of the process results in another error.. * dumping of the process results in another error..
*/ */
static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file) static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
{ {
mm_segment_t fs; mm_segment_t fs;
int has_dumped = 0; int has_dumped = 0;
...@@ -105,13 +105,11 @@ static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file) ...@@ -105,13 +105,11 @@ static int aout32_core_dump(long signr, struct pt_regs *regs, struct file *file)
/* If the size of the dump file exceeds the rlimit, then see what would happen /* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */ if we wrote the stack, but not the data area. */
if ((dump.u_dsize+dump.u_ssize) > if (dump.u_dsize + dump.u_ssize > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0; dump.u_dsize = 0;
/* Make sure we have enough room to write the stack and data areas. */ /* Make sure we have enough room to write the stack and data areas. */
if ((dump.u_ssize) > if (dump.u_ssize > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0; dump.u_ssize = 0;
/* make sure we actually have a data and stack area to dump */ /* make sure we actually have a data and stack area to dump */
......
...@@ -40,7 +40,7 @@ static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); ...@@ -40,7 +40,7 @@ static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(struct file*); static int load_aout_library(struct file*);
#ifdef CORE_DUMP #ifdef CORE_DUMP
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file); static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
/* /*
* fill in the user structure for a core dump.. * fill in the user structure for a core dump..
...@@ -148,7 +148,7 @@ if (file->f_op->llseek) { \ ...@@ -148,7 +148,7 @@ if (file->f_op->llseek) { \
* dumping of the process results in another error.. * dumping of the process results in another error..
*/ */
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
{ {
mm_segment_t fs; mm_segment_t fs;
int has_dumped = 0; int has_dumped = 0;
...@@ -168,13 +168,11 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) ...@@ -168,13 +168,11 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
/* If the size of the dump file exceeds the rlimit, then see what would happen /* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */ if we wrote the stack, but not the data area. */
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > if ((dump.u_dsize + dump.u_ssize + 1) * PAGE_SIZE > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0; dump.u_dsize = 0;
/* Make sure we have enough room to write the stack and data areas. */ /* Make sure we have enough room to write the stack and data areas. */
if ((dump.u_ssize+1) * PAGE_SIZE > if ((dump.u_ssize + 1) * PAGE_SIZE > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0; dump.u_ssize = 0;
/* make sure we actually have a data and stack area to dump */ /* make sure we actually have a data and stack area to dump */
......
...@@ -31,7 +31,7 @@ ...@@ -31,7 +31,7 @@
static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs);
static int load_aout_library(struct file*); static int load_aout_library(struct file*);
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file); static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
static struct linux_binfmt aout_format = { static struct linux_binfmt aout_format = {
.module = THIS_MODULE, .module = THIS_MODULE,
...@@ -88,7 +88,7 @@ if (file->f_op->llseek) { \ ...@@ -88,7 +88,7 @@ if (file->f_op->llseek) { \
* dumping of the process results in another error.. * dumping of the process results in another error..
*/ */
static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
{ {
mm_segment_t fs; mm_segment_t fs;
int has_dumped = 0; int has_dumped = 0;
...@@ -123,23 +123,19 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file) ...@@ -123,23 +123,19 @@ static int aout_core_dump(long signr, struct pt_regs * regs, struct file *file)
/* If the size of the dump file exceeds the rlimit, then see what would happen /* If the size of the dump file exceeds the rlimit, then see what would happen
if we wrote the stack, but not the data area. */ if we wrote the stack, but not the data area. */
#ifdef __sparc__ #ifdef __sparc__
if ((dump.u_dsize+dump.u_ssize) > if ((dump.u_dsize + dump.u_ssize) > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0; dump.u_dsize = 0;
#else #else
if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_dsize = 0; dump.u_dsize = 0;
#endif #endif
/* Make sure we have enough room to write the stack and data areas. */ /* Make sure we have enough room to write the stack and data areas. */
#ifdef __sparc__ #ifdef __sparc__
if ((dump.u_ssize) > if (dump.u_ssize > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0; dump.u_ssize = 0;
#else #else
if ((dump.u_ssize+1) * PAGE_SIZE > if ((dump.u_ssize + 1) * PAGE_SIZE > limit)
current->signal->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0; dump.u_ssize = 0;
#endif #endif
......
...@@ -52,7 +52,7 @@ static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, i ...@@ -52,7 +52,7 @@ static unsigned long elf_map (struct file *, unsigned long, struct elf_phdr *, i
* don't even try. * don't even try.
*/ */
#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file); static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
#else #else
#define elf_core_dump NULL #define elf_core_dump NULL
#endif #endif
...@@ -1488,7 +1488,7 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, ...@@ -1488,7 +1488,7 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma,
* and then they are actually written out. If we run out of core limit * and then they are actually written out. If we run out of core limit
* we just truncate. * we just truncate.
*/ */
static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
{ {
#define NUM_NOTES 6 #define NUM_NOTES 6
int has_dumped = 0; int has_dumped = 0;
...@@ -1499,7 +1499,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file) ...@@ -1499,7 +1499,6 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file)
struct vm_area_struct *vma, *gate_vma; struct vm_area_struct *vma, *gate_vma;
struct elfhdr *elf = NULL; struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff, foffset; loff_t offset = 0, dataoff, foffset;
unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
int numnote; int numnote;
struct memelfnote *notes = NULL; struct memelfnote *notes = NULL;
struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
......
...@@ -75,7 +75,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, ...@@ -75,7 +75,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *,
struct file *, struct mm_struct *); struct file *, struct mm_struct *);
#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *); static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *, unsigned long limit);
#endif #endif
static struct linux_binfmt elf_fdpic_format = { static struct linux_binfmt elf_fdpic_format = {
...@@ -1552,7 +1552,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size, ...@@ -1552,7 +1552,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size,
* we just truncate. * we just truncate.
*/ */
static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
struct file *file) struct file *file, unsigned long limit)
{ {
#define NUM_NOTES 6 #define NUM_NOTES 6
int has_dumped = 0; int has_dumped = 0;
...@@ -1563,7 +1563,6 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, ...@@ -1563,7 +1563,6 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs,
struct vm_area_struct *vma; struct vm_area_struct *vma;
struct elfhdr *elf = NULL; struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff; loff_t offset = 0, dataoff;
unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
int numnote; int numnote;
struct memelfnote *notes = NULL; struct memelfnote *notes = NULL;
struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */ struct elf_prstatus *prstatus = NULL; /* NT_PRSTATUS */
......
...@@ -75,7 +75,7 @@ static int load_flat_shared_library(int id, struct lib_info *p); ...@@ -75,7 +75,7 @@ static int load_flat_shared_library(int id, struct lib_info *p);
#endif #endif
static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs); static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs);
static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file); static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
static struct linux_binfmt flat_format = { static struct linux_binfmt flat_format = {
.module = THIS_MODULE, .module = THIS_MODULE,
...@@ -90,7 +90,7 @@ static struct linux_binfmt flat_format = { ...@@ -90,7 +90,7 @@ static struct linux_binfmt flat_format = {
* Currently only a stub-function. * Currently only a stub-function.
*/ */
static int flat_core_dump(long signr, struct pt_regs * regs, struct file *file) static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit)
{ {
printk("Process %s:%d received signr %d and should have core dumped\n", printk("Process %s:%d received signr %d and should have core dumped\n",
current->comm, current->pid, (int) signr); current->comm, current->pid, (int) signr);
......
...@@ -44,7 +44,7 @@ static int load_som_library(struct file *); ...@@ -44,7 +44,7 @@ static int load_som_library(struct file *);
* don't even try. * don't even try.
*/ */
#if 0 #if 0
static int som_core_dump(long signr, struct pt_regs * regs); static int som_core_dump(long signr, struct pt_regs *regs, unsigned long limit);
#else #else
#define som_core_dump NULL #define som_core_dump NULL
#endif #endif
......
...@@ -1697,6 +1697,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) ...@@ -1697,6 +1697,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
int fsuid = current->fsuid; int fsuid = current->fsuid;
int flag = 0; int flag = 0;
int ispipe = 0; int ispipe = 0;
unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
audit_core_dumps(signr); audit_core_dumps(signr);
...@@ -1730,9 +1731,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) ...@@ -1730,9 +1731,6 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
*/ */
clear_thread_flag(TIF_SIGPENDING); clear_thread_flag(TIF_SIGPENDING);
if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump)
goto fail_unlock;
/* /*
* lock_kernel() because format_corename() is controlled by sysctl, which * lock_kernel() because format_corename() is controlled by sysctl, which
* uses lock_kernel() * uses lock_kernel()
...@@ -1740,7 +1738,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) ...@@ -1740,7 +1738,20 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
lock_kernel(); lock_kernel();
ispipe = format_corename(corename, core_pattern, signr); ispipe = format_corename(corename, core_pattern, signr);
unlock_kernel(); unlock_kernel();
/*
* Don't bother to check the RLIMIT_CORE value if core_pattern points
* to a pipe. Since we're not writing directly to the filesystem
* RLIMIT_CORE doesn't really apply, as no actual core file will be
* created unless the pipe reader choses to write out the core file
* at which point file size limits and permissions will be imposed
* as it does with any other process
*/
if ((!ispipe) &&
(core_limit < binfmt->min_coredump))
goto fail_unlock;
if (ispipe) { if (ispipe) {
core_limit = RLIM_INFINITY;
/* SIGPIPE can happen, but it's just never processed */ /* SIGPIPE can happen, but it's just never processed */
if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) { if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
printk(KERN_INFO "Core dump to %s pipe failed\n", printk(KERN_INFO "Core dump to %s pipe failed\n",
...@@ -1770,7 +1781,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs) ...@@ -1770,7 +1781,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0) if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0)
goto close_fail; goto close_fail;
retval = binfmt->core_dump(signr, regs, file); retval = binfmt->core_dump(signr, regs, file, core_limit);
if (retval) if (retval)
current->signal->group_exit_code |= 0x80; current->signal->group_exit_code |= 0x80;
......
...@@ -67,7 +67,7 @@ struct linux_binfmt { ...@@ -67,7 +67,7 @@ struct linux_binfmt {
struct module *module; struct module *module;
int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); int (*load_binary)(struct linux_binprm *, struct pt_regs * regs);
int (*load_shlib)(struct file *); int (*load_shlib)(struct file *);
int (*core_dump)(long signr, struct pt_regs * regs, struct file * file); int (*core_dump)(long signr, struct pt_regs *regs, struct file *file, unsigned long limit);
unsigned long min_coredump; /* minimal dump size */ unsigned long min_coredump; /* minimal dump size */
int hasvdso; int hasvdso;
}; };
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment