diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-13 17:13:48 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-11-13 17:13:48 -0500 |
commit | d6ec9d9a4def52a5094237564eaf6f6979fd7a27 (patch) | |
tree | adfb80f83f04a021e82cb25227b64b1bb9e793dc /tools | |
parent | 3e2014637c50e5d6a77cd63d5db6c209fe29d1b1 (diff) | |
parent | 91a6a6cfee8ad34ea4cc10a54c0765edfe437cdb (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.c | 7 | ||||
-rw-r--r-- | tools/objtool/objtool.c | 6 | ||||
-rw-r--r-- | tools/testing/selftests/x86/entry_from_vm86.c | 89 | ||||
-rw-r--r-- | tools/testing/selftests/x86/ldt_gdt.c | 88 | ||||
-rw-r--r-- | tools/testing/selftests/x86/protection_keys.c | 24 |
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 | ||
76 | static void handle_options(int *argc, const char ***argv) | 76 | static 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 | ||
104 | extern unsigned char vmcode[], end_vmcode[]; | 125 | extern unsigned char vmcode[], end_vmcode[]; |
105 | extern unsigned char vmcode_bound[], vmcode_sysenter[], vmcode_syscall[], | 126 | extern 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. */ |
109 | static bool do_test(struct vm86plus_struct *v86, unsigned long eip, | 131 | static 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 | ||
185 | void 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 | |||
163 | int main(void) | 247 | int 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 | ||
132 | static bool install_valid_mode(const struct user_desc *desc, uint32_t ar, | 140 | static 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 | ||
161 | static bool install_valid(const struct user_desc *desc, uint32_t ar) | 190 | static 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 | ||
166 | static void install_invalid(const struct user_desc *desc, bool oldmode) | 203 | static 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 | ||
205 | void dump_mem(void *dumpme, int len_bytes) | 217 | void dump_mem(void *dumpme, int len_bytes) |