diff options
author | Kawai, Hidehiro <hidehiro.kawai.ez@hitachi.com> | 2007-07-19 04:48:28 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-07-19 13:04:47 -0400 |
commit | 3cb4a0bb1e773e3c41800b33a3f7dab32bd06c64 (patch) | |
tree | d363522865706f0674b7b104a8fc7b151f336764 | |
parent | 6c5d523826dc639df709ed0f88c5d2ce25379652 (diff) |
coredump masking: add an interface for core dump filter
This patch adds an interface to set/reset flags which determines each memory
segment should be dumped or not when a core file is generated.
/proc/<pid>/coredump_filter file is provided to access the flags. You can
change the flag status for a particular process by writing to or reading from
the file.
The flag status is inherited to the child process when it is created.
Signed-off-by: Hidehiro Kawai <hidehiro.kawai.ez@hitachi.com>
Cc: Alan Cox <alan@lxorguk.ukuu.org.uk>
Cc: David Howells <dhowells@redhat.com>
Cc: Hugh Dickins <hugh@veritas.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | fs/proc/base.c | 89 | ||||
-rw-r--r-- | include/linux/sched.h | 14 | ||||
-rw-r--r-- | kernel/fork.c | 2 |
3 files changed, 105 insertions, 0 deletions
diff --git a/fs/proc/base.c b/fs/proc/base.c index 49b3ab0175e0..3c77d5a64e7c 100644 --- a/fs/proc/base.c +++ b/fs/proc/base.c | |||
@@ -72,6 +72,7 @@ | |||
72 | #include <linux/poll.h> | 72 | #include <linux/poll.h> |
73 | #include <linux/nsproxy.h> | 73 | #include <linux/nsproxy.h> |
74 | #include <linux/oom.h> | 74 | #include <linux/oom.h> |
75 | #include <linux/elf.h> | ||
75 | #include "internal.h" | 76 | #include "internal.h" |
76 | 77 | ||
77 | /* NOTE: | 78 | /* NOTE: |
@@ -1785,6 +1786,91 @@ static const struct inode_operations proc_attr_dir_inode_operations = { | |||
1785 | 1786 | ||
1786 | #endif | 1787 | #endif |
1787 | 1788 | ||
1789 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | ||
1790 | static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf, | ||
1791 | size_t count, loff_t *ppos) | ||
1792 | { | ||
1793 | struct task_struct *task = get_proc_task(file->f_dentry->d_inode); | ||
1794 | struct mm_struct *mm; | ||
1795 | char buffer[PROC_NUMBUF]; | ||
1796 | size_t len; | ||
1797 | int ret; | ||
1798 | |||
1799 | if (!task) | ||
1800 | return -ESRCH; | ||
1801 | |||
1802 | ret = 0; | ||
1803 | mm = get_task_mm(task); | ||
1804 | if (mm) { | ||
1805 | len = snprintf(buffer, sizeof(buffer), "%08lx\n", | ||
1806 | ((mm->flags & MMF_DUMP_FILTER_MASK) >> | ||
1807 | MMF_DUMP_FILTER_SHIFT)); | ||
1808 | mmput(mm); | ||
1809 | ret = simple_read_from_buffer(buf, count, ppos, buffer, len); | ||
1810 | } | ||
1811 | |||
1812 | put_task_struct(task); | ||
1813 | |||
1814 | return ret; | ||
1815 | } | ||
1816 | |||
1817 | static ssize_t proc_coredump_filter_write(struct file *file, | ||
1818 | const char __user *buf, | ||
1819 | size_t count, | ||
1820 | loff_t *ppos) | ||
1821 | { | ||
1822 | struct task_struct *task; | ||
1823 | struct mm_struct *mm; | ||
1824 | char buffer[PROC_NUMBUF], *end; | ||
1825 | unsigned int val; | ||
1826 | int ret; | ||
1827 | int i; | ||
1828 | unsigned long mask; | ||
1829 | |||
1830 | ret = -EFAULT; | ||
1831 | memset(buffer, 0, sizeof(buffer)); | ||
1832 | if (count > sizeof(buffer) - 1) | ||
1833 | count = sizeof(buffer) - 1; | ||
1834 | if (copy_from_user(buffer, buf, count)) | ||
1835 | goto out_no_task; | ||
1836 | |||
1837 | ret = -EINVAL; | ||
1838 | val = (unsigned int)simple_strtoul(buffer, &end, 0); | ||
1839 | if (*end == '\n') | ||
1840 | end++; | ||
1841 | if (end - buffer == 0) | ||
1842 | goto out_no_task; | ||
1843 | |||
1844 | ret = -ESRCH; | ||
1845 | task = get_proc_task(file->f_dentry->d_inode); | ||
1846 | if (!task) | ||
1847 | goto out_no_task; | ||
1848 | |||
1849 | ret = end - buffer; | ||
1850 | mm = get_task_mm(task); | ||
1851 | if (!mm) | ||
1852 | goto out_no_mm; | ||
1853 | |||
1854 | for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) { | ||
1855 | if (val & mask) | ||
1856 | set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags); | ||
1857 | else | ||
1858 | clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags); | ||
1859 | } | ||
1860 | |||
1861 | mmput(mm); | ||
1862 | out_no_mm: | ||
1863 | put_task_struct(task); | ||
1864 | out_no_task: | ||
1865 | return ret; | ||
1866 | } | ||
1867 | |||
1868 | static const struct file_operations proc_coredump_filter_operations = { | ||
1869 | .read = proc_coredump_filter_read, | ||
1870 | .write = proc_coredump_filter_write, | ||
1871 | }; | ||
1872 | #endif | ||
1873 | |||
1788 | /* | 1874 | /* |
1789 | * /proc/self: | 1875 | * /proc/self: |
1790 | */ | 1876 | */ |
@@ -2005,6 +2091,9 @@ static const struct pid_entry tgid_base_stuff[] = { | |||
2005 | #ifdef CONFIG_FAULT_INJECTION | 2091 | #ifdef CONFIG_FAULT_INJECTION |
2006 | REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), | 2092 | REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject), |
2007 | #endif | 2093 | #endif |
2094 | #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) | ||
2095 | REG("coredump_filter", S_IRUGO|S_IWUSR, coredump_filter), | ||
2096 | #endif | ||
2008 | #ifdef CONFIG_TASK_IO_ACCOUNTING | 2097 | #ifdef CONFIG_TASK_IO_ACCOUNTING |
2009 | INF("io", S_IRUGO, pid_io_accounting), | 2098 | INF("io", S_IRUGO, pid_io_accounting), |
2010 | #endif | 2099 | #endif |
diff --git a/include/linux/sched.h b/include/linux/sched.h index 8dbd08366400..94f624aef017 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -349,8 +349,22 @@ extern void set_dumpable(struct mm_struct *mm, int value); | |||
349 | extern int get_dumpable(struct mm_struct *mm); | 349 | extern int get_dumpable(struct mm_struct *mm); |
350 | 350 | ||
351 | /* mm flags */ | 351 | /* mm flags */ |
352 | /* dumpable bits */ | ||
352 | #define MMF_DUMPABLE 0 /* core dump is permitted */ | 353 | #define MMF_DUMPABLE 0 /* core dump is permitted */ |
353 | #define MMF_DUMP_SECURELY 1 /* core file is readable only by root */ | 354 | #define MMF_DUMP_SECURELY 1 /* core file is readable only by root */ |
355 | #define MMF_DUMPABLE_BITS 2 | ||
356 | |||
357 | /* coredump filter bits */ | ||
358 | #define MMF_DUMP_ANON_PRIVATE 2 | ||
359 | #define MMF_DUMP_ANON_SHARED 3 | ||
360 | #define MMF_DUMP_MAPPED_PRIVATE 4 | ||
361 | #define MMF_DUMP_MAPPED_SHARED 5 | ||
362 | #define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS | ||
363 | #define MMF_DUMP_FILTER_BITS 4 | ||
364 | #define MMF_DUMP_FILTER_MASK \ | ||
365 | (((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT) | ||
366 | #define MMF_DUMP_FILTER_DEFAULT \ | ||
367 | ((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED)) | ||
354 | 368 | ||
355 | struct mm_struct { | 369 | struct mm_struct { |
356 | struct vm_area_struct * mmap; /* list of VMAs */ | 370 | struct vm_area_struct * mmap; /* list of VMAs */ |
diff --git a/kernel/fork.c b/kernel/fork.c index ba39bdb2a7b8..469838998220 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -334,6 +334,8 @@ static struct mm_struct * mm_init(struct mm_struct * mm) | |||
334 | atomic_set(&mm->mm_count, 1); | 334 | atomic_set(&mm->mm_count, 1); |
335 | init_rwsem(&mm->mmap_sem); | 335 | init_rwsem(&mm->mmap_sem); |
336 | INIT_LIST_HEAD(&mm->mmlist); | 336 | INIT_LIST_HEAD(&mm->mmlist); |
337 | mm->flags = (current->mm) ? current->mm->flags | ||
338 | : MMF_DUMP_FILTER_DEFAULT; | ||
337 | mm->core_waiters = 0; | 339 | mm->core_waiters = 0; |
338 | mm->nr_ptes = 0; | 340 | mm->nr_ptes = 0; |
339 | set_mm_counter(mm, file_rss, 0); | 341 | set_mm_counter(mm, file_rss, 0); |