lkml.org 
[lkml]   [2007]   [Jul]   [26]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[PATCH] core_pattern: Add ability for core_pattern to parse arguments when pattern is a pipe
    Hey-
    Currently, core dumps can be redirected to a pipe by placing the
    following string template in /proc/sys/kernel/core_pattern:
    |<path/to/application>
    This patch extends this ability, allowing the core_pattern to contain arguments
    to be passed as an argv array to the userspace helper application. It also add
    a format specifier, %c, which allows the RLIM_CORE value of the crashing
    application to be passed on the command line, since RLIMIT_CORE is reduced to
    zero when execing the userspace helper

    Tested successfully by me on x86 & x86_64.

    Regards
    Neil

    Signed-off-by: Neil Horman <nhorman@tuxdriver.com>


    exec.c | 122 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
    1 file changed, 119 insertions(+), 3 deletions(-)



    diff --git a/fs/exec.c b/fs/exec.c
    index c0b5def..e862019 100644
    --- a/fs/exec.c
    +++ b/fs/exec.c
    @@ -51,6 +51,7 @@
    #include <linux/cn_proc.h>
    #include <linux/audit.h>
    #include <linux/signalfd.h>
    +#include <linux/string.h>

    #include <asm/uaccess.h>
    #include <asm/mmu_context.h>
    @@ -1448,6 +1449,109 @@ int set_binfmt(struct linux_binfmt *new)

    EXPORT_SYMBOL(set_binfmt);

    +static void free_argv_array(char **argv)
    +{
    + int i;
    + if (argv != NULL) {
    + for (i = 0; argv[i] != NULL; i++)
    + kfree(argv[i]);
    + kfree(argv);
    + }
    +
    +}
    +
    +/*
    + * format_corename_argv will inspect the corename string,
    + * and for every option found after the binary name
    + * it will remove the option from the string, and place it
    + * in the argv array, that can then be passed to the
    + * usermodehelper if core_pattern is a pipe
    + * Assumes that corename is declared on the stack of the caller
    + */
    +static char **format_corename_argv(char *corename)
    +{
    + char *nptr = corename;
    + char *fptr = NULL;
    + char **orig_argv;
    + char **argv_ptr;
    + int i = 2;
    +
    + /*
    + * Start by populating element 0 with the name of the binary
    + */
    + argv_ptr = kmalloc(sizeof(char **)*i, GFP_KERNEL);
    + if (!argv_ptr)
    + goto out;
    + orig_argv = argv_ptr;
    +
    + argv_ptr[0] = NULL;
    + argv_ptr[1] = NULL;
    + fptr = strchr(nptr, ' ');
    +
    + /* This trucates the string command line for use in exec */
    + if (fptr != NULL)
    + *fptr = '\0';
    +
    + nptr = nptr + 1; /*this removes the leading | */
    + argv_ptr[0] = kmalloc(strlen(nptr), GFP_KERNEL);
    + if (argv_ptr[0] == NULL)
    + goto out_free;
    +
    + strcpy(argv_ptr[0], nptr);
    +
    + /*
    + * This handles the case where we have no options
    + */
    + if (fptr == NULL)
    + goto out;
    + /*
    + * Now walk through the rest of the corename with nptr and
    + * fptr, delimiting by spaces and filling out the array
    + */
    + nptr = fptr + 1;
    + for(;;) {
    + fptr = strchr(nptr, ' ');
    +
    + /*
    + * Found a new option, lets add to the array
    + */
    + argv_ptr = krealloc(argv_ptr, (sizeof(char **)*(i+1)), GFP_KERNEL);
    + if (!argv_ptr)
    + goto out_free;
    +
    + argv_ptr[i] = NULL; /* set the end of the array to NULL */
    + if (fptr != NULL)
    + *fptr = '\0';
    +
    + argv_ptr[i-1] = kmalloc(strlen(nptr), GFP_KERNEL);
    + if (argv_ptr[i-1] == NULL)
    + goto out_free;
    +
    + /*
    + * copy the option and advance our pointers
    + */
    + strcpy(argv_ptr[i-1],nptr);
    + if (fptr == NULL)
    + break;
    + i++;
    + nptr = fptr + 1;
    + }
    +
    +
    + /*
    + * now we have our array built
    + */
    + return argv_ptr;
    +
    +out_free:
    + for (i = 0;orig_argv[i] != NULL; i++)
    + kfree(orig_argv[i]);
    + kfree(orig_argv);
    + argv_ptr = NULL;
    +out:
    + return argv_ptr;
    +}
    +
    /* format_corename will inspect the pattern parameter, and output a
    * name into corename, which must have space for at least
    * CORENAME_MAX_SIZE bytes plus one byte for the zero terminator.
    @@ -1543,6 +1647,14 @@ static int format_corename(char *corename, const char *pattern, long signr)
    goto out;
    out_ptr += rc;
    break;
    + /* core limit size */
    + case 'c':
    + rc = snprintf(out_ptr, out_end - out_ptr,
    + "%lu", current->signal->rlim[RLIMIT_CORE].rlim_cur);
    + if (rc > out_end - out_ptr)
    + goto out;
    + out_ptr += rc;
    + break;
    default:
    break;
    }
    @@ -1727,6 +1839,7 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
    int flag = 0;
    int ispipe = 0;
    unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur;
    + char **helper_argv = NULL;

    audit_core_dumps(signr);

    @@ -1775,14 +1888,14 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
    * at which point file size limits and permissions will be imposed
    * as it does with any other process
    */
    - if ((!ispipe) &&
    - (core_limit < binfmt->min_coredump))
    + if ((!ispipe) && (core_limit < binfmt->min_coredump))
    goto fail_unlock;

    if (ispipe) {
    core_limit = RLIM_INFINITY;
    + helper_argv = format_corename_argv(corename);
    /* SIGPIPE can happen, but it's just never processed */
    - if(call_usermodehelper_pipe(corename+1, NULL, NULL, &file)) {
    + if(call_usermodehelper_pipe(corename+1, helper_argv, NULL, &file)) {
    printk(KERN_INFO "Core dump to %s pipe failed\n",
    corename);
    goto fail_unlock;
    @@ -1817,6 +1930,9 @@ int do_coredump(long signr, int exit_code, struct pt_regs * regs)
    close_fail:
    filp_close(file, NULL);
    fail_unlock:
    + if (ispipe)
    + free_argv_array(helper_argv);
    +
    current->fsuid = fsuid;
    complete_all(&mm->core_done);
    fail:
    --
    /***************************************************
    *Neil Horman
    *Software Engineer
    *Red Hat, Inc.
    *nhorman@tuxdriver.com
    *gpg keyid: 1024D / 0x92A74FA1
    *http://pgp.mit.edu
    ***************************************************/
    -
    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: 2007-07-26 19:45    [W:0.066 / U:62.896 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site