This source file includes following definitions.
- enable_watchpoint
- sethandler
- sigtrap
- handle_and_return
- handle_and_longjmp
- main
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #define _GNU_SOURCE
23
24 #include <stdlib.h>
25 #include <sys/ptrace.h>
26 #include <sys/types.h>
27 #include <sys/wait.h>
28 #include <sys/user.h>
29 #include <sys/syscall.h>
30 #include <unistd.h>
31 #include <errno.h>
32 #include <stddef.h>
33 #include <stdio.h>
34 #include <err.h>
35 #include <string.h>
36 #include <setjmp.h>
37 #include <sys/prctl.h>
38
39 #define X86_EFLAGS_RF (1UL << 16)
40
41 #if __x86_64__
42 # define REG_IP REG_RIP
43 #else
44 # define REG_IP REG_EIP
45 #endif
46
47 unsigned short ss;
48 extern unsigned char breakpoint_insn[];
49 sigjmp_buf jmpbuf;
50 static unsigned char altstack_data[SIGSTKSZ];
51
52 static void enable_watchpoint(void)
53 {
54 pid_t parent = getpid();
55 int status;
56
57 pid_t child = fork();
58 if (child < 0)
59 err(1, "fork");
60
61 if (child) {
62 if (waitpid(child, &status, 0) != child)
63 err(1, "waitpid for child");
64 } else {
65 unsigned long dr0, dr1, dr7;
66
67 dr0 = (unsigned long)&ss;
68 dr1 = (unsigned long)breakpoint_insn;
69 dr7 = ((1UL << 1) |
70 (3UL << 16) |
71 (1UL << 18) |
72 (1UL << 3));
73
74 if (ptrace(PTRACE_ATTACH, parent, NULL, NULL) != 0)
75 err(1, "PTRACE_ATTACH");
76
77 if (waitpid(parent, &status, 0) != parent)
78 err(1, "waitpid for child");
79
80 if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[0]), dr0) != 0)
81 err(1, "PTRACE_POKEUSER DR0");
82
83 if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[1]), dr1) != 0)
84 err(1, "PTRACE_POKEUSER DR1");
85
86 if (ptrace(PTRACE_POKEUSER, parent, (void *)offsetof(struct user, u_debugreg[7]), dr7) != 0)
87 err(1, "PTRACE_POKEUSER DR7");
88
89 printf("\tDR0 = %lx, DR1 = %lx, DR7 = %lx\n", dr0, dr1, dr7);
90
91 if (ptrace(PTRACE_DETACH, parent, NULL, NULL) != 0)
92 err(1, "PTRACE_DETACH");
93
94 exit(0);
95 }
96 }
97
98 static void sethandler(int sig, void (*handler)(int, siginfo_t *, void *),
99 int flags)
100 {
101 struct sigaction sa;
102 memset(&sa, 0, sizeof(sa));
103 sa.sa_sigaction = handler;
104 sa.sa_flags = SA_SIGINFO | flags;
105 sigemptyset(&sa.sa_mask);
106 if (sigaction(sig, &sa, 0))
107 err(1, "sigaction");
108 }
109
110 static char const * const signames[] = {
111 [SIGSEGV] = "SIGSEGV",
112 [SIGBUS] = "SIBGUS",
113 [SIGTRAP] = "SIGTRAP",
114 [SIGILL] = "SIGILL",
115 };
116
117 static void sigtrap(int sig, siginfo_t *si, void *ctx_void)
118 {
119 ucontext_t *ctx = ctx_void;
120
121 printf("\tGot SIGTRAP with RIP=%lx, EFLAGS.RF=%d\n",
122 (unsigned long)ctx->uc_mcontext.gregs[REG_IP],
123 !!(ctx->uc_mcontext.gregs[REG_EFL] & X86_EFLAGS_RF));
124 }
125
126 static void handle_and_return(int sig, siginfo_t *si, void *ctx_void)
127 {
128 ucontext_t *ctx = ctx_void;
129
130 printf("\tGot %s with RIP=%lx\n", signames[sig],
131 (unsigned long)ctx->uc_mcontext.gregs[REG_IP]);
132 }
133
134 static void handle_and_longjmp(int sig, siginfo_t *si, void *ctx_void)
135 {
136 ucontext_t *ctx = ctx_void;
137
138 printf("\tGot %s with RIP=%lx\n", signames[sig],
139 (unsigned long)ctx->uc_mcontext.gregs[REG_IP]);
140
141 siglongjmp(jmpbuf, 1);
142 }
143
144 int main()
145 {
146 unsigned long nr;
147
148 asm volatile ("mov %%ss, %[ss]" : [ss] "=m" (ss));
149 printf("\tSS = 0x%hx, &SS = 0x%p\n", ss, &ss);
150
151 if (prctl(PR_SET_PTRACER, PR_SET_PTRACER_ANY, 0, 0, 0) == 0)
152 printf("\tPR_SET_PTRACER_ANY succeeded\n");
153
154 printf("\tSet up a watchpoint\n");
155 sethandler(SIGTRAP, sigtrap, 0);
156 enable_watchpoint();
157
158 printf("[RUN]\tRead from watched memory (should get SIGTRAP)\n");
159 asm volatile ("mov %[ss], %[tmp]" : [tmp] "=r" (nr) : [ss] "m" (ss));
160
161 printf("[RUN]\tMOV SS; INT3\n");
162 asm volatile ("mov %[ss], %%ss; int3" :: [ss] "m" (ss));
163
164 printf("[RUN]\tMOV SS; INT 3\n");
165 asm volatile ("mov %[ss], %%ss; .byte 0xcd, 0x3" :: [ss] "m" (ss));
166
167 printf("[RUN]\tMOV SS; CS CS INT3\n");
168 asm volatile ("mov %[ss], %%ss; .byte 0x2e, 0x2e; int3" :: [ss] "m" (ss));
169
170 printf("[RUN]\tMOV SS; CSx14 INT3\n");
171 asm volatile ("mov %[ss], %%ss; .fill 14,1,0x2e; int3" :: [ss] "m" (ss));
172
173 printf("[RUN]\tMOV SS; INT 4\n");
174 sethandler(SIGSEGV, handle_and_return, SA_RESETHAND);
175 asm volatile ("mov %[ss], %%ss; int $4" :: [ss] "m" (ss));
176
177 #ifdef __i386__
178 printf("[RUN]\tMOV SS; INTO\n");
179 sethandler(SIGSEGV, handle_and_return, SA_RESETHAND);
180 nr = -1;
181 asm volatile ("add $1, %[tmp]; mov %[ss], %%ss; into"
182 : [tmp] "+r" (nr) : [ss] "m" (ss));
183 #endif
184
185 if (sigsetjmp(jmpbuf, 1) == 0) {
186 printf("[RUN]\tMOV SS; ICEBP\n");
187
188
189 sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND);
190
191 asm volatile ("mov %[ss], %%ss; .byte 0xf1" :: [ss] "m" (ss));
192 }
193
194 if (sigsetjmp(jmpbuf, 1) == 0) {
195 printf("[RUN]\tMOV SS; CLI\n");
196 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
197 asm volatile ("mov %[ss], %%ss; cli" :: [ss] "m" (ss));
198 }
199
200 if (sigsetjmp(jmpbuf, 1) == 0) {
201 printf("[RUN]\tMOV SS; #PF\n");
202 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
203 asm volatile ("mov %[ss], %%ss; mov (-1), %[tmp]"
204 : [tmp] "=r" (nr) : [ss] "m" (ss));
205 }
206
207
208
209
210
211 if (sigsetjmp(jmpbuf, 1) == 0) {
212 printf("[RUN]\tMOV SS; INT 1\n");
213 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
214 asm volatile ("mov %[ss], %%ss; int $1" :: [ss] "m" (ss));
215 }
216
217 #ifdef __x86_64__
218
219
220
221
222
223 if (sigsetjmp(jmpbuf, 1) == 0) {
224 printf("[RUN]\tMOV SS; SYSCALL\n");
225 sethandler(SIGILL, handle_and_longjmp, SA_RESETHAND);
226 nr = SYS_getpid;
227
228
229
230
231 asm volatile ("btc $63, %%rsp\n\t"
232 "mov %[ss], %%ss; syscall\n\t"
233 "btc $63, %%rsp"
234 : "+a" (nr) : [ss] "m" (ss)
235 : "rcx"
236 #ifdef __x86_64__
237 , "r11"
238 #endif
239 );
240 }
241 #endif
242
243 printf("[RUN]\tMOV SS; breakpointed NOP\n");
244 asm volatile ("mov %[ss], %%ss; breakpoint_insn: nop" :: [ss] "m" (ss));
245
246
247
248
249
250 if (sigsetjmp(jmpbuf, 1) == 0) {
251 printf("[RUN]\tMOV SS; SYSENTER\n");
252 stack_t stack = {
253 .ss_sp = altstack_data,
254 .ss_size = SIGSTKSZ,
255 };
256 if (sigaltstack(&stack, NULL) != 0)
257 err(1, "sigaltstack");
258 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND | SA_ONSTACK);
259 nr = SYS_getpid;
260
261 asm volatile ("xorl %%ebp, %%ebp; mov %[ss], %%ss; SYSENTER" : "+a" (nr)
262 : [ss] "m" (ss) : "flags", "rcx"
263 #ifdef __x86_64__
264 , "r11"
265 #endif
266 );
267
268
269 }
270
271 if (sigsetjmp(jmpbuf, 1) == 0) {
272 printf("[RUN]\tMOV SS; INT $0x80\n");
273 sethandler(SIGSEGV, handle_and_longjmp, SA_RESETHAND);
274 nr = 20;
275 asm volatile ("mov %[ss], %%ss; int $0x80"
276 : "+a" (nr) : [ss] "m" (ss)
277 : "flags"
278 #ifdef __x86_64__
279 , "r8", "r9", "r10", "r11"
280 #endif
281 );
282 }
283
284 printf("[OK]\tI aten't dead\n");
285 return 0;
286 }