diff options
author | Andy Lutomirski <luto@kernel.org> | 2015-03-18 17:19:19 -0700 |
---|---|---|
committer | Andy Lutomirski <luto@kernel.org> | 2015-03-18 17:19:19 -0700 |
commit | 8b0d8912aaea07e207d93829294bb1b3cd8e0c6a (patch) | |
tree | d098dd98947138337fb7280c8650c31a93bd6b2a | |
parent | 2c10d8ca605c8ebd24fbb2e920a91bd5ae04ec36 (diff) | |
download | misc-tests-8b0d8912aaea07e207d93829294bb1b3cd8e0c6a.tar.gz |
segregs: Test gs switch failures
Signed-off-by: Andy Lutomirski <luto@kernel.org>
-rw-r--r-- | segregs.c | 80 |
1 files changed, 78 insertions, 2 deletions
@@ -5,6 +5,7 @@ #include <stdio.h> #include <unistd.h> +#include <string.h> #include <time.h> #include <err.h> #include <asm/ldt.h> @@ -15,6 +16,11 @@ static unsigned short GDT3(int idx) return (idx << 3) | 3; } +static unsigned short LDT3(int idx) +{ + return (idx << 3) | 7; +} + static int create_tls(int idx, unsigned int base) { struct user_desc desc = { @@ -35,8 +41,73 @@ static int create_tls(int idx, unsigned int base) return desc.entry_number; } +static void do_gs_test(int idx, int np) +{ + unsigned short orig_gs, new_gs; + int ax; + + /* + * Install a valid LDT entry (set_thread_area's hardening measures + * defeat the #NP part of this test). + */ + struct user_desc desc; + memset(&desc, 0, sizeof(desc)); + desc.entry_number = 0; + desc.limit = 0xffff; + desc.seg_32bit = 1; + desc.contents = 0; /* Data, grow-up */ + desc.read_exec_only = 0; + desc.limit_in_pages = 1; + desc.seg_not_present = 0; + if (syscall(SYS_modify_ldt, 1, &desc, sizeof(desc)) != 0) + err(1, "modify_ldt"); + + if (np) { + /* valid but not present */ + desc.seg_not_present = 1; + } else { + /* "empty" user_desc -> destroy the segment. */ + desc.limit = 0; + desc.seg_32bit = 0; + desc.limit_in_pages = 0; + desc.read_exec_only = 1; + desc.seg_not_present = 1; + } + + struct timespec req = { + .tv_sec = 0, + .tv_nsec = 100000, + }; + + printf("[RUN]\tGS %s\n", (np ? "not present" : "deleted")); + asm volatile ("mov %%gs,%0" : "=rm" (orig_gs)); + asm volatile ("mov %0,%%gs" : : "rm" (LDT3(0))); + + asm volatile ("int $0x80" + : "=a" (ax) + : "a" (SYS_modify_ldt), "b" (1), "c" (&desc), + "d" (sizeof(desc))); + if (ax != 0) + err(1, "set_thread_area"); + + /* + * Force rescheduling. On 32-bit kernels, fast syscalls + * destroy DS and ES, so force int 80. + */ + asm volatile ("int $0x80" + : "=a" (ax) + : "a" (SYS_nanosleep), "b" (&req), + "c" (0)); + + asm volatile ("mov %%gs,%0" : "=rm" (new_gs)); + asm volatile ("mov %0,%%gs" : : "rm" (orig_gs)); + printf("[OK]\tGS changed from %x to %x\n", (unsigned)GDT3(idx), + (unsigned)new_gs); +} + int main() { + int ret; int idx = create_tls(-1, 0); printf("Allocated GDT index %d\n", idx); @@ -76,9 +147,14 @@ int main() if (errors) { printf("[FAIL]\tES was corrupted %d/%d times\n", errors, total); - return 1; + ret = 1; } else { printf("[OK]\tES was preserved\n"); - return 0; + ret = 0; } + + do_gs_test(idx, 1); + create_tls(idx, 0); + do_gs_test(idx, 0); + return ret; } |