diff options
author | Jesse Keating <jkeating@redhat.com> | 2010-07-29 17:18:45 -0700 |
---|---|---|
committer | Jesse Keating <jkeating@redhat.com> | 2010-07-29 17:18:45 -0700 |
commit | 2f82dda4a9bf41e64e864889bf06564bdf826e25 (patch) | |
tree | 118a7b483ae5de4dbf83d20001302f1404866ef0 /fix-abrtd.patch | |
parent | 64ba2e5ffde5f2418eb26c700cb0ab62b04e5013 (diff) | |
download | dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.gz dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.tar.xz dom0-kernel-2f82dda4a9bf41e64e864889bf06564bdf826e25.zip |
initial srpm import
Diffstat (limited to 'fix-abrtd.patch')
-rw-r--r-- | fix-abrtd.patch | 774 |
1 files changed, 774 insertions, 0 deletions
diff --git a/fix-abrtd.patch b/fix-abrtd.patch new file mode 100644 index 0000000..4a8db58 --- /dev/null +++ b/fix-abrtd.patch @@ -0,0 +1,774 @@ +diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c +index b639dcf..346b694 100644 +--- a/fs/binfmt_aout.c ++++ b/fs/binfmt_aout.c +@@ -32,7 +32,7 @@ + + static int load_aout_binary(struct linux_binprm *, struct pt_regs * regs); + static int load_aout_library(struct file*); +-static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); ++static int aout_core_dump(struct coredump_params *cprm); + + static struct linux_binfmt aout_format = { + .module = THIS_MODULE, +@@ -89,8 +89,9 @@ if (file->f_op->llseek) { \ + * dumping of the process results in another error.. + */ + +-static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) ++static int aout_core_dump(struct coredump_params *cprm) + { ++ struct file *file = cprm->file; + mm_segment_t fs; + int has_dumped = 0; + unsigned long dump_start, dump_size; +@@ -108,16 +109,16 @@ static int aout_core_dump(long signr, struct pt_regs *regs, struct file *file, u + current->flags |= PF_DUMPCORE; + strncpy(dump.u_comm, current->comm, sizeof(dump.u_comm)); + dump.u_ar0 = offsetof(struct user, regs); +- dump.signal = signr; +- aout_dump_thread(regs, &dump); ++ dump.signal = cprm->signr; ++ aout_dump_thread(cprm->regs, &dump); + + /* If the size of the dump file exceeds the rlimit, then see what would happen + if we wrote the stack, but not the data area. */ +- if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > limit) ++ if ((dump.u_dsize + dump.u_ssize+1) * PAGE_SIZE > cprm->limit) + dump.u_dsize = 0; + + /* Make sure we have enough room to write the stack and data areas. */ +- if ((dump.u_ssize + 1) * PAGE_SIZE > limit) ++ if ((dump.u_ssize + 1) * PAGE_SIZE > cprm->limit) + dump.u_ssize = 0; + + /* make sure we actually have a data and stack area to dump */ +diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c +index b9b3bb5..4ee5bb2 100644 +--- a/fs/binfmt_elf.c ++++ b/fs/binfmt_elf.c +@@ -45,7 +45,7 @@ static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, + * don't even try. + */ + #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); ++static int elf_core_dump(struct coredump_params *cprm); + #else + #define elf_core_dump NULL + #endif +@@ -1277,8 +1277,9 @@ static int writenote(struct memelfnote *men, struct file *file, + } + #undef DUMP_WRITE + +-#define DUMP_WRITE(addr, nr) \ +- if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ ++#define DUMP_WRITE(addr, nr) \ ++ if ((size += (nr)) > cprm->limit || \ ++ !dump_write(cprm->file, (addr), (nr))) \ + goto end_coredump; + + static void fill_elf_header(struct elfhdr *elf, int segs, +@@ -1906,7 +1907,7 @@ static struct vm_area_struct *next_vma(struct vm_area_struct *this_vma, + * and then they are actually written out. If we run out of core limit + * we just truncate. + */ +-static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) ++static int elf_core_dump(struct coredump_params *cprm) + { + int has_dumped = 0; + mm_segment_t fs; +@@ -1952,7 +1953,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un + * notes. This also sets up the file header. + */ + if (!fill_note_info(elf, segs + 1, /* including notes section */ +- &info, signr, regs)) ++ &info, cprm->signr, cprm->regs)) + goto cleanup; + + has_dumped = 1; +@@ -2014,14 +2015,14 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un + #endif + + /* write out the notes section */ +- if (!write_note_info(&info, file, &foffset)) ++ if (!write_note_info(&info, cprm->file, &foffset)) + goto end_coredump; + +- if (elf_coredump_extra_notes_write(file, &foffset)) ++ if (elf_coredump_extra_notes_write(cprm->file, &foffset)) + goto end_coredump; + + /* Align to page */ +- if (!dump_seek(file, dataoff - foffset)) ++ if (!dump_seek(cprm->file, dataoff - foffset)) + goto end_coredump; + + for (vma = first_vma(current, gate_vma); vma != NULL; +@@ -2038,12 +2039,13 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un + page = get_dump_page(addr); + if (page) { + void *kaddr = kmap(page); +- stop = ((size += PAGE_SIZE) > limit) || +- !dump_write(file, kaddr, PAGE_SIZE); ++ stop = ((size += PAGE_SIZE) > cprm->limit) || ++ !dump_write(cprm->file, kaddr, ++ PAGE_SIZE); + kunmap(page); + page_cache_release(page); + } else +- stop = !dump_seek(file, PAGE_SIZE); ++ stop = !dump_seek(cprm->file, PAGE_SIZE); + if (stop) + goto end_coredump; + } +diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c +index 38502c6..917e1b4 100644 +--- a/fs/binfmt_elf_fdpic.c ++++ b/fs/binfmt_elf_fdpic.c +@@ -76,7 +76,7 @@ static int elf_fdpic_map_file_by_direct_mmap(struct elf_fdpic_params *, + struct file *, struct mm_struct *); + + #if defined(USE_ELF_CORE_DUMP) && defined(CONFIG_ELF_CORE) +-static int elf_fdpic_core_dump(long, struct pt_regs *, struct file *, unsigned long limit); ++static int elf_fdpic_core_dump(struct coredump_params *cprm); + #endif + + static struct linux_binfmt elf_fdpic_format = { +@@ -1325,8 +1325,9 @@ static int writenote(struct memelfnote *men, struct file *file) + #undef DUMP_WRITE + #undef DUMP_SEEK + +-#define DUMP_WRITE(addr, nr) \ +- if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ ++#define DUMP_WRITE(addr, nr) \ ++ if ((size += (nr)) > cprm->limit || \ ++ !dump_write(cprm->file, (addr), (nr))) \ + goto end_coredump; + + static inline void fill_elf_fdpic_header(struct elfhdr *elf, int segs) +@@ -1581,8 +1582,7 @@ static int elf_fdpic_dump_segments(struct file *file, size_t *size, + * and then they are actually written out. If we run out of core limit + * we just truncate. + */ +-static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, +- struct file *file, unsigned long limit) ++static int elf_fdpic_core_dump(struct coredump_params *cprm) + { + #define NUM_NOTES 6 + int has_dumped = 0; +@@ -1641,7 +1641,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, + goto cleanup; + #endif + +- if (signr) { ++ if (cprm->signr) { + struct core_thread *ct; + struct elf_thread_status *tmp; + +@@ -1660,14 +1660,14 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, + int sz; + + tmp = list_entry(t, struct elf_thread_status, list); +- sz = elf_dump_thread_status(signr, tmp); ++ sz = elf_dump_thread_status(cprm->signr, tmp); + thread_status_size += sz; + } + } + + /* now collect the dump for the current */ +- fill_prstatus(prstatus, current, signr); +- elf_core_copy_regs(&prstatus->pr_reg, regs); ++ fill_prstatus(prstatus, current, cprm->signr); ++ elf_core_copy_regs(&prstatus->pr_reg, cprm->regs); + + segs = current->mm->map_count; + #ifdef ELF_CORE_EXTRA_PHDRS +@@ -1702,7 +1702,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, + + /* Try to dump the FPU. */ + if ((prstatus->pr_fpvalid = +- elf_core_copy_task_fpregs(current, regs, fpu))) ++ elf_core_copy_task_fpregs(current, cprm->regs, fpu))) + fill_note(notes + numnote++, + "CORE", NT_PRFPREG, sizeof(*fpu), fpu); + #ifdef ELF_CORE_COPY_XFPREGS +@@ -1773,7 +1773,7 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, + + /* write out the notes section */ + for (i = 0; i < numnote; i++) +- if (!writenote(notes + i, file)) ++ if (!writenote(notes + i, cprm->file)) + goto end_coredump; + + /* write out the thread status notes section */ +@@ -1782,14 +1782,15 @@ static int elf_fdpic_core_dump(long signr, struct pt_regs *regs, + 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], cprm->file)) + goto end_coredump; + } + +- if (!dump_seek(file, dataoff)) ++ if (!dump_seek(cprm->file, dataoff)) + goto end_coredump; + +- if (elf_fdpic_dump_segments(file, &size, &limit, mm_flags) < 0) ++ if (elf_fdpic_dump_segments(cprm->file, &size, &cprm->limit, ++ mm_flags) < 0) + goto end_coredump; + + #ifdef ELF_CORE_WRITE_EXTRA_DATA +diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c +index a279665..d4a00ea 100644 +--- a/fs/binfmt_flat.c ++++ b/fs/binfmt_flat.c +@@ -87,7 +87,7 @@ static int load_flat_shared_library(int id, struct lib_info *p); + #endif + + static int load_flat_binary(struct linux_binprm *, struct pt_regs * regs); +-static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); ++static int flat_core_dump(struct coredump_params *cprm); + + static struct linux_binfmt flat_format = { + .module = THIS_MODULE, +@@ -102,10 +102,10 @@ static struct linux_binfmt flat_format = { + * Currently only a stub-function. + */ + +-static int flat_core_dump(long signr, struct pt_regs *regs, struct file *file, unsigned long limit) ++static int flat_core_dump(struct coredump_params *cprm) + { + printk("Process %s:%d received signr %d and should have core dumped\n", +- current->comm, current->pid, (int) signr); ++ current->comm, current->pid, (int) cprm->signr); + return(1); + } + +diff --git a/fs/binfmt_som.c b/fs/binfmt_som.c +index eff74b9..2a9b533 100644 +--- a/fs/binfmt_som.c ++++ b/fs/binfmt_som.c +@@ -43,7 +43,7 @@ static int load_som_library(struct file *); + * don't even try. + */ + #if 0 +-static int som_core_dump(long signr, struct pt_regs *regs, unsigned long limit); ++static int som_core_dump(struct coredump_params *cprm); + #else + #define som_core_dump NULL + #endif +diff --git a/fs/exec.c b/fs/exec.c +index ba112bd..08ec506 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1749,6 +1749,50 @@ static void wait_for_dump_helpers(struct file *file) + } + + ++/* ++ * uhm_pipe_setup ++ * helper function to customize the process used ++ * to collect the core in userspace. Specifically ++ * it sets up a pipe and installs it as fd 0 (stdin) ++ * for the process. Returns 0 on success, or ++ * PTR_ERR on failure. ++ * Note that it also sets the core limit to 1. This ++ * is a special value that we use to trap recursive ++ * core dumps ++ */ ++static int umh_pipe_setup(struct subprocess_info *info) ++{ ++ struct file *rp, *wp; ++ struct fdtable *fdt; ++ struct coredump_params *cp = (struct coredump_params *)info->data; ++ struct files_struct *cf = current->files; ++ ++ wp = create_write_pipe(0); ++ if (IS_ERR(wp)) ++ return PTR_ERR(wp); ++ ++ rp = create_read_pipe(wp, 0); ++ if (IS_ERR(rp)) { ++ free_write_pipe(wp); ++ return PTR_ERR(rp); ++ } ++ ++ cp->file = wp; ++ ++ sys_close(0); ++ fd_install(0, rp); ++ spin_lock(&cf->file_lock); ++ fdt = files_fdtable(cf); ++ FD_SET(0, fdt->open_fds); ++ FD_CLR(0, fdt->close_on_exec); ++ spin_unlock(&cf->file_lock); ++ ++ /* and disallow core files too */ ++ current->signal->rlim[RLIMIT_CORE] = (struct rlimit){1, 1}; ++ ++ return 0; ++} ++ + void do_coredump(long signr, int exit_code, struct pt_regs *regs) + { + struct core_state core_state; +@@ -1756,17 +1800,20 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) + struct mm_struct *mm = current->mm; + struct linux_binfmt * binfmt; + struct inode * inode; +- struct file * file; + const struct cred *old_cred; + struct cred *cred; + int retval = 0; + int flag = 0; + int ispipe = 0; +- unsigned long core_limit = current->signal->rlim[RLIMIT_CORE].rlim_cur; + char **helper_argv = NULL; + int helper_argc = 0; + int dump_count = 0; + static atomic_t core_dump_count = ATOMIC_INIT(0); ++ struct coredump_params cprm = { ++ .signr = signr, ++ .regs = regs, ++ .limit = current->signal->rlim[RLIMIT_CORE].rlim_cur, ++ }; + + audit_core_dumps(signr); + +@@ -1822,19 +1869,19 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) + ispipe = format_corename(corename, signr); + unlock_kernel(); + +- if ((!ispipe) && (core_limit < binfmt->min_coredump)) ++ if ((!ispipe) && (cprm.limit < binfmt->min_coredump)) + goto fail_unlock; + + if (ispipe) { +- if (core_limit == 0) { ++ if (cprm.limit == 1) { + /* + * Normally core limits are irrelevant to pipes, since + * we're not writing to the file system, but we use +- * core_limit of 0 here as a speacial value. Any +- * non-zero limit gets set to RLIM_INFINITY below, but ++ * cprm.limit of 1 here as a speacial value. Any ++ * non-1 limit gets set to RLIM_INFINITY below, but + * a limit of 0 skips the dump. This is a consistent + * way to catch recursive crashes. We can still crash +- * if the core_pattern binary sets RLIM_CORE = !0 ++ * if the core_pattern binary sets RLIM_CORE = !1 + * but it runs as root, and can do lots of stupid things + * Note that we use task_tgid_vnr here to grab the pid + * of the process group leader. That way we get the +@@ -1842,7 +1889,7 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) + * core_pattern process dies. + */ + printk(KERN_WARNING +- "Process %d(%s) has RLIMIT_CORE set to 0\n", ++ "Process %d(%s) has RLIMIT_CORE set to 1\n", + task_tgid_vnr(current), current->comm); + printk(KERN_WARNING "Aborting core\n"); + goto fail_unlock; +@@ -1863,25 +1910,30 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) + goto fail_dropcount; + } + +- core_limit = RLIM_INFINITY; ++ cprm.limit = RLIM_INFINITY; + + /* SIGPIPE can happen, but it's just never processed */ +- if (call_usermodehelper_pipe(helper_argv[0], helper_argv, NULL, +- &file)) { ++ cprm.file = NULL; ++ if (call_usermodehelper_fns(helper_argv[0], helper_argv, NULL, ++ UMH_WAIT_EXEC, umh_pipe_setup, ++ NULL, &cprm)) { ++ if (cprm.file) ++ filp_close(cprm.file, NULL); ++ + printk(KERN_INFO "Core dump to %s pipe failed\n", + corename); + goto fail_dropcount; + } + } else +- file = filp_open(corename, ++ cprm.file = filp_open(corename, + O_CREAT | 2 | O_NOFOLLOW | O_LARGEFILE | flag, + 0600); +- if (IS_ERR(file)) ++ if (IS_ERR(cprm.file)) + goto fail_dropcount; +- inode = file->f_path.dentry->d_inode; ++ inode = cprm.file->f_path.dentry->d_inode; + if (inode->i_nlink > 1) + goto close_fail; /* multiple links - don't dump */ +- if (!ispipe && d_unhashed(file->f_path.dentry)) ++ if (!ispipe && d_unhashed(cprm.file->f_path.dentry)) + goto close_fail; + + /* AK: actually i see no reason to not allow this for named pipes etc., +@@ -1894,21 +1946,22 @@ void do_coredump(long signr, int exit_code, struct pt_regs *regs) + */ + if (!ispipe && (inode->i_uid != current_fsuid())) + goto close_fail; +- if (!file->f_op) ++ if (!cprm.file->f_op) + goto close_fail; +- if (!file->f_op->write) ++ if (!cprm.file->f_op->write) + goto close_fail; +- if (!ispipe && do_truncate(file->f_path.dentry, 0, 0, file) != 0) ++ if (!ispipe && ++ do_truncate(cprm.file->f_path.dentry, 0, 0, cprm.file) != 0) + goto close_fail; + +- retval = binfmt->core_dump(signr, regs, file, core_limit); ++ retval = binfmt->core_dump(&cprm); + + if (retval) + current->signal->group_exit_code |= 0x80; + close_fail: + if (ispipe && core_pipe_limit) +- wait_for_dump_helpers(file); +- filp_close(file, NULL); ++ wait_for_dump_helpers(cprm.file); ++ filp_close(cprm.file, NULL); + fail_dropcount: + if (dump_count) + atomic_dec(&core_dump_count); +diff --git a/include/linux/binfmts.h b/include/linux/binfmts.h +index aece486..cd4349b 100644 +--- a/include/linux/binfmts.h ++++ b/include/linux/binfmts.h +@@ -68,6 +68,14 @@ struct linux_binprm{ + + #define BINPRM_MAX_RECURSION 4 + ++/* Function parameter for binfmt->coredump */ ++struct coredump_params { ++ long signr; ++ struct pt_regs *regs; ++ struct file *file; ++ unsigned long limit; ++}; ++ + /* + * This structure defines the functions that are used to load the binary formats that + * linux accepts. +@@ -77,7 +85,7 @@ struct linux_binfmt { + struct module *module; + int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); + int (*load_shlib)(struct file *); +- int (*core_dump)(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); ++ int (*core_dump)(struct coredump_params *cprm); + unsigned long min_coredump; /* minimal dump size */ + int hasvdso; + }; +diff --git a/include/linux/kmod.h b/include/linux/kmod.h +index 384ca8b..ec69956 100644 +--- a/include/linux/kmod.h ++++ b/include/linux/kmod.h +@@ -23,6 +23,7 @@ + #include <linux/stddef.h> + #include <linux/errno.h> + #include <linux/compiler.h> ++#include <linux/workqueue.h> + + #define KMOD_PATH_LEN 256 + +@@ -44,7 +45,26 @@ static inline int request_module_nowait(const char *name, ...) { return -ENOSYS; + + struct key; + struct file; +-struct subprocess_info; ++ ++enum umh_wait { ++ UMH_NO_WAIT = -1, /* don't wait at all */ ++ UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */ ++ UMH_WAIT_PROC = 1, /* wait for the process to complete */ ++}; ++ ++struct subprocess_info { ++ struct work_struct work; ++ struct completion *complete; ++ struct cred *cred; ++ char *path; ++ char **argv; ++ char **envp; ++ enum umh_wait wait; ++ int retval; ++ int (*init)(struct subprocess_info *info); ++ void (*cleanup)(struct subprocess_info *info); ++ void *data; ++}; + + /* Allocate a subprocess_info structure */ + struct subprocess_info *call_usermodehelper_setup(char *path, char **argv, +@@ -55,14 +75,10 @@ void call_usermodehelper_setkeys(struct subprocess_info *info, + struct key *session_keyring); + int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info, + struct file **filp); +-void call_usermodehelper_setcleanup(struct subprocess_info *info, +- void (*cleanup)(char **argv, char **envp)); +- +-enum umh_wait { +- UMH_NO_WAIT = -1, /* don't wait at all */ +- UMH_WAIT_EXEC = 0, /* wait for the exec, but not the process */ +- UMH_WAIT_PROC = 1, /* wait for the process to complete */ +-}; ++void call_usermodehelper_setfns(struct subprocess_info *info, ++ int (*init)(struct subprocess_info *info), ++ void (*cleanup)(struct subprocess_info *info), ++ void *data); + + /* Actually execute the sub-process */ + int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait); +@@ -72,7 +88,10 @@ int call_usermodehelper_exec(struct subprocess_info *info, enum umh_wait wait); + void call_usermodehelper_freeinfo(struct subprocess_info *info); + + static inline int +-call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait) ++call_usermodehelper_fns(char *path, char **argv, char **envp, ++ enum umh_wait wait, ++ int (*init)(struct subprocess_info *info), ++ void (*cleanup)(struct subprocess_info *), void *data) + { + struct subprocess_info *info; + gfp_t gfp_mask = (wait == UMH_NO_WAIT) ? GFP_ATOMIC : GFP_KERNEL; +@@ -80,10 +99,18 @@ call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait) + info = call_usermodehelper_setup(path, argv, envp, gfp_mask); + if (info == NULL) + return -ENOMEM; ++ call_usermodehelper_setfns(info, init, cleanup, data); + return call_usermodehelper_exec(info, wait); + } + + static inline int ++call_usermodehelper(char *path, char **argv, char **envp, enum umh_wait wait) ++{ ++ return call_usermodehelper_fns(path, argv, envp, ++ wait, NULL, NULL, NULL); ++} ++ ++static inline int + call_usermodehelper_keys(char *path, char **argv, char **envp, + struct key *session_keyring, enum umh_wait wait) + { +@@ -100,10 +127,6 @@ call_usermodehelper_keys(char *path, char **argv, char **envp, + + extern void usermodehelper_init(void); + +-struct file; +-extern int call_usermodehelper_pipe(char *path, char *argv[], char *envp[], +- struct file **filp); +- + extern int usermodehelper_disable(void); + extern void usermodehelper_enable(void); + +diff --git a/kernel/kmod.c b/kernel/kmod.c +index 9fcb53a..7281229 100644 +--- a/kernel/kmod.c ++++ b/kernel/kmod.c +@@ -124,19 +124,6 @@ int __request_module(bool wait, const char *fmt, ...) + EXPORT_SYMBOL(__request_module); + #endif /* CONFIG_MODULES */ + +-struct subprocess_info { +- struct work_struct work; +- struct completion *complete; +- struct cred *cred; +- char *path; +- char **argv; +- char **envp; +- enum umh_wait wait; +- int retval; +- struct file *stdin; +- void (*cleanup)(char **argv, char **envp); +-}; +- + /* + * This is the task which runs the usermode application + */ +@@ -158,26 +145,15 @@ static int ____call_usermodehelper(void *data) + commit_creds(sub_info->cred); + sub_info->cred = NULL; + +- /* Install input pipe when needed */ +- if (sub_info->stdin) { +- struct files_struct *f = current->files; +- struct fdtable *fdt; +- /* no races because files should be private here */ +- sys_close(0); +- fd_install(0, sub_info->stdin); +- spin_lock(&f->file_lock); +- fdt = files_fdtable(f); +- FD_SET(0, fdt->open_fds); +- FD_CLR(0, fdt->close_on_exec); +- spin_unlock(&f->file_lock); +- +- /* and disallow core files too */ +- current->signal->rlim[RLIMIT_CORE] = (struct rlimit){0, 0}; +- } +- + /* We can run anywhere, unlike our parent keventd(). */ + set_cpus_allowed_ptr(current, cpu_all_mask); + ++ if (sub_info->init) { ++ retval = sub_info->init(sub_info); ++ if (retval) ++ goto fail; ++ } ++ + /* + * Our parent is keventd, which runs with elevated scheduling priority. + * Avoid propagating that into the userspace child. +@@ -187,6 +163,7 @@ static int ____call_usermodehelper(void *data) + retval = kernel_execve(sub_info->path, sub_info->argv, sub_info->envp); + + /* Exec failed? */ ++fail: + sub_info->retval = retval; + do_exit(0); + } +@@ -194,7 +171,7 @@ static int ____call_usermodehelper(void *data) + void call_usermodehelper_freeinfo(struct subprocess_info *info) + { + if (info->cleanup) +- (*info->cleanup)(info->argv, info->envp); ++ (*info->cleanup)(info); + if (info->cred) + put_cred(info->cred); + kfree(info); +@@ -406,50 +383,31 @@ void call_usermodehelper_setkeys(struct subprocess_info *info, + EXPORT_SYMBOL(call_usermodehelper_setkeys); + + /** +- * call_usermodehelper_setcleanup - set a cleanup function ++ * call_usermodehelper_setfns - set a cleanup/init function + * @info: a subprocess_info returned by call_usermodehelper_setup + * @cleanup: a cleanup function ++ * @init: an init function ++ * @data: arbitrary context sensitive data ++ * ++ * The init function is used to customize the helper process prior to ++ * exec. A non-zero return code causes the process to error out, exit, ++ * and return the failure to the calling process + * +- * The cleanup function is just befor ethe subprocess_info is about to ++ * The cleanup function is just before ethe subprocess_info is about to + * be freed. This can be used for freeing the argv and envp. The + * Function must be runnable in either a process context or the + * context in which call_usermodehelper_exec is called. + */ +-void call_usermodehelper_setcleanup(struct subprocess_info *info, +- void (*cleanup)(char **argv, char **envp)) ++void call_usermodehelper_setfns(struct subprocess_info *info, ++ int (*init)(struct subprocess_info *info), ++ void (*cleanup)(struct subprocess_info *info), ++ void *data) + { + info->cleanup = cleanup; ++ info->init = init; ++ info->data = data; + } +-EXPORT_SYMBOL(call_usermodehelper_setcleanup); +- +-/** +- * call_usermodehelper_stdinpipe - set up a pipe to be used for stdin +- * @sub_info: a subprocess_info returned by call_usermodehelper_setup +- * @filp: set to the write-end of a pipe +- * +- * This constructs a pipe, and sets the read end to be the stdin of the +- * subprocess, and returns the write-end in *@filp. +- */ +-int call_usermodehelper_stdinpipe(struct subprocess_info *sub_info, +- struct file **filp) +-{ +- struct file *f; +- +- f = create_write_pipe(0); +- if (IS_ERR(f)) +- return PTR_ERR(f); +- *filp = f; +- +- f = create_read_pipe(f, 0); +- if (IS_ERR(f)) { +- free_write_pipe(*filp); +- return PTR_ERR(f); +- } +- sub_info->stdin = f; +- +- return 0; +-} +-EXPORT_SYMBOL(call_usermodehelper_stdinpipe); ++EXPORT_SYMBOL(call_usermodehelper_setfns); + + /** + * call_usermodehelper_exec - start a usermode application +@@ -498,39 +456,6 @@ unlock: + } + EXPORT_SYMBOL(call_usermodehelper_exec); + +-/** +- * call_usermodehelper_pipe - call a usermode helper process with a pipe stdin +- * @path: path to usermode executable +- * @argv: arg vector for process +- * @envp: environment for process +- * @filp: set to the write-end of a pipe +- * +- * This is a simple wrapper which executes a usermode-helper function +- * with a pipe as stdin. It is implemented entirely in terms of +- * lower-level call_usermodehelper_* functions. +- */ +-int call_usermodehelper_pipe(char *path, char **argv, char **envp, +- struct file **filp) +-{ +- struct subprocess_info *sub_info; +- int ret; +- +- sub_info = call_usermodehelper_setup(path, argv, envp, GFP_KERNEL); +- if (sub_info == NULL) +- return -ENOMEM; +- +- ret = call_usermodehelper_stdinpipe(sub_info, filp); +- if (ret < 0) +- goto out; +- +- return call_usermodehelper_exec(sub_info, UMH_WAIT_EXEC); +- +- out: +- call_usermodehelper_freeinfo(sub_info); +- return ret; +-} +-EXPORT_SYMBOL(call_usermodehelper_pipe); +- + void __init usermodehelper_init(void) + { + khelper_wq = create_singlethread_workqueue("khelper"); +diff --git a/kernel/sys.c b/kernel/sys.c +index ce17760..0b8a55e 100644 +--- a/kernel/sys.c ++++ b/kernel/sys.c +@@ -1600,9 +1600,9 @@ SYSCALL_DEFINE3(getcpu, unsigned __user *, cpup, unsigned __user *, nodep, + + char poweroff_cmd[POWEROFF_CMD_PATH_LEN] = "/sbin/poweroff"; + +-static void argv_cleanup(char **argv, char **envp) ++static void argv_cleanup(struct subprocess_info *info) + { +- argv_free(argv); ++ argv_free(info->argv); + } + + /** +@@ -1636,7 +1636,7 @@ int orderly_poweroff(bool force) + goto out; + } + +- call_usermodehelper_setcleanup(info, argv_cleanup); ++ call_usermodehelper_setfns(info, NULL, argv_cleanup, NULL); + + ret = call_usermodehelper_exec(info, UMH_NO_WAIT); + |