aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-11-13 17:13:48 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2017-11-13 17:13:48 -0500
commitd6ec9d9a4def52a5094237564eaf6f6979fd7a27 (patch)
treeadfb80f83f04a021e82cb25227b64b1bb9e793dc /tools
parent3e2014637c50e5d6a77cd63d5db6c209fe29d1b1 (diff)
parent91a6a6cfee8ad34ea4cc10a54c0765edfe437cdb (diff)
Merge branch 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip
Pull x86 core updates from Ingo Molnar: "Note that in this cycle most of the x86 topics interacted at a level that caused them to be merged into tip:x86/asm - but this should be a temporary phenomenon, hopefully we'll back to the usual patterns in the next merge window. The main changes in this cycle were: Hardware enablement: - Add support for the Intel UMIP (User Mode Instruction Prevention) CPU feature. This is a security feature that disables certain instructions such as SGDT, SLDT, SIDT, SMSW and STR. (Ricardo Neri) [ Note that this is disabled by default for now, there are some smaller enhancements in the pipeline that I'll follow up with in the next 1-2 days, which allows this to be enabled by default.] - Add support for the AMD SEV (Secure Encrypted Virtualization) CPU feature, on top of SME (Secure Memory Encryption) support that was added in v4.14. (Tom Lendacky, Brijesh Singh) - Enable new SSE/AVX/AVX512 CPU features: AVX512_VBMI2, GFNI, VAES, VPCLMULQDQ, AVX512_VNNI, AVX512_BITALG. (Gayatri Kammela) Other changes: - A big series of entry code simplifications and enhancements (Andy Lutomirski) - Make the ORC unwinder default on x86 and various objtool enhancements. (Josh Poimboeuf) - 5-level paging enhancements (Kirill A. Shutemov) - Micro-optimize the entry code a bit (Borislav Petkov) - Improve the handling of interdependent CPU features in the early FPU init code (Andi Kleen) - Build system enhancements (Changbin Du, Masahiro Yamada) - ... plus misc enhancements, fixes and cleanups" * 'x86-asm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip: (118 commits) x86/build: Make the boot image generation less verbose selftests/x86: Add tests for the STR and SLDT instructions selftests/x86: Add tests for User-Mode Instruction Prevention x86/traps: Fix up general protection faults caused by UMIP x86/umip: Enable User-Mode Instruction Prevention at runtime x86/umip: Force a page fault when unable to copy emulated result to user x86/umip: Add emulation code for UMIP instructions x86/cpufeature: Add User-Mode Instruction Prevention definitions x86/insn-eval: Add support to resolve 16-bit address encodings x86/insn-eval: Handle 32-bit address encodings in virtual-8086 mode x86/insn-eval: Add wrapper function for 32 and 64-bit addresses x86/insn-eval: Add support to resolve 32-bit address encodings x86/insn-eval: Compute linear address in several utility functions resource: Fix resource_size.cocci warnings X86/KVM: Clear encryption attribute when SEV is active X86/KVM: Decrypt shared per-cpu variables when SEV is active percpu: Introduce DEFINE_PER_CPU_DECRYPTED x86: Add support for changing memory encryption attribute in early boot x86/io: Unroll string I/O when SEV is active x86/boot: Add early boot support when running with SEV active ...
Diffstat (limited to 'tools')
-rw-r--r--tools/objtool/check.c7
-rw-r--r--tools/objtool/objtool.c6
-rw-r--r--tools/testing/selftests/x86/entry_from_vm86.c89
-rw-r--r--tools/testing/selftests/x86/ldt_gdt.c88
-rw-r--r--tools/testing/selftests/x86/protection_keys.c24
5 files changed, 183 insertions, 31 deletions
diff --git a/tools/objtool/check.c b/tools/objtool/check.c
index c0e26ad1fa7e..9b341584eb1b 100644
--- a/tools/objtool/check.c
+++ b/tools/objtool/check.c
@@ -1757,11 +1757,14 @@ static int validate_branch(struct objtool_file *file, struct instruction *first,
1757 if (insn->dead_end) 1757 if (insn->dead_end)
1758 return 0; 1758 return 0;
1759 1759
1760 insn = next_insn; 1760 if (!next_insn) {
1761 if (!insn) { 1761 if (state.cfa.base == CFI_UNDEFINED)
1762 return 0;
1762 WARN("%s: unexpected end of section", sec->name); 1763 WARN("%s: unexpected end of section", sec->name);
1763 return 1; 1764 return 1;
1764 } 1765 }
1766
1767 insn = next_insn;
1765 } 1768 }
1766 1769
1767 return 0; 1770 return 0;
diff --git a/tools/objtool/objtool.c b/tools/objtool/objtool.c
index 31e0f9143840..07f329919828 100644
--- a/tools/objtool/objtool.c
+++ b/tools/objtool/objtool.c
@@ -70,7 +70,7 @@ static void cmd_usage(void)
70 70
71 printf("\n"); 71 printf("\n");
72 72
73 exit(1); 73 exit(129);
74} 74}
75 75
76static void handle_options(int *argc, const char ***argv) 76static void handle_options(int *argc, const char ***argv)
@@ -86,9 +86,7 @@ static void handle_options(int *argc, const char ***argv)
86 break; 86 break;
87 } else { 87 } else {
88 fprintf(stderr, "Unknown option: %s\n", cmd); 88 fprintf(stderr, "Unknown option: %s\n", cmd);
89 fprintf(stderr, "\n Usage: %s\n", 89 cmd_usage();
90 objtool_usage_string);
91 exit(1);
92 } 90 }
93 91
94 (*argv)++; 92 (*argv)++;
diff --git a/tools/testing/selftests/x86/entry_from_vm86.c b/tools/testing/selftests/x86/entry_from_vm86.c
index d075ea0e5ca1..361466a2eaef 100644
--- a/tools/testing/selftests/x86/entry_from_vm86.c
+++ b/tools/testing/selftests/x86/entry_from_vm86.c
@@ -95,6 +95,27 @@ asm (
95 "int3\n\t" 95 "int3\n\t"
96 "vmcode_int80:\n\t" 96 "vmcode_int80:\n\t"
97 "int $0x80\n\t" 97 "int $0x80\n\t"
98 "vmcode_umip:\n\t"
99 /* addressing via displacements */
100 "smsw (2052)\n\t"
101 "sidt (2054)\n\t"
102 "sgdt (2060)\n\t"
103 /* addressing via registers */
104 "mov $2066, %bx\n\t"
105 "smsw (%bx)\n\t"
106 "mov $2068, %bx\n\t"
107 "sidt (%bx)\n\t"
108 "mov $2074, %bx\n\t"
109 "sgdt (%bx)\n\t"
110 /* register operands, only for smsw */
111 "smsw %ax\n\t"
112 "mov %ax, (2080)\n\t"
113 "int3\n\t"
114 "vmcode_umip_str:\n\t"
115 "str %eax\n\t"
116 "vmcode_umip_sldt:\n\t"
117 "sldt %eax\n\t"
118 "int3\n\t"
98 ".size vmcode, . - vmcode\n\t" 119 ".size vmcode, . - vmcode\n\t"
99 "end_vmcode:\n\t" 120 "end_vmcode:\n\t"
100 ".code32\n\t" 121 ".code32\n\t"
@@ -103,7 +124,8 @@ asm (
103 124
104extern unsigned char vmcode[], end_vmcode[]; 125extern unsigned char vmcode[], end_vmcode[];
105extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], 126extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[],
106 vmcode_sti[], vmcode_int3[], vmcode_int80[]; 127 vmcode_sti[], vmcode_int3[], vmcode_int80[], vmcode_umip[],
128 vmcode_umip_str[], vmcode_umip_sldt[];
107 129
108/* Returns false if the test was skipped. */ 130/* Returns false if the test was skipped. */
109static bool do_test(struct vm86plus_struct *v86, unsigned long eip, 131static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
@@ -160,6 +182,68 @@ static bool do_test(struct vm86plus_struct *v86, unsigned long eip,
160 return true; 182 return true;
161} 183}
162 184
185void do_umip_tests(struct vm86plus_struct *vm86, unsigned char *test_mem)
186{
187 struct table_desc {
188 unsigned short limit;
189 unsigned long base;
190 } __attribute__((packed));
191
192 /* Initialize variables with arbitrary values */
193 struct table_desc gdt1 = { .base = 0x3c3c3c3c, .limit = 0x9999 };
194 struct table_desc gdt2 = { .base = 0x1a1a1a1a, .limit = 0xaeae };
195 struct table_desc idt1 = { .base = 0x7b7b7b7b, .limit = 0xf1f1 };
196 struct table_desc idt2 = { .base = 0x89898989, .limit = 0x1313 };
197 unsigned short msw1 = 0x1414, msw2 = 0x2525, msw3 = 3737;
198
199 /* UMIP -- exit with INT3 unless kernel emulation did not trap #GP */
200 do_test(vm86, vmcode_umip - vmcode, VM86_TRAP, 3, "UMIP tests");
201
202 /* Results from displacement-only addressing */
203 msw1 = *(unsigned short *)(test_mem + 2052);
204 memcpy(&idt1, test_mem + 2054, sizeof(idt1));
205 memcpy(&gdt1, test_mem + 2060, sizeof(gdt1));
206
207 /* Results from register-indirect addressing */
208 msw2 = *(unsigned short *)(test_mem + 2066);
209 memcpy(&idt2, test_mem + 2068, sizeof(idt2));
210 memcpy(&gdt2, test_mem + 2074, sizeof(gdt2));
211
212 /* Results when using register operands */
213 msw3 = *(unsigned short *)(test_mem + 2080);
214
215 printf("[INFO]\tResult from SMSW:[0x%04x]\n", msw1);
216 printf("[INFO]\tResult from SIDT: limit[0x%04x]base[0x%08lx]\n",
217 idt1.limit, idt1.base);
218 printf("[INFO]\tResult from SGDT: limit[0x%04x]base[0x%08lx]\n",
219 gdt1.limit, gdt1.base);
220
221 if (msw1 != msw2 || msw1 != msw3)
222 printf("[FAIL]\tAll the results of SMSW should be the same.\n");
223 else
224 printf("[PASS]\tAll the results from SMSW are identical.\n");
225
226 if (memcmp(&gdt1, &gdt2, sizeof(gdt1)))
227 printf("[FAIL]\tAll the results of SGDT should be the same.\n");
228 else
229 printf("[PASS]\tAll the results from SGDT are identical.\n");
230
231 if (memcmp(&idt1, &idt2, sizeof(idt1)))
232 printf("[FAIL]\tAll the results of SIDT should be the same.\n");
233 else
234 printf("[PASS]\tAll the results from SIDT are identical.\n");
235
236 sethandler(SIGILL, sighandler, 0);
237 do_test(vm86, vmcode_umip_str - vmcode, VM86_SIGNAL, 0,
238 "STR instruction");
239 clearhandler(SIGILL);
240
241 sethandler(SIGILL, sighandler, 0);
242 do_test(vm86, vmcode_umip_sldt - vmcode, VM86_SIGNAL, 0,
243 "SLDT instruction");
244 clearhandler(SIGILL);
245}
246
163int main(void) 247int main(void)
164{ 248{
165 struct vm86plus_struct v86; 249 struct vm86plus_struct v86;
@@ -218,6 +302,9 @@ int main(void)
218 v86.regs.eax = (unsigned int)-1; 302 v86.regs.eax = (unsigned int)-1;
219 do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80"); 303 do_test(&v86, vmcode_int80 - vmcode, VM86_INTx, 0x80, "int80");
220 304
305 /* UMIP -- should exit with INTx 0x80 unless UMIP was not disabled */
306 do_umip_tests(&v86, addr);
307
221 /* Execute a null pointer */ 308 /* Execute a null pointer */
222 v86.regs.cs = 0; 309 v86.regs.cs = 0;
223 v86.regs.ss = 0; 310 v86.regs.ss = 0;
diff --git a/tools/testing/selftests/x86/ldt_gdt.c b/tools/testing/selftests/x86/ldt_gdt.c
index 961e3ee26c27..66e5ce5b91f0 100644
--- a/tools/testing/selftests/x86/ldt_gdt.c
+++ b/tools/testing/selftests/x86/ldt_gdt.c
@@ -115,7 +115,15 @@ static void check_valid_segment(uint16_t index, int ldt,
115 return; 115 return;
116 } 116 }
117 117
118 if (ar != expected_ar) { 118 /* The SDM says "bits 19:16 are undefined". Thanks. */
119 ar &= ~0xF0000;
120
121 /*
122 * NB: Different Linux versions do different things with the
123 * accessed bit in set_thread_area().
124 */
125 if (ar != expected_ar &&
126 (ldt || ar != (expected_ar | AR_ACCESSED))) {
119 printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n", 127 printf("[FAIL]\t%s entry %hu has AR 0x%08X but expected 0x%08X\n",
120 (ldt ? "LDT" : "GDT"), index, ar, expected_ar); 128 (ldt ? "LDT" : "GDT"), index, ar, expected_ar);
121 nerrs++; 129 nerrs++;
@@ -129,30 +137,51 @@ static void check_valid_segment(uint16_t index, int ldt,
129 } 137 }
130} 138}
131 139
132static bool install_valid_mode(const struct user_desc *desc, uint32_t ar, 140static bool install_valid_mode(const struct user_desc *d, uint32_t ar,
133 bool oldmode) 141 bool oldmode, bool ldt)
134{ 142{
135 int ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11, 143 struct user_desc desc = *d;
136 desc, sizeof(*desc)); 144 int ret;
137 if (ret < -1) 145
138 errno = -ret; 146 if (!ldt) {
147#ifndef __i386__
148 /* No point testing set_thread_area in a 64-bit build */
149 return false;
150#endif
151 if (!gdt_entry_num)
152 return false;
153 desc.entry_number = gdt_entry_num;
154
155 ret = syscall(SYS_set_thread_area, &desc);
156 } else {
157 ret = syscall(SYS_modify_ldt, oldmode ? 1 : 0x11,
158 &desc, sizeof(desc));
159
160 if (ret < -1)
161 errno = -ret;
162
163 if (ret != 0 && errno == ENOSYS) {
164 printf("[OK]\tmodify_ldt returned -ENOSYS\n");
165 return false;
166 }
167 }
168
139 if (ret == 0) { 169 if (ret == 0) {
140 uint32_t limit = desc->limit; 170 uint32_t limit = desc.limit;
141 if (desc->limit_in_pages) 171 if (desc.limit_in_pages)
142 limit = (limit << 12) + 4095; 172 limit = (limit << 12) + 4095;
143 check_valid_segment(desc->entry_number, 1, ar, limit, true); 173 check_valid_segment(desc.entry_number, ldt, ar, limit, true);
144 return true; 174 return true;
145 } else if (errno == ENOSYS) {
146 printf("[OK]\tmodify_ldt returned -ENOSYS\n");
147 return false;
148 } else { 175 } else {
149 if (desc->seg_32bit) { 176 if (desc.seg_32bit) {
150 printf("[FAIL]\tUnexpected modify_ldt failure %d\n", 177 printf("[FAIL]\tUnexpected %s failure %d\n",
178 ldt ? "modify_ldt" : "set_thread_area",
151 errno); 179 errno);
152 nerrs++; 180 nerrs++;
153 return false; 181 return false;
154 } else { 182 } else {
155 printf("[OK]\tmodify_ldt rejected 16 bit segment\n"); 183 printf("[OK]\t%s rejected 16 bit segment\n",
184 ldt ? "modify_ldt" : "set_thread_area");
156 return false; 185 return false;
157 } 186 }
158 } 187 }
@@ -160,7 +189,15 @@ static bool install_valid_mode(const struct user_desc *desc, uint32_t ar,
160 189
161static bool install_valid(const struct user_desc *desc, uint32_t ar) 190static bool install_valid(const struct user_desc *desc, uint32_t ar)
162{ 191{
163 return install_valid_mode(desc, ar, false); 192 bool ret = install_valid_mode(desc, ar, false, true);
193
194 if (desc->contents <= 1 && desc->seg_32bit &&
195 !desc->seg_not_present) {
196 /* Should work in the GDT, too. */
197 install_valid_mode(desc, ar, false, false);
198 }
199
200 return ret;
164} 201}
165 202
166static void install_invalid(const struct user_desc *desc, bool oldmode) 203static void install_invalid(const struct user_desc *desc, bool oldmode)
@@ -367,9 +404,24 @@ static void do_simple_tests(void)
367 install_invalid(&desc, false); 404 install_invalid(&desc, false);
368 405
369 desc.seg_not_present = 0; 406 desc.seg_not_present = 0;
370 desc.read_exec_only = 0;
371 desc.seg_32bit = 1; 407 desc.seg_32bit = 1;
408 desc.read_exec_only = 0;
409 desc.limit = 0xfffff;
410
372 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB); 411 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB);
412
413 desc.limit_in_pages = 1;
414
415 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA | AR_S | AR_P | AR_DB | AR_G);
416 desc.read_exec_only = 1;
417 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA | AR_S | AR_P | AR_DB | AR_G);
418 desc.contents = 1;
419 desc.read_exec_only = 0;
420 install_valid(&desc, AR_DPL3 | AR_TYPE_RWDATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);
421 desc.read_exec_only = 1;
422 install_valid(&desc, AR_DPL3 | AR_TYPE_RODATA_EXPDOWN | AR_S | AR_P | AR_DB | AR_G);
423
424 desc.limit = 0;
373 install_invalid(&desc, true); 425 install_invalid(&desc, true);
374} 426}
375 427
diff --git a/tools/testing/selftests/x86/protection_keys.c b/tools/testing/selftests/x86/protection_keys.c
index 555e43ca846b..7a1cc0e56d2d 100644
--- a/tools/testing/selftests/x86/protection_keys.c
+++ b/tools/testing/selftests/x86/protection_keys.c
@@ -189,17 +189,29 @@ void lots_o_noops_around_write(int *write_to_me)
189#define u64 uint64_t 189#define u64 uint64_t
190 190
191#ifdef __i386__ 191#ifdef __i386__
192#define SYS_mprotect_key 380 192
193#define SYS_pkey_alloc 381 193#ifndef SYS_mprotect_key
194#define SYS_pkey_free 382 194# define SYS_mprotect_key 380
195#endif
196#ifndef SYS_pkey_alloc
197# define SYS_pkey_alloc 381
198# define SYS_pkey_free 382
199#endif
195#define REG_IP_IDX REG_EIP 200#define REG_IP_IDX REG_EIP
196#define si_pkey_offset 0x14 201#define si_pkey_offset 0x14
202
197#else 203#else
198#define SYS_mprotect_key 329 204
199#define SYS_pkey_alloc 330 205#ifndef SYS_mprotect_key
200#define SYS_pkey_free 331 206# define SYS_mprotect_key 329
207#endif
208#ifndef SYS_pkey_alloc
209# define SYS_pkey_alloc 330
210# define SYS_pkey_free 331
211#endif
201#define REG_IP_IDX REG_RIP 212#define REG_IP_IDX REG_RIP
202#define si_pkey_offset 0x20 213#define si_pkey_offset 0x20
214
203#endif 215#endif
204 216
205void dump_mem(void *dumpme, int len_bytes) 217void dump_mem(void *dumpme, int len_bytes)