From: Peter Zijlstra 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) Signed-off-by: Thomas Gleixner --- 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();