1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2018 The FreeBSD Foundation 5 * 6 * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 7 * under sponsorship from the FreeBSD Foundation. 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 20 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 21 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 22 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 23 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 24 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 25 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 26 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 27 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28 * SUCH DAMAGE. 29 * 30 * $Id: popss.c,v 1.28 2018/05/09 21:35:29 kostik Exp kostik $ 31 * 32 * cc -m32 -Wall -Wextra -O2 -g -o popss popss.c 33 * Use as "popss <instruction>", where instruction is one of 34 * bound, into, int1, int3, int80, syscall, sysenter. 35 */ 36 37 #include <sys/param.h> 38 #include <sys/ptrace.h> 39 #include <sys/wait.h> 40 #include <err.h> 41 #include <signal.h> 42 #include <stdio.h> 43 #include <stdlib.h> 44 #include <string.h> 45 #include <unistd.h> 46 #include <machine/reg.h> 47 48 static u_long *stk; 49 50 #define ITERATIONS 4 51 52 static void 53 setup(pid_t child) 54 { 55 struct reg r; 56 struct dbreg dbr; 57 int error, i, status; 58 59 error = waitpid(child, &status, WTRAPPED | WEXITED); 60 if (error == -1) 61 err(1, "waitpid 1"); 62 error = ptrace(PT_GETREGS, child, (caddr_t)&r, 0); 63 if (error == -1) 64 err(1, "ptrace PT_GETREGS"); 65 printf("child %d stopped eip %#x esp %#x\n", child, r.r_eip, r.r_esp); 66 67 error = ptrace(PT_GETDBREGS, child, (caddr_t)&dbr, 0); 68 if (error != 0) 69 err(1, "ptrace PT_GETDBREGS"); 70 dbr.dr[7] &= ~DBREG_DR7_MASK(0); 71 dbr.dr[7] |= DBREG_DR7_SET(0, DBREG_DR7_LEN_4, DBREG_DR7_RDWR, 72 DBREG_DR7_LOCAL_ENABLE | DBREG_DR7_GLOBAL_ENABLE); 73 dbr.dr[0] = (uintptr_t)stk; 74 error = ptrace(PT_SETDBREGS, child, (caddr_t)&dbr, 0); 75 if (error != 0) 76 err(1, "ptrace PT_SETDBREGS"); 77 error = ptrace(PT_CONTINUE, child, (caddr_t)1, 0); 78 if (error != 0) 79 err(1, "ptrace PT_CONTINUE fire"); 80 81 for (i = 0; i < ITERATIONS; i++) { 82 error = waitpid(child, &status, WTRAPPED | WEXITED); 83 if (error == -1) 84 err(1, "waitpid 2"); 85 if (WIFEXITED(status)) 86 break; 87 error = ptrace(PT_GETREGS, child, (caddr_t)&r, 0); 88 if (error == -1) 89 err(1, "ptrace PT_GETREGS"); 90 error = ptrace(PT_GETDBREGS, child, (caddr_t)&dbr, 0); 91 if (error != 0) 92 err(1, "ptrace PT_GETDBREGS"); 93 printf("child %d stopped eip %#x esp %#x dr0 %#x " 94 "dr6 %#x dr7 %#x\n", child, r.r_eip, r.r_esp, 95 dbr.dr[0], dbr.dr[6], dbr.dr[7]); 96 error = ptrace(PT_CONTINUE, child, (caddr_t)1, 0); 97 if (error == -1) 98 err(1, "ptrace PT_CONTINUE tail"); 99 } 100 if (i == ITERATIONS) { 101 kill(child, SIGKILL); 102 ptrace(PT_DETACH, child, NULL, 0); 103 } 104 } 105 106 static u_long tmpstk[1024 * 128]; 107 108 static u_int 109 read_ss(void) 110 { 111 u_int res; 112 113 __asm volatile("movl\t%%ss,%0" : "=r" (res)); 114 return (res); 115 } 116 117 #define PROLOGUE "int3;movl\t%0,%%esp;popl\t%%ss;" 118 119 static void 120 act(const char *cmd) 121 { 122 int error; 123 static const int boundx[2] = {0, 1}; 124 125 printf("child pid %d, stk at %p\n", getpid(), stk); 126 *stk = read_ss(); 127 128 error = ptrace(PT_TRACE_ME, 0, NULL, 0); 129 if (error != 0) 130 err(1, "ptrace PT_TRACE_ME"); 131 132 if (strcmp(cmd, "bound") == 0) { 133 /* XXX BOUND args order clang ias bug */ 134 __asm volatile("int3;movl\t$11,%%eax;" 135 "movl\t%0,%%esp;popl\t%%ss;bound\t%1,%%eax" 136 : : "r" (stk), "m" (boundx) : "memory"); 137 } else if (strcmp(cmd, "int1") == 0) { 138 __asm volatile(PROLOGUE ".byte 0xf1" 139 : : "r" (stk) : "memory"); 140 } else if (strcmp(cmd, "int3") == 0) { 141 __asm volatile(PROLOGUE "int3" 142 : : "r" (stk) : "memory"); 143 } else if (strcmp(cmd, "into") == 0) { 144 __asm volatile("int3;movl\t$0x80000000,%%eax;" 145 "addl\t%%eax,%%eax;movl\t%0,%%esp;popl\t%%ss;into" 146 : : "r" (stk) : "memory"); 147 } else if (strcmp(cmd, "int80") == 0) { 148 __asm volatile(PROLOGUE "int\t$0x80" 149 : : "r" (stk) : "memory"); 150 } else if (strcmp(cmd, "syscall") == 0) { 151 __asm volatile(PROLOGUE "syscall" 152 : : "r" (stk) : "memory"); 153 } else if (strcmp(cmd, "sysenter") == 0) { 154 __asm volatile(PROLOGUE "sysenter" 155 : : "r" (stk) : "memory"); 156 } else { 157 fprintf(stderr, "unknown instruction\n"); 158 exit(1); 159 } 160 printf("ho\n"); 161 } 162 163 int 164 main(int argc, char *argv[]) 165 { 166 int child; 167 168 if (argc != 2) { 169 printf( 170 "Usage: popss [bound|int1|int3|into|int80|syscall|sysenter]\n"); 171 exit(1); 172 } 173 stk = &tmpstk[nitems(tmpstk) - 1]; 174 child = fork(); 175 if (child == -1) 176 err(1, "fork"); 177 if (child == 0) 178 act(argv[1]); 179 else 180 setup(child); 181 } 182