diff options
Diffstat (limited to 'x86-tls-Validate-TLS-entries-to-protect-espfix.patch')
-rw-r--r-- | x86-tls-Validate-TLS-entries-to-protect-espfix.patch | 77 |
1 files changed, 77 insertions, 0 deletions
diff --git a/x86-tls-Validate-TLS-entries-to-protect-espfix.patch b/x86-tls-Validate-TLS-entries-to-protect-espfix.patch new file mode 100644 index 000000000..52c049767 --- /dev/null +++ b/x86-tls-Validate-TLS-entries-to-protect-espfix.patch @@ -0,0 +1,77 @@ +From: Andy Lutomirski <luto@amacapital.net> +Date: Thu, 4 Dec 2014 16:48:16 -0800 +Subject: [PATCH] x86/tls: Validate TLS entries to protect espfix + +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@amacapital.net> +Acked-by: H. Peter Anvin <hpa@zytor.com> +Cc: stable@vger.kernel.org +Cc: Konrad Rzeszutek Wilk <konrad.wilk@oracle.com> +Cc: Linus Torvalds <torvalds@linux-foundation.org> +Cc: security@kernel.org <security@kernel.org> +Cc: Willy Tarreau <w@1wt.eu> +Signed-off-by: Ingo Molnar <mingo@kernel.org> +--- + arch/x86/kernel/tls.c | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c +index f7fec09e3e3a..e7650bd71109 100644 +--- a/arch/x86/kernel/tls.c ++++ b/arch/x86/kernel/tls.c +@@ -27,6 +27,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) + { +@@ -66,6 +81,9 @@ int do_set_thread_area(struct task_struct *p, int idx, + 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; + +@@ -192,6 +210,7 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, + { + 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 || +@@ -205,6 +224,10 @@ int regset_tls_set(struct task_struct *target, const struct user_regset *regset, + 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)); +-- +2.1.0 + |