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    [W:0.031 / U:4.668 seconds]
    ©2003-2017 Jasper Spaans. hosted at Digital OceanAdvertise on this site