Commit | Line | Data |
---|---|---|
edeed305 AV |
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> | |
0054f4b7 RD |
14 | #include <linux/slab.h> |
15 | ||
edeed305 | 16 | #include <asm/uaccess.h> |
92909098 | 17 | #include <asm/asm.h> |
edeed305 AV |
18 | |
19 | extern 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 | */ | |
45 | static 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 | */ | |
71 | void 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 | */ | |
80 | static 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" | |
92909098 | 95 | _ASM_EXTABLE(0b,2b) |
edeed305 AV |
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 | ||
107 | static unsigned char test_data = 0xC3; /* 0xC3 is the opcode for "ret" */ | |
108 | ||
109 | static 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 | */ | |
edeed305 AV |
144 | |
145 | #ifdef CONFIG_DEBUG_RODATA | |
146 | /* Test 3: Check if the .rodata section is executable */ | |
147 | if (rodata_test_data != 0xC3) { | |
148 | printk(KERN_ERR "test_nx: .rodata marker has invalid value\n"); | |
149 | ret = -ENODEV; | |
150 | } else if (test_address(&rodata_test_data)) { | |
151 | printk(KERN_ERR "test_nx: .rodata section is executable\n"); | |
152 | ret = -ENODEV; | |
153 | } | |
154 | #endif | |
155 | ||
984bb80d | 156 | #if 0 |
edeed305 AV |
157 | /* Test 4: Check if the .data section of a module is executable */ |
158 | if (test_address(&test_data)) { | |
159 | printk(KERN_ERR "test_nx: .data section is executable\n"); | |
160 | ret = -ENODEV; | |
161 | } | |
162 | ||
163 | #endif | |
6ec5ff4b | 164 | return ret; |
edeed305 AV |
165 | } |
166 | ||
167 | static void test_exit(void) | |
168 | { | |
169 | } | |
170 | ||
171 | module_init(test_NX); | |
172 | module_exit(test_exit); | |
173 | MODULE_LICENSE("GPL"); | |
174 | MODULE_DESCRIPTION("Testcase for the NX infrastructure"); | |
175 | MODULE_AUTHOR("Arjan van de Ven <arjan@linux.intel.com>"); |