[patch 07/16] selftest/x86: Implement additional LDT selftests
From: Thomas Gleixner
Date: Tue Dec 12 2017 - 12:38:04 EST
From: Peter Zijlstra <peterz@xxxxxxxxxxxxx>
do_ldt_ss_test() - tests modifying the SS segment while in use; this
tends to come apart with RO LDT maps
do_ldt_unmap_test() - tests the mechanics of unmapping the (future)
LDT VMA. Additional tests would make sense; like unmapping it while in
use (TODO).
Signed-off-by: Peter Zijlstra (Intel) <peterz@xxxxxxxxxxxxx>
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
---
tools/testing/selftests/x86/ldt_gdt.c | 71 +++++++++++++++++++++++++++++++++-
1 file changed, 70 insertions(+), 1 deletion(-)
--- a/tools/testing/selftests/x86/ldt_gdt.c
+++ b/tools/testing/selftests/x86/ldt_gdt.c
@@ -242,6 +242,72 @@ static void fail_install(struct user_des
}
}
+static void do_ldt_ss_test(void)
+{
+ unsigned short prev_sel, sel = (2 << 3) | (1 << 2) | 3;
+ struct user_desc *ldt_desc = low_user_desc + 2;
+ int ret;
+
+ ldt_desc->entry_number = 2;
+ ldt_desc->base_addr = (unsigned long)&counter_page[1];
+ ldt_desc->limit = 0xfffff;
+ ldt_desc->seg_32bit = 1;
+ ldt_desc->contents = 0; /* Data, grow-up*/
+ ldt_desc->read_exec_only = 0;
+ ldt_desc->limit_in_pages = 1;
+ ldt_desc->seg_not_present = 0;
+ ldt_desc->useable = 0;
+
+ ret = safe_modify_ldt(1, ldt_desc, sizeof(*ldt_desc));
+ if (ret)
+ perror("ponies");
+
+ /*
+ * syscall (eax) 123 - modify_ldt / return value
+ * (ebx) - func
+ * (ecx) - ptr
+ * (edx) - bytecount
+ */
+
+ int eax = 123;
+ int ebx = 1;
+ int ecx = (unsigned int)(unsigned long)ldt_desc;
+ int edx = sizeof(struct user_desc);
+
+ asm volatile ("movw %%ss, %[prev_sel]\n\t"
+ "movw %[sel], %%ss\n\t"
+ "int $0x80\n\t"
+ "movw %[prev_sel], %%ss"
+ : [prev_sel] "=&R" (prev_sel), "+a" (eax)
+ : [sel] "R" (sel), "b" (ebx), "c" (ecx), "d" (edx)
+ : INT80_CLOBBERS);
+
+ printf("[OK]\tSS modify_ldt()\n");
+}
+
+static void do_ldt_unmap_test(void)
+{
+ FILE *file = fopen("/proc/self/maps", "r");
+ char *line = NULL;
+ size_t len = 0;
+ ssize_t nread;
+ unsigned long start, end;
+
+ while ((nread = getline(&line, &len, file)) != -1) {
+ if (strstr(line, "[ldt]")) {
+ if (sscanf(line, "%lx-%lx", &start, &end) == 2) {
+ munmap((void *)start, end-start);
+ printf("[OK]\tmunmap LDT\n");
+ break;
+ }
+ }
+ }
+
+ free(line);
+ fclose(file);
+
+}
+
static void do_simple_tests(void)
{
struct user_desc desc = {
@@ -696,7 +762,7 @@ static int invoke_set_thread_area(void)
static void setup_low_user_desc(void)
{
- low_user_desc = mmap(NULL, 2 * sizeof(struct user_desc),
+ low_user_desc = mmap(NULL, 3 * sizeof(struct user_desc),
PROT_READ | PROT_WRITE,
MAP_ANONYMOUS | MAP_PRIVATE | MAP_32BIT, -1, 0);
if (low_user_desc == MAP_FAILED)
@@ -916,6 +982,9 @@ int main(int argc, char **argv)
setup_counter_page();
setup_low_user_desc();
+ do_ldt_ss_test();
+ do_ldt_unmap_test();
+
do_simple_tests();
do_multicpu_tests();