/* * Compile with: * * gcc -m32 -O -g -o ldttest ldttest.c -lpthread * * Should harmlessly segfault (SIGSEGV) when running. */ #define _GNU_SOURCE #include #include #include #include #include #include static void setup_ldt(void) { const struct user_desc code32_desc = { .entry_number = 0, .base_addr = 0, .limit = 0xfffff, .seg_32bit = 1, .contents = 2, .read_exec_only = 0, .limit_in_pages = 1, .seg_not_present = 0, .useable = 0 }; const struct user_desc data32_desc = { .entry_number = 1, .base_addr = 0, .limit = 0xfffff, .seg_32bit = 1, .contents = 0, .read_exec_only = 0, .limit_in_pages = 1, .seg_not_present = 0, .useable = 0 }; syscall(SYS_modify_ldt, 1, &code32_desc, sizeof code32_desc); syscall(SYS_modify_ldt, 1, &data32_desc, sizeof data32_desc); } static void nuke_ldt(void) { const struct user_desc nuke_desc = { .entry_number = 0, .base_addr = 0, .limit = 0, .seg_32bit = 0, .contents = 0, .read_exec_only = 1, .limit_in_pages = 0, .seg_not_present = 1, .useable = 0 }; syscall(SYS_modify_ldt, 1, &nuke_desc, sizeof nuke_desc); } void *aux_thread(void *dummy) { struct timespec ts; (void)dummy; ts.tv_sec = 0; ts.tv_nsec = 50000000; while (nanosleep(&ts, &ts) == -1 && errno == EINTR) ; nuke_ldt(); return NULL; } int main(void) { pthread_attr_t attr; pthread_t thread; setup_ldt(); pthread_attr_init(&attr); pthread_create(&thread, &attr, aux_thread, NULL); asm volatile("push $7 ; push $1f ; lretl ; 1:"); asm volatile("movl %0,%%ss" : : "r" (15)); while (1) { /* getpid() using int $0x80 to force IRET return */ asm volatile("movl $20,%%eax ; int $0x80" : : : "eax"); } }