--- /dev/null
+From d049f74f2dbe71354d43d393ac3a188947811348 Mon Sep 17 00:00:00 2001
+From: Kees Cook <keescook@chromium.org>
+Date: Tue, 12 Nov 2013 15:11:17 -0800
+Subject: exec/ptrace: fix get_dumpable() incorrect tests
+
+From: Kees Cook <keescook@chromium.org>
+
+commit d049f74f2dbe71354d43d393ac3a188947811348 upstream.
+
+The get_dumpable() return value is not boolean. Most users of the
+function actually want to be testing for non-SUID_DUMP_USER(1) rather than
+SUID_DUMP_DISABLE(0). The SUID_DUMP_ROOT(2) is also considered a
+protected state. Almost all places did this correctly, excepting the two
+places fixed in this patch.
+
+Wrong logic:
+ if (dumpable == SUID_DUMP_DISABLE) { /* be protective */ }
+ or
+ if (dumpable == 0) { /* be protective */ }
+ or
+ if (!dumpable) { /* be protective */ }
+
+Correct logic:
+ if (dumpable != SUID_DUMP_USER) { /* be protective */ }
+ or
+ if (dumpable != 1) { /* be protective */ }
+
+Without this patch, if the system had set the sysctl fs/suid_dumpable=2, a
+user was able to ptrace attach to processes that had dropped privileges to
+that user. (This may have been partially mitigated if Yama was enabled.)
+
+The macros have been moved into the file that declares get/set_dumpable(),
+which means things like the ia64 code can see them too.
+
+CVE-2013-2929
+
+Reported-by: Vasily Kulikov <segoon@openwall.com>
+Signed-off-by: Kees Cook <keescook@chromium.org>
+Cc: "Luck, Tony" <tony.luck@intel.com>
+Cc: Oleg Nesterov <oleg@redhat.com>
+Cc: "Eric W. Biederman" <ebiederm@xmission.com>
+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>
+
+---
+ arch/ia64/include/asm/processor.h | 2 +-
+ fs/exec.c | 6 ++++++
+ include/linux/binfmts.h | 3 ---
+ include/linux/sched.h | 4 ++++
+ kernel/ptrace.c | 3 ++-
+ 5 files changed, 13 insertions(+), 5 deletions(-)
+
+--- a/arch/ia64/include/asm/processor.h
++++ b/arch/ia64/include/asm/processor.h
+@@ -319,7 +319,7 @@ struct thread_struct {
+ regs->loadrs = 0; \
+ regs->r8 = get_dumpable(current->mm); /* set "don't zap registers" flag */ \
+ regs->r12 = new_sp - 16; /* allocate 16 byte scratch area */ \
+- if (unlikely(!get_dumpable(current->mm))) { \
++ if (unlikely(get_dumpable(current->mm) != SUID_DUMP_USER)) { \
+ /* \
+ * Zap scratch regs to avoid leaking bits between processes with different \
+ * uid/privileges. \
+--- a/fs/exec.c
++++ b/fs/exec.c
+@@ -1670,6 +1670,12 @@ int __get_dumpable(unsigned long mm_flag
+ return (ret > SUID_DUMP_USER) ? SUID_DUMP_ROOT : ret;
+ }
+
++/*
++ * This returns the actual value of the suid_dumpable flag. For things
++ * that are using this for checking for privilege transitions, it must
++ * test against SUID_DUMP_USER rather than treating it as a boolean
++ * value.
++ */
+ int get_dumpable(struct mm_struct *mm)
+ {
+ return __get_dumpable(mm->flags);
+--- a/include/linux/binfmts.h
++++ b/include/linux/binfmts.h
+@@ -99,9 +99,6 @@ extern void setup_new_exec(struct linux_
+ extern void would_dump(struct linux_binprm *, struct file *);
+
+ extern int suid_dumpable;
+-#define SUID_DUMP_DISABLE 0 /* No setuid dumping */
+-#define SUID_DUMP_USER 1 /* Dump as user of process */
+-#define SUID_DUMP_ROOT 2 /* Dump as root */
+
+ /* Stack area protections */
+ #define EXSTACK_DEFAULT 0 /* Whatever the arch defaults to */
+--- a/include/linux/sched.h
++++ b/include/linux/sched.h
+@@ -330,6 +330,10 @@ static inline void arch_pick_mmap_layout
+ extern void set_dumpable(struct mm_struct *mm, int value);
+ extern int get_dumpable(struct mm_struct *mm);
+
++#define SUID_DUMP_DISABLE 0 /* No setuid dumping */
++#define SUID_DUMP_USER 1 /* Dump as user of process */
++#define SUID_DUMP_ROOT 2 /* Dump as root */
++
+ /* mm flags */
+ /* dumpable bits */
+ #define MMF_DUMPABLE 0 /* core dump is permitted */
+--- a/kernel/ptrace.c
++++ b/kernel/ptrace.c
+@@ -257,7 +257,8 @@ ok:
+ if (task->mm)
+ dumpable = get_dumpable(task->mm);
+ rcu_read_lock();
+- if (!dumpable && !ptrace_has_cap(__task_cred(task)->user_ns, mode)) {
++ if (dumpable != SUID_DUMP_USER &&
++ !ptrace_has_cap(__task_cred(task)->user_ns, mode)) {
+ rcu_read_unlock();
+ return -EPERM;
+ }