aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/Kconfig.debug8
-rw-r--r--arch/x86/include/asm/io.h46
-rw-r--r--arch/x86/kernel/Makefile1
-rw-r--r--arch/x86/kernel/test_nx.c173
-rw-r--r--arch/x86/mm/dump_pagetables.c25
-rw-r--r--arch/x86/mm/pageattr.c13
-rw-r--r--arch/x86/mm/pat_rbtree.c12
-rw-r--r--tools/testing/selftests/x86/Makefile2
8 files changed, 79 insertions, 201 deletions
diff --git a/arch/x86/Kconfig.debug b/arch/x86/Kconfig.debug
index 67eec55093a5..783099f2ac72 100644
--- a/arch/x86/Kconfig.debug
+++ b/arch/x86/Kconfig.debug
@@ -120,14 +120,6 @@ config DEBUG_SET_MODULE_RONX
120 against certain classes of kernel exploits. 120 against certain classes of kernel exploits.
121 If in doubt, say "N". 121 If in doubt, say "N".
122 122
123config DEBUG_NX_TEST
124 tristate "Testcase for the NX non-executable stack feature"
125 depends on DEBUG_KERNEL && m
126 ---help---
127 This option enables a testcase for the CPU NX capability
128 and the software setup of this feature.
129 If in doubt, say "N"
130
131config DOUBLEFAULT 123config DOUBLEFAULT
132 default y 124 default y
133 bool "Enable doublefault exception handler" if EXPERT 125 bool "Enable doublefault exception handler" if EXPERT
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index d34bd370074b..7afb0e2f07f4 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -164,6 +164,17 @@ static inline unsigned int isa_virt_to_bus(volatile void *address)
164#define virt_to_bus virt_to_phys 164#define virt_to_bus virt_to_phys
165#define bus_to_virt phys_to_virt 165#define bus_to_virt phys_to_virt
166 166
167/*
168 * The default ioremap() behavior is non-cached; if you need something
169 * else, you probably want one of the following.
170 */
171extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size);
172extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size);
173#define ioremap_uc ioremap_uc
174
175extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size);
176extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size, unsigned long prot_val);
177
167/** 178/**
168 * ioremap - map bus memory into CPU space 179 * ioremap - map bus memory into CPU space
169 * @offset: bus address of the memory 180 * @offset: bus address of the memory
@@ -178,17 +189,6 @@ static inline unsigned int isa_virt_to_bus(volatile void *address)
178 * If the area you are trying to map is a PCI BAR you should have a 189 * If the area you are trying to map is a PCI BAR you should have a
179 * look at pci_iomap(). 190 * look at pci_iomap().
180 */ 191 */
181extern void __iomem *ioremap_nocache(resource_size_t offset, unsigned long size);
182extern void __iomem *ioremap_uc(resource_size_t offset, unsigned long size);
183#define ioremap_uc ioremap_uc
184
185extern void __iomem *ioremap_cache(resource_size_t offset, unsigned long size);
186extern void __iomem *ioremap_prot(resource_size_t offset, unsigned long size,
187 unsigned long prot_val);
188
189/*
190 * The default ioremap() behavior is non-cached:
191 */
192static inline void __iomem *ioremap(resource_size_t offset, unsigned long size) 192static inline void __iomem *ioremap(resource_size_t offset, unsigned long size)
193{ 193{
194 return ioremap_nocache(offset, size); 194 return ioremap_nocache(offset, size);
@@ -207,18 +207,42 @@ extern void set_iounmap_nonlazy(void);
207 */ 207 */
208#define xlate_dev_kmem_ptr(p) p 208#define xlate_dev_kmem_ptr(p) p
209 209
210/**
211 * memset_io Set a range of I/O memory to a constant value
212 * @addr: The beginning of the I/O-memory range to set
213 * @val: The value to set the memory to
214 * @count: The number of bytes to set
215 *
216 * Set a range of I/O memory to a given value.
217 */
210static inline void 218static inline void
211memset_io(volatile void __iomem *addr, unsigned char val, size_t count) 219memset_io(volatile void __iomem *addr, unsigned char val, size_t count)
212{ 220{
213 memset((void __force *)addr, val, count); 221 memset((void __force *)addr, val, count);
214} 222}
215 223
224/**
225 * memcpy_fromio Copy a block of data from I/O memory
226 * @dst: The (RAM) destination for the copy
227 * @src: The (I/O memory) source for the data
228 * @count: The number of bytes to copy
229 *
230 * Copy a block of data from I/O memory.
231 */
216static inline void 232static inline void
217memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count) 233memcpy_fromio(void *dst, const volatile void __iomem *src, size_t count)
218{ 234{
219 memcpy(dst, (const void __force *)src, count); 235 memcpy(dst, (const void __force *)src, count);
220} 236}
221 237
238/**
239 * memcpy_toio Copy a block of data into I/O memory
240 * @dst: The (I/O memory) destination for the copy
241 * @src: The (RAM) source for the data
242 * @count: The number of bytes to copy
243 *
244 * Copy a block of data to I/O memory.
245 */
222static inline void 246static inline void
223memcpy_toio(volatile void __iomem *dst, const void *src, size_t count) 247memcpy_toio(volatile void __iomem *dst, const void *src, size_t count)
224{ 248{
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 581386c7e429..bdcdb3b3a219 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -101,7 +101,6 @@ obj-$(CONFIG_APB_TIMER) += apb_timer.o
101 101
102obj-$(CONFIG_AMD_NB) += amd_nb.o 102obj-$(CONFIG_AMD_NB) += amd_nb.o
103obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o 103obj-$(CONFIG_DEBUG_RODATA_TEST) += test_rodata.o
104obj-$(CONFIG_DEBUG_NX_TEST) += test_nx.o
105obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o 104obj-$(CONFIG_DEBUG_NMI_SELFTEST) += nmi_selftest.o
106 105
107obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o 106obj-$(CONFIG_KVM_GUEST) += kvm.o kvmclock.o
diff --git a/arch/x86/kernel/test_nx.c b/arch/x86/kernel/test_nx.c
deleted file mode 100644
index a3b875c9e6af..000000000000
--- a/arch/x86/kernel/test_nx.c
+++ /dev/null
@@ -1,173 +0,0 @@
1/*
2 * test_nx.c: functional test for NX functionality
3 *
4 * (C) Copyright 2008 Intel Corporation
5 * Author: Arjan van de Ven <arjan@linux.intel.com>
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; version 2
10 * of the License.
11 */
12#include <linux/module.h>
13#include <linux/sort.h>
14#include <linux/slab.h>
15
16#include <linux/uaccess.h>
17#include <asm/asm.h>
18
19extern int rodata_test_data;
20
21/*
22 * This file checks 4 things:
23 * 1) Check if the stack is not executable
24 * 2) Check if kmalloc memory is not executable
25 * 3) Check if the .rodata section is not executable
26 * 4) Check if the .data section of a module is not executable
27 *
28 * To do this, the test code tries to execute memory in stack/kmalloc/etc,
29 * and then checks if the expected trap happens.
30 *
31 * Sadly, this implies having a dynamic exception handling table entry.
32 * ... which can be done (and will make Rusty cry)... but it can only
33 * be done in a stand-alone module with only 1 entry total.
34 * (otherwise we'd have to sort and that's just too messy)
35 */
36
37
38
39/*
40 * We want to set up an exception handling point on our stack,
41 * which means a variable value. This function is rather dirty
42 * and walks the exception table of the module, looking for a magic
43 * marker and replaces it with a specific function.
44 */
45static void fudze_exception_table(void *marker, void *new)
46{
47 struct module *mod = THIS_MODULE;
48 struct exception_table_entry *extable;
49
50 /*
51 * Note: This module has only 1 exception table entry,
52 * so searching and sorting is not needed. If that changes,
53 * this would be the place to search and re-sort the exception
54 * table.
55 */
56 if (mod->num_exentries > 1) {
57 printk(KERN_ERR "test_nx: too many exception table entries!\n");
58 printk(KERN_ERR "test_nx: test results are not reliable.\n");
59 return;
60 }
61 extable = (struct exception_table_entry *)mod->extable;
62 extable[0].insn = (unsigned long)new;
63}
64
65
66/*
67 * exception tables get their symbols translated so we need
68 * to use a fake function to put in there, which we can then
69 * replace at runtime.
70 */
71void foo_label(void);
72
73/*
74 * returns 0 for not-executable, negative for executable
75 *
76 * Note: we cannot allow this function to be inlined, because
77 * that would give us more than 1 exception table entry.
78 * This in turn would break the assumptions above.
79 */
80static noinline int test_address(void *address)
81{
82 unsigned long result;
83
84 /* Set up an exception table entry for our address */
85 fudze_exception_table(&foo_label, address);
86 result = 1;
87 asm volatile(
88 "foo_label:\n"
89 "0: call *%[fake_code]\n"
90 "1:\n"
91 ".section .fixup,\"ax\"\n"
92 "2: mov %[zero], %[rslt]\n"
93 " ret\n"
94 ".previous\n"
95 _ASM_EXTABLE(0b,2b)
96 : [rslt] "=r" (result)
97 : [fake_code] "r" (address), [zero] "r" (0UL), "0" (result)
98 );
99 /* change the exception table back for the next round */
100 fudze_exception_table(address, &foo_label);
101
102 if (result)
103 return -ENODEV;
104 return 0;
105}
106
107static unsigned char test_data = 0xC3; /* 0xC3 is the opcode for "ret" */
108
109static int test_NX(void)
110{
111 int ret = 0;
112 /* 0xC3 is the opcode for "ret" */
113 char stackcode[] = {0xC3, 0x90, 0 };
114 char *heap;
115
116 test_data = 0xC3;
117
118 printk(KERN_INFO "Testing NX protection\n");
119
120 /* Test 1: check if the stack is not executable */
121 if (test_address(&stackcode)) {
122 printk(KERN_ERR "test_nx: stack was executable\n");
123 ret = -ENODEV;
124 }
125
126
127 /* Test 2: Check if the heap is executable */
128 heap = kmalloc(64, GFP_KERNEL);
129 if (!heap)
130 return -ENOMEM;
131 heap[0] = 0xC3; /* opcode for "ret" */
132
133 if (test_address(heap)) {
134 printk(KERN_ERR "test_nx: heap was executable\n");
135 ret = -ENODEV;
136 }
137 kfree(heap);
138
139 /*
140 * The following 2 tests currently fail, this needs to get fixed
141 * Until then, don't run them to avoid too many people getting scared
142 * by the error message
143 */
144
145 /* Test 3: Check if the .rodata section is executable */
146 if (rodata_test_data != 0xC3) {
147 printk(KERN_ERR "test_nx: .rodata marker has invalid value\n");
148 ret = -ENODEV;
149 } else if (test_address(&rodata_test_data)) {
150 printk(KERN_ERR "test_nx: .rodata section is executable\n");
151 ret = -ENODEV;
152 }
153
154#if 0
155 /* Test 4: Check if the .data section of a module is executable */
156 if (test_address(&test_data)) {
157 printk(KERN_ERR "test_nx: .data section is executable\n");
158 ret = -ENODEV;
159 }
160
161#endif
162 return ret;
163}
164
165static void test_exit(void)
166{
167}
168
169module_init(test_NX);
170module_exit(test_exit);
171MODULE_LICENSE("GPL");
172MODULE_DESCRIPTION("Testcase for the NX infrastructure");
173MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>");
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 8aa6bea1cd6c..58b5bee7ea27 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -18,6 +18,7 @@
18#include <linux/sched.h> 18#include <linux/sched.h>
19#include <linux/seq_file.h> 19#include <linux/seq_file.h>
20 20
21#include <asm/kasan.h>
21#include <asm/pgtable.h> 22#include <asm/pgtable.h>
22 23
23/* 24/*
@@ -51,6 +52,10 @@ enum address_markers_idx {
51 LOW_KERNEL_NR, 52 LOW_KERNEL_NR,
52 VMALLOC_START_NR, 53 VMALLOC_START_NR,
53 VMEMMAP_START_NR, 54 VMEMMAP_START_NR,
55#ifdef CONFIG_KASAN
56 KASAN_SHADOW_START_NR,
57 KASAN_SHADOW_END_NR,
58#endif
54# ifdef CONFIG_X86_ESPFIX64 59# ifdef CONFIG_X86_ESPFIX64
55 ESPFIX_START_NR, 60 ESPFIX_START_NR,
56# endif 61# endif
@@ -76,6 +81,10 @@ static struct addr_marker address_markers[] = {
76 { 0/* PAGE_OFFSET */, "Low Kernel Mapping" }, 81 { 0/* PAGE_OFFSET */, "Low Kernel Mapping" },
77 { 0/* VMALLOC_START */, "vmalloc() Area" }, 82 { 0/* VMALLOC_START */, "vmalloc() Area" },
78 { 0/* VMEMMAP_START */, "Vmemmap" }, 83 { 0/* VMEMMAP_START */, "Vmemmap" },
84#ifdef CONFIG_KASAN
85 { KASAN_SHADOW_START, "KASAN shadow" },
86 { KASAN_SHADOW_END, "KASAN shadow end" },
87#endif
79# ifdef CONFIG_X86_ESPFIX64 88# ifdef CONFIG_X86_ESPFIX64
80 { ESPFIX_BASE_ADDR, "ESPfix Area", 16 }, 89 { ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
81# endif 90# endif
@@ -327,18 +336,31 @@ static void walk_pmd_level(struct seq_file *m, struct pg_state *st, pud_t addr,
327 336
328#if PTRS_PER_PUD > 1 337#if PTRS_PER_PUD > 1
329 338
339/*
340 * This is an optimization for CONFIG_DEBUG_WX=y + CONFIG_KASAN=y
341 * KASAN fills page tables with the same values. Since there is no
342 * point in checking page table more than once we just skip repeated
343 * entries. This saves us dozens of seconds during boot.
344 */
345static bool pud_already_checked(pud_t *prev_pud, pud_t *pud, bool checkwx)
346{
347 return checkwx && prev_pud && (pud_val(*prev_pud) == pud_val(*pud));
348}
349
330static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr, 350static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
331 unsigned long P) 351 unsigned long P)
332{ 352{
333 int i; 353 int i;
334 pud_t *start; 354 pud_t *start;
335 pgprotval_t prot; 355 pgprotval_t prot;
356 pud_t *prev_pud = NULL;
336 357
337 start = (pud_t *) pgd_page_vaddr(addr); 358 start = (pud_t *) pgd_page_vaddr(addr);
338 359
339 for (i = 0; i < PTRS_PER_PUD; i++) { 360 for (i = 0; i < PTRS_PER_PUD; i++) {
340 st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT); 361 st->current_address = normalize_addr(P + i * PUD_LEVEL_MULT);
341 if (!pud_none(*start)) { 362 if (!pud_none(*start) &&
363 !pud_already_checked(prev_pud, start, st->check_wx)) {
342 if (pud_large(*start) || !pud_present(*start)) { 364 if (pud_large(*start) || !pud_present(*start)) {
343 prot = pud_flags(*start); 365 prot = pud_flags(*start);
344 note_page(m, st, __pgprot(prot), 2); 366 note_page(m, st, __pgprot(prot), 2);
@@ -349,6 +371,7 @@ static void walk_pud_level(struct seq_file *m, struct pg_state *st, pgd_t addr,
349 } else 371 } else
350 note_page(m, st, __pgprot(0), 2); 372 note_page(m, st, __pgprot(0), 2);
351 373
374 prev_pud = start;
352 start++; 375 start++;
353 } 376 }
354} 377}
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 5a287e523eab..28d42130243c 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -214,7 +214,20 @@ static void cpa_flush_array(unsigned long *start, int numpages, int cache,
214 int in_flags, struct page **pages) 214 int in_flags, struct page **pages)
215{ 215{
216 unsigned int i, level; 216 unsigned int i, level;
217#ifdef CONFIG_PREEMPT
218 /*
219 * Avoid wbinvd() because it causes latencies on all CPUs,
220 * regardless of any CPU isolation that may be in effect.
221 *
222 * This should be extended for CAT enabled systems independent of
223 * PREEMPT because wbinvd() does not respect the CAT partitions and
224 * this is exposed to unpriviledged users through the graphics
225 * subsystem.
226 */
227 unsigned long do_wbinvd = 0;
228#else
217 unsigned long do_wbinvd = cache && numpages >= 1024; /* 4M threshold */ 229 unsigned long do_wbinvd = cache && numpages >= 1024; /* 4M threshold */
230#endif
218 231
219 BUG_ON(irqs_disabled()); 232 BUG_ON(irqs_disabled());
220 233
diff --git a/arch/x86/mm/pat_rbtree.c b/arch/x86/mm/pat_rbtree.c
index 159b52ccd600..d76485b22824 100644
--- a/arch/x86/mm/pat_rbtree.c
+++ b/arch/x86/mm/pat_rbtree.c
@@ -47,7 +47,7 @@ static u64 get_subtree_max_end(struct rb_node *node)
47{ 47{
48 u64 ret = 0; 48 u64 ret = 0;
49 if (node) { 49 if (node) {
50 struct memtype *data = container_of(node, struct memtype, rb); 50 struct memtype *data = rb_entry(node, struct memtype, rb);
51 ret = data->subtree_max_end; 51 ret = data->subtree_max_end;
52 } 52 }
53 return ret; 53 return ret;
@@ -79,7 +79,7 @@ static struct memtype *memtype_rb_lowest_match(struct rb_root *root,
79 struct memtype *last_lower = NULL; 79 struct memtype *last_lower = NULL;
80 80
81 while (node) { 81 while (node) {
82 struct memtype *data = container_of(node, struct memtype, rb); 82 struct memtype *data = rb_entry(node, struct memtype, rb);
83 83
84 if (get_subtree_max_end(node->rb_left) > start) { 84 if (get_subtree_max_end(node->rb_left) > start) {
85 /* Lowest overlap if any must be on left side */ 85 /* Lowest overlap if any must be on left side */
@@ -121,7 +121,7 @@ static struct memtype *memtype_rb_match(struct rb_root *root,
121 121
122 node = rb_next(&match->rb); 122 node = rb_next(&match->rb);
123 if (node) 123 if (node)
124 match = container_of(node, struct memtype, rb); 124 match = rb_entry(node, struct memtype, rb);
125 else 125 else
126 match = NULL; 126 match = NULL;
127 } 127 }
@@ -150,7 +150,7 @@ static int memtype_rb_check_conflict(struct rb_root *root,
150 150
151 node = rb_next(&match->rb); 151 node = rb_next(&match->rb);
152 while (node) { 152 while (node) {
153 match = container_of(node, struct memtype, rb); 153 match = rb_entry(node, struct memtype, rb);
154 154
155 if (match->start >= end) /* Checked all possible matches */ 155 if (match->start >= end) /* Checked all possible matches */
156 goto success; 156 goto success;
@@ -181,7 +181,7 @@ static void memtype_rb_insert(struct rb_root *root, struct memtype *newdata)
181 struct rb_node *parent = NULL; 181 struct rb_node *parent = NULL;
182 182
183 while (*node) { 183 while (*node) {
184 struct memtype *data = container_of(*node, struct memtype, rb); 184 struct memtype *data = rb_entry(*node, struct memtype, rb);
185 185
186 parent = *node; 186 parent = *node;
187 if (data->subtree_max_end < newdata->end) 187 if (data->subtree_max_end < newdata->end)
@@ -270,7 +270,7 @@ int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos)
270 } 270 }
271 271
272 if (node) { /* pos == i */ 272 if (node) { /* pos == i */
273 struct memtype *this = container_of(node, struct memtype, rb); 273 struct memtype *this = rb_entry(node, struct memtype, rb);
274 *out = *this; 274 *out = *this;
275 return 0; 275 return 0;
276 } else { 276 } else {
diff --git a/tools/testing/selftests/x86/Makefile b/tools/testing/selftests/x86/Makefile
index 25d4067c11e4..83d8b1c6cb0e 100644
--- a/tools/testing/selftests/x86/Makefile
+++ b/tools/testing/selftests/x86/Makefile
@@ -5,7 +5,7 @@ include ../lib.mk
5.PHONY: all all_32 all_64 warn_32bit_failure clean 5.PHONY: all all_32 all_64 warn_32bit_failure clean
6 6
7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \ 7TARGETS_C_BOTHBITS := single_step_syscall sysret_ss_attrs syscall_nt ptrace_syscall test_mremap_vdso \
8 check_initial_reg_state sigreturn ldt_gdt iopl \ 8 check_initial_reg_state sigreturn ldt_gdt iopl mpx-mini-test \
9 protection_keys test_vdso 9 protection_keys test_vdso
10TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \ 10TARGETS_C_32BIT_ONLY := entry_from_vm86 syscall_arg_fault test_syscall_vdso unwind_vdso \
11 test_FCMOV test_FCOMI test_FISTTP \ 11 test_FCMOV test_FCOMI test_FISTTP \