Skip to content

Commit

Permalink
coredump masking: add an interface for core dump filter
Browse files Browse the repository at this point in the history
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 <[email protected]>
Cc: Alan Cox <[email protected]>
Cc: David Howells <[email protected]>
Cc: Hugh Dickins <[email protected]>
Cc: Nick Piggin <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
Kawai, Hidehiro authored and Linus Torvalds committed Jul 19, 2007
1 parent 6c5d523 commit 3cb4a0b
Show file tree
Hide file tree
Showing 3 changed files with 105 additions and 0 deletions.
89 changes: 89 additions & 0 deletions fs/proc/base.c
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@
#include <linux/poll.h>
#include <linux/nsproxy.h>
#include <linux/oom.h>
#include <linux/elf.h>
#include "internal.h"

/* NOTE:
Expand Down Expand Up @@ -1785,6 +1786,91 @@ static const struct inode_operations proc_attr_dir_inode_operations = {

#endif

#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
static ssize_t proc_coredump_filter_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct task_struct *task = get_proc_task(file->f_dentry->d_inode);
struct mm_struct *mm;
char buffer[PROC_NUMBUF];
size_t len;
int ret;

if (!task)
return -ESRCH;

ret = 0;
mm = get_task_mm(task);
if (mm) {
len = snprintf(buffer, sizeof(buffer), "%08lx\n",
((mm->flags & MMF_DUMP_FILTER_MASK) >>
MMF_DUMP_FILTER_SHIFT));
mmput(mm);
ret = simple_read_from_buffer(buf, count, ppos, buffer, len);
}

put_task_struct(task);

return ret;
}

static ssize_t proc_coredump_filter_write(struct file *file,
const char __user *buf,
size_t count,
loff_t *ppos)
{
struct task_struct *task;
struct mm_struct *mm;
char buffer[PROC_NUMBUF], *end;
unsigned int val;
int ret;
int i;
unsigned long mask;

ret = -EFAULT;
memset(buffer, 0, sizeof(buffer));
if (count > sizeof(buffer) - 1)
count = sizeof(buffer) - 1;
if (copy_from_user(buffer, buf, count))
goto out_no_task;

ret = -EINVAL;
val = (unsigned int)simple_strtoul(buffer, &end, 0);
if (*end == '\n')
end++;
if (end - buffer == 0)
goto out_no_task;

ret = -ESRCH;
task = get_proc_task(file->f_dentry->d_inode);
if (!task)
goto out_no_task;

ret = end - buffer;
mm = get_task_mm(task);
if (!mm)
goto out_no_mm;

for (i = 0, mask = 1; i < MMF_DUMP_FILTER_BITS; i++, mask <<= 1) {
if (val & mask)
set_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
else
clear_bit(i + MMF_DUMP_FILTER_SHIFT, &mm->flags);
}

mmput(mm);
out_no_mm:
put_task_struct(task);
out_no_task:
return ret;
}

static const struct file_operations proc_coredump_filter_operations = {
.read = proc_coredump_filter_read,
.write = proc_coredump_filter_write,
};
#endif

/*
* /proc/self:
*/
Expand Down Expand Up @@ -2005,6 +2091,9 @@ static const struct pid_entry tgid_base_stuff[] = {
#ifdef CONFIG_FAULT_INJECTION
REG("make-it-fail", S_IRUGO|S_IWUSR, fault_inject),
#endif
#if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE)
REG("coredump_filter", S_IRUGO|S_IWUSR, coredump_filter),
#endif
#ifdef CONFIG_TASK_IO_ACCOUNTING
INF("io", S_IRUGO, pid_io_accounting),
#endif
Expand Down
14 changes: 14 additions & 0 deletions include/linux/sched.h
Original file line number Diff line number Diff line change
Expand Up @@ -349,8 +349,22 @@ extern void set_dumpable(struct mm_struct *mm, int value);
extern int get_dumpable(struct mm_struct *mm);

/* mm flags */
/* dumpable bits */
#define MMF_DUMPABLE 0 /* core dump is permitted */
#define MMF_DUMP_SECURELY 1 /* core file is readable only by root */
#define MMF_DUMPABLE_BITS 2

/* coredump filter bits */
#define MMF_DUMP_ANON_PRIVATE 2
#define MMF_DUMP_ANON_SHARED 3
#define MMF_DUMP_MAPPED_PRIVATE 4
#define MMF_DUMP_MAPPED_SHARED 5
#define MMF_DUMP_FILTER_SHIFT MMF_DUMPABLE_BITS
#define MMF_DUMP_FILTER_BITS 4
#define MMF_DUMP_FILTER_MASK \
(((1 << MMF_DUMP_FILTER_BITS) - 1) << MMF_DUMP_FILTER_SHIFT)
#define MMF_DUMP_FILTER_DEFAULT \
((1 << MMF_DUMP_ANON_PRIVATE) | (1 << MMF_DUMP_ANON_SHARED))

struct mm_struct {
struct vm_area_struct * mmap; /* list of VMAs */
Expand Down
2 changes: 2 additions & 0 deletions kernel/fork.c
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,8 @@ static struct mm_struct * mm_init(struct mm_struct * mm)
atomic_set(&mm->mm_count, 1);
init_rwsem(&mm->mmap_sem);
INIT_LIST_HEAD(&mm->mmlist);
mm->flags = (current->mm) ? current->mm->flags
: MMF_DUMP_FILTER_DEFAULT;
mm->core_waiters = 0;
mm->nr_ptes = 0;
set_mm_counter(mm, file_rss, 0);
Expand Down

0 comments on commit 3cb4a0b

Please sign in to comment.