diff options
author | Andy Lutomirski <luto@amacapital.net> | 2014-12-15 08:53:40 -0800 |
---|---|---|
committer | Andy Lutomirski <luto@amacapital.net> | 2014-12-15 08:53:40 -0800 |
commit | f628de6e15f9dd95a773d778e12a9342b524a3de (patch) | |
tree | a13d542c95084435d2f0c5ead0ae90c4557ea7ed | |
parent | 5f8e5fb1b11f894e2a691a02aed8f4cc1a257484 (diff) | |
parent | 574e57a2d7134584984d1c611d529406d6324679 (diff) | |
download | misc-tests-f628de6e15f9dd95a773d778e12a9342b524a3de.tar.gz |
Merge tests for previously embargoed issues
-rw-r--r-- | sigreturn.c | 137 |
1 files changed, 111 insertions, 26 deletions
diff --git a/sigreturn.c b/sigreturn.c index bbf13ce..9979764 100644 --- a/sigreturn.c +++ b/sigreturn.c @@ -23,6 +23,10 @@ struct selectors { unsigned short cs, gs, fs, ss; }; +static bool has_code16, has_data16, has_npcode32, has_npdata32; + +static int gdt_data16_idx, gdt_npdata32_idx; + static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *), int flags) { @@ -51,13 +55,23 @@ asm (".pushsection .text\n\t" ".type int3, @function\n\t" ".align 4096\n\t" "int3:\n\t" - "mov %ss,%ax\n\t" + "mov %ss,%eax\n\t" "int3\n\t" ".size int3, . - int3\n\t" ".align 4096, 0xcc\n\t" ".popsection"); extern char int3[4096]; +static void add_ldt(const struct user_desc *desc, bool *var, const char *name) +{ + if (syscall(SYS_modify_ldt, 1, desc, sizeof(*desc)) == 0) { + *var = true; + } else { + printf("[NOTE]\tFailed to create %s segment\n", name); + *var = false; + } +} + static void setup_ldt(void) { if ((unsigned long)stack16 > (1ULL << 32) - sizeof(stack16)) @@ -77,6 +91,8 @@ static void setup_ldt(void) .seg_not_present = 0, .useable = 0 }; + add_ldt(&code16_desc, &has_code16, "code16"); + const struct user_desc data16_desc = { .entry_number = 1, .base_addr = (unsigned long)stack16, @@ -88,7 +104,9 @@ static void setup_ldt(void) .seg_not_present = 0, .useable = 0 }; - const struct user_desc npcode16_desc = { + add_ldt(&data16_desc, &has_data16, "data16"); + + const struct user_desc npcode32_desc = { .entry_number = 3, .base_addr = (unsigned long)int3, .limit = 4095, @@ -99,26 +117,60 @@ static void setup_ldt(void) .seg_not_present = 1, .useable = 0 }; - const struct user_desc npdata16_desc = { + add_ldt(&npcode32_desc, &has_npcode32, "npcode32"); + + const struct user_desc npdata32_desc = { .entry_number = 4, .base_addr = (unsigned long)stack16, .limit = 0xffff, + .seg_32bit = 1, + .contents = 0, /* Data, grow-up */ + .read_exec_only = 0, + .limit_in_pages = 0, + .seg_not_present = 1, + .useable = 0 + }; + add_ldt(&npdata32_desc, &has_npdata32, "npdata32"); + + struct user_desc gdt_data16_desc = { + .entry_number = -1, + .base_addr = (unsigned long)stack16, + .limit = 0xffff, .seg_32bit = 0, .contents = 0, /* Data, grow-up */ .read_exec_only = 0, .limit_in_pages = 0, + .seg_not_present = 0, + .useable = 0 + }; + + if (syscall(SYS_set_thread_area, &gdt_data16_desc) == 0) { + printf("[FAIL]\tset_thread_area allocated data16 at index %d\n", + gdt_data16_desc.entry_number); + gdt_data16_idx = gdt_data16_desc.entry_number; + } else { + printf("[OK]\tset_thread_area refused 16-bit data\n"); + } + + struct user_desc gdt_npdata32_desc = { + .entry_number = -1, + .base_addr = (unsigned long)stack16, + .limit = 0xffff, + .seg_32bit = 1, + .contents = 0, /* Data, grow-up */ + .read_exec_only = 0, + .limit_in_pages = 0, .seg_not_present = 1, .useable = 0 }; - if (syscall(SYS_modify_ldt, 1, &code16_desc, sizeof code16_desc) != 0) - err(1, "modify_ldt"); - if (syscall(SYS_modify_ldt, 1, &data16_desc, sizeof data16_desc) != 0) - err(1, "modify_ldt"); - if (syscall(SYS_modify_ldt, 1, &npcode16_desc, sizeof npcode16_desc) != 0) - err(1, "modify_ldt"); - if (syscall(SYS_modify_ldt, 1, &npdata16_desc, sizeof npdata16_desc) != 0) - err(1, "modify_ldt"); + if (syscall(SYS_set_thread_area, &gdt_npdata32_desc) == 0) { + printf("[WARN]\tset_thread_area allocated npdata32 at index %d\n", + gdt_npdata32_desc.entry_number); + gdt_npdata32_idx = gdt_npdata32_desc.entry_number; + } else { + printf("[OK]\tset_thread_area refused 16-bit data\n"); + } } static gregset_t initial_regs, requested_regs, resulting_regs; @@ -253,21 +305,35 @@ int find_cs(int bitness) return -1; } -static int do_test(int cs_bits, bool use_16bit_ss) +static int do_test(int cs_bits, bool use_16bit_ss, int force_ss) { int cs = find_cs(cs_bits); - if (cs == -1) + if (cs == -1) { + printf("[SKIP]\tCode segment unavailable for %d-bit CS, %d-bit SS\n", + cs_bits, use_16bit_ss ? 16 : 32); return 0; + } - if (use_16bit_ss) - sig_ss = (1 << 3) | 7; /* LDT selector 1, RPL = 3 */ - else - asm volatile ("mov %%ss,%0" : "=r" (sig_ss)); + if (force_ss != -1) { + sig_ss = force_ss; + } else { + if (use_16bit_ss) { + if (!has_data16) { + printf("[SKIP]\tData segment unavailable for %d-bit CS, 16-bit SS\n", + cs_bits); + return 0; + } + sig_ss = (1 << 3) | 7; /* LDT selector 1, RPL = 3 */ + } else { + asm volatile ("mov %%ss,%0" : "=r" (sig_ss)); + } + } sig_cs = cs; - printf("[RUN]\t%d-bit CS (%hx), %d-bit SS (%hx)\n", - cs_bits, sig_cs, use_16bit_ss ? 16 : 32, sig_ss); + printf("[RUN]\t%d-bit CS (%hx), %d-bit SS (%hx%s)\n", + cs_bits, sig_cs, use_16bit_ss ? 16 : 32, sig_ss, + (sig_ss & 4) ? "" : ", GDT"); raise(SIGUSR1); @@ -372,6 +438,8 @@ static int test_bad_iret(int cs_bits, unsigned short ss, int force_cs) strcpy(trapname, "NP"); else if (sig_trapno == 12) strcpy(trapname, "SS"); + else if (sig_trapno == 32) + strcpy(trapname, "IRET"); /* X86_TRAP_IRET */ else sprintf(trapname, "%d", sig_trapno); @@ -390,6 +458,12 @@ int main() int total_nerrs = 0; unsigned short my_cs, my_ss; +#ifdef __x86_64__ + printf("[WARN]\t***** The 64-bit version requires a special kernel. *****\n"); + printf("[WARN]\t***** Build with -m32. *****\n"); + usleep(1000000); +#endif + asm volatile ("mov %%cs,%0" : "=r" (my_cs)); asm volatile ("mov %%ss,%0" : "=r" (my_ss)); setup_ldt(); @@ -404,16 +478,23 @@ int main() sethandler(SIGUSR1, sigusr1, 0); sethandler(SIGTRAP, sigtrap, SA_ONSTACK); - total_nerrs += do_test(64, false); - total_nerrs += do_test(32, false); - total_nerrs += do_test(16, false); - total_nerrs += do_test(64, true); - total_nerrs += do_test(32, true); - total_nerrs += do_test(16, true); + total_nerrs += do_test(64, false, -1); + total_nerrs += do_test(32, false, -1); + total_nerrs += do_test(16, false, -1); + total_nerrs += do_test(64, true, -1); + total_nerrs += do_test(32, true, -1); + total_nerrs += do_test(16, true, -1); + + if (gdt_data16_idx) { + total_nerrs += do_test(64, true, (gdt_data16_idx << 3) | 3); + total_nerrs += do_test(32, true, (gdt_data16_idx << 3) | 3); + total_nerrs += do_test(16, true, (gdt_data16_idx << 3) | 3); + } clearhandler(SIGTRAP); sethandler(SIGSEGV, sigtrap, SA_ONSTACK); sethandler(SIGBUS, sigtrap, SA_ONSTACK); + sethandler(SIGILL, sigtrap, SA_ONSTACK); /* 32-bit kernels do this */ test_bad_iret(64, (2 << 3) | 7, -1); test_bad_iret(32, (2 << 3) | 7, -1); @@ -426,8 +507,12 @@ int main() /* IRET will fail with #NP */ test_bad_iret(32, my_ss, (3 << 3) | 7); - /* IRET will fail with #SS */ + /* IRET will fail with #SS on the espfix stack */ test_bad_iret(32, (4 << 3) | 7, -1); + /* IRET will fail with #SS on the normal stack */ + if (gdt_npdata32_idx) + test_bad_iret(32, (gdt_npdata32_idx << 3) | 3, -1); + return total_nerrs ? 1 : 0; } |