summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Lutomirski <luto@amacapital.net>2014-12-15 08:53:40 -0800
committerAndy Lutomirski <luto@amacapital.net>2014-12-15 08:53:40 -0800
commitf628de6e15f9dd95a773d778e12a9342b524a3de (patch)
treea13d542c95084435d2f0c5ead0ae90c4557ea7ed
parent5f8e5fb1b11f894e2a691a02aed8f4cc1a257484 (diff)
parent574e57a2d7134584984d1c611d529406d6324679 (diff)
downloadmisc-tests-f628de6e15f9dd95a773d778e12a9342b524a3de.tar.gz
Merge tests for previously embargoed issues
-rw-r--r--sigreturn.c137
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;
}