0001
0002
0003
0004
0005
0006
0007 #define _GNU_SOURCE
0008
0009 #include <stdlib.h>
0010 #include <stdio.h>
0011 #include <string.h>
0012 #include <sys/signal.h>
0013 #include <sys/ucontext.h>
0014 #include <err.h>
0015 #include <setjmp.h>
0016 #include <errno.h>
0017
0018 #include "helpers.h"
0019
0020 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
0021 int flags)
0022 {
0023 struct sigaction sa;
0024 memset(&sa, 0, sizeof(sa));
0025 sa.sa_sigaction = handler;
0026 sa.sa_flags = SA_SIGINFO | flags;
0027 sigemptyset(&sa.sa_mask);
0028 if (sigaction(sig, &sa, 0))
0029 err(1, "sigaction");
0030 }
0031
0032 static volatile sig_atomic_t sig_traps;
0033 static sigjmp_buf jmpbuf;
0034
0035 static volatile sig_atomic_t n_errs;
0036
0037 #ifdef __x86_64__
0038 #define REG_AX REG_RAX
0039 #define REG_IP REG_RIP
0040 #else
0041 #define REG_AX REG_EAX
0042 #define REG_IP REG_EIP
0043 #endif
0044
0045 static void sigsegv_or_sigbus(int sig, siginfo_t *info, void *ctx_void)
0046 {
0047 ucontext_t *ctx = (ucontext_t*)ctx_void;
0048 long ax = (long)ctx->uc_mcontext.gregs[REG_AX];
0049
0050 if (ax != -EFAULT && ax != -ENOSYS) {
0051 printf("[FAIL]\tAX had the wrong value: 0x%lx\n",
0052 (unsigned long)ax);
0053 printf("\tIP = 0x%lx\n", (unsigned long)ctx->uc_mcontext.gregs[REG_IP]);
0054 n_errs++;
0055 } else {
0056 printf("[OK]\tSeems okay\n");
0057 }
0058
0059 siglongjmp(jmpbuf, 1);
0060 }
0061
0062 static volatile sig_atomic_t sigtrap_consecutive_syscalls;
0063
0064 static void sigtrap(int sig, siginfo_t *info, void *ctx_void)
0065 {
0066
0067
0068
0069
0070
0071
0072 ucontext_t *ctx = (ucontext_t*)ctx_void;
0073 unsigned short *ip = (unsigned short *)ctx->uc_mcontext.gregs[REG_IP];
0074
0075 if (*ip == 0x340f || *ip == 0x050f) {
0076
0077 sigtrap_consecutive_syscalls++;
0078 if (sigtrap_consecutive_syscalls > 3) {
0079 printf("[WARN]\tGot stuck single-stepping -- you probably have a KVM bug\n");
0080 siglongjmp(jmpbuf, 1);
0081 }
0082 } else {
0083 sigtrap_consecutive_syscalls = 0;
0084 }
0085 }
0086
0087 static void sigill(int sig, siginfo_t *info, void *ctx_void)
0088 {
0089 ucontext_t *ctx = (ucontext_t*)ctx_void;
0090 unsigned short *ip = (unsigned short *)ctx->uc_mcontext.gregs[REG_IP];
0091
0092 if (*ip == 0x0b0f) {
0093
0094 printf("[OK]\tSYSCALL returned normally\n");
0095 } else {
0096 printf("[SKIP]\tIllegal instruction\n");
0097 }
0098 siglongjmp(jmpbuf, 1);
0099 }
0100
0101 int main()
0102 {
0103 stack_t stack = {
0104
0105 .ss_sp = malloc(sizeof(char) * SIGSTKSZ),
0106 .ss_size = SIGSTKSZ,
0107 };
0108 if (sigaltstack(&stack, NULL) != 0)
0109 err(1, "sigaltstack");
0110
0111 sethandler(SIGSEGV, sigsegv_or_sigbus, SA_ONSTACK);
0112
0113
0114
0115
0116
0117 sethandler(SIGBUS, sigsegv_or_sigbus, SA_ONSTACK);
0118 sethandler(SIGILL, sigill, SA_ONSTACK);
0119
0120
0121
0122
0123
0124
0125
0126
0127
0128
0129
0130
0131
0132
0133
0134
0135
0136
0137
0138
0139 printf("[RUN]\tSYSENTER with invalid state\n");
0140 if (sigsetjmp(jmpbuf, 1) == 0) {
0141 asm volatile (
0142 "movl $-1, %%eax\n\t"
0143 "movl $-1, %%ebx\n\t"
0144 "movl $-1, %%ecx\n\t"
0145 "movl $-1, %%edx\n\t"
0146 "movl $-1, %%esi\n\t"
0147 "movl $-1, %%edi\n\t"
0148 "movl $-1, %%ebp\n\t"
0149 "movl $-1, %%esp\n\t"
0150 "sysenter"
0151 : : : "memory", "flags");
0152 }
0153
0154 printf("[RUN]\tSYSCALL with invalid state\n");
0155 if (sigsetjmp(jmpbuf, 1) == 0) {
0156 asm volatile (
0157 "movl $-1, %%eax\n\t"
0158 "movl $-1, %%ebx\n\t"
0159 "movl $-1, %%ecx\n\t"
0160 "movl $-1, %%edx\n\t"
0161 "movl $-1, %%esi\n\t"
0162 "movl $-1, %%edi\n\t"
0163 "movl $-1, %%ebp\n\t"
0164 "movl $-1, %%esp\n\t"
0165 "syscall\n\t"
0166 "ud2"
0167 : : : "memory", "flags");
0168 }
0169
0170 printf("[RUN]\tSYSENTER with TF and invalid state\n");
0171 sethandler(SIGTRAP, sigtrap, SA_ONSTACK);
0172
0173 if (sigsetjmp(jmpbuf, 1) == 0) {
0174 sigtrap_consecutive_syscalls = 0;
0175 set_eflags(get_eflags() | X86_EFLAGS_TF);
0176 asm volatile (
0177 "movl $-1, %%eax\n\t"
0178 "movl $-1, %%ebx\n\t"
0179 "movl $-1, %%ecx\n\t"
0180 "movl $-1, %%edx\n\t"
0181 "movl $-1, %%esi\n\t"
0182 "movl $-1, %%edi\n\t"
0183 "movl $-1, %%ebp\n\t"
0184 "movl $-1, %%esp\n\t"
0185 "sysenter"
0186 : : : "memory", "flags");
0187 }
0188 set_eflags(get_eflags() & ~X86_EFLAGS_TF);
0189
0190 printf("[RUN]\tSYSCALL with TF and invalid state\n");
0191 if (sigsetjmp(jmpbuf, 1) == 0) {
0192 sigtrap_consecutive_syscalls = 0;
0193 set_eflags(get_eflags() | X86_EFLAGS_TF);
0194 asm volatile (
0195 "movl $-1, %%eax\n\t"
0196 "movl $-1, %%ebx\n\t"
0197 "movl $-1, %%ecx\n\t"
0198 "movl $-1, %%edx\n\t"
0199 "movl $-1, %%esi\n\t"
0200 "movl $-1, %%edi\n\t"
0201 "movl $-1, %%ebp\n\t"
0202 "movl $-1, %%esp\n\t"
0203 "syscall\n\t"
0204 "ud2"
0205 : : : "memory", "flags");
0206 }
0207 set_eflags(get_eflags() & ~X86_EFLAGS_TF);
0208
0209 #ifdef __x86_64__
0210 printf("[RUN]\tSYSENTER with TF, invalid state, and GSBASE < 0\n");
0211
0212 if (sigsetjmp(jmpbuf, 1) == 0) {
0213 sigtrap_consecutive_syscalls = 0;
0214
0215 asm volatile ("wrgsbase %%rax\n\t"
0216 :: "a" (0xffffffffffff0000UL));
0217
0218 set_eflags(get_eflags() | X86_EFLAGS_TF);
0219 asm volatile (
0220 "movl $-1, %%eax\n\t"
0221 "movl $-1, %%ebx\n\t"
0222 "movl $-1, %%ecx\n\t"
0223 "movl $-1, %%edx\n\t"
0224 "movl $-1, %%esi\n\t"
0225 "movl $-1, %%edi\n\t"
0226 "movl $-1, %%ebp\n\t"
0227 "movl $-1, %%esp\n\t"
0228 "sysenter"
0229 : : : "memory", "flags");
0230 }
0231 set_eflags(get_eflags() & ~X86_EFLAGS_TF);
0232 #endif
0233
0234 free(stack.ss_sp);
0235 return 0;
0236 }