diff options
13 files changed, 1483 insertions, 1 deletions
diff --git a/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch b/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch new file mode 100644 index 0000000..2053e03 --- /dev/null +++ b/01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch @@ -0,0 +1,198 @@ +From f45716729488bd8263b06e7d672c8ff8f2ded8b7 Mon Sep 17 00:00:00 2001 +From: H. Peter Anvin <hpa@linux.intel.com> +Date: Tue, 7 Sep 2010 16:16:18 -0700 +Subject: [PATCH 1/4] compat: Make compat_alloc_user_space() incorporate the access_ok() + +compat_alloc_user_space() expects the caller to independently call +access_ok() to verify the returned area. A missing call could +introduce problems on some architectures. + +This patch incorporates the access_ok() check into +compat_alloc_user_space() and also adds a sanity check on the length. +The existing compat_alloc_user_space() implementations are renamed +arch_compat_alloc_user_space() and are used as part of the +implementation of the new global function. + +This patch assumes NULL will cause __get_user()/__put_user() to either +fail or access userspace on all architectures. This should be +followed by checking the return value of compat_access_user_space() +for NULL in the callers, at which time the access_ok() in the callers +can also be removed. + +Reported-by: Ben Hawkes <hawkes@sota.gen.nz> +Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> +Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org> +Acked-by: Chris Metcalf <cmetcalf@tilera.com> +Acked-by: David S. Miller <davem@davemloft.net> +Acked-by: Ingo Molnar <mingo@elte.hu> +Acked-by: Thomas Gleixner <tglx@linutronix.de> +Acked-by: Tony Luck <tony.luck@intel.com> +Cc: Andrew Morton <akpm@linux-foundation.org> +Cc: Arnd Bergmann <arnd@arndb.de> +Cc: Fenghua Yu <fenghua.yu@intel.com> +Cc: H. Peter Anvin <hpa@zytor.com> +Cc: Heiko Carstens <heiko.carstens@de.ibm.com> +Cc: Helge Deller <deller@gmx.de> +Cc: James Bottomley <jejb@parisc-linux.org> +Cc: Kyle McMartin <kyle@mcmartin.ca> +Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> +Cc: Paul Mackerras <paulus@samba.org> +Cc: Ralf Baechle <ralf@linux-mips.org> +Cc: <stable@kernel.org> +--- + + [ edited to fix build on 2.6.32 ] + + arch/ia64/include/asm/compat.h | 2 +- + arch/mips/include/asm/compat.h | 2 +- + arch/parisc/include/asm/compat.h | 2 +- + arch/powerpc/include/asm/compat.h | 2 +- + arch/s390/include/asm/compat.h | 2 +- + arch/sparc/include/asm/compat.h | 2 +- + arch/x86/include/asm/compat.h | 2 +- + include/linux/compat.h | 2 ++ + kernel/compat.c | 22 +++++++++++++++++++++ + 9 files changed, 30 insertions(+), 7 deletions(-) + +diff --git a/arch/ia64/include/asm/compat.h b/arch/ia64/include/asm/compat.h +index dfcf75b..c8662cd 100644 +--- a/arch/ia64/include/asm/compat.h ++++ b/arch/ia64/include/asm/compat.h +@@ -198,7 +198,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 f58aed3..27505bd 100644 +--- a/arch/mips/include/asm/compat.h ++++ b/arch/mips/include/asm/compat.h +@@ -144,7 +144,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 7f32611..7c77fa9 100644 +--- a/arch/parisc/include/asm/compat.h ++++ b/arch/parisc/include/asm/compat.h +@@ -146,7 +146,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 = ¤t->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 4774c2f..8d0fff3 100644 +--- a/arch/powerpc/include/asm/compat.h ++++ b/arch/powerpc/include/asm/compat.h +@@ -133,7 +133,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 01a0802..0c940d3 100644 +--- a/arch/s390/include/asm/compat.h ++++ b/arch/s390/include/asm/compat.h +@@ -180,7 +180,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 0e70625..612bb38 100644 +--- a/arch/sparc/include/asm/compat.h ++++ b/arch/sparc/include/asm/compat.h +@@ -166,7 +166,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/include/asm/compat.h b/arch/x86/include/asm/compat.h +index 9a9c7bd..c8c9a74 100644 +--- a/arch/x86/include/asm/compat.h ++++ b/arch/x86/include/asm/compat.h +@@ -204,7 +204,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 af931ee..cab23f2 100644 +--- a/include/linux/compat.h ++++ b/include/linux/compat.h +@@ -309,5 +309,7 @@ asmlinkage long compat_sys_newfstatat(unsigned int dfd, char __user * filename, + asmlinkage long compat_sys_openat(unsigned int dfd, const char __user *filename, + int flags, int mode); + ++extern void __user *compat_alloc_user_space(unsigned long len); ++ + #endif /* CONFIG_COMPAT */ + #endif /* _LINUX_COMPAT_H */ +diff a/kernel/compat.c b/kernel/compat.c +--- a/kernel/compat.c ++++ b/kernel/compat.c +@@ -13,6 +13,7 @@ + + #include <linux/linkage.h> + #include <linux/compat.h> ++#include <linux/module.h> + #include <linux/errno.h> + #include <linux/time.h> + #include <linux/signal.h> +@@ -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); +-- +1.7.2.3 + diff --git a/02-compat-test-rax-for-the-system-call-number-not-eax.patch b/02-compat-test-rax-for-the-system-call-number-not-eax.patch new file mode 100644 index 0000000..8fd7490 --- /dev/null +++ b/02-compat-test-rax-for-the-system-call-number-not-eax.patch @@ -0,0 +1,97 @@ +From aaeacea2992c28f1d355ff7cd4c4754131bdd831 Mon Sep 17 00:00:00 2001 +From: H. Peter Anvin <hpa@linux.intel.com> +Date: Tue, 14 Sep 2010 12:42:41 -0700 +Subject: [PATCH 2/4] x86-64, compat: Test %rax for the syscall number, not %eax + +On 64 bits, we always, by necessity, jump through the system call +table via %rax. For 32-bit system calls, in theory the system call +number is stored in %eax, and the code was testing %eax for a valid +system call number. At one point we loaded the stored value back from +the stack to enforce zero-extension, but that was removed in checkin +d4d67150165df8bf1cc05e532f6efca96f907cab. An actual 32-bit process +will not be able to introduce a non-zero-extended number, but it can +happen via ptrace. + +Instead of re-introducing the zero-extension, test what we are +actually going to use, i.e. %rax. This only adds a handful of REX +prefixes to the code. + +Reported-by: Ben Hawkes <hawkes@sota.gen.nz> +Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> +Cc: <stable@kernel.org> +Cc: Roland McGrath <roland@redhat.com> +Cc: Andrew Morton <akpm@linux-foundation.org> +--- + arch/x86/ia32/ia32entry.S | 14 +++++++------- + 1 files changed, 7 insertions(+), 7 deletions(-) + +diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S +index 5294d84..7f9eb54 100644 +--- a/arch/x86/ia32/ia32entry.S ++++ b/arch/x86/ia32/ia32entry.S +@@ -153,7 +153,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 +195,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 +248,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 +314,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 +367,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 +425,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 +444,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) +-- +1.7.2.3 + diff --git a/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch b/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch new file mode 100644 index 0000000..96c269b --- /dev/null +++ b/03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch @@ -0,0 +1,49 @@ +From 1fa16daaa76d1b132c8fee027c11bad5a5d25761 Mon Sep 17 00:00:00 2001 +From: Roland McGrath <roland@redhat.com> +Date: Tue, 14 Sep 2010 12:22:58 -0700 +Subject: [PATCH 3/4] x86-64, compat: Retruncate rax after ia32 syscall entry tracing + +In commit d4d6715, we reopened an old hole for a 64-bit ptracer touching a +32-bit tracee in system call entry. A %rax value set via ptrace at the +entry tracing stop gets used whole as a 32-bit syscall number, while we +only check the low 32 bits for validity. + +Fix it by truncating %rax back to 32 bits after syscall_trace_enter, +in addition to testing the full 64 bits as has already been added. + +Reported-by: Ben Hawkes <hawkes@sota.gen.nz> +Signed-off-by: Roland McGrath <roland@redhat.com> +Signed-off-by: H. Peter Anvin <hpa@linux.intel.com> +--- + arch/x86/ia32/ia32entry.S | 8 +++++++- + 1 files changed, 7 insertions(+), 1 deletions(-) + +diff --git a/arch/x86/ia32/ia32entry.S b/arch/x86/ia32/ia32entry.S +index 7f9eb54..4edd8eb 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 +-- +1.7.2.3 + diff --git a/aio-check-for-multiplication-overflow-in-do_io_submit.patch b/aio-check-for-multiplication-overflow-in-do_io_submit.patch new file mode 100644 index 0000000..8706792 --- /dev/null +++ b/aio-check-for-multiplication-overflow-in-do_io_submit.patch @@ -0,0 +1,47 @@ +From be18992d0630149403bfae5882601cf01a7d4eea Mon Sep 17 00:00:00 2001 +From: Jeff Moyer <jmoyer@redhat.com> +Date: Fri, 10 Sep 2010 14:16:00 -0700 +Subject: [PATCH 4/4] aio: check for multiplication overflow in do_io_submit +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +Tavis Ormandy pointed out that do_io_submit does not do proper bounds +checking on the passed-in iocb array: + + if (unlikely(nr < 0)) + return -EINVAL; + + if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(iocbpp))))) + return -EFAULT; ^^^^^^^^^^^^^^^^^^ + +The attached patch checks for overflow, and if it is detected, the +number of iocbs submitted is scaled down to a number that will fit in +the long. This is an ok thing to do, as sys_io_submit is documented as +returning the number of iocbs submitted, so callers should handle a +return value of less than the 'nr' argument passed in. + +Reported-by: Tavis Ormandy <taviso@cmpxchg8b.com> +Signed-off-by: Jeff Moyer <jmoyer@redhat.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + fs/aio.c | 3 +++ + 1 files changed, 3 insertions(+), 0 deletions(-) + +diff --git a/fs/aio.c b/fs/aio.c +index 02a2c93..b84a769 100644 +--- a/fs/aio.c ++++ b/fs/aio.c +@@ -1639,6 +1639,9 @@ SYSCALL_DEFINE3(io_submit, aio_context_t, ctx_id, long, nr, + if (unlikely(nr < 0)) + return -EINVAL; + ++ if (unlikely(nr > LONG_MAX/sizeof(*iocbpp))) ++ nr = LONG_MAX/sizeof(*iocbpp); ++ + if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) + return -EFAULT; + +-- +1.7.2.3 + diff --git a/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch b/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch new file mode 100644 index 0000000..73e65ec --- /dev/null +++ b/alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch @@ -0,0 +1,53 @@ +From: Takashi Iwai <tiwai@suse.de> +Date: Mon, 6 Sep 2010 07:13:45 +0000 (+0200) +Subject: ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open() +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=27f7ad53829f79e799a253285318bff79ece15bd + +ALSA: seq/oss - Fix double-free at error path of snd_seq_oss_open() + +The error handling in snd_seq_oss_open() has several bad codes that +do dereferecing released pointers and double-free of kmalloc'ed data. +The object dp is release in free_devinfo() that is called via +private_free callback. The rest shouldn't touch this object any more. + +The patch changes delete_port() to call kfree() in any case, and gets +rid of unnecessary calls of destructors in snd_seq_oss_open(). + +Fixes CVE-2010-3080. + +Reported-and-tested-by: Tavis Ormandy <taviso@cmpxchg8b.com> +Cc: <stable@kernel.org> +Signed-off-by: Takashi Iwai <tiwai@suse.de> +--- + +diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c +index 6857122..69cd7b3 100644 +--- a/sound/core/seq/oss/seq_oss_init.c ++++ b/sound/core/seq/oss/seq_oss_init.c +@@ -281,13 +281,10 @@ snd_seq_oss_open(struct file *file, int level) + return 0; + + _error: +- snd_seq_oss_writeq_delete(dp->writeq); +- snd_seq_oss_readq_delete(dp->readq); + snd_seq_oss_synth_cleanup(dp); + snd_seq_oss_midi_cleanup(dp); +- delete_port(dp); + delete_seq_queue(dp->queue); +- kfree(dp); ++ delete_port(dp); + + return rc; + } +@@ -350,8 +347,10 @@ create_port(struct seq_oss_devinfo *dp) + static int + delete_port(struct seq_oss_devinfo *dp) + { +- if (dp->port < 0) ++ if (dp->port < 0) { ++ kfree(dp); + return 0; ++ } + + debug_printk(("delete_port %i\n", dp->port)); + return snd_seq_event_port_detach(dp->cseq, dp->port); diff --git a/execve-improve-interactivity-with-large-arguments.patch b/execve-improve-interactivity-with-large-arguments.patch new file mode 100644 index 0000000..7908e6c --- /dev/null +++ b/execve-improve-interactivity-with-large-arguments.patch @@ -0,0 +1,36 @@ +From: Roland McGrath <roland@redhat.com> +Date: Wed, 8 Sep 2010 02:36:28 +0000 (-0700) +Subject: execve: improve interactivity with large arguments +X-Git-Tag: v2.6.36-rc4~13 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=7993bc1f4663c0db67bb8f0d98e6678145b387cd + +execve: improve interactivity with large arguments + +This adds a preemption point during the copying of the argument and +environment strings for execve, in copy_strings(). There is already +a preemption point in the count() loop, so this doesn't add any new +points in the abstract sense. + +When the total argument+environment strings are very large, the time +spent copying them can be much more than a normal user time slice. +So this change improves the interactivity of the rest of the system +when one process is doing an execve with very large arguments. + +Signed-off-by: Roland McGrath <roland@redhat.com> +Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/fs/exec.c b/fs/exec.c +index 1b63237..6f2d777 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -419,6 +419,8 @@ static int copy_strings(int argc, const char __user *const __user *argv, + while (len > 0) { + int offset, bytes_to_copy; + ++ cond_resched(); ++ + offset = pos % PAGE_SIZE; + if (offset == 0) + offset = PAGE_SIZE; diff --git a/execve-make-responsive-to-sigkill-with-large-arguments.patch b/execve-make-responsive-to-sigkill-with-large-arguments.patch new file mode 100644 index 0000000..a9e531a --- /dev/null +++ b/execve-make-responsive-to-sigkill-with-large-arguments.patch @@ -0,0 +1,51 @@ +From: Roland McGrath <roland@redhat.com> +Date: Wed, 8 Sep 2010 02:37:06 +0000 (-0700) +Subject: execve: make responsive to SIGKILL with large arguments +X-Git-Tag: v2.6.36-rc4~12 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9aea5a65aa7a1af9a4236dfaeb0088f1624f9919 + +execve: make responsive to SIGKILL with large arguments + +An execve with a very large total of argument/environment strings +can take a really long time in the execve system call. It runs +uninterruptibly to count and copy all the strings. This change +makes it abort the exec quickly if sent a SIGKILL. + +Note that this is the conservative change, to interrupt only for +SIGKILL, by using fatal_signal_pending(). It would be perfectly +correct semantics to let any signal interrupt the string-copying in +execve, i.e. use signal_pending() instead of fatal_signal_pending(). +We'll save that change for later, since it could have user-visible +consequences, such as having a timer set too quickly make it so that +an execve can never complete, though it always happened to work before. + +Signed-off-by: Roland McGrath <roland@redhat.com> +Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/fs/exec.c b/fs/exec.c +index 6f2d777..828dd24 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -376,6 +376,9 @@ static int count(const char __user * const __user * argv, int max) + argv++; + if (i++ >= max) + return -E2BIG; ++ ++ if (fatal_signal_pending(current)) ++ return -ERESTARTNOHAND; + cond_resched(); + } + } +@@ -419,6 +422,10 @@ static int copy_strings(int argc, const char __user *const __user *argv, + while (len > 0) { + int offset, bytes_to_copy; + ++ if (fatal_signal_pending(current)) { ++ ret = -ERESTARTNOHAND; ++ goto out; ++ } + cond_resched(); + + offset = pos % PAGE_SIZE; diff --git a/kernel.spec b/kernel.spec index 797f477..e87e09e 100644 --- a/kernel.spec +++ b/kernel.spec @@ -48,7 +48,7 @@ Summary: The Linux kernel # reset this by hand to 1 (or to 0 and then use rpmdev-bumpspec). # scripts/rebase.sh should be made to do that for you, actually. # -%global baserelease 167 +%global baserelease 168 %global fedora_build %{baserelease} # base_sublevel is the kernel version we're starting with and patching @@ -640,6 +640,11 @@ Patch21: linux-2.6-tracehook.patch Patch22: linux-2.6-utrace.patch Patch23: linux-2.6-utrace-ptrace.patch +Patch100: 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch +Patch101: 02-compat-test-rax-for-the-system-call-number-not-eax.patch +Patch102: 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch +Patch103: aio-check-for-multiplication-overflow-in-do_io_submit.patch + Patch141: linux-2.6-ps3-storage-alias.patch Patch143: linux-2.6-g5-therm-shutdown.patch Patch144: linux-2.6-vio-modalias.patch @@ -842,6 +847,21 @@ Patch14141: hid-02-fix-suspend-crash-by-moving-initializations-earlier.patch Patch14150: irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch +Patch14200: net-do-not-check-capable-if-kernel.patch + +# Mitigate DOS with large argument lists +Patch14210: execve-improve-interactivity-with-large-arguments.patch +Patch14211: execve-make-responsive-to-sigkill-with-large-arguments.patch +Patch14212: setup_arg_pages-diagnose-excessive-argument-size.patch + +# CVE-2010-3080 +Patch14220: alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch +# CVE-2010-2960 +Patch14230: keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch +Patch14231: keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch +# CVE-2010-3079 +Patch14240: tracing-do-not-allow-llseek-to-set_ftrace_filter.patch + Patch19997: xen.pvops.pre.patch Patch19998: xen.pvops.patch Patch19999: xen.pvops.post.patch @@ -1286,6 +1306,11 @@ ApplyPatch linux-2.6-utrace-ptrace.patch ApplyPatch via-hwmon-temp-sensor.patch ApplyPatch linux-2.6-dell-laptop-rfkill-fix.patch +ApplyPatch 01-compat-make-compat_alloc_user_space-incorporate-the-access_ok-check.patch +ApplyPatch 02-compat-test-rax-for-the-system-call-number-not-eax.patch +ApplyPatch 03-compat-retruncate-rax-after-ia32-syscall-entry-tracing.patch + + # # Intel IOMMU # @@ -1319,6 +1344,7 @@ ApplyPatch linux-2.6-execshield.patch # # bugfixes to drivers and filesystems # +ApplyPatch aio-check-for-multiplication-overflow-in-do_io_submit.patch # ext4 @@ -1556,6 +1582,22 @@ ApplyPatch hid-02-fix-suspend-crash-by-moving-initializations-earlier.patch # CVE-2010-2954 ApplyPatch irda-correctly-clean-up-self-ias_obj-on-irda_bind-failure.patch +# rhbz #598796 +ApplyPatch net-do-not-check-capable-if-kernel.patch + +# Mitigate DOS with large argument lists +ApplyPatch execve-improve-interactivity-with-large-arguments.patch +ApplyPatch execve-make-responsive-to-sigkill-with-large-arguments.patch +ApplyPatch setup_arg_pages-diagnose-excessive-argument-size.patch + +# CVE-2010-3080 +ApplyPatch alsa-seq-oss-fix-double-free-at-error-path-of-snd_seq_oss_open.patch +# CVE-2010-2960 +ApplyPatch keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch +ApplyPatch keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch +# CVE-2010-3079 +ApplyPatch tracing-do-not-allow-llseek-to-set_ftrace_filter.patch + ApplyPatch xen.pvops.pre.patch ApplyPatch xen.pvops.patch ApplyPatch xen.pvops.post.patch @@ -2212,6 +2254,24 @@ fi %kernel_variant_files -k vmlinux %{with_kdump} kdump %changelog +* Tue Sep 14 2010 Chuck Ebbert <cebbert@redhat.com> 2.6.32.21-168 +- Fix three CVEs: + CVE-2010-3080: /dev/sequencer open failure is not handled correctly + CVE-2010-2960: keyctl_session_to_parent NULL deref system crash + CVE-2010-3079: ftrace NULL pointer dereference + +* Tue Sep 14 2010 Chuck Ebbert <cebbert@redhat.com> +- Mitigate DOS with large argument lists. + +* Tue Sep 14 2010 Kyle McMartin <kyle@redhat.com> +- x86_64: plug compat syscalls holes. (CVE-2010-3081, CVE-2010-3301) + upgrading is highly recommended. +- aio: check for multiplication overflow in do_io_submit. (CVE-2010-3067) + +* Mon Sep 06 2010 Kyle McMartin <kyle@redhat.com> +- Backport two fixes from Eric Paris to resolve #598796 which avoids a + capability check if the request comes from the kernel. + * Fri Sep 03 2010 Michael Young <m.a.young@durham.ac.uk> - update pvops to 2.6.32.21 - Set new dom0 related option CONFIG_NET_SCH_PLUG=m diff --git a/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch b/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch new file mode 100644 index 0000000..fb62519 --- /dev/null +++ b/keys-fix-bug-in-keyctl_session_to_parent-if-parent-has-no-session-keyring.patch @@ -0,0 +1,52 @@ +From: David Howells <dhowells@redhat.com> +Date: Fri, 10 Sep 2010 08:59:51 +0000 (+0100) +Subject: KEYS: Fix bug in keyctl_session_to_parent() if parent has no session keyring +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=3d96406c7da1ed5811ea52a3b0905f4f0e295376 + +KEYS: Fix bug in keyctl_session_to_parent() if parent has no session keyring + +Fix a bug in keyctl_session_to_parent() whereby it tries to check the ownership +of the parent process's session keyring whether or not the parent has a session +keyring [CVE-2010-2960]. + +This results in the following oops: + + BUG: unable to handle kernel NULL pointer dereference at 00000000000000a0 + IP: [<ffffffff811ae4dd>] keyctl_session_to_parent+0x251/0x443 + ... + Call Trace: + [<ffffffff811ae2f3>] ? keyctl_session_to_parent+0x67/0x443 + [<ffffffff8109d286>] ? __do_fault+0x24b/0x3d0 + [<ffffffff811af98c>] sys_keyctl+0xb4/0xb8 + [<ffffffff81001eab>] system_call_fastpath+0x16/0x1b + +if the parent process has no session keyring. + +If the system is using pam_keyinit then it mostly protected against this as all +processes derived from a login will have inherited the session keyring created +by pam_keyinit during the log in procedure. + +To test this, pam_keyinit calls need to be commented out in /etc/pam.d/. + +Reported-by: Tavis Ormandy <taviso@cmpxchg8b.com> +Signed-off-by: David Howells <dhowells@redhat.com> +Acked-by: Tavis Ormandy <taviso@cmpxchg8b.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +[ 2.6.32 backport ] + +diff a/security/keys/keyctl.c b/security/keys/keyctl.c +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -1291,7 +1291,8 @@ long keyctl_session_to_parent(void) + goto not_permitted; + + /* the keyrings must have the same UID */ +- if (pcred ->tgcred->session_keyring->uid != mycred->euid || ++ if ((pcred->tgcred->session_keyring && ++ pcred->tgcred->session_keyring->uid != mycred->euid) || + mycred->tgcred->session_keyring->uid != mycred->euid) + goto not_permitted; + + diff --git a/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch b/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch new file mode 100644 index 0000000..5318f7e --- /dev/null +++ b/keys-fix-rcu-no-lock-warning-in-keyctl_session_to_parent.patch @@ -0,0 +1,64 @@ +From: David Howells <dhowells@redhat.com> +Date: Fri, 10 Sep 2010 08:59:46 +0000 (+0100) +Subject: KEYS: Fix RCU no-lock warning in keyctl_session_to_parent() +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9d1ac65a9698513d00e5608d93fca0c53f536c14 + +KEYS: Fix RCU no-lock warning in keyctl_session_to_parent() + +There's an protected access to the parent process's credentials in the middle +of keyctl_session_to_parent(). This results in the following RCU warning: + + =================================================== + [ INFO: suspicious rcu_dereference_check() usage. ] + --------------------------------------------------- + security/keys/keyctl.c:1291 invoked rcu_dereference_check() without protection! + + other info that might help us debug this: + + rcu_scheduler_active = 1, debug_locks = 0 + 1 lock held by keyctl-session-/2137: + #0: (tasklist_lock){.+.+..}, at: [<ffffffff811ae2ec>] keyctl_session_to_parent+0x60/0x236 + + stack backtrace: + Pid: 2137, comm: keyctl-session- Not tainted 2.6.36-rc2-cachefs+ #1 + Call Trace: + [<ffffffff8105606a>] lockdep_rcu_dereference+0xaa/0xb3 + [<ffffffff811ae379>] keyctl_session_to_parent+0xed/0x236 + [<ffffffff811af77e>] sys_keyctl+0xb4/0xb6 + [<ffffffff81001eab>] system_call_fastpath+0x16/0x1b + +The code should take the RCU read lock to make sure the parents credentials +don't go away, even though it's holding a spinlock and has IRQ disabled. + +Signed-off-by: David Howells <dhowells@redhat.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/security/keys/keyctl.c b/security/keys/keyctl.c +index b2b0998..3868c67 100644 +--- a/security/keys/keyctl.c ++++ b/security/keys/keyctl.c +@@ -1272,6 +1272,7 @@ long keyctl_session_to_parent(void) + keyring_r = NULL; + + me = current; ++ rcu_read_lock(); + write_lock_irq(&tasklist_lock); + + parent = me->real_parent; +@@ -1319,6 +1320,7 @@ long keyctl_session_to_parent(void) + set_ti_thread_flag(task_thread_info(parent), TIF_NOTIFY_RESUME); + + write_unlock_irq(&tasklist_lock); ++ rcu_read_unlock(); + if (oldcred) + put_cred(oldcred); + return 0; +@@ -1327,6 +1329,7 @@ already_same: + ret = 0; + not_permitted: + write_unlock_irq(&tasklist_lock); ++ rcu_read_unlock(); + put_cred(cred); + return ret; + diff --git a/net-do-not-check-capable-if-kernel.patch b/net-do-not-check-capable-if-kernel.patch new file mode 100644 index 0000000..0669a6c --- /dev/null +++ b/net-do-not-check-capable-if-kernel.patch @@ -0,0 +1,682 @@ +commit abbee616fa69a781c6e58249318a7ae6796a3394 +Author: Eric Paris <eparis@redhat.com> +Date: Thu Nov 5 20:45:52 2009 -0800 + + net: check kern before calling security subsystem + + Before calling capable(CAP_NET_RAW) check if this operations is on behalf + of the kernel or on behalf of userspace. Do not do the security check if + it is on behalf of the kernel. + + Signed-off-by: Eric Paris <eparis@redhat.com> + Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com> + Signed-off-by: David S. Miller <davem@davemloft.net> + +commit 8b7950c0735ab6228f08e7b19fc0f94c09c7f2ba +Author: Eric Paris <eparis@redhat.com> +Date: Thu Nov 5 22:18:14 2009 -0800 + + net: pass kern to net_proto_family create function + + The generic __sock_create function has a kern argument which allows the + security system to make decisions based on if a socket is being created by + the kernel or by userspace. This patch passes that flag to the + net_proto_family specific create function, so it can do the same thing. + + Signed-off-by: Eric Paris <eparis@redhat.com> + Acked-by: Arnaldo Carvalho de Melo <acme@redhat.com> + Signed-off-by: David S. Miller <davem@davemloft.net> + +--- + drivers/isdn/mISDN/socket.c | 2 +- + drivers/net/pppox.c | 3 ++- + include/linux/net.h | 3 ++- + net/appletalk/ddp.c | 3 ++- + net/atm/pvc.c | 3 ++- + net/atm/svc.c | 7 ++++--- + net/ax25/af_ax25.c | 3 ++- + net/bluetooth/af_bluetooth.c | 5 +++-- + net/bluetooth/bnep/sock.c | 3 ++- + net/bluetooth/cmtp/sock.c | 3 ++- + net/bluetooth/hci_sock.c | 3 ++- + net/bluetooth/hidp/sock.c | 3 ++- + net/bluetooth/l2cap.c | 5 +++-- + net/bluetooth/rfcomm/sock.c | 3 ++- + net/bluetooth/sco.c | 3 ++- + net/can/af_can.c | 3 ++- + net/decnet/af_decnet.c | 3 ++- + net/econet/af_econet.c | 3 ++- + net/ieee802154/af_ieee802154.c | 2 +- + net/ipv4/af_inet.c | 5 +++-- + net/ipv6/af_inet6.c | 5 +++-- + net/ipx/af_ipx.c | 3 ++- + net/irda/af_irda.c | 7 ++++--- + net/iucv/af_iucv.c | 3 ++- + net/key/af_key.c | 3 ++- + net/llc/af_llc.c | 5 ++++- + net/netlink/af_netlink.c | 3 ++- + net/netrom/af_netrom.c | 3 ++- + net/packet/af_packet.c | 3 ++- + net/phonet/af_phonet.c | 3 ++- + net/rds/af_rds.c | 3 ++- + net/rose/af_rose.c | 3 ++- + net/rxrpc/af_rxrpc.c | 3 ++- + net/socket.c | 2 +- + net/tipc/socket.c | 6 ++++-- + net/unix/af_unix.c | 3 ++- + net/x25/af_x25.c | 3 ++- + 37 files changed, 83 insertions(+), 46 deletions(-) + +diff --git a/drivers/isdn/mISDN/socket.c b/drivers/isdn/mISDN/socket.c +index feb0fa4..8167346 100644 +--- a/drivers/isdn/mISDN/socket.c ++++ b/drivers/isdn/mISDN/socket.c +@@ -779,7 +779,7 @@ base_sock_create(struct net *net, struct socket *sock, int protocol) + } + + static int +-mISDN_sock_create(struct net *net, struct socket *sock, int proto) ++mISDN_sock_create(struct net *net, struct socket *sock, int proto, int kern) + { + int err = -EPROTONOSUPPORT; + +diff --git a/drivers/net/pppox.c b/drivers/net/pppox.c +index 4f6d33f..a155baf 100644 +--- a/drivers/net/pppox.c ++++ b/drivers/net/pppox.c +@@ -104,7 +104,8 @@ int pppox_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) + + EXPORT_SYMBOL(pppox_ioctl); + +-static int pppox_create(struct net *net, struct socket *sock, int protocol) ++static int pppox_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + int rc = -EPROTOTYPE; + +diff --git a/include/linux/net.h b/include/linux/net.h +index 529a093..3a63efd 100644 +--- a/include/linux/net.h ++++ b/include/linux/net.h +@@ -200,7 +200,8 @@ struct proto_ops { + + struct net_proto_family { + int family; +- int (*create)(struct net *net, struct socket *sock, int protocol); ++ int (*create)(struct net *net, struct socket *sock, ++ int protocol, int kern); + struct module *owner; + }; + +diff --git a/net/appletalk/ddp.c b/net/appletalk/ddp.c +index b1a4290..7c22d90 100644 +--- a/net/appletalk/ddp.c ++++ b/net/appletalk/ddp.c +@@ -1021,7 +1021,8 @@ static struct proto ddp_proto = { + * Create a socket. Initialise the socket, blank the addresses + * set the state. + */ +-static int atalk_create(struct net *net, struct socket *sock, int protocol) ++static int atalk_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + int rc = -ESOCKTNOSUPPORT; +diff --git a/net/atm/pvc.c b/net/atm/pvc.c +index d4c0245..e879725 100644 +--- a/net/atm/pvc.c ++++ b/net/atm/pvc.c +@@ -127,7 +127,8 @@ static const struct proto_ops pvc_proto_ops = { + }; + + +-static int pvc_create(struct net *net, struct socket *sock,int protocol) ++static int pvc_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + if (net != &init_net) + return -EAFNOSUPPORT; +diff --git a/net/atm/svc.c b/net/atm/svc.c +index f90d143..ed096a6 100644 +--- a/net/atm/svc.c ++++ b/net/atm/svc.c +@@ -25,7 +25,7 @@ + #include "signaling.h" + #include "addr.h" + +-static int svc_create(struct net *net, struct socket *sock,int protocol); ++static int svc_create(struct net *net, struct socket *sock, int protocol, int kern); + + /* + * Note: since all this is still nicely synchronized with the signaling demon, +@@ -330,7 +330,7 @@ static int svc_accept(struct socket *sock,struct socket *newsock,int flags) + + lock_sock(sk); + +- error = svc_create(sock_net(sk), newsock,0); ++ error = svc_create(sock_net(sk), newsock, 0, 0); + if (error) + goto out; + +@@ -650,7 +650,8 @@ static const struct proto_ops svc_proto_ops = { + }; + + +-static int svc_create(struct net *net, struct socket *sock,int protocol) ++static int svc_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + int error; + +diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c +index f454607..274d5c0 100644 +--- a/net/ax25/af_ax25.c ++++ b/net/ax25/af_ax25.c +@@ -800,7 +800,8 @@ static struct proto ax25_proto = { + .obj_size = sizeof(struct sock), + }; + +-static int ax25_create(struct net *net, struct socket *sock, int protocol) ++static int ax25_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + ax25_cb *ax25; +diff --git a/net/bluetooth/af_bluetooth.c b/net/bluetooth/af_bluetooth.c +index 8cfb5a8..af074ed 100644 +--- a/net/bluetooth/af_bluetooth.c ++++ b/net/bluetooth/af_bluetooth.c +@@ -126,7 +126,8 @@ int bt_sock_unregister(int proto) + } + EXPORT_SYMBOL(bt_sock_unregister); + +-static int bt_sock_create(struct net *net, struct socket *sock, int proto) ++static int bt_sock_create(struct net *net, struct socket *sock, int proto, ++ int kern) + { + int err; + +@@ -144,7 +145,7 @@ static int bt_sock_create(struct net *net, struct socket *sock, int proto) + read_lock(&bt_proto_lock); + + if (bt_proto[proto] && try_module_get(bt_proto[proto]->owner)) { +- err = bt_proto[proto]->create(net, sock, proto); ++ err = bt_proto[proto]->create(net, sock, proto, kern); + bt_sock_reclassify_lock(sock, proto); + module_put(bt_proto[proto]->owner); + } +diff --git a/net/bluetooth/bnep/sock.c b/net/bluetooth/bnep/sock.c +index e857628..ee86b31 100644 +--- a/net/bluetooth/bnep/sock.c ++++ b/net/bluetooth/bnep/sock.c +@@ -195,7 +195,8 @@ static struct proto bnep_proto = { + .obj_size = sizeof(struct bt_sock) + }; + +-static int bnep_sock_create(struct net *net, struct socket *sock, int protocol) ++static int bnep_sock_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/bluetooth/cmtp/sock.c b/net/bluetooth/cmtp/sock.c +index 16b0fad..536482f 100644 +--- a/net/bluetooth/cmtp/sock.c ++++ b/net/bluetooth/cmtp/sock.c +@@ -190,7 +190,8 @@ static struct proto cmtp_proto = { + .obj_size = sizeof(struct bt_sock) + }; + +-static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol) ++static int cmtp_sock_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/bluetooth/hci_sock.c b/net/bluetooth/hci_sock.c +index 75302a9..94a138f 100644 +--- a/net/bluetooth/hci_sock.c ++++ b/net/bluetooth/hci_sock.c +@@ -621,7 +621,8 @@ static struct proto hci_sk_proto = { + .obj_size = sizeof(struct hci_pinfo) + }; + +-static int hci_sock_create(struct net *net, struct socket *sock, int protocol) ++static int hci_sock_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/bluetooth/hidp/sock.c b/net/bluetooth/hidp/sock.c +index 37c9d7d..40fac2c 100644 +--- a/net/bluetooth/hidp/sock.c ++++ b/net/bluetooth/hidp/sock.c +@@ -241,7 +241,8 @@ static struct proto hidp_proto = { + .obj_size = sizeof(struct bt_sock) + }; + +-static int hidp_sock_create(struct net *net, struct socket *sock, int protocol) ++static int hidp_sock_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/bluetooth/l2cap.c b/net/bluetooth/l2cap.c +index 8d1c4a9..0fdf477 100644 +--- a/net/bluetooth/l2cap.c ++++ b/net/bluetooth/l2cap.c +@@ -819,7 +819,8 @@ static struct sock *l2cap_sock_alloc(struct net *net, struct socket *sock, int p + return sk; + } + +-static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol) ++static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +@@ -831,7 +832,7 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol) + sock->type != SOCK_DGRAM && sock->type != SOCK_RAW) + return -ESOCKTNOSUPPORT; + +- if (sock->type == SOCK_RAW && !capable(CAP_NET_RAW)) ++ if (sock->type == SOCK_RAW && !kern && !capable(CAP_NET_RAW)) + return -EPERM; + + sock->ops = &l2cap_sock_ops; +diff --git a/net/bluetooth/rfcomm/sock.c b/net/bluetooth/rfcomm/sock.c +index 30a3649..f596455 100644 +--- a/net/bluetooth/rfcomm/sock.c ++++ b/net/bluetooth/rfcomm/sock.c +@@ -323,7 +323,8 @@ static struct sock *rfcomm_sock_alloc(struct net *net, struct socket *sock, int + return sk; + } + +-static int rfcomm_sock_create(struct net *net, struct socket *sock, int protocol) ++static int rfcomm_sock_create(struct net *net, struct socket *sock, ++ int protocol, int kern) + { + struct sock *sk; + +diff --git a/net/bluetooth/sco.c b/net/bluetooth/sco.c +index 5c0685e..2c06950 100644 +--- a/net/bluetooth/sco.c ++++ b/net/bluetooth/sco.c +@@ -430,7 +430,8 @@ static struct sock *sco_sock_alloc(struct net *net, struct socket *sock, int pro + return sk; + } + +-static int sco_sock_create(struct net *net, struct socket *sock, int protocol) ++static int sco_sock_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/can/af_can.c b/net/can/af_can.c +index 6068321..bcd546f 100644 +--- a/net/can/af_can.c ++++ b/net/can/af_can.c +@@ -114,7 +114,8 @@ static void can_sock_destruct(struct sock *sk) + skb_queue_purge(&sk->sk_receive_queue); + } + +-static int can_create(struct net *net, struct socket *sock, int protocol) ++static int can_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct can_proto *cp; +diff --git a/net/decnet/af_decnet.c b/net/decnet/af_decnet.c +index 7a58c87..5540230 100644 +--- a/net/decnet/af_decnet.c ++++ b/net/decnet/af_decnet.c +@@ -675,7 +675,8 @@ char *dn_addr2asc(__u16 addr, char *buf) + + + +-static int dn_create(struct net *net, struct socket *sock, int protocol) ++static int dn_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/econet/af_econet.c b/net/econet/af_econet.c +index 0e0254f..b9d5f2f 100644 +--- a/net/econet/af_econet.c ++++ b/net/econet/af_econet.c +@@ -605,7 +605,8 @@ static struct proto econet_proto = { + * Create an Econet socket + */ + +-static int econet_create(struct net *net, struct socket *sock, int protocol) ++static int econet_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct econet_sock *eo; +diff --git a/net/ieee802154/af_ieee802154.c b/net/ieee802154/af_ieee802154.c +index cd949d5..40dcb54 100644 +--- a/net/ieee802154/af_ieee802154.c ++++ b/net/ieee802154/af_ieee802154.c +@@ -234,7 +234,7 @@ static const struct proto_ops ieee802154_dgram_ops = { + * set the state. + */ + static int ieee802154_create(struct net *net, struct socket *sock, +- int protocol) ++ int protocol, int kern) + { + struct sock *sk; + int rc; +diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c +index 57737b8..e718ab6 100644 +--- a/net/ipv4/af_inet.c ++++ b/net/ipv4/af_inet.c +@@ -262,7 +262,8 @@ static inline int inet_netns_ok(struct net *net, int protocol) + * Create an inet socket. + */ + +-static int inet_create(struct net *net, struct socket *sock, int protocol) ++static int inet_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct inet_protosw *answer; +@@ -325,7 +326,7 @@ lookup_protocol: + } + + err = -EPERM; +- if (answer->capability > 0 && !capable(answer->capability)) ++ if (answer->capability > 0 && !kern && !capable(answer->capability)) + goto out_rcu_unlock; + + err = -EAFNOSUPPORT; +diff --git a/net/ipv6/af_inet6.c b/net/ipv6/af_inet6.c +index e127a32..10776f0 100644 +--- a/net/ipv6/af_inet6.c ++++ b/net/ipv6/af_inet6.c +@@ -95,7 +95,8 @@ static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk) + return (struct ipv6_pinfo *)(((u8 *)sk) + offset); + } + +-static int inet6_create(struct net *net, struct socket *sock, int protocol) ++static int inet6_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct inet_sock *inet; + struct ipv6_pinfo *np; +@@ -158,7 +159,7 @@ lookup_protocol: + } + + err = -EPERM; +- if (answer->capability > 0 && !capable(answer->capability)) ++ if (answer->capability > 0 && !kern && !capable(answer->capability)) + goto out_rcu_unlock; + + sock->ops = answer->ops; +diff --git a/net/ipx/af_ipx.c b/net/ipx/af_ipx.c +index 66c7a20..7a7ac38 100644 +--- a/net/ipx/af_ipx.c ++++ b/net/ipx/af_ipx.c +@@ -1352,7 +1352,8 @@ static struct proto ipx_proto = { + .obj_size = sizeof(struct ipx_sock), + }; + +-static int ipx_create(struct net *net, struct socket *sock, int protocol) ++static int ipx_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + int rc = -ESOCKTNOSUPPORT; + struct sock *sk; +diff --git a/net/irda/af_irda.c b/net/irda/af_irda.c +index dd35641..ef1ac44 100644 +--- a/net/irda/af_irda.c ++++ b/net/irda/af_irda.c +@@ -61,7 +61,7 @@ + + #include <net/irda/af_irda.h> + +-static int irda_create(struct net *net, struct socket *sock, int protocol); ++static int irda_create(struct net *net, struct socket *sock, int protocol, int kern); + + static const struct proto_ops irda_stream_ops; + static const struct proto_ops irda_seqpacket_ops; +@@ -839,7 +839,7 @@ static int irda_accept(struct socket *sock, struct socket *newsock, int flags) + + IRDA_DEBUG(2, "%s()\n", __func__); + +- err = irda_create(sock_net(sk), newsock, sk->sk_protocol); ++ err = irda_create(sock_net(sk), newsock, sk->sk_protocol, 0); + if (err) + return err; + +@@ -1062,7 +1062,8 @@ static struct proto irda_proto = { + * Create IrDA socket + * + */ +-static int irda_create(struct net *net, struct socket *sock, int protocol) ++static int irda_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct irda_sock *self; +diff --git a/net/iucv/af_iucv.c b/net/iucv/af_iucv.c +index bada1b9..efc05e1 100644 +--- a/net/iucv/af_iucv.c ++++ b/net/iucv/af_iucv.c +@@ -482,7 +482,8 @@ static struct sock *iucv_sock_alloc(struct socket *sock, int proto, gfp_t prio) + } + + /* Create an IUCV socket */ +-static int iucv_sock_create(struct net *net, struct socket *sock, int protocol) ++static int iucv_sock_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/key/af_key.c b/net/key/af_key.c +index 4e98193..8c44f69 100644 +--- a/net/key/af_key.c ++++ b/net/key/af_key.c +@@ -177,7 +177,8 @@ static struct proto key_proto = { + .obj_size = sizeof(struct pfkey_sock), + }; + +-static int pfkey_create(struct net *net, struct socket *sock, int protocol) ++static int pfkey_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct netns_pfkey *net_pfkey = net_generic(net, pfkey_net_id); + struct sock *sk; +diff --git a/net/llc/af_llc.c b/net/llc/af_llc.c +index 7aa4fd1..6f38b8a 100644 +--- a/net/llc/af_llc.c ++++ b/net/llc/af_llc.c +@@ -140,14 +140,17 @@ static struct proto llc_proto = { + + /** + * llc_ui_create - alloc and init a new llc_ui socket ++ * @net: network namespace (must be default network) + * @sock: Socket to initialize and attach allocated sk to. + * @protocol: Unused. ++ * @kern: on behalf of kernel or userspace + * + * Allocate and initialize a new llc_ui socket, validate the user wants a + * socket type we have available. + * Returns 0 upon success, negative upon failure. + */ +-static int llc_ui_create(struct net *net, struct socket *sock, int protocol) ++static int llc_ui_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + int rc = -ESOCKTNOSUPPORT; +diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c +index 5a7dcdf..eadedb5 100644 +--- a/net/netlink/af_netlink.c ++++ b/net/netlink/af_netlink.c +@@ -428,7 +428,8 @@ static int __netlink_create(struct net *net, struct socket *sock, + return 0; + } + +-static int netlink_create(struct net *net, struct socket *sock, int protocol) ++static int netlink_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct module *module = NULL; + struct mutex *cb_mutex; +diff --git a/net/netrom/af_netrom.c b/net/netrom/af_netrom.c +index 7a83495..837e10b 100644 +--- a/net/netrom/af_netrom.c ++++ b/net/netrom/af_netrom.c +@@ -425,7 +425,8 @@ static struct proto nr_proto = { + .obj_size = sizeof(struct nr_sock), + }; + +-static int nr_create(struct net *net, struct socket *sock, int protocol) ++static int nr_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct nr_sock *nr; +diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c +index 41866eb..e0e3f6c 100644 +--- a/net/packet/af_packet.c ++++ b/net/packet/af_packet.c +@@ -1350,7 +1350,8 @@ static struct proto packet_proto = { + * Create a packet of type SOCK_PACKET. + */ + +-static int packet_create(struct net *net, struct socket *sock, int protocol) ++static int packet_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct packet_sock *po; +diff --git a/net/phonet/af_phonet.c b/net/phonet/af_phonet.c +index f60c0c2..61bcae9 100644 +--- a/net/phonet/af_phonet.c ++++ b/net/phonet/af_phonet.c +@@ -60,7 +60,8 @@ static inline void phonet_proto_put(struct phonet_protocol *pp) + + /* protocol family functions */ + +-static int pn_socket_create(struct net *net, struct socket *sock, int protocol) ++static int pn_socket_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct pn_sock *pn; +diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c +index 98e0538..ca35aad 100644 +--- a/net/rds/af_rds.c ++++ b/net/rds/af_rds.c +@@ -407,7 +407,8 @@ static int __rds_create(struct socket *sock, struct sock *sk, int protocol) + return 0; + } + +-static int rds_create(struct net *net, struct socket *sock, int protocol) ++static int rds_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + +diff --git a/net/rose/af_rose.c b/net/rose/af_rose.c +index 502cce7..f167ed0 100644 +--- a/net/rose/af_rose.c ++++ b/net/rose/af_rose.c +@@ -512,7 +512,8 @@ static struct proto rose_proto = { + .obj_size = sizeof(struct rose_sock), + }; + +-static int rose_create(struct net *net, struct socket *sock, int protocol) ++static int rose_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct rose_sock *rose; +diff --git a/net/rxrpc/af_rxrpc.c b/net/rxrpc/af_rxrpc.c +index a86afce..b37e304 100644 +--- a/net/rxrpc/af_rxrpc.c ++++ b/net/rxrpc/af_rxrpc.c +@@ -608,7 +608,8 @@ static unsigned int rxrpc_poll(struct file *file, struct socket *sock, + /* + * create an RxRPC socket + */ +-static int rxrpc_create(struct net *net, struct socket *sock, int protocol) ++static int rxrpc_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct rxrpc_sock *rx; + struct sock *sk; +diff --git a/net/socket.c b/net/socket.c +index 7565536..55c6e4f 100644 +--- a/net/socket.c ++++ b/net/socket.c +@@ -1216,7 +1216,7 @@ static int __sock_create(struct net *net, int family, int type, int protocol, + /* Now protected by module ref count */ + rcu_read_unlock(); + +- err = pf->create(net, sock, protocol); ++ err = pf->create(net, sock, protocol, kern); + if (err < 0) + goto out_module_put; + +diff --git a/net/tipc/socket.c b/net/tipc/socket.c +index e6d9abf..d00c211 100644 +--- a/net/tipc/socket.c ++++ b/net/tipc/socket.c +@@ -177,6 +177,7 @@ static void reject_rx_queue(struct sock *sk) + * @net: network namespace (must be default network) + * @sock: pre-allocated socket structure + * @protocol: protocol indicator (must be 0) ++ * @kern: caused by kernel or by userspace? + * + * This routine creates additional data structures used by the TIPC socket, + * initializes them, and links them together. +@@ -184,7 +185,8 @@ static void reject_rx_queue(struct sock *sk) + * Returns 0 on success, errno otherwise + */ + +-static int tipc_create(struct net *net, struct socket *sock, int protocol) ++static int tipc_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + const struct proto_ops *ops; + socket_state state; +@@ -1528,7 +1530,7 @@ static int accept(struct socket *sock, struct socket *new_sock, int flags) + + buf = skb_peek(&sk->sk_receive_queue); + +- res = tipc_create(sock_net(sock->sk), new_sock, 0); ++ res = tipc_create(sock_net(sock->sk), new_sock, 0, 0); + if (!res) { + struct sock *new_sk = new_sock->sk; + struct tipc_sock *new_tsock = tipc_sk(new_sk); +diff --git a/net/unix/af_unix.c b/net/unix/af_unix.c +index fc820cd..a1e3c85 100644 +--- a/net/unix/af_unix.c ++++ b/net/unix/af_unix.c +@@ -621,7 +621,8 @@ out: + return sk; + } + +-static int unix_create(struct net *net, struct socket *sock, int protocol) ++static int unix_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + if (protocol && protocol != PF_UNIX) + return -EPROTONOSUPPORT; +diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c +index 7fa9c7a..62c47a4 100644 +--- a/net/x25/af_x25.c ++++ b/net/x25/af_x25.c +@@ -501,7 +501,8 @@ out: + return sk; + } + +-static int x25_create(struct net *net, struct socket *sock, int protocol) ++static int x25_create(struct net *net, struct socket *sock, int protocol, ++ int kern) + { + struct sock *sk; + struct x25_sock *x25; diff --git a/setup_arg_pages-diagnose-excessive-argument-size.patch b/setup_arg_pages-diagnose-excessive-argument-size.patch new file mode 100644 index 0000000..ead972a --- /dev/null +++ b/setup_arg_pages-diagnose-excessive-argument-size.patch @@ -0,0 +1,42 @@ +From: Roland McGrath <roland@redhat.com> +Date: Wed, 8 Sep 2010 02:35:49 +0000 (-0700) +Subject: setup_arg_pages: diagnose excessive argument size +X-Git-Tag: v2.6.36-rc4~14 +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=1b528181b2ffa14721fb28ad1bd539fe1732c583 + +setup_arg_pages: diagnose excessive argument size + +The CONFIG_STACK_GROWSDOWN variant of setup_arg_pages() does not +check the size of the argument/environment area on the stack. +When it is unworkably large, shift_arg_pages() hits its BUG_ON. +This is exploitable with a very large RLIMIT_STACK limit, to +create a crash pretty easily. + +Check that the initial stack is not too large to make it possible +to map in any executable. We're not checking that the actual +executable (or intepreter, for binfmt_elf) will fit. So those +mappings might clobber part of the initial stack mapping. But +that is just userland lossage that userland made happen, not a +kernel problem. + +Signed-off-by: Roland McGrath <roland@redhat.com> +Reviewed-by: KOSAKI Motohiro <kosaki.motohiro@jp.fujitsu.com> +Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> +--- + +diff --git a/fs/exec.c b/fs/exec.c +index 2d94552..1b63237 100644 +--- a/fs/exec.c ++++ b/fs/exec.c +@@ -594,6 +594,11 @@ int setup_arg_pages(struct linux_binprm *bprm, + #else + stack_top = arch_align_stack(stack_top); + stack_top = PAGE_ALIGN(stack_top); ++ ++ if (unlikely(stack_top < mmap_min_addr) || ++ unlikely(vma->vm_end - vma->vm_start >= stack_top - mmap_min_addr)) ++ return -ENOMEM; ++ + stack_shift = vma->vm_end - stack_top; + + bprm->p -= stack_shift; diff --git a/tracing-do-not-allow-llseek-to-set_ftrace_filter.patch b/tracing-do-not-allow-llseek-to-set_ftrace_filter.patch new file mode 100644 index 0000000..4bbae71 --- /dev/null +++ b/tracing-do-not-allow-llseek-to-set_ftrace_filter.patch @@ -0,0 +1,51 @@ +From: Steven Rostedt <srostedt@redhat.com> +Date: Wed, 8 Sep 2010 15:20:37 +0000 (-0400) +Subject: tracing: Do not allow llseek to set_ftrace_filter +X-Git-Url: http://git.kernel.org/?p=linux%2Fkernel%2Fgit%2Ftorvalds%2Flinux-2.6.git;a=commitdiff_plain;h=9c55cb12c1c172e2d51e85fbb5a4796ca86b77e7 + +tracing: Do not allow llseek to set_ftrace_filter + +Reading the file set_ftrace_filter does three things. + +1) shows whether or not filters are set for the function tracer +2) shows what functions are set for the function tracer +3) shows what triggers are set on any functions + +3 is independent from 1 and 2. + +The way this file currently works is that it is a state machine, +and as you read it, it may change state. But this assumption breaks +when you use lseek() on the file. The state machine gets out of sync +and the t_show() may use the wrong pointer and cause a kernel oops. + +Luckily, this will only kill the app that does the lseek, but the app +dies while holding a mutex. This prevents anyone else from using the +set_ftrace_filter file (or any other function tracing file for that matter). + +A real fix for this is to rewrite the code, but that is too much for +a -rc release or stable. This patch simply disables llseek on the +set_ftrace_filter() file for now, and we can do the proper fix for the +next major release. + +Reported-by: Robert Swiecki <swiecki@google.com> +Cc: Chris Wright <chrisw@sous-sol.org> +Cc: Tavis Ormandy <taviso@google.com> +Cc: Eugene Teo <eugene@redhat.com> +Cc: vendor-sec@lst.de +Cc: <stable@kernel.org> +Signed-off-by: Steven Rostedt <rostedt@goodmis.org> +--- + +diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c +index 7cb1f45..83a16e9 100644 +--- a/kernel/trace/ftrace.c ++++ b/kernel/trace/ftrace.c +@@ -2416,7 +2416,7 @@ static const struct file_operations ftrace_filter_fops = { + .open = ftrace_filter_open, + .read = seq_read, + .write = ftrace_filter_write, +- .llseek = ftrace_regex_lseek, ++ .llseek = no_llseek, + .release = ftrace_filter_release, + }; + |