Skip to content

Commit 9f5cb6b

Browse files
KAGA-KOKOIngo Molnar
authored andcommitted
x86/ldt: Make the LDT mapping RO
Now that the LDT mapping is in a known area when PAGE_TABLE_ISOLATION is enabled its a primary target for attacks, if a user space interface fails to validate a write address correctly. That can never happen, right? The SDM states: If the segment descriptors in the GDT or an LDT are placed in ROM, the processor can enter an indefinite loop if software or the processor attempts to update (write to) the ROM-based segment descriptors. To prevent this problem, set the accessed bits for all segment descriptors placed in a ROM. Also, remove operating-system or executive code that attempts to modify segment descriptors located in ROM. So its a valid approach to set the ACCESS bit when setting up the LDT entry and to map the table RO. Fixup the selftest so it can handle that new mode. Remove the manual ACCESS bit setter in set_tls_desc() as this is now pointless. Folded the patch from Peter Ziljstra. Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Cc: Andy Lutomirski <luto@kernel.org> Cc: Borislav Petkov <bp@alien8.de> Cc: Dave Hansen <dave.hansen@linux.intel.com> Cc: H. Peter Anvin <hpa@zytor.com> Cc: Josh Poimboeuf <jpoimboe@redhat.com> Cc: Juergen Gross <jgross@suse.com> Cc: Linus Torvalds <torvalds@linux-foundation.org> Cc: Peter Zijlstra <peterz@infradead.org> Signed-off-by: Ingo Molnar <mingo@kernel.org>
1 parent a4b51ef commit 9f5cb6b

File tree

4 files changed

+11
-12
lines changed

4 files changed

+11
-12
lines changed

arch/x86/include/asm/desc.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ static inline void fill_ldt(struct desc_struct *desc, const struct user_desc *in
2121

2222
desc->type = (info->read_exec_only ^ 1) << 1;
2323
desc->type |= info->contents << 2;
24+
/* Set the ACCESS bit so it can be mapped RO */
25+
desc->type |= 1;
2426

2527
desc->s = 1;
2628
desc->dpl = 0x3;

arch/x86/kernel/ldt.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,12 @@ map_ldt_struct(struct mm_struct *mm, struct ldt_struct *ldt, int slot)
158158
ptep = get_locked_pte(mm, va, &ptl);
159159
if (!ptep)
160160
return -ENOMEM;
161-
pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL & ~_PAGE_GLOBAL));
161+
/*
162+
* Map it RO so the easy to find address is not a primary
163+
* target via some kernel interface which misses a
164+
* permission check.
165+
*/
166+
pte = pfn_pte(pfn, __pgprot(__PAGE_KERNEL_RO & ~_PAGE_GLOBAL));
162167
set_pte_at(mm, va, ptep, pte);
163168
pte_unmap_unlock(ptep, ptl);
164169
}

arch/x86/kernel/tls.c

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -93,17 +93,10 @@ static void set_tls_desc(struct task_struct *p, int idx,
9393
cpu = get_cpu();
9494

9595
while (n-- > 0) {
96-
if (LDT_empty(info) || LDT_zero(info)) {
96+
if (LDT_empty(info) || LDT_zero(info))
9797
memset(desc, 0, sizeof(*desc));
98-
} else {
98+
else
9999
fill_ldt(desc, info);
100-
101-
/*
102-
* Always set the accessed bit so that the CPU
103-
* doesn't try to write to the (read-only) GDT.
104-
*/
105-
desc->type |= 1;
106-
}
107100
++info;
108101
++desc;
109102
}

tools/testing/selftests/x86/ldt_gdt.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,8 +122,7 @@ static void check_valid_segment(uint16_t index, int ldt,
122122
* NB: Different Linux versions do different things with the
123123
* accessed bit in set_thread_area().
124124
*/
125-
if (ar != expected_ar &&
126-
(ldt || ar != (expected_ar | AR_ACCESSED))) {
125+
if (ar != expected_ar && ar != (expected_ar | AR_ACCESSED)) {
127126
printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n",
128127
(ldt ? "LDT" : "GDT"), index, ar, expected_ar);
129128
nerrs++;

0 commit comments

Comments
 (0)