0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022 #define _GNU_SOURCE
0023
0024 #include <stdlib.h>
0025 #include <sys/ptrace.h>
0026 #include <sys/types.h>
0027 #include <sys/wait.h>
0028 #include <sys/user.h>
0029 #include <sys/syscall.h>
0030 #include <unistd.h>
0031 #include <errno.h>
0032 #include <stddef.h>
0033 #include <stdio.h>
0034 #include <err.h>
0035 #include <string.h>
0036 #include <setjmp.h>
0037 #include <sys/prctl.h>
0038
0039 #define X86_EFLAGS_RF (1UL << 16)
0040
0041 #if __x86_64__
0042 # define REG_IP REG_RIP
0043 #else
0044 # define REG_IP REG_EIP
0045 #endif
0046
0047 unsigned short ss;
0048 extern unsigned char breakpoint_insn[];
0049 sigjmp_buf jmpbuf;
0050
0051 static void enable_watchpoint(void)
0052 {
0053 pid_t parent = getpid();
0054 int status;
0055
0056 pid_t child = fork();
0057 if (child < 0)
0058 err(1, "fork");
0059
0060 if (child) {
0061 if (waitpid(child, &status, 0) != child)
0062 err(1, "waitpid for child");
0063 } else {
0064 unsigned long dr0, dr1, dr7;
0065
0066 dr0 = (unsigned long)&ss;
0067 dr1 = (unsigned long)breakpoint_insn;
0068 dr7 = ((1UL << 1) |
0069 (3UL << 16) |
0070 (1UL << 18) |
0071 (1UL << 3));
0072
0073 if (ptrace(PTRACE_ATTACH, parent, NULL, NULL) != 0)
0074 err(1, "PTRACE_ATTACH");
0075
0076 if (waitpid(parent, &status, 0) != parent)
0077 err(1, "waitpid for child");
0078
0079 if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[0]), dr0) != 0)
0080 err(1, "PTRACE_POKEUSER DR0");
0081
0082 if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[1]), dr1) != 0)
0083 err(1, "PTRACE_POKEUSER DR1");
0084
0085 if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[7]), dr7) != 0)
0086 err(1, "PTRACE_POKEUSER DR7");
0087
0088 printf("\tDR0 = %lx, DR1 = %lx, DR7 = %lx\n", dr0, dr1, dr7);
0089
0090 if (ptrace(PTRACE_DETACH, parent, NULL, NULL) != 0)
0091 err(1, "PTRACE_DETACH");
0092
0093 exit(0);
0094 }
0095 }
0096
0097 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
0098 int flags)
0099 {
0100 struct sigaction sa;
0101 memset(&sa, 0, sizeof(sa));
0102 sa.sa_sigaction = handler;
0103 sa.sa_flags = SA_SIGINFO | flags;
0104 sigemptyset(&sa.sa_mask);
0105 if (sigaction(sig, &sa, 0))
0106 err(1, "sigaction");
0107 }
0108
0109 static char const * const signames[] = {
0110 [SIGSEGV] = "SIGSEGV",
0111 [SIGBUS] = "SIBGUS",
0112 [SIGTRAP] = "SIGTRAP",
0113 [SIGILL] = "SIGILL",
0114 };
0115
0116 static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
0117 {
0118 ucontext_t *ctx = ctx_void;
0119
0120 printf("\tGot SIGTRAP with RIP=%lx, EFLAGS.RF=%d\n",
0121 (unsigned long)ctx->uc_mcontext.gregs[REG_IP],
0122 !!(ctx->uc_mcontext.gregs[REG_EFL] & X86_EFLAGS_RF));
0123 }
0124
0125 static void handle_and_return(int sig, siginfo_t *si, void *ctx_void)
0126 {
0127 ucontext_t *ctx = ctx_void;
0128
0129 printf("\tGot %s with RIP=%lx\n", signames[sig],
0130 (unsigned long)ctx->uc_mcontext.gregs[REG_IP]);
0131 }
0132
0133 static void handle_and_longjmp(int sig, siginfo_t *si, void *ctx_void)
0134 {
0135 ucontext_t *ctx = ctx_void;
0136
0137 printf("\tGot %s with RIP=%lx\n", signames[sig],
0138 (unsigned long)ctx->uc_mcontext.gregs[REG_IP]);
0139
0140 siglongjmp(jmpbuf, 1);
0141 }
0142
0143 int main()
0144 {
0145 unsigned long nr;
0146
0147 asm volatile ("mov %%ss, %[ss]" : [ss] "=m" (ss));
0148 printf("\tSS = 0x%hx, &SS = 0x%p\n", ss, &ss);
0149
0150 if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) == 0)
0151 printf("\tPR_SET_PTRACER_ANY succeeded\n");
0152
0153 printf("\tSet up a watchpoint\n");
0154 sethandler(SIGTRAP, sigtrap, 0);
0155 enable_watchpoint();
0156
0157 printf("[RUN]\tRead from watched memory (should get SIGTRAP)\n");
0158 asm volatile ("mov %[ss], %[tmp]" : [tmp] "=r" (nr) : [ss] "m" (ss));
0159
0160 printf("[RUN]\tMOV SS; INT3\n");
0161 asm volatile ("mov %[ss], %%ss; int3" :: [ss] "m" (ss));
0162
0163 printf("[RUN]\tMOV SS; INT 3\n");
0164 asm volatile ("mov %[ss], %%ss; .byte 0xcd, 0x3" :: [ss] "m" (ss));
0165
0166 printf("[RUN]\tMOV SS; CS CS INT3\n");
0167 asm volatile ("mov %[ss], %%ss; .byte 0x2e, 0x2e; int3" :: [ss] "m" (ss));
0168
0169 printf("[RUN]\tMOV SS; CSx14 INT3\n");
0170 asm volatile ("mov %[ss], %%ss; .fill 14,1,0x2e; int3" :: [ss] "m" (ss));
0171
0172 printf("[RUN]\tMOV SS; INT 4\n");
0173 sethandler(SIGSEGV, handle_and_return, SA_RESETHAND);
0174 asm volatile ("mov %[ss], %%ss; int $4" :: [ss] "m" (ss));
0175
0176 #ifdef __i386__
0177 printf("[RUN]\tMOV SS; INTO\n");
0178 sethandler(SIGSEGV, handle_and_return, SA_RESETHAND);
0179 nr = -1;
0180 asm volatile ("add $1, %[tmp]; mov %[ss], %%ss; into"
0181 : [tmp] "+r" (nr) : [ss] "m" (ss));
0182 #endif
0183
0184 if (sigsetjmp(jmpbuf, 1) == 0) {
0185 printf("[RUN]\tMOV SS; ICEBP\n");
0186
0187
0188 sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND);
0189
0190 asm volatile ("mov %[ss], %%ss; .byte 0xf1" :: [ss] "m" (ss));
0191 }
0192
0193 if (sigsetjmp(jmpbuf, 1) == 0) {
0194 printf("[RUN]\tMOV SS; CLI\n");
0195 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
0196 asm volatile ("mov %[ss], %%ss; cli" :: [ss] "m" (ss));
0197 }
0198
0199 if (sigsetjmp(jmpbuf, 1) == 0) {
0200 printf("[RUN]\tMOV SS; #PF\n");
0201 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
0202 asm volatile ("mov %[ss], %%ss; mov (-1), %[tmp]"
0203 : [tmp] "=r" (nr) : [ss] "m" (ss));
0204 }
0205
0206
0207
0208
0209
0210 if (sigsetjmp(jmpbuf, 1) == 0) {
0211 printf("[RUN]\tMOV SS; INT 1\n");
0212 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
0213 asm volatile ("mov %[ss], %%ss; int $1" :: [ss] "m" (ss));
0214 }
0215
0216 #ifdef __x86_64__
0217
0218
0219
0220
0221
0222 if (sigsetjmp(jmpbuf, 1) == 0) {
0223 printf("[RUN]\tMOV SS; SYSCALL\n");
0224 sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND);
0225 nr = SYS_getpid;
0226
0227
0228
0229
0230 asm volatile ("btc $63, %%rsp\n\t"
0231 "mov %[ss], %%ss; syscall\n\t"
0232 "btc $63, %%rsp"
0233 : "+a" (nr) : [ss] "m" (ss)
0234 : "rcx"
0235 #ifdef __x86_64__
0236 , "r11"
0237 #endif
0238 );
0239 }
0240 #endif
0241
0242 printf("[RUN]\tMOV SS; breakpointed NOP\n");
0243 asm volatile ("mov %[ss], %%ss; breakpoint_insn: nop" :: [ss] "m" (ss));
0244
0245
0246
0247
0248
0249 if (sigsetjmp(jmpbuf, 1) == 0) {
0250 printf("[RUN]\tMOV SS; SYSENTER\n");
0251 stack_t stack = {
0252 .ss_sp = malloc(sizeof(char) * SIGSTKSZ),
0253 .ss_size = SIGSTKSZ,
0254 };
0255 if (sigaltstack(&stack, NULL) != 0)
0256 err(1, "sigaltstack");
0257 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND | SA_ONSTACK);
0258 nr = SYS_getpid;
0259 free(stack.ss_sp);
0260
0261 asm volatile ("xorl %%ebp, %%ebp; mov %[ss], %%ss; SYSENTER" : "+a" (nr)
0262 : [ss] "m" (ss) : "flags", "rcx"
0263 #ifdef __x86_64__
0264 , "r11"
0265 #endif
0266 );
0267
0268
0269 }
0270
0271 if (sigsetjmp(jmpbuf, 1) == 0) {
0272 printf("[RUN]\tMOV SS; INT $0x80\n");
0273 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
0274 nr = 20;
0275 asm volatile ("mov %[ss], %%ss; int $0x80"
0276 : "+a" (nr) : [ss] "m" (ss)
0277 : "flags"
0278 #ifdef __x86_64__
0279 , "r8", "r9", "r10", "r11"
0280 #endif
0281 );
0282 }
0283
0284 printf("[OK]\tI aten't dead\n");
0285 return 0;
0286 }