[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)
|
||||
* [x86] Revert "KVM: Fix of previously incomplete fix for CVE-2014-8480"
|
||||
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 ]
|
||||
* [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/x86/kvm-x86-sysenter-emulation-is-broken.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