lkml.org 
[lkml]   [2006]   [Aug]   [14]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
Patch in this message
/
From
Subject[PATCH] [3/3] Support piping into commands in /proc/sys/kernel/core_pattern
Date

Using the infrastructure created in previous patches implement support
to pipe core dumps into programs.

This is done by overloading the existing core_pattern sysctl
with a new syntax:

|program

When the first character of the pattern is a '|' the kernel will
instead threat the rest of the pattern as a command to run. The
core dump will be written to the standard input of that program
instead of to a file.
This is useful for having automatic core dump analysis without
filling up disks. The program can do some simple analysis and save only
a summary of the core dump.

The core dump proces will run with the privileges and in the name space
of the process that caused the core dump.

I also increased the core pattern size to 128 bytes so that
longer command lines fit.

Most of the changes comes from allowing core dumps without seeks.
They are fairly straight forward though.

One small incompatibility is that if someone had a core pattern previously that
started with '|' they will get suddenly new behaviour. I think that's
unlikely to be a real problem though.
Signed-off-by: Andi Kleen <ak@suse.de>

Index: linux/fs/exec.c
===================================================================
--- linux.orig/fs/exec.c
+++ linux/fs/exec.c
@@ -58,7 +58,7 @@
#endif

int core_uses_pid;
-char core_pattern[65] = "core";
+char core_pattern[128] = "core";
int suid_dumpable = 0;

EXPORT_SYMBOL(suid_dumpable);
@@ -1475,6 +1475,7 @@ int do_coredump(long signr, int exit_cod
int retval = 0;
int fsuid = current->fsuid;
int flag = 0;
+ int ispipe = 0;

binfmt = current->binfmt;
if (!binfmt || !binfmt->core_dump)
@@ -1516,22 +1517,34 @@ int do_coredump(long signr, int exit_cod
lock_kernel();
format_corename(corename, core_pattern, signr);
unlock_kernel();
- file = filp_open(corename, O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, 0600);
+ if (corename[0] == '|') {
+ /* SIGPIPE can happen, but it's just never processed */
+ if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
+ printk(KERN_INFO "Core dump to %s pipe failed\n",
+ corename);
+ goto fail_unlock;
+ }
+ ispipe = 1;
+ } else
+ file = filp_open(corename,
+ O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE, 0600);
if (IS_ERR(file))
goto fail_unlock;
inode = file->f_dentry->d_inode;
if (inode->i_nlink > 1)
goto close_fail; /* multiple links - don't dump */
- if (d_unhashed(file->f_dentry))
+ if (!ispipe && d_unhashed(file->f_dentry))
goto close_fail;

- if (!S_ISREG(inode->i_mode))
+ /* AK: actually i see no reason to not allow this for named pipes etc.,
+ but keep the previous behaviour for now. */
+ if (!ispipe && !S_ISREG(inode->i_mode))
goto close_fail;
if (!file->f_op)
goto close_fail;
if (!file->f_op->write)
goto close_fail;
- if (do_truncate(file->f_dentry, 0, 0, file) != 0)
+ if (!ispipe && do_truncate(file->f_dentry, 0, 0, file) != 0)
goto close_fail;

retval = binfmt->core_dump(signr, regs, file);
Index: linux/fs/binfmt_elf.c
===================================================================
--- linux.orig/fs/binfmt_elf.c
+++ linux/fs/binfmt_elf.c
@@ -1153,11 +1153,23 @@ static int dump_write(struct file *file,

static int dump_seek(struct file *file, loff_t off)
{
- if (file->f_op->llseek) {
- if (file->f_op->llseek(file, off, 0) != off)
+ if (file->f_op->llseek && file->f_op->llseek != no_llseek) {
+ if (file->f_op->llseek(file, off, 1) != off)
return 0;
- } else
- file->f_pos = off;
+ } else {
+ char *buf = (char *)get_zeroed_page(GFP_KERNEL);
+ if (!buf)
+ return 0;
+ while (off > 0) {
+ unsigned long n = off;
+ if (n > PAGE_SIZE)
+ n = PAGE_SIZE;
+ if (!dump_write(file, buf, n))
+ return 0;
+ off -= n;
+ }
+ free_page((unsigned long)buf);
+ }
return 1;
}

@@ -1205,30 +1217,32 @@ static int notesize(struct memelfnote *e
return sz;
}

-#define DUMP_WRITE(addr, nr) \
- do { if (!dump_write(file, (addr), (nr))) return 0; } while(0)
-#define DUMP_SEEK(off) \
- do { if (!dump_seek(file, (off))) return 0; } while(0)
+#define DUMP_WRITE(addr, nr, foffset) \
+ do { if (!dump_write(file, (addr), (nr))) return 0; *foffset += (nr); } while(0)

-static int writenote(struct memelfnote *men, struct file *file)
+static int alignfile(struct file *file, unsigned long *foffset)
{
- struct elf_note en;
+ char buf[4] = { 0, };
+ DUMP_WRITE(buf, roundup(*foffset, 4) - *foffset, foffset);
+ return 1;
+}

+static int writenote(struct memelfnote *men, struct file *file, unsigned long *foffset)
+{
+ struct elf_note en;
en.n_namesz = strlen(men->name) + 1;
en.n_descsz = men->datasz;
en.n_type = men->type;

- DUMP_WRITE(&en, sizeof(en));
- DUMP_WRITE(men->name, en.n_namesz);
- /* XXX - cast from long long to long to avoid need for libgcc.a */
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
- DUMP_WRITE(men->data, men->datasz);
- DUMP_SEEK(roundup((unsigned long)file->f_pos, 4)); /* XXX */
+ DUMP_WRITE(&en, sizeof(en), foffset);
+ DUMP_WRITE(men->name, en.n_namesz, foffset);
+ if (!alignfile(file, foffset)) return 0;
+ DUMP_WRITE(men->data, men->datasz, foffset);
+ if (!alignfile(file, foffset)) return 0;

return 1;
}
#undef DUMP_WRITE
-#undef DUMP_SEEK

#define DUMP_WRITE(addr, nr) \
if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \
@@ -1428,7 +1442,7 @@ static int elf_core_dump(long signr, str
int i;
struct vm_area_struct *vma;
struct elfhdr *elf = NULL;
- off_t offset = 0, dataoff;
+ off_t offset = 0, dataoff, foffset;
unsigned long limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
int numnote;
struct memelfnote *notes = NULL;
@@ -1572,7 +1586,8 @@ static int elf_core_dump(long signr, str
DUMP_WRITE(&phdr, sizeof(phdr));
}

- /* Page-align dumped data */
+ foffset = offset;
+
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);

/* Write program headers for segments dump */
@@ -1597,6 +1612,7 @@ static int elf_core_dump(long signr, str
phdr.p_align = ELF_EXEC_PAGESIZE;

DUMP_WRITE(&phdr, sizeof(phdr));
+ foffset += sizeof(phdr);
}

#ifdef ELF_CORE_WRITE_EXTRA_PHDRS
@@ -1605,7 +1621,7 @@ static int elf_core_dump(long signr, str

/* write out the notes section */
for (i = 0; i < numnote; i++)
- if (!writenote(notes + i, file))
+ if (!writenote(notes + i, file, &foffset))
goto end_coredump;

/* write out the thread status notes section */
@@ -1614,11 +1630,12 @@ static int elf_core_dump(long signr, str
list_entry(t, struct elf_thread_status, list);

for (i = 0; i < tmp->num_notes; i++)
- if (!writenote(&tmp->notes[i], file))
+ if (!writenote(&tmp->notes[i], file, &foffset))
goto end_coredump;
}
-
- DUMP_SEEK(dataoff);
+
+ /* Align to page */
+ DUMP_SEEK(dataoff - foffset);

for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) {
unsigned long addr;
@@ -1634,10 +1651,10 @@ static int elf_core_dump(long signr, str

if (get_user_pages(current, current->mm, addr, 1, 0, 1,
&page, &vma) <= 0) {
- DUMP_SEEK(file->f_pos + PAGE_SIZE);
+ DUMP_SEEK(PAGE_SIZE);
} else {
if (page == ZERO_PAGE(addr)) {
- DUMP_SEEK(file->f_pos + PAGE_SIZE);
+ DUMP_SEEK(PAGE_SIZE);
} else {
void *kaddr;
flush_cache_page(vma, addr,
@@ -1661,13 +1678,6 @@ static int elf_core_dump(long signr, str
ELF_CORE_WRITE_EXTRA_DATA;
#endif

- if ((off_t)file->f_pos != offset) {
- /* Sanity check */
- printk(KERN_WARNING
- "elf_core_dump: file->f_pos (%ld) != offset (%ld)\n",
- (off_t)file->f_pos, offset);
- }
-
end_coredump:
set_fs(fs);

Index: linux/kernel/sysctl.c
===================================================================
--- linux.orig/kernel/sysctl.c
+++ linux/kernel/sysctl.c
@@ -293,7 +293,7 @@ static ctl_table kern_table[] = {
.ctl_name = KERN_CORE_PATTERN,
.procname = "core_pattern",
.data = core_pattern,
- .maxlen = 64,
+ .maxlen = 128,
.mode = 0644,
.proc_handler = &proc_dostring,
.strategy = &sysctl_string,
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
\
 
 \ /
  Last update: 2006-08-14 13:31    [from the cache]
©2003-2011 Jasper Spaans