]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
3.7-stable patches
authorGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Dec 2012 22:55:27 +0000 (14:55 -0800)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 27 Dec 2012 22:55:27 +0000 (14:55 -0800)
added patches:
exec-do-not-leave-bprm-interp-on-stack.patch
sgi-xp-handle-non-fatal-traps.patch

queue-3.7/exec-do-not-leave-bprm-interp-on-stack.patch [new file with mode: 0644]
queue-3.7/series
queue-3.7/sgi-xp-handle-non-fatal-traps.patch [new file with mode: 0644]

diff --git a/queue-3.7/exec-do-not-leave-bprm-interp-on-stack.patch b/queue-3.7/exec-do-not-leave-bprm-interp-on-stack.patch
new file mode 100644 (file)
index 0000000..99c988b
--- /dev/null
@@ -0,0 +1,114 @@
+From b66c5984017533316fd1951770302649baf1aa33 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Thu, 20 Dec 2012 15:05:16 -0800
+Subject: exec: do not leave bprm->interp on stack
+
+From: Kees Cook <keescook@chromium.org>
+
+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 <keescook@chromium.org>
+Cc: halfdog <me@halfdog.net>
+Cc: P J P <ppandit@redhat.com>
+Cc: Alexander Viro <viro@zeniv.linux.org.uk>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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
+@@ -1175,9 +1175,24 @@ void free_bprm(struct linux_binprm *bprm
+               mutex_unlock(&current->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
+@@ -114,6 +114,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);
index c462511c920a2364fe5038069b926b1ca508afee..f9f86dd3ab1fc5f915f25f6758a90f5c0c205c01 100644 (file)
@@ -4,3 +4,5 @@ firmware-loader-fix-the-concurrent-request_firmware-race-for-kref_get-put.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.7/sgi-xp-handle-non-fatal-traps.patch b/queue-3.7/sgi-xp-handle-non-fatal-traps.patch
new file mode 100644 (file)
index 0000000..5ff9a69
--- /dev/null
@@ -0,0 +1,106 @@
+From 891348ca0f66206f1dc0e30d63757e3df1ae2d15 Mon Sep 17 00:00:00 2001
+From: Robin Holt <holt@sgi.com>
+Date: Thu, 20 Dec 2012 15:05:50 -0800
+Subject: SGI-XP: handle non-fatal traps
+
+From: Robin Holt <holt@sgi.com>
+
+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 <holt@sgi.com>
+Cc: Thomas Gleixner <tglx@linutronix.de>
+Cc: Ingo Molnar <mingo@elte.hu>
+Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
+Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+
+---
+ 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 <linux/kthread.h>
+ #include "xpc.h"
++#ifdef CONFIG_X86_64
++#include <asm/traps.h>
++#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;