diff options
author | Neil Horman <nhorman@tuxdriver.com> | 2009-09-23 18:56:56 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2009-09-24 10:21:00 -0400 |
commit | a293980c2e261bd5b0d2a77340dd04f684caff58 (patch) | |
tree | 69f2b2747548deafb146c18953ebce21ae1f02d4 /fs | |
parent | 725eae32df7754044809973034429a47e6035158 (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>
Diffstat (limited to 'fs')
-rw-r--r-- | fs/exec.c | 23 |
1 files changed, 18 insertions, 5 deletions
@@ -63,6 +63,7 @@ | |||
63 | 63 | ||
64 | int core_uses_pid; | 64 | int core_uses_pid; |
65 | char core_pattern[CORENAME_MAX_SIZE] = "core"; | 65 | char core_pattern[CORENAME_MAX_SIZE] = "core"; |
66 | unsigned int core_pipe_limit; | ||
66 | int suid_dumpable = 0; | 67 | int 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; |
1878 | close_fail: | 1888 | close_fail: |
1879 | filp_close(file, NULL); | 1889 | filp_close(file, NULL); |
1890 | fail_dropcount: | ||
1891 | if (dump_count) | ||
1892 | atomic_dec(&core_dump_count); | ||
1880 | fail_unlock: | 1893 | fail_unlock: |
1881 | if (helper_argv) | 1894 | if (helper_argv) |
1882 | argv_free(helper_argv); | 1895 | argv_free(helper_argv); |