aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNeil Horman <nhorman@tuxdriver.com>2009-09-23 18:56:56 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2009-09-24 10:21:00 -0400
commita293980c2e261bd5b0d2a77340dd04f684caff58 (patch)
tree69f2b2747548deafb146c18953ebce21ae1f02d4
parent725eae32df7754044809973034429a47e6035158 (diff)
exec: let do_coredump() limit the number of concurrent dumps to pipes
Introduce core pipe limiting sysctl. Since we can dump cores to pipe, rather than directly to the filesystem, we create a condition in which a user can create a very high load on the system simply by running bad applications. If the pipe reader specified in core_pattern is poorly written, we can have lots of ourstandig resources and processes in the system. This sysctl introduces an ability to limit that resource consumption. core_pipe_limit defines how many in-flight dumps may be run in parallel, dumps beyond this value are skipped and a note is made in the kernel log. A special value of 0 in core_pipe_limit denotes unlimited core dumps may be handled (this is the default value). [akpm@linux-foundation.org: coding-style fixes] 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>
-rw-r--r--Documentation/sysctl/kernel.txt22
-rw-r--r--fs/exec.c23
-rw-r--r--kernel/sysctl.c9
3 files changed, 49 insertions, 5 deletions
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index b3d8b4922740..a028b92001ed 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -22,6 +22,7 @@ show up in /proc/sys/kernel:
22- callhome [ S390 only ] 22- callhome [ S390 only ]
23- auto_msgmni 23- auto_msgmni
24- core_pattern 24- core_pattern
25- core_pipe_limit
25- core_uses_pid 26- core_uses_pid
26- ctrl-alt-del 27- ctrl-alt-del
27- dentry-state 28- dentry-state
@@ -135,6 +136,27 @@ core_pattern is used to specify a core dumpfile pattern name.
135 136
136============================================================== 137==============================================================
137 138
139core_pipe_limit:
140
141This sysctl is only applicable when core_pattern is configured to pipe core
142files to user space helper a (when the first character of core_pattern is a '|',
143see above). When collecting cores via a pipe to an application, it is
144occasionally usefull for the collecting application to gather data about the
145crashing process from its /proc/pid directory. In order to do this safely, the
146kernel must wait for the collecting process to exit, so as not to remove the
147crashing processes proc files prematurely. This in turn creates the possibility
148that a misbehaving userspace collecting process can block the reaping of a
149crashed process simply by never exiting. This sysctl defends against that. It
150defines how many concurrent crashing processes may be piped to user space
151applications in parallel. If this value is exceeded, then those crashing
152processes above that value are noted via the kernel log and their cores are
153skipped. 0 is a special value, indicating that unlimited processes may be
154captured in parallel, but that no waiting will take place (i.e. the collecting
155process is not guaranteed access to /proc/<crahing pid>/). This value defaults
156to 0.
157
158==============================================================
159
138core_uses_pid: 160core_uses_pid:
139 161
140The default coredump filename is "core". By setting 162The default coredump filename is "core". By setting
diff --git a/fs/exec.c b/fs/exec.c
index 735d9c18ec71..dc022dd15d51 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -63,6 +63,7 @@
63 63
64int core_uses_pid; 64int core_uses_pid;
65char core_pattern[CORENAME_MAX_SIZE] = "core"; 65char core_pattern[CORENAME_MAX_SIZE] = "core";
66unsigned int core_pipe_limit;
66int suid_dumpable = 0; 67int suid_dumpable = 0;
67 68
68/* The maximal length of core_pattern is also specified in sysctl.c */ 69/* The maximal length of core_pattern is also specified in sysctl.c */
@@ -1744,7 +1745,8 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1744 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; 1745 unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
1745 char **helper_argv = NULL; 1746 char **helper_argv = NULL;
1746 int helper_argc = 0; 1747 int helper_argc = 0;
1747 char *delimit; 1748 int dump_count = 0;
1749 static atomic_t core_dump_count = ATOMIC_INIT(0);
1748 1750
1749 audit_core_dumps(signr); 1751 audit_core_dumps(signr);
1750 1752
@@ -1826,28 +1828,36 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1826 goto fail_unlock; 1828 goto fail_unlock;
1827 } 1829 }
1828 1830
1831 dump_count = atomic_inc_return(&core_dump_count);
1832 if (core_pipe_limit && (core_pipe_limit < dump_count)) {
1833 printk(KERN_WARNING "Pid %d(%s) over core_pipe_limit\n",
1834 task_tgid_vnr(current), current->comm);
1835 printk(KERN_WARNING "Skipping core dump\n");
1836 goto fail_dropcount;
1837 }
1838
1829 helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); 1839 helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc);
1830 if (!helper_argv) { 1840 if (!helper_argv) {
1831 printk(KERN_WARNING "%s failed to allocate memory\n", 1841 printk(KERN_WARNING "%s failed to allocate memory\n",
1832 __func__); 1842 __func__);
1833 goto fail_unlock; 1843 goto fail_dropcount;
1834 } 1844 }
1835 1845
1836 core_limit = RLIM_INFINITY; 1846 core_limit = RLIM_INFINITY;
1837 1847
1838 /* SIGPIPE can happen, but it's just never processed */ 1848 /* SIGPIPE can happen, but it's just never processed */
1839 if (call_usermodehelper_pipe(corename+1, helper_argv, NULL, 1849 if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL,
1840 &file)) { 1850 &file)) {
1841 printk(KERN_INFO "Core dump to %s pipe failed\n", 1851 printk(KERN_INFO "Core dump to %s pipe failed\n",
1842 corename); 1852 corename);
1843 goto fail_unlock; 1853 goto fail_dropcount;
1844 } 1854 }
1845 } else 1855 } else
1846 file = filp_open(corename, 1856 file = filp_open(corename,
1847 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 1857 O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag,
1848 0600); 1858 0600);
1849 if (IS_ERR(file)) 1859 if (IS_ERR(file))
1850 goto fail_unlock; 1860 goto fail_dropcount;
1851 inode = file->f_path.dentry->d_inode; 1861 inode = file->f_path.dentry->d_inode;
1852 if (inode->i_nlink > 1) 1862 if (inode->i_nlink > 1)
1853 goto close_fail; /* multiple links - don't dump */ 1863 goto close_fail; /* multiple links - don't dump */
@@ -1877,6 +1887,9 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs)
1877 current->signal->group_exit_code |= 0x80; 1887 current->signal->group_exit_code |= 0x80;
1878close_fail: 1888close_fail:
1879 filp_close(file, NULL); 1889 filp_close(file, NULL);
1890fail_dropcount:
1891 if (dump_count)
1892 atomic_dec(&core_dump_count);
1880fail_unlock: 1893fail_unlock:
1881 if (helper_argv) 1894 if (helper_argv)
1882 argv_free(helper_argv); 1895 argv_free(helper_argv);
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 7f4f57bea4ce..37abb8c3995b 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -76,6 +76,7 @@ extern int max_threads;
76extern int core_uses_pid; 76extern int core_uses_pid;
77extern int suid_dumpable; 77extern int suid_dumpable;
78extern char core_pattern[]; 78extern char core_pattern[];
79extern unsigned int core_pipe_limit;
79extern int pid_max; 80extern int pid_max;
80extern int min_free_kbytes; 81extern int min_free_kbytes;
81extern int pid_max_min, pid_max_max; 82extern int pid_max_min, pid_max_max;
@@ -423,6 +424,14 @@ static struct ctl_table kern_table[] = {
423 .proc_handler = &proc_dostring, 424 .proc_handler = &proc_dostring,
424 .strategy = &sysctl_string, 425 .strategy = &sysctl_string,
425 }, 426 },
427 {
428 .ctl_name = CTL_UNNUMBERED,
429 .procname = "core_pipe_limit",
430 .data = &core_pipe_limit,
431 .maxlen = sizeof(unsigned int),
432 .mode = 0644,
433 .proc_handler = &proc_dointvec,
434 },
426#ifdef CONFIG_PROC_SYSCTL 435#ifdef CONFIG_PROC_SYSCTL
427 { 436 {
428 .procname = "tainted", 437 .procname = "tainted",