[kernel] r22247 - in dists/wheezy-security/linux/debian: . patches patches/bugfix/all patches/bugfix/x86
Ben Hutchings
benh at moszumanska.debian.org
Mon Jan 12 02:52:02 UTC 2015
Author: benh
Date: Mon Jan 12 02:52:01 2015
New Revision: 22247
Log:
Add various security fixes
Added:
dists/wheezy-security/linux/debian/patches/bugfix/all/isofs-fix-unchecked-printing-of-er-records.patch
dists/wheezy-security/linux/debian/patches/bugfix/all/keys-close-race-between-key-lookup-and-freeing.patch
dists/wheezy-security/linux/debian/patches/bugfix/x86/x86-tls-validate-tls-entries-to-protect-espfix.patch
dists/wheezy-security/linux/debian/patches/bugfix/x86/x86_64-switch_to-load-tls-descriptors-before-switchi.patch
Modified:
dists/wheezy-security/linux/debian/changelog
dists/wheezy-security/linux/debian/patches/series
Modified: dists/wheezy-security/linux/debian/changelog
==============================================================================
--- dists/wheezy-security/linux/debian/changelog Mon Jan 12 02:43:01 2015 (r22246)
+++ dists/wheezy-security/linux/debian/changelog Mon Jan 12 02:52:01 2015 (r22247)
@@ -5,6 +5,11 @@
- Revert "x86, mm: Set NX across entire PMD at boot"
- Revert "x86, 64bit, mm: Mark data/bss/brk to nx"
* [x86] cpu, amd: Add workaround for family 16h, erratum 793 (CVE-2013-6885)
+ * [x86] tls: Validate TLS entries to protect espfix (CVE-2014-8133)
+ * [amd64] switch_to(): Load TLS descriptors before switching DS and ES
+ (CVE-2014-9419)
+ * KEYS: close race between key lookup and freeing (CVE-2014-9529)
+ * isofs: Fix unchecked printing of ER records (CVE-2014-9584)
-- Ben Hutchings <ben at decadent.org.uk> Sun, 11 Jan 2015 00:33:09 +0000
Added: dists/wheezy-security/linux/debian/patches/bugfix/all/isofs-fix-unchecked-printing-of-er-records.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/all/isofs-fix-unchecked-printing-of-er-records.patch Mon Jan 12 02:52:01 2015 (r22247)
@@ -0,0 +1,30 @@
+From: Jan Kara <jack at suse.cz>
+Date: Thu, 18 Dec 2014 17:26:10 +0100
+Subject: isofs: Fix unchecked printing of ER records
+Origin: https://git.kernel.org/linus/4e2024624e678f0ebb916e6192bd23c1f9fdf696
+
+We didn't check length of rock ridge ER records before printing them.
+Thus corrupted isofs image can cause us to access and print some memory
+behind the buffer with obvious consequences.
+
+Reported-and-tested-by: Carl Henrik Lunde <chlunde at ping.uio.no>
+CC: stable at vger.kernel.org
+Signed-off-by: Jan Kara <jack at suse.cz>
+---
+ fs/isofs/rock.c | 3 +++
+ 1 file changed, 3 insertions(+)
+
+diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
+index bb63254..735d752 100644
+--- a/fs/isofs/rock.c
++++ b/fs/isofs/rock.c
+@@ -362,6 +362,9 @@ repeat:
+ rs.cont_size = isonum_733(rr->u.CE.size);
+ break;
+ case SIG('E', 'R'):
++ /* Invalid length of ER tag id? */
++ if (rr->u.ER.len_id + offsetof(struct rock_ridge, u.ER.data) > rr->len)
++ goto out;
+ ISOFS_SB(inode->i_sb)->s_rock = 1;
+ printk(KERN_DEBUG "ISO 9660 Extensions: ");
+ {
Added: dists/wheezy-security/linux/debian/patches/bugfix/all/keys-close-race-between-key-lookup-and-freeing.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/all/keys-close-race-between-key-lookup-and-freeing.patch Mon Jan 12 02:52:01 2015 (r22247)
@@ -0,0 +1,43 @@
+From: Sasha Levin <sasha.levin at oracle.com>
+Date: Mon, 29 Dec 2014 09:39:01 -0500
+Subject: KEYS: close race between key lookup and freeing
+Origin: https://git.kernel.org/linus/a3a8784454692dd72e5d5d34dcdab17b4420e74c
+
+When a key is being garbage collected, it's key->user would get put before
+the ->destroy() callback is called, where the key is removed from it's
+respective tracking structures.
+
+This leaves a key hanging in a semi-invalid state which leaves a window open
+for a different task to try an access key->user. An example is
+find_keyring_by_name() which would dereference key->user for a key that is
+in the process of being garbage collected (where key->user was freed but
+->destroy() wasn't called yet - so it's still present in the linked list).
+
+This would cause either a panic, or corrupt memory.
+
+Fixes CVE-2014-9529.
+
+Signed-off-by: Sasha Levin <sasha.levin at oracle.com>
+Signed-off-by: David Howells <dhowells at redhat.com>
+[bwh: Backported to 3.2: adjust indentation]
+---
+ security/keys/gc.c | 4 ++--
+ 1 file changed, 2 insertions(+), 2 deletions(-)
+
+--- a/security/keys/gc.c
++++ b/security/keys/gc.c
+@@ -186,12 +186,12 @@ static noinline void key_gc_unused_key(s
+ if (test_bit(KEY_FLAG_INSTANTIATED, &key->flags))
+ atomic_dec(&key->user->nikeys);
+
+- key_user_put(key->user);
+-
+ /* now throw away the key memory */
+ if (key->type->destroy)
+ key->type->destroy(key);
+
++ key_user_put(key->user);
++
+ kfree(key->description);
+
+ #ifdef KEY_DEBUGGING
Added: dists/wheezy-security/linux/debian/patches/bugfix/x86/x86-tls-validate-tls-entries-to-protect-espfix.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/x86/x86-tls-validate-tls-entries-to-protect-espfix.patch Mon Jan 12 02:52:01 2015 (r22247)
@@ -0,0 +1,73 @@
+From: Andy Lutomirski <luto at amacapital.net>
+Date: Thu, 4 Dec 2014 16:48:16 -0800
+Subject: x86/tls: Validate TLS entries to protect espfix
+Origin: https://git.kernel.org/linus/41bdc78544b8a93a9c6814b8bbbfef966272abbe
+
+Installing a 16-bit RW data segment into the GDT defeats espfix.
+AFAICT this will not affect glibc, Wine, or dosemu at all.
+
+Signed-off-by: Andy Lutomirski <luto at amacapital.net>
+Acked-by: H. Peter Anvin <hpa at zytor.com>
+Cc: Konrad Rzeszutek Wilk <konrad.wilk at oracle.com>
+Cc: Linus Torvalds <torvalds at linux-foundation.org>
+Cc: security at kernel.org <security at kernel.org>
+Cc: Willy Tarreau <w at 1wt.eu>
+Signed-off-by: Ingo Molnar <mingo at kernel.org>
+Signed-off-by: Ben Hutchings <ben at decadent.org.uk>
+---
+ arch/x86/kernel/tls.c | 23 +++++++++++++++++++++++
+ 1 file changed, 23 insertions(+)
+
+--- a/arch/x86/kernel/tls.c
++++ b/arch/x86/kernel/tls.c
+@@ -28,6 +28,21 @@ static int get_free_idx(void)
+ return -ESRCH;
+ }
+
++static bool tls_desc_okay(const struct user_desc *info)
++{
++ if (LDT_empty(info))
++ return true;
++
++ /*
++ * espfix is required for 16-bit data segments, but espfix
++ * only works for LDT segments.
++ */
++ if (!info->seg_32bit)
++ return false;
++
++ return true;
++}
++
+ static void set_tls_desc(struct task_struct *p, int idx,
+ const struct user_desc *info, int n)
+ {
+@@ -67,6 +82,9 @@ int do_set_thread_area(struct task_struc
+ if (copy_from_user(&info, u_info, sizeof(info)))
+ return -EFAULT;
+
++ if (!tls_desc_okay(&info))
++ return -EINVAL;
++
+ if (idx == -1)
+ idx = info.entry_number;
+
+@@ -197,6 +215,7 @@ int regset_tls_set(struct task_struct *t
+ {
+ struct user_desc infobuf[GDT_ENTRY_TLS_ENTRIES];
+ const struct user_desc *info;
++ int i;
+
+ if (pos >= GDT_ENTRY_TLS_ENTRIES * sizeof(struct user_desc) ||
+ (pos % sizeof(struct user_desc)) != 0 ||
+@@ -210,6 +229,10 @@ int regset_tls_set(struct task_struct *t
+ else
+ info = infobuf;
+
++ for (i = 0; i < count / sizeof(struct user_desc); i++)
++ if (!tls_desc_okay(info + i))
++ return -EINVAL;
++
+ set_tls_desc(target,
+ GDT_ENTRY_TLS_MIN + (pos / sizeof(struct user_desc)),
+ info, count / sizeof(struct user_desc));
Added: dists/wheezy-security/linux/debian/patches/bugfix/x86/x86_64-switch_to-load-tls-descriptors-before-switchi.patch
==============================================================================
--- /dev/null 00:00:00 1970 (empty, because file is newly added)
+++ dists/wheezy-security/linux/debian/patches/bugfix/x86/x86_64-switch_to-load-tls-descriptors-before-switchi.patch Mon Jan 12 02:52:01 2015 (r22247)
@@ -0,0 +1,304 @@
+From: Andy Lutomirski <luto at amacapital.net>
+Date: Mon, 8 Dec 2014 13:55:20 -0800
+Subject: x86_64, switch_to(): Load TLS descriptors before switching DS and ES
+Origin: https://git.kernel.org/linus/f647d7c155f069c1a068030255c300663516420e
+
+Otherwise, if buggy user code points DS or ES into the TLS
+array, they would be corrupted after a context switch.
+
+This also significantly improves the comments and documents some
+gotchas in the code.
+
+Before this patch, the both tests below failed. With this
+patch, the es test passes, although the gsbase test still fails.
+
+ ----- begin es test -----
+
+/*
+ * Copyright (c) 2014 Andy Lutomirski
+ * GPL v2
+ */
+
+static unsigned short GDT3(int idx)
+{
+ return (idx << 3) | 3;
+}
+
+static int create_tls(int idx, unsigned int base)
+{
+ struct user_desc desc = {
+ .entry_number = idx,
+ .base_addr = base,
+ .limit = 0xfffff,
+ .seg_32bit = 1,
+ .contents = 0, /* Data, grow-up */
+ .read_exec_only = 0,
+ .limit_in_pages = 1,
+ .seg_not_present = 0,
+ .useable = 0,
+ };
+
+ if (syscall(SYS_set_thread_area, &desc) != 0)
+ err(1, "set_thread_area");
+
+ return desc.entry_number;
+}
+
+int main()
+{
+ int idx = create_tls(-1, 0);
+ printf("Allocated GDT index %d\n", idx);
+
+ unsigned short orig_es;
+ asm volatile ("mov %%es,%0" : "=rm" (orig_es));
+
+ int errors = 0;
+ int total = 1000;
+ for (int i = 0; i < total; i++) {
+ asm volatile ("mov %0,%%es" : : "rm" (GDT3(idx)));
+ usleep(100);
+
+ unsigned short es;
+ asm volatile ("mov %%es,%0" : "=rm" (es));
+ asm volatile ("mov %0,%%es" : : "rm" (orig_es));
+ if (es != GDT3(idx)) {
+ if (errors == 0)
+ printf("[FAIL]\tES changed from 0x%hx to 0x%hx\n",
+ GDT3(idx), es);
+ errors++;
+ }
+ }
+
+ if (errors) {
+ printf("[FAIL]\tES was corrupted %d/%d times\n", errors, total);
+ return 1;
+ } else {
+ printf("[OK]\tES was preserved\n");
+ return 0;
+ }
+}
+
+ ----- end es test -----
+
+ ----- begin gsbase test -----
+
+/*
+ * gsbase.c, a gsbase test
+ * Copyright (c) 2014 Andy Lutomirski
+ * GPL v2
+ */
+
+static unsigned char *testptr, *testptr2;
+
+static unsigned char read_gs_testvals(void)
+{
+ unsigned char ret;
+ asm volatile ("movb %%gs:%1, %0" : "=r" (ret) : "m" (*testptr));
+ return ret;
+}
+
+int main()
+{
+ int errors = 0;
+
+ testptr = mmap((void *)0x200000000UL, 1, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+ if (testptr == MAP_FAILED)
+ err(1, "mmap");
+
+ testptr2 = mmap((void *)0x300000000UL, 1, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_FIXED | MAP_ANONYMOUS, -1, 0);
+ if (testptr2 == MAP_FAILED)
+ err(1, "mmap");
+
+ *testptr = 0;
+ *testptr2 = 1;
+
+ if (syscall(SYS_arch_prctl, ARCH_SET_GS,
+ (unsigned long)testptr2 - (unsigned long)testptr) != 0)
+ err(1, "ARCH_SET_GS");
+
+ usleep(100);
+
+ if (read_gs_testvals() == 1) {
+ printf("[OK]\tARCH_SET_GS worked\n");
+ } else {
+ printf("[FAIL]\tARCH_SET_GS failed\n");
+ errors++;
+ }
+
+ asm volatile ("mov %0,%%gs" : : "r" (0));
+
+ if (read_gs_testvals() == 0) {
+ printf("[OK]\tWriting 0 to gs worked\n");
+ } else {
+ printf("[FAIL]\tWriting 0 to gs failed\n");
+ errors++;
+ }
+
+ usleep(100);
+
+ if (read_gs_testvals() == 0) {
+ printf("[OK]\tgsbase is still zero\n");
+ } else {
+ printf("[FAIL]\tgsbase was corrupted\n");
+ errors++;
+ }
+
+ return errors == 0 ? 0 : 1;
+}
+
+ ----- end gsbase test -----
+
+Signed-off-by: Andy Lutomirski <luto at amacapital.net>
+Cc: <stable at vger.kernel.org>
+Cc: Andi Kleen <andi at firstfloor.org>
+Cc: Linus Torvalds <torvalds at linux-foundation.org>
+Link: http://lkml.kernel.org/r/509d27c9fec78217691c3dad91cec87e1006b34a.1418075657.git.luto@amacapital.net
+Signed-off-by: Ingo Molnar <mingo at kernel.org>
+---
+ arch/x86/kernel/process_64.c | 101 +++++++++++++++++++++++++++++++------------
+ 1 file changed, 73 insertions(+), 28 deletions(-)
+
+--- a/arch/x86/kernel/process_64.c
++++ b/arch/x86/kernel/process_64.c
+@@ -385,24 +385,9 @@ __switch_to(struct task_struct *prev_p,
+
+ fpu = switch_fpu_prepare(prev_p, next_p);
+
+- /*
+- * Reload esp0, LDT and the page table pointer:
+- */
++ /* Reload esp0 and ss1. */
+ load_sp0(tss, next);
+
+- /*
+- * Switch DS and ES.
+- * This won't pick up thread selector changes, but I guess that is ok.
+- */
+- savesegment(es, prev->es);
+- if (unlikely(next->es | prev->es))
+- loadsegment(es, next->es);
+-
+- savesegment(ds, prev->ds);
+- if (unlikely(next->ds | prev->ds))
+- loadsegment(ds, next->ds);
+-
+-
+ /* We must save %fs and %gs before load_TLS() because
+ * %fs and %gs may be cleared by load_TLS().
+ *
+@@ -411,41 +396,101 @@ __switch_to(struct task_struct *prev_p,
+ savesegment(fs, fsindex);
+ savesegment(gs, gsindex);
+
++ /*
++ * Load TLS before restoring any segments so that segment loads
++ * reference the correct GDT entries.
++ */
+ load_TLS(next, cpu);
+
+ /*
+- * Leave lazy mode, flushing any hypercalls made here.
+- * This must be done before restoring TLS segments so
+- * the GDT and LDT are properly updated, and must be
+- * done before math_state_restore, so the TS bit is up
+- * to date.
++ * Leave lazy mode, flushing any hypercalls made here. This
++ * must be done after loading TLS entries in the GDT but before
++ * loading segments that might reference them, and and it must
++ * be done before math_state_restore, so the TS bit is up to
++ * date.
+ */
+ arch_end_context_switch(next_p);
+
++ /* Switch DS and ES.
++ *
++ * Reading them only returns the selectors, but writing them (if
++ * nonzero) loads the full descriptor from the GDT or LDT. The
++ * LDT for next is loaded in switch_mm, and the GDT is loaded
++ * above.
++ *
++ * We therefore need to write new values to the segment
++ * registers on every context switch unless both the new and old
++ * values are zero.
++ *
++ * Note that we don't need to do anything for CS and SS, as
++ * those are saved and restored as part of pt_regs.
++ */
++ savesegment(es, prev->es);
++ if (unlikely(next->es | prev->es))
++ loadsegment(es, next->es);
++
++ savesegment(ds, prev->ds);
++ if (unlikely(next->ds | prev->ds))
++ loadsegment(ds, next->ds);
++
+ /*
+ * Switch FS and GS.
+ *
+- * Segment register != 0 always requires a reload. Also
+- * reload when it has changed. When prev process used 64bit
+- * base always reload to avoid an information leak.
++ * These are even more complicated than FS and GS: they have
++ * 64-bit bases are that controlled by arch_prctl. Those bases
++ * only differ from the values in the GDT or LDT if the selector
++ * is 0.
++ *
++ * Loading the segment register resets the hidden base part of
++ * the register to 0 or the value from the GDT / LDT. If the
++ * next base address zero, writing 0 to the segment register is
++ * much faster than using wrmsr to explicitly zero the base.
++ *
++ * The thread_struct.fs and thread_struct.gs values are 0
++ * if the fs and gs bases respectively are not overridden
++ * from the values implied by fsindex and gsindex. They
++ * are nonzero, and store the nonzero base addresses, if
++ * the bases are overridden.
++ *
++ * (fs != 0 && fsindex != 0) || (gs != 0 && gsindex != 0) should
++ * be impossible.
++ *
++ * Therefore we need to reload the segment registers if either
++ * the old or new selector is nonzero, and we need to override
++ * the base address if next thread expects it to be overridden.
++ *
++ * This code is unnecessarily slow in the case where the old and
++ * new indexes are zero and the new base is nonzero -- it will
++ * unnecessarily write 0 to the selector before writing the new
++ * base address.
++ *
++ * Note: This all depends on arch_prctl being the only way that
++ * user code can override the segment base. Once wrfsbase and
++ * wrgsbase are enabled, most of this code will need to change.
+ */
+ if (unlikely(fsindex | next->fsindex | prev->fs)) {
+ loadsegment(fs, next->fsindex);
++
+ /*
+- * Check if the user used a selector != 0; if yes
+- * clear 64bit base, since overloaded base is always
+- * mapped to the Null selector
++ * If user code wrote a nonzero value to FS, then it also
++ * cleared the overridden base address.
++ *
++ * XXX: if user code wrote 0 to FS and cleared the base
++ * address itself, we won't notice and we'll incorrectly
++ * restore the prior base address next time we reschdule
++ * the process.
+ */
+ if (fsindex)
+ prev->fs = 0;
+ }
+- /* when next process has a 64bit base use it */
+ if (next->fs)
+ wrmsrl(MSR_FS_BASE, next->fs);
+ prev->fsindex = fsindex;
+
+ if (unlikely(gsindex | next->gsindex | prev->gs)) {
+ load_gs_index(next->gsindex);
++
++ /* This works (and fails) the same way as fsindex above. */
+ if (gsindex)
+ prev->gs = 0;
+ }
Modified: dists/wheezy-security/linux/debian/patches/series
==============================================================================
--- dists/wheezy-security/linux/debian/patches/series Mon Jan 12 02:43:01 2015 (r22246)
+++ dists/wheezy-security/linux/debian/patches/series Mon Jan 12 02:52:01 2015 (r22247)
@@ -1149,3 +1149,7 @@
bugfix/x86/revert-x86-mm-set-nx-across-entire-pmd-at-boot.patch
bugfix/x86/revert-x86-64bit-mm-mark-data-bss-brk-to-nx.patch
bugfix/x86/x86-cpu-amd-add-workaround-for-family-16h-erratum-79.patch
+bugfix/x86/x86-tls-validate-tls-entries-to-protect-espfix.patch
+bugfix/x86/x86_64-switch_to-load-tls-descriptors-before-switchi.patch
+bugfix/all/keys-close-race-between-key-lookup-and-freeing.patch
+bugfix/all/isofs-fix-unchecked-printing-of-er-records.patch
More information about the Kernel-svn-changes
mailing list