summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Bächler <thomas@archlinux.org>2010-09-17 18:02:09 +0200
committerThomas Bächler <thomas@archlinux.org>2010-09-17 18:02:09 +0200
commit209d5ce787450bcb89223b4605182af0b997011a (patch)
tree35df25f44e865a6350c2dc2503d480517dd58274
parent0a2e00333e8f374116e8df5edd0c6886d4d585d7 (diff)
2.6.35.4-2: Fix x86_64 local root exploit
-rw-r--r--PATCHCFG8
-rw-r--r--patches/compat-root-exploit.patch222
2 files changed, 229 insertions, 1 deletions
diff --git a/PATCHCFG b/PATCHCFG
index 5557bfb..2a93c11 100644
--- a/PATCHCFG
+++ b/PATCHCFG
@@ -15,13 +15,19 @@ PATCHES=(
# add latest fixes from stable queue, if needed
# http://git.kernel.org/?p=linux/kernel/git/stable/stable-queue.git
+ # Fix local root exploits
+ # http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff&h=c41d68a513c71e35a14f66d71782d27a79a81ea6
+ # http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=36d001c70d8a0144ac1d038f6876c484849a74de
+ # http://git.kernel.org/?p=linux/kernel/git/torvalds/linux-2.6.git;a=commitdiff;h=eefdca043e8391dcd719711716492063030b55ac
+ compat-root-exploit.patch%1
+
# add aufs2 support, in reference to:
# http://aufs.sourceforge.net
aufs2-base-20100802.patch%1
aufs2-standalone-20100802.patch%1
)
# Name of the resulting patch (will be bzipped afterwards)
-PATCHNAME="patch-2.6.35.4-1-ARCH"
+PATCHNAME="patch-2.6.35.4-2-ARCH"
# Run this before applying patches
pre_apply() {
diff --git a/patches/compat-root-exploit.patch b/patches/compat-root-exploit.patch
new file mode 100644
index 0000000..d686595
--- /dev/null
+++ b/patches/compat-root-exploit.patch
@@ -0,0 +1,222 @@
+diff --git a/arch/ia64/include/asm/compat.h b/arch/ia64/include/asm/compat.h
+index f90edc8..9301a28 100644
+--- a/arch/ia64/include/asm/compat.h
++++ b/arch/ia64/include/asm/compat.h
+@@ -199,7 +199,7 @@ ptr_to_compat(void __user *uptr)
+ }
+
+ static __inline__ void __user *
+-compat_alloc_user_space (long len)
++arch_compat_alloc_user_space (long len)
+ {
+ struct pt_regs *regs = task_pt_regs(current);
+ return (void __user *) (((regs->r12 & 0xffffffff) & -16) - len);
+diff --git a/arch/mips/include/asm/compat.h b/arch/mips/include/asm/compat.h
+index 613f691..dbc5106 100644
+--- a/arch/mips/include/asm/compat.h
++++ b/arch/mips/include/asm/compat.h
+@@ -145,7 +145,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+ return (u32)(unsigned long)uptr;
+ }
+
+-static inline void __user *compat_alloc_user_space(long len)
++static inline void __user *arch_compat_alloc_user_space(long len)
+ {
+ struct pt_regs *regs = (struct pt_regs *)
+ ((unsigned long) current_thread_info() + THREAD_SIZE - 32) - 1;
+diff --git a/arch/parisc/include/asm/compat.h b/arch/parisc/include/asm/compat.h
+index 02b77ba..efa0b60 100644
+--- a/arch/parisc/include/asm/compat.h
++++ b/arch/parisc/include/asm/compat.h
+@@ -147,7 +147,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+ return (u32)(unsigned long)uptr;
+ }
+
+-static __inline__ void __user *compat_alloc_user_space(long len)
++static __inline__ void __user *arch_compat_alloc_user_space(long len)
+ {
+ struct pt_regs *regs = &current->thread.regs;
+ return (void __user *)regs->gr[30];
+diff --git a/arch/powerpc/include/asm/compat.h b/arch/powerpc/include/asm/compat.h
+index 396d21a..a11d4ea 100644
+--- a/arch/powerpc/include/asm/compat.h
++++ b/arch/powerpc/include/asm/compat.h
+@@ -134,7 +134,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+ return (u32)(unsigned long)uptr;
+ }
+
+-static inline void __user *compat_alloc_user_space(long len)
++static inline void __user *arch_compat_alloc_user_space(long len)
+ {
+ struct pt_regs *regs = current->thread.regs;
+ unsigned long usp = regs->gpr[1];
+diff --git a/arch/s390/include/asm/compat.h b/arch/s390/include/asm/compat.h
+index 104f200..a875c2f 100644
+--- a/arch/s390/include/asm/compat.h
++++ b/arch/s390/include/asm/compat.h
+@@ -181,7 +181,7 @@ static inline int is_compat_task(void)
+
+ #endif
+
+-static inline void __user *compat_alloc_user_space(long len)
++static inline void __user *arch_compat_alloc_user_space(long len)
+ {
+ unsigned long stack;
+
+diff --git a/arch/sparc/include/asm/compat.h b/arch/sparc/include/asm/compat.h
+index 5016f76..6f57325 100644
+--- a/arch/sparc/include/asm/compat.h
++++ b/arch/sparc/include/asm/compat.h
+@@ -167,7 +167,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+ return (u32)(unsigned long)uptr;
+ }
+
+-static inline void __user *compat_alloc_user_space(long len)
++static inline void __user *arch_compat_alloc_user_space(long len)
+ {
+ struct pt_regs *regs = current_thread_info()->kregs;
+ unsigned long usp = regs->u_regs[UREG_I6];
+diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S
+index e790bc1..4f5f71e 100644
+--- a/arch/x86/ia32/ia32entry.S
++++ b/arch/x86/ia32/ia32entry.S
+@@ -50,7 +50,12 @@
+ /*
+ * Reload arg registers from stack in case ptrace changed them.
+ * We don't reload %eax because syscall_trace_enter() returned
+- * the value it wants us to use in the table lookup.
++ * the %rax value we should see. Instead, we just truncate that
++ * value to 32 bits again as we did on entry from user mode.
++ * If it's a new value set by user_regset during entry tracing,
++ * this matches the normal truncation of the user-mode value.
++ * If it's -1 to make us punt the syscall, then (u32)-1 is still
++ * an appropriately invalid value.
+ */
+ .macro LOAD_ARGS32 offset, _r9=0
+ .if \_r9
+@@ -60,6 +65,7 @@
+ movl \offset+48(%rsp),%edx
+ movl \offset+56(%rsp),%esi
+ movl \offset+64(%rsp),%edi
++ movl %eax,%eax /* zero extension */
+ .endm
+
+ .macro CFI_STARTPROC32 simple
+@@ -153,7 +159,7 @@ ENTRY(ia32_sysenter_target)
+ testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
+ CFI_REMEMBER_STATE
+ jnz sysenter_tracesys
+- cmpl $(IA32_NR_syscalls-1),%eax
++ cmpq $(IA32_NR_syscalls-1),%rax
+ ja ia32_badsys
+ sysenter_do_call:
+ IA32_ARG_FIXUP
+@@ -195,7 +201,7 @@ sysexit_from_sys_call:
+ movl $AUDIT_ARCH_I386,%edi /* 1st arg: audit arch */
+ call audit_syscall_entry
+ movl RAX-ARGOFFSET(%rsp),%eax /* reload syscall number */
+- cmpl $(IA32_NR_syscalls-1),%eax
++ cmpq $(IA32_NR_syscalls-1),%rax
+ ja ia32_badsys
+ movl %ebx,%edi /* reload 1st syscall arg */
+ movl RCX-ARGOFFSET(%rsp),%esi /* reload 2nd syscall arg */
+@@ -248,7 +254,7 @@ sysenter_tracesys:
+ call syscall_trace_enter
+ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
+ RESTORE_REST
+- cmpl $(IA32_NR_syscalls-1),%eax
++ cmpq $(IA32_NR_syscalls-1),%rax
+ ja int_ret_from_sys_call /* sysenter_tracesys has set RAX(%rsp) */
+ jmp sysenter_do_call
+ CFI_ENDPROC
+@@ -314,7 +320,7 @@ ENTRY(ia32_cstar_target)
+ testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
+ CFI_REMEMBER_STATE
+ jnz cstar_tracesys
+- cmpl $IA32_NR_syscalls-1,%eax
++ cmpq $IA32_NR_syscalls-1,%rax
+ ja ia32_badsys
+ cstar_do_call:
+ IA32_ARG_FIXUP 1
+@@ -367,7 +373,7 @@ cstar_tracesys:
+ LOAD_ARGS32 ARGOFFSET, 1 /* reload args from stack in case ptrace changed it */
+ RESTORE_REST
+ xchgl %ebp,%r9d
+- cmpl $(IA32_NR_syscalls-1),%eax
++ cmpq $(IA32_NR_syscalls-1),%rax
+ ja int_ret_from_sys_call /* cstar_tracesys has set RAX(%rsp) */
+ jmp cstar_do_call
+ END(ia32_cstar_target)
+@@ -425,7 +431,7 @@ ENTRY(ia32_syscall)
+ orl $TS_COMPAT,TI_status(%r10)
+ testl $_TIF_WORK_SYSCALL_ENTRY,TI_flags(%r10)
+ jnz ia32_tracesys
+- cmpl $(IA32_NR_syscalls-1),%eax
++ cmpq $(IA32_NR_syscalls-1),%rax
+ ja ia32_badsys
+ ia32_do_call:
+ IA32_ARG_FIXUP
+@@ -444,7 +450,7 @@ ia32_tracesys:
+ call syscall_trace_enter
+ LOAD_ARGS32 ARGOFFSET /* reload args from stack in case ptrace changed it */
+ RESTORE_REST
+- cmpl $(IA32_NR_syscalls-1),%eax
++ cmpq $(IA32_NR_syscalls-1),%rax
+ ja int_ret_from_sys_call /* ia32_tracesys has set RAX(%rsp) */
+ jmp ia32_do_call
+ END(ia32_syscall)
+diff --git a/arch/x86/include/asm/compat.h b/arch/x86/include/asm/compat.h
+index 306160e..1d9cd27 100644
+--- a/arch/x86/include/asm/compat.h
++++ b/arch/x86/include/asm/compat.h
+@@ -205,7 +205,7 @@ static inline compat_uptr_t ptr_to_compat(void __user *uptr)
+ return (u32)(unsigned long)uptr;
+ }
+
+-static inline void __user *compat_alloc_user_space(long len)
++static inline void __user *arch_compat_alloc_user_space(long len)
+ {
+ struct pt_regs *regs = task_pt_regs(current);
+ return (void __user *)regs->sp - len;
+diff --git a/include/linux/compat.h b/include/linux/compat.h
+index 168f7da..c766441 100644
+--- a/include/linux/compat.h
++++ b/include/linux/compat.h
+@@ -360,5 +360,8 @@ extern ssize_t compat_rw_copy_check_uvector(int type,
+ const struct compat_iovec __user *uvector, unsigned long nr_segs,
+ unsigned long fast_segs, struct iovec *fast_pointer,
+ struct iovec **ret_pointer);
++
++extern void __user *compat_alloc_user_space(unsigned long len);
++
+ #endif /* CONFIG_COMPAT */
+ #endif /* _LINUX_COMPAT_H */
+diff --git a/kernel/compat.c b/kernel/compat.c
+index 5adab05..91b33fb 100644
+--- a/kernel/compat.c
++++ b/kernel/compat.c
+@@ -1137,3 +1137,24 @@ compat_sys_sysinfo(struct compat_sysinfo __user *info)
+
+ return 0;
+ }
++
++/*
++ * Allocate user-space memory for the duration of a single system call,
++ * in order to marshall parameters inside a compat thunk.
++ */
++void __user *compat_alloc_user_space(unsigned long len)
++{
++ void __user *ptr;
++
++ /* If len would occupy more than half of the entire compat space... */
++ if (unlikely(len > (((compat_uptr_t)~0) >> 1)))
++ return NULL;
++
++ ptr = arch_compat_alloc_user_space(len);
++
++ if (unlikely(!access_ok(VERIFY_WRITE, ptr, len)))
++ return NULL;
++
++ return ptr;
++}
++EXPORT_SYMBOL_GPL(compat_alloc_user_space);