]> git.proxmox.com Git - pve-kernel.git/blob - patches/kernel/0218-x86-ldt-Make-the-LDT-mapping-RO.patch
f730cb5bb75b938372989546333739deb50e6654
[pve-kernel.git] / patches / kernel / 0218-x86-ldt-Make-the-LDT-mapping-RO.patch
1 From d1feee4957a5cb314ec0b3c4ca86ba79ccaeceb8 Mon Sep 17 00:00:00 2001
2 From: Thomas Gleixner <tglx@linutronix.de>
3 Date: Fri, 15 Dec 2017 20:35:11 +0100
4 Subject: [PATCH 218/233] x86/ldt: Make the LDT mapping RO
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 CVE-2017-5754
10
11 Now that the LDT mapping is in a known area when PAGE_TABLE_ISOLATION is
12 enabled its a primary target for attacks, if a user space interface fails
13 to validate a write address correctly. That can never happen, right?
14
15 The SDM states:
16
17 If the segment descriptors in the GDT or an LDT are placed in ROM, the
18 processor can enter an indefinite loop if software or the processor
19 attempts to update (write to) the ROM-based segment descriptors. To
20 prevent this problem, set the accessed bits for all segment descriptors
21 placed in a ROM. Also, remove operating-system or executive code that
22 attempts to modify segment descriptors located in ROM.
23
24 So its a valid approach to set the ACCESS bit when setting up the LDT entry
25 and to map the table RO. Fixup the selftest so it can handle that new mode.
26
27 Remove the manual ACCESS bit setter in set_tls_desc() as this is now
28 pointless. Folded the patch from Peter Ziljstra.
29
30 Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
31 Cc: Andy Lutomirski <luto@kernel.org>
32 Cc: Borislav Petkov <bp@alien8.de>
33 Cc: Dave Hansen <dave.hansen@linux.intel.com>
34 Cc: H. Peter Anvin <hpa@zytor.com>
35 Cc: Josh Poimboeuf <jpoimboe@redhat.com>
36 Cc: Juergen Gross <jgross@suse.com>
37 Cc: Linus Torvalds <torvalds@linux-foundation.org>
38 Cc: Peter Zijlstra <peterz@infradead.org>
39 Signed-off-by: Ingo Molnar <mingo@kernel.org>
40 (cherry picked from commit 9f5cb6b32d9e0a3a7453222baaf15664d92adbf2)
41 Signed-off-by: Andy Whitcroft <apw@canonical.com>
42 Signed-off-by: Kleber Sacilotto de Souza <kleber.souza@canonical.com>
43 (cherry picked from commit f4b13d6f67b3a89d878094901a9ca834b39415c1)
44 Signed-off-by: Fabian Grünbichler <f.gruenbichler@proxmox.com>
45 ---
46 arch/x86/include/asm/desc.h | 2 ++
47 arch/x86/kernel/ldt.c | 7 ++++++-
48 arch/x86/kernel/tls.c | 11 ++---------
49 tools/testing/selftests/x86/ldt_gdt.c | 3 +--
50 4 files changed, 11 insertions(+), 12 deletions(-)
51
52 diff --git a/arch/x86/include/asm/desc.h b/arch/x86/include/asm/desc.h
53 index de40c514ba25..c765bc294a9d 100644
54 --- a/arch/x86/include/asm/desc.h
55 +++ b/arch/x86/include/asm/desc.h
56 @@ -20,6 +20,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in
57
58 desc->type = (info->read_exec_only ^ 1) << 1;
59 desc->type |= info->contents << 2;
60 + /* Set the ACCESS bit so it can be mapped RO */
61 + desc->type |= 1;
62
63 desc->s = 1;
64 desc->dpl = 0x3;
65 diff --git a/arch/x86/kernel/ldt.c b/arch/x86/kernel/ldt.c
66 index eceaada581ff..2260eb6e2de7 100644
67 --- a/arch/x86/kernel/ldt.c
68 +++ b/arch/x86/kernel/ldt.c
69 @@ -157,7 +157,12 @@ map_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt, int slot)
70 ptep = get_locked_pte(mm, va, &ptl);
71 if (!ptep)
72 return -ENOMEM;
73 - pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL & ~_PAGE_GLOBAL));
74 + /*
75 + * Map it RO so the easy to find address is not a primary
76 + * target via some kernel interface which misses a
77 + * permission check.
78 + */
79 + pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL));
80 set_pte_at(mm, va, ptep, pte);
81 pte_unmap_unlock(ptep, ptl);
82 }
83 diff --git a/arch/x86/kernel/tls.c b/arch/x86/kernel/tls.c
84 index a106b9719c58..41880a2421ea 100644
85 --- a/arch/x86/kernel/tls.c
86 +++ b/arch/x86/kernel/tls.c
87 @@ -92,17 +92,10 @@ static void set_tls_desc(struct task_struct *p, int idx,
88 cpu = get_cpu();
89
90 while (n-- > 0) {
91 - if (LDT_empty(info) || LDT_zero(info)) {
92 + if (LDT_empty(info) || LDT_zero(info))
93 memset(desc, 0, sizeof(*desc));
94 - } else {
95 + else
96 fill_ldt(desc, info);
97 -
98 - /*
99 - * Always set the accessed bit so that the CPU
100 - * doesn't try to write to the (read-only) GDT.
101 - */
102 - desc->type |= 1;
103 - }
104 ++info;
105 ++desc;
106 }
107 diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
108 index 783e1a754b78..bbd1d0e4d683 100644
109 --- a/tools/testing/selftests/x86/ldt_gdt.c
110 +++ b/tools/testing/selftests/x86/ldt_gdt.c
111 @@ -121,8 +121,7 @@ static void check_valid_segment(uint16_t index, int ldt,
112 * NB: Different Linux versions do different things with the
113 * accessed bit in set_thread_area().
114 */
115 - if (ar != expected_ar &&
116 - (ldt || ar != (expected_ar | AR_ACCESSED))) {
117 + if (ar != expected_ar && ar != (expected_ar | AR_ACCESSED)) {
118 printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n",
119 (ldt ? "LDT" : "GDT"), index, ar, expected_ar);
120 nerrs++;
121 --
122 2.14.2
123