[x86] Fix TLS regressions resulting from CVE-2014-8133 related fixes
svn path=/dists/sid/linux/; revision=22339
This commit is contained in:
parent
0bbb351bb6
commit
6215101edd
|
@ -4,6 +4,9 @@ linux (3.16.7-ckt4-3) UNRELEASED; urgency=medium
|
||||||
* [sh4] ftrace: Remove -m32 option from recordmcount.pl (Closes: #775611)
|
* [sh4] ftrace: Remove -m32 option from recordmcount.pl (Closes: #775611)
|
||||||
* [x86] Revert "KVM: Fix of previously incomplete fix for CVE-2014-8480"
|
* [x86] Revert "KVM: Fix of previously incomplete fix for CVE-2014-8480"
|
||||||
as that issue does not affect 3.16
|
as that issue does not affect 3.16
|
||||||
|
* [amd64] tls, ldt: Stop checking lm in LDT_empty (regression in 3.16.7-ckt4)
|
||||||
|
* [x86] tls: Interpret an all-zero struct user_desc as "no segment"
|
||||||
|
(regression in 3.16.7-ckt4)
|
||||||
|
|
||||||
[ Ian Campbell ]
|
[ Ian Campbell ]
|
||||||
* [xen] cancel ballooning if adding new memory failed (Closes: #776448)
|
* [xen] cancel ballooning if adding new memory failed (Closes: #776448)
|
||||||
|
|
112
debian/patches/bugfix/x86/x86-tls-interpret-an-all-zero-struct-user_desc-as-no.patch
vendored
Normal file
112
debian/patches/bugfix/x86/x86-tls-interpret-an-all-zero-struct-user_desc-as-no.patch
vendored
Normal file
|
@ -0,0 +1,112 @@
|
||||||
|
From: Andy Lutomirski <luto@amacapital.net>
|
||||||
|
Date: Thu, 22 Jan 2015 11:27:59 -0800
|
||||||
|
Subject: x86, tls: Interpret an all-zero struct user_desc as "no segment"
|
||||||
|
Origin: https://git.kernel.org/linus/3669ef9fa7d35f573ec9c0e0341b29251c2734a7
|
||||||
|
|
||||||
|
The Witcher 2 did something like this to allocate a TLS segment index:
|
||||||
|
|
||||||
|
struct user_desc u_info;
|
||||||
|
bzero(&u_info, sizeof(u_info));
|
||||||
|
u_info.entry_number = (uint32_t)-1;
|
||||||
|
|
||||||
|
syscall(SYS_set_thread_area, &u_info);
|
||||||
|
|
||||||
|
Strictly speaking, this code was never correct. It should have set
|
||||||
|
read_exec_only and seg_not_present to 1 to indicate that it wanted
|
||||||
|
to find a free slot without putting anything there, or it should
|
||||||
|
have put something sensible in the TLS slot if it wanted to allocate
|
||||||
|
a TLS entry for real. The actual effect of this code was to
|
||||||
|
allocate a bogus segment that could be used to exploit espfix.
|
||||||
|
|
||||||
|
The set_thread_area hardening patches changed the behavior, causing
|
||||||
|
set_thread_area to return -EINVAL and crashing the game.
|
||||||
|
|
||||||
|
This changes set_thread_area to interpret this as a request to find
|
||||||
|
a free slot and to leave it empty, which isn't *quite* what the game
|
||||||
|
expects but should be close enough to keep it working. In
|
||||||
|
particular, using the code above to allocate two segments will
|
||||||
|
allocate the same segment both times.
|
||||||
|
|
||||||
|
According to FrostbittenKing on Github, this fixes The Witcher 2.
|
||||||
|
|
||||||
|
If this somehow still causes problems, we could instead allocate
|
||||||
|
a limit==0 32-bit data segment, but that seems rather ugly to me.
|
||||||
|
|
||||||
|
Fixes: 41bdc78544b8 x86/tls: Validate TLS entries to protect espfix
|
||||||
|
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
|
||||||
|
Cc: stable@vger.kernel.org
|
||||||
|
Cc: torvalds@linux-foundation.org
|
||||||
|
Link: http://lkml.kernel.org/r/0cb251abe1ff0958b8e468a9a9a905b80ae3a746.1421954363.git.luto@amacapital.net
|
||||||
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
||||||
|
---
|
||||||
|
arch/x86/include/asm/desc.h | 13 +++++++++++++
|
||||||
|
arch/x86/kernel/tls.c | 25 +++++++++++++++++++++++--
|
||||||
|
2 files changed, 36 insertions(+), 2 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
|
||||||
|
index fc237fd..a94b82e 100644
|
||||||
|
--- a/arch/x86/include/asm/desc.h
|
||||||
|
+++ b/arch/x86/include/asm/desc.h
|
||||||
|
@@ -262,6 +262,19 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
|
||||||
|
(info)->seg_not_present == 1 && \
|
||||||
|
(info)->useable == 0)
|
||||||
|
|
||||||
|
+/* Lots of programs expect an all-zero user_desc to mean "no segment at all". */
|
||||||
|
+static inline bool LDT_zero(const struct user_desc *info)
|
||||||
|
+{
|
||||||
|
+ return (info->base_addr == 0 &&
|
||||||
|
+ info->limit == 0 &&
|
||||||
|
+ info->contents == 0 &&
|
||||||
|
+ info->read_exec_only == 0 &&
|
||||||
|
+ info->seg_32bit == 0 &&
|
||||||
|
+ info->limit_in_pages == 0 &&
|
||||||
|
+ info->seg_not_present == 0 &&
|
||||||
|
+ info->useable == 0);
|
||||||
|
+}
|
||||||
|
+
|
||||||
|
static inline void clear_LDT(void)
|
||||||
|
{
|
||||||
|
set_ldt(NULL, 0);
|
||||||
|
diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
|
||||||
|
index 4e942f3..7fc5e84 100644
|
||||||
|
--- a/arch/x86/kernel/tls.c
|
||||||
|
+++ b/arch/x86/kernel/tls.c
|
||||||
|
@@ -29,7 +29,28 @@ static int get_free_idx(void)
|
||||||
|
|
||||||
|
static bool tls_desc_okay(const struct user_desc *info)
|
||||||
|
{
|
||||||
|
- if (LDT_empty(info))
|
||||||
|
+ /*
|
||||||
|
+ * For historical reasons (i.e. no one ever documented how any
|
||||||
|
+ * of the segmentation APIs work), user programs can and do
|
||||||
|
+ * assume that a struct user_desc that's all zeros except for
|
||||||
|
+ * entry_number means "no segment at all". This never actually
|
||||||
|
+ * worked. In fact, up to Linux 3.19, a struct user_desc like
|
||||||
|
+ * this would create a 16-bit read-write segment with base and
|
||||||
|
+ * limit both equal to zero.
|
||||||
|
+ *
|
||||||
|
+ * That was close enough to "no segment at all" until we
|
||||||
|
+ * hardened this function to disallow 16-bit TLS segments. Fix
|
||||||
|
+ * it up by interpreting these zeroed segments the way that they
|
||||||
|
+ * were almost certainly intended to be interpreted.
|
||||||
|
+ *
|
||||||
|
+ * The correct way to ask for "no segment at all" is to specify
|
||||||
|
+ * a user_desc that satisfies LDT_empty. To keep everything
|
||||||
|
+ * working, we accept both.
|
||||||
|
+ *
|
||||||
|
+ * Note that there's a similar kludge in modify_ldt -- look at
|
||||||
|
+ * the distinction between modes 1 and 0x11.
|
||||||
|
+ */
|
||||||
|
+ if (LDT_empty(info) || LDT_zero(info))
|
||||||
|
return true;
|
||||||
|
|
||||||
|
/*
|
||||||
|
@@ -71,7 +92,7 @@ static void set_tls_desc(struct task_struct *p, int idx,
|
||||||
|
cpu = get_cpu();
|
||||||
|
|
||||||
|
while (n-- > 0) {
|
||||||
|
- if (LDT_empty(info))
|
||||||
|
+ if (LDT_empty(info) || LDT_zero(info))
|
||||||
|
desc->a = desc->b = 0;
|
||||||
|
else
|
||||||
|
fill_ldt(desc, info);
|
|
@ -0,0 +1,49 @@
|
||||||
|
From: Andy Lutomirski <luto@amacapital.net>
|
||||||
|
Date: Thu, 22 Jan 2015 11:27:58 -0800
|
||||||
|
Subject: x86, tls, ldt: Stop checking lm in LDT_empty
|
||||||
|
Origin: https://git.kernel.org/linus/e30ab185c490e9a9381385529e0fd32f0a399495
|
||||||
|
|
||||||
|
32-bit programs don't have an lm bit in their ABI, so they can't
|
||||||
|
reliably cause LDT_empty to return true without resorting to memset.
|
||||||
|
They shouldn't need to do this.
|
||||||
|
|
||||||
|
This should fix a longstanding, if minor, issue in all 64-bit kernels
|
||||||
|
as well as a potential regression in the TLS hardening code.
|
||||||
|
|
||||||
|
Fixes: 41bdc78544b8 x86/tls: Validate TLS entries to protect espfix
|
||||||
|
Cc: stable@vger.kernel.org
|
||||||
|
Signed-off-by: Andy Lutomirski <luto@amacapital.net>
|
||||||
|
Cc: torvalds@linux-foundation.org
|
||||||
|
Link: http://lkml.kernel.org/r/72a059de55e86ad5e2935c80aa91880ddf19d07c.1421954363.git.luto@amacapital.net
|
||||||
|
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
|
||||||
|
---
|
||||||
|
arch/x86/include/asm/desc.h | 9 ++-------
|
||||||
|
1 file changed, 2 insertions(+), 7 deletions(-)
|
||||||
|
|
||||||
|
diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
|
||||||
|
index 50d033a..fc237fd 100644
|
||||||
|
--- a/arch/x86/include/asm/desc.h
|
||||||
|
+++ b/arch/x86/include/asm/desc.h
|
||||||
|
@@ -251,7 +251,8 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
|
||||||
|
gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
-#define _LDT_empty(info) \
|
||||||
|
+/* This intentionally ignores lm, since 32-bit apps don't have that field. */
|
||||||
|
+#define LDT_empty(info) \
|
||||||
|
((info)->base_addr == 0 && \
|
||||||
|
(info)->limit == 0 && \
|
||||||
|
(info)->contents == 0 && \
|
||||||
|
@@ -261,12 +262,6 @@ static inline void native_load_tls(struct thread_struct *t, unsigned int cpu)
|
||||||
|
(info)->seg_not_present == 1 && \
|
||||||
|
(info)->useable == 0)
|
||||||
|
|
||||||
|
-#ifdef CONFIG_X86_64
|
||||||
|
-#define LDT_empty(info) (_LDT_empty(info) && ((info)->lm == 0))
|
||||||
|
-#else
|
||||||
|
-#define LDT_empty(info) (_LDT_empty(info))
|
||||||
|
-#endif
|
||||||
|
-
|
||||||
|
static inline void clear_LDT(void)
|
||||||
|
{
|
||||||
|
set_ldt(NULL, 0);
|
|
@ -497,3 +497,5 @@ bugfix/all/crypto-include-crypto-module-prefix-in-template.patch
|
||||||
bugfix/all/crypto-add-missing-crypto-module-aliases.patch
|
bugfix/all/crypto-add-missing-crypto-module-aliases.patch
|
||||||
bugfix/x86/kvm-x86-sysenter-emulation-is-broken.patch
|
bugfix/x86/kvm-x86-sysenter-emulation-is-broken.patch
|
||||||
bugfix/sh4/scripts-recordmcount.pl-there-is-no-m32-option-on-super-h.patch
|
bugfix/sh4/scripts-recordmcount.pl-there-is-no-m32-option-on-super-h.patch
|
||||||
|
bugfix/x86/x86-tls-ldt-stop-checking-lm-in-ldt_empty.patch
|
||||||
|
bugfix/x86/x86-tls-interpret-an-all-zero-struct-user_desc-as-no.patch
|
||||||
|
|
Loading…
Reference in New Issue