From: Greg Kroah-Hartman Date: Thu, 27 Dec 2012 22:59:56 +0000 (-0800) Subject: 3.4-stable patches X-Git-Tag: v3.0.58~30 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=a0f1e82745a941be2bac5924faef1efe99ed96af;p=thirdparty%2Fkernel%2Fstable-queue.git 3.4-stable patches added patches: exec-do-not-leave-bprm-interp-on-stack.patch sgi-xp-handle-non-fatal-traps.patch --- diff --git a/queue-3.4/exec-do-not-leave-bprm-interp-on-stack.patch b/queue-3.4/exec-do-not-leave-bprm-interp-on-stack.patch new file mode 100644 index 00000000000..2d953da9625 --- /dev/null +++ b/queue-3.4/exec-do-not-leave-bprm-interp-on-stack.patch @@ -0,0 +1,114 @@ +From b66c5984017533316fd1951770302649baf1aa33 Mon Sep 17 00:00:00 2001 +From: Kees Cook +Date: Thu, 20 Dec 2012 15:05:16 -0800 +Subject: exec: do not leave bprm->interp on stack + +From: Kees Cook + +commit b66c5984017533316fd1951770302649baf1aa33 upstream. + +If a series of scripts are executed, each triggering module loading via +unprintable bytes in the script header, kernel stack contents can leak +into the command line. + +Normally execution of binfmt_script and binfmt_misc happens recursively. +However, when modules are enabled, and unprintable bytes exist in the +bprm->buf, execution will restart after attempting to load matching +binfmt modules. Unfortunately, the logic in binfmt_script and +binfmt_misc does not expect to get restarted. They leave bprm->interp +pointing to their local stack. This means on restart bprm->interp is +left pointing into unused stack memory which can then be copied into the +userspace argv areas. + +After additional study, it seems that both recursion and restart remains +the desirable way to handle exec with scripts, misc, and modules. As +such, we need to protect the changes to interp. + +This changes the logic to require allocation for any changes to the +bprm->interp. To avoid adding a new kmalloc to every exec, the default +value is left as-is. Only when passing through binfmt_script or +binfmt_misc does an allocation take place. + +For a proof of concept, see DoTest.sh from: + + http://www.halfdog.net/Security/2012/LinuxKernelBinfmtScriptStackDataDisclosure/ + +Signed-off-by: Kees Cook +Cc: halfdog +Cc: P J P +Cc: Alexander Viro +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + fs/binfmt_misc.c | 5 ++++- + fs/binfmt_script.c | 4 +++- + fs/exec.c | 15 +++++++++++++++ + include/linux/binfmts.h | 1 + + 4 files changed, 23 insertions(+), 2 deletions(-) + +--- a/fs/binfmt_misc.c ++++ b/fs/binfmt_misc.c +@@ -176,7 +176,10 @@ static int load_misc_binary(struct linux + goto _error; + bprm->argc ++; + +- bprm->interp = iname; /* for binfmt_script */ ++ /* Update interp in case binfmt_script needs it. */ ++ retval = bprm_change_interp(iname, bprm); ++ if (retval < 0) ++ goto _error; + + interp_file = open_exec (iname); + retval = PTR_ERR (interp_file); +--- a/fs/binfmt_script.c ++++ b/fs/binfmt_script.c +@@ -82,7 +82,9 @@ static int load_script(struct linux_binp + retval = copy_strings_kernel(1, &i_name, bprm); + if (retval) return retval; + bprm->argc++; +- bprm->interp = interp; ++ retval = bprm_change_interp(interp, bprm); ++ if (retval < 0) ++ return retval; + + /* + * OK, now restart the process with the interpreter's dentry. +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -1206,9 +1206,24 @@ void free_bprm(struct linux_binprm *bprm + mutex_unlock(¤t->signal->cred_guard_mutex); + abort_creds(bprm->cred); + } ++ /* If a binfmt changed the interp, free it. */ ++ if (bprm->interp != bprm->filename) ++ kfree(bprm->interp); + kfree(bprm); + } + ++int bprm_change_interp(char *interp, struct linux_binprm *bprm) ++{ ++ /* If a binfmt changed the interp, free it first. */ ++ if (bprm->interp != bprm->filename) ++ kfree(bprm->interp); ++ bprm->interp = kstrdup(interp, GFP_KERNEL); ++ if (!bprm->interp) ++ return -ENOMEM; ++ return 0; ++} ++EXPORT_SYMBOL(bprm_change_interp); ++ + /* + * install the new credentials for this executable + */ +--- a/include/linux/binfmts.h ++++ b/include/linux/binfmts.h +@@ -128,6 +128,7 @@ extern int setup_arg_pages(struct linux_ + unsigned long stack_top, + int executable_stack); + extern int bprm_mm_init(struct linux_binprm *bprm); ++extern int bprm_change_interp(char *interp, struct linux_binprm *bprm); + extern int copy_strings_kernel(int argc, const char *const *argv, + struct linux_binprm *bprm); + extern int prepare_bprm_creds(struct linux_binprm *bprm); diff --git a/queue-3.4/series b/queue-3.4/series index 58486e484d6..2fe3dd43ae5 100644 --- a/queue-3.4/series +++ b/queue-3.4/series @@ -13,3 +13,5 @@ inet_diag-validate-port-comparison-byte-code-to-prevent-unsafe-reads.patch b43legacy-fix-firmware-loading-when-driver-is-built-into-the-kernel.patch b43-fix-tx-path-skb-leaks.patch pnpacpi-fix-incorrect-test_alpha-test.patch +sgi-xp-handle-non-fatal-traps.patch +exec-do-not-leave-bprm-interp-on-stack.patch diff --git a/queue-3.4/sgi-xp-handle-non-fatal-traps.patch b/queue-3.4/sgi-xp-handle-non-fatal-traps.patch new file mode 100644 index 00000000000..5ff9a691cb2 --- /dev/null +++ b/queue-3.4/sgi-xp-handle-non-fatal-traps.patch @@ -0,0 +1,106 @@ +From 891348ca0f66206f1dc0e30d63757e3df1ae2d15 Mon Sep 17 00:00:00 2001 +From: Robin Holt +Date: Thu, 20 Dec 2012 15:05:50 -0800 +Subject: SGI-XP: handle non-fatal traps + +From: Robin Holt + +commit 891348ca0f66206f1dc0e30d63757e3df1ae2d15 upstream. + +We found a user code which was raising a divide-by-zero trap. That trap +would lead to XPC connections between system-partitions being torn down +due to the die_chain notifier callouts it received. + +This also revealed a different issue where multiple callers into +xpc_die_deactivate() would all attempt to do the disconnect in parallel +which would sometimes lock up but often overwhelm the console on very +large machines as each would print at least one line of output at the +end of the deactivate. + +I reviewed all the users of the die_chain notifier and changed the code +to ignore the notifier callouts for reasons which will not actually lead +to a system to continue on to call die(). + +[akpm@linux-foundation.org: fix ia64] +Signed-off-by: Robin Holt +Cc: Thomas Gleixner +Cc: Ingo Molnar +Signed-off-by: Andrew Morton +Signed-off-by: Linus Torvalds +Signed-off-by: Greg Kroah-Hartman + +--- + drivers/misc/sgi-xp/xpc_main.c | 34 ++++++++++++++++++++++++++++++++-- + 1 file changed, 32 insertions(+), 2 deletions(-) + +--- a/drivers/misc/sgi-xp/xpc_main.c ++++ b/drivers/misc/sgi-xp/xpc_main.c +@@ -53,6 +53,10 @@ + #include + #include "xpc.h" + ++#ifdef CONFIG_X86_64 ++#include ++#endif ++ + /* define two XPC debug device structures to be used with dev_dbg() et al */ + + struct device_driver xpc_dbg_name = { +@@ -1079,6 +1083,9 @@ xpc_system_reboot(struct notifier_block + return NOTIFY_DONE; + } + ++/* Used to only allow one cpu to complete disconnect */ ++static unsigned int xpc_die_disconnecting; ++ + /* + * Notify other partitions to deactivate from us by first disengaging from all + * references to our memory. +@@ -1092,6 +1099,9 @@ xpc_die_deactivate(void) + long keep_waiting; + long wait_to_print; + ++ if (cmpxchg(&xpc_die_disconnecting, 0, 1)) ++ return; ++ + /* keep xpc_hb_checker thread from doing anything (just in case) */ + xpc_exiting = 1; + +@@ -1159,7 +1169,7 @@ xpc_die_deactivate(void) + * about the lack of a heartbeat. + */ + static int +-xpc_system_die(struct notifier_block *nb, unsigned long event, void *unused) ++xpc_system_die(struct notifier_block *nb, unsigned long event, void *_die_args) + { + #ifdef CONFIG_IA64 /* !!! temporary kludge */ + switch (event) { +@@ -1191,7 +1201,27 @@ xpc_system_die(struct notifier_block *nb + break; + } + #else +- xpc_die_deactivate(); ++ struct die_args *die_args = _die_args; ++ ++ switch (event) { ++ case DIE_TRAP: ++ if (die_args->trapnr == X86_TRAP_DF) ++ xpc_die_deactivate(); ++ ++ if (((die_args->trapnr == X86_TRAP_MF) || ++ (die_args->trapnr == X86_TRAP_XF)) && ++ !user_mode_vm(die_args->regs)) ++ xpc_die_deactivate(); ++ ++ break; ++ case DIE_INT3: ++ case DIE_DEBUG: ++ break; ++ case DIE_OOPS: ++ case DIE_GPF: ++ default: ++ xpc_die_deactivate(); ++ } + #endif + + return NOTIFY_DONE;