From 32f1e15e155aa239cedc2fba1a319ed38b7674e5 Mon Sep 17 00:00:00 2001
From: Josh Boyer <jwboyer@fedoraproject.org>
Date: Mon, 15 Dec 2014 14:26:22 -0500
Subject: [PATCH] CVE-2014-8133 x86: espfix(64) bypass via set_thread_area and
 CLONE_SETTLS (rhbz 1172797 1174374)

---
 kernel.spec                                   |  7 ++
 ...lidate-TLS-entries-to-protect-espfix.patch | 77 +++++++++++++++++++
 2 files changed, 84 insertions(+)
 create mode 100644 x86-tls-Validate-TLS-entries-to-protect-espfix.patch

diff --git a/kernel.spec b/kernel.spec
index 25e337239..215c64e2d 100644
--- a/kernel.spec
+++ b/kernel.spec
@@ -627,6 +627,9 @@ Patch26096: cfg80211-don-t-WARN-about-two-consecutive-Country-IE.patch
 Patch26098: move-d_rcu-from-overlapping-d_child-to-overlapping-d.patch
 Patch26099: deal-with-deadlock-in-d_walk.patch
 
+#CVE-2014-8133 rhbz 1172797 1174374
+Patch26100: x86-tls-Validate-TLS-entries-to-protect-espfix.patch
+
 # git clone ssh://git.fedorahosted.org/git/kernel-arm64.git, git diff master...devel
 Patch30000: kernel-arm64.patch
 
@@ -1363,6 +1366,9 @@ ApplyPatch cfg80211-don-t-WARN-about-two-consecutive-Country-IE.patch
 ApplyPatch move-d_rcu-from-overlapping-d_child-to-overlapping-d.patch
 ApplyPatch deal-with-deadlock-in-d_walk.patch
 
+#CVE-2014-8133 rhbz 1172797 1174374
+ApplyPatch x86-tls-Validate-TLS-entries-to-protect-espfix.patch
+
 %if 0%{?aarch64patches}
 ApplyPatch kernel-arm64.patch
 %ifnarch aarch64 # this is stupid, but i want to notice before secondary koji does.
@@ -2232,6 +2238,7 @@ fi
 #                                    ||     ||
 %changelog
 * Mon Dec 15 2014 Josh Boyer <jwboyer@fedoraproject.org>
+- CVE-2014-8133 x86: espfix(64) bypass via set_thread_area and CLONE_SETTLS (rhbz 1172797 1174374)
 - CVE-2014-8559 deadlock due to incorrect usage of rename_lock (rhbz 1159313 1173814)
 
 * Fri Dec 12 2014 Kyle McMartin <kyle@fedoraproject.org>
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
+