14072ae4eSKonstantin Belousov /*- 2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause 34072ae4eSKonstantin Belousov * 44072ae4eSKonstantin Belousov * Copyright (c) 2018 The FreeBSD Foundation 54072ae4eSKonstantin Belousov * 64072ae4eSKonstantin Belousov * This software was developed by Konstantin Belousov <kib@FreeBSD.org> 74072ae4eSKonstantin Belousov * under sponsorship from the FreeBSD Foundation. 84072ae4eSKonstantin Belousov * 94072ae4eSKonstantin Belousov * Redistribution and use in source and binary forms, with or without 104072ae4eSKonstantin Belousov * modification, are permitted provided that the following conditions 114072ae4eSKonstantin Belousov * are met: 124072ae4eSKonstantin Belousov * 1. Redistributions of source code must retain the above copyright 134072ae4eSKonstantin Belousov * notice, this list of conditions and the following disclaimer. 144072ae4eSKonstantin Belousov * 2. Redistributions in binary form must reproduce the above copyright 154072ae4eSKonstantin Belousov * notice, this list of conditions and the following disclaimer in the 164072ae4eSKonstantin Belousov * documentation and/or other materials provided with the distribution. 174072ae4eSKonstantin Belousov * 184072ae4eSKonstantin Belousov * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 194072ae4eSKonstantin Belousov * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 204072ae4eSKonstantin Belousov * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 214072ae4eSKonstantin Belousov * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 224072ae4eSKonstantin Belousov * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 234072ae4eSKonstantin Belousov * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 244072ae4eSKonstantin Belousov * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 254072ae4eSKonstantin Belousov * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 264072ae4eSKonstantin Belousov * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 274072ae4eSKonstantin Belousov * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 284072ae4eSKonstantin Belousov * SUCH DAMAGE. 294072ae4eSKonstantin Belousov * 304072ae4eSKonstantin Belousov * $Id: popss.c,v 1.28 2018/05/09 21:35:29 kostik Exp kostik $ 314072ae4eSKonstantin Belousov * 324072ae4eSKonstantin Belousov * cc -m32 -Wall -Wextra -O2 -g -o popss popss.c 334072ae4eSKonstantin Belousov * Use as "popss <instruction>", where instruction is one of 344072ae4eSKonstantin Belousov * bound, into, int1, int3, int80, syscall, sysenter. 354072ae4eSKonstantin Belousov */ 364072ae4eSKonstantin Belousov 374072ae4eSKonstantin Belousov #include <sys/param.h> 384072ae4eSKonstantin Belousov #include <sys/ptrace.h> 394072ae4eSKonstantin Belousov #include <sys/wait.h> 404072ae4eSKonstantin Belousov #include <err.h> 414072ae4eSKonstantin Belousov #include <signal.h> 424072ae4eSKonstantin Belousov #include <stdio.h> 434072ae4eSKonstantin Belousov #include <stdlib.h> 444072ae4eSKonstantin Belousov #include <string.h> 454072ae4eSKonstantin Belousov #include <unistd.h> 464072ae4eSKonstantin Belousov #include <machine/reg.h> 474072ae4eSKonstantin Belousov 484072ae4eSKonstantin Belousov static u_long *stk; 494072ae4eSKonstantin Belousov 504072ae4eSKonstantin Belousov #define ITERATIONS 4 514072ae4eSKonstantin Belousov 524072ae4eSKonstantin Belousov static void 534072ae4eSKonstantin Belousov setup(pid_t child) 544072ae4eSKonstantin Belousov { 554072ae4eSKonstantin Belousov struct reg r; 564072ae4eSKonstantin Belousov struct dbreg dbr; 574072ae4eSKonstantin Belousov int error, i, status; 584072ae4eSKonstantin Belousov 594072ae4eSKonstantin Belousov error = waitpid(child, &status, WTRAPPED | WEXITED); 604072ae4eSKonstantin Belousov if (error == -1) 614072ae4eSKonstantin Belousov err(1, "waitpid 1"); 624072ae4eSKonstantin Belousov error = ptrace(PT_GETREGS, child, (caddr_t)&r, 0); 634072ae4eSKonstantin Belousov if (error == -1) 644072ae4eSKonstantin Belousov err(1, "ptrace PT_GETREGS"); 654072ae4eSKonstantin Belousov printf("child %d stopped eip %#x esp %#x\n", child, r.r_eip, r.r_esp); 664072ae4eSKonstantin Belousov 674072ae4eSKonstantin Belousov error = ptrace(PT_GETDBREGS, child, (caddr_t)&dbr, 0); 684072ae4eSKonstantin Belousov if (error != 0) 694072ae4eSKonstantin Belousov err(1, "ptrace PT_GETDBREGS"); 704072ae4eSKonstantin Belousov dbr.dr[7] &= ~DBREG_DR7_MASK(0); 714072ae4eSKonstantin Belousov dbr.dr[7] |= DBREG_DR7_SET(0, DBREG_DR7_LEN_4, DBREG_DR7_RDWR, 724072ae4eSKonstantin Belousov DBREG_DR7_LOCAL_ENABLE | DBREG_DR7_GLOBAL_ENABLE); 734072ae4eSKonstantin Belousov dbr.dr[0] = (uintptr_t)stk; 744072ae4eSKonstantin Belousov error = ptrace(PT_SETDBREGS, child, (caddr_t)&dbr, 0); 754072ae4eSKonstantin Belousov if (error != 0) 764072ae4eSKonstantin Belousov err(1, "ptrace PT_SETDBREGS"); 774072ae4eSKonstantin Belousov error = ptrace(PT_CONTINUE, child, (caddr_t)1, 0); 784072ae4eSKonstantin Belousov if (error != 0) 794072ae4eSKonstantin Belousov err(1, "ptrace PT_CONTINUE fire"); 804072ae4eSKonstantin Belousov 814072ae4eSKonstantin Belousov for (i = 0; i < ITERATIONS; i++) { 824072ae4eSKonstantin Belousov error = waitpid(child, &status, WTRAPPED | WEXITED); 834072ae4eSKonstantin Belousov if (error == -1) 844072ae4eSKonstantin Belousov err(1, "waitpid 2"); 854072ae4eSKonstantin Belousov if (WIFEXITED(status)) 864072ae4eSKonstantin Belousov break; 874072ae4eSKonstantin Belousov error = ptrace(PT_GETREGS, child, (caddr_t)&r, 0); 884072ae4eSKonstantin Belousov if (error == -1) 894072ae4eSKonstantin Belousov err(1, "ptrace PT_GETREGS"); 904072ae4eSKonstantin Belousov error = ptrace(PT_GETDBREGS, child, (caddr_t)&dbr, 0); 914072ae4eSKonstantin Belousov if (error != 0) 924072ae4eSKonstantin Belousov err(1, "ptrace PT_GETDBREGS"); 934072ae4eSKonstantin Belousov printf("child %d stopped eip %#x esp %#x dr0 %#x " 944072ae4eSKonstantin Belousov "dr6 %#x dr7 %#x\n", child, r.r_eip, r.r_esp, 954072ae4eSKonstantin Belousov dbr.dr[0], dbr.dr[6], dbr.dr[7]); 964072ae4eSKonstantin Belousov error = ptrace(PT_CONTINUE, child, (caddr_t)1, 0); 974072ae4eSKonstantin Belousov if (error == -1) 984072ae4eSKonstantin Belousov err(1, "ptrace PT_CONTINUE tail"); 994072ae4eSKonstantin Belousov } 1004072ae4eSKonstantin Belousov if (i == ITERATIONS) { 1014072ae4eSKonstantin Belousov kill(child, SIGKILL); 1024072ae4eSKonstantin Belousov ptrace(PT_DETACH, child, NULL, 0); 1034072ae4eSKonstantin Belousov } 1044072ae4eSKonstantin Belousov } 1054072ae4eSKonstantin Belousov 1064072ae4eSKonstantin Belousov static u_long tmpstk[1024 * 128]; 1074072ae4eSKonstantin Belousov 1084072ae4eSKonstantin Belousov static u_int 1094072ae4eSKonstantin Belousov read_ss(void) 1104072ae4eSKonstantin Belousov { 1114072ae4eSKonstantin Belousov u_int res; 1124072ae4eSKonstantin Belousov 1134072ae4eSKonstantin Belousov __asm volatile("movl\t%%ss,%0" : "=r" (res)); 1144072ae4eSKonstantin Belousov return (res); 1154072ae4eSKonstantin Belousov } 1164072ae4eSKonstantin Belousov 1174072ae4eSKonstantin Belousov #define PROLOGUE "int3;movl\t%0,%%esp;popl\t%%ss;" 1184072ae4eSKonstantin Belousov 1194072ae4eSKonstantin Belousov static void 1204072ae4eSKonstantin Belousov act(const char *cmd) 1214072ae4eSKonstantin Belousov { 1224072ae4eSKonstantin Belousov int error; 1234072ae4eSKonstantin Belousov static const int boundx[2] = {0, 1}; 1244072ae4eSKonstantin Belousov 1254072ae4eSKonstantin Belousov printf("child pid %d, stk at %p\n", getpid(), stk); 1264072ae4eSKonstantin Belousov *stk = read_ss(); 1274072ae4eSKonstantin Belousov 1284072ae4eSKonstantin Belousov error = ptrace(PT_TRACE_ME, 0, NULL, 0); 1294072ae4eSKonstantin Belousov if (error != 0) 1304072ae4eSKonstantin Belousov err(1, "ptrace PT_TRACE_ME"); 1314072ae4eSKonstantin Belousov 1324072ae4eSKonstantin Belousov if (strcmp(cmd, "bound") == 0) { 1334072ae4eSKonstantin Belousov /* XXX BOUND args order clang ias bug */ 1344072ae4eSKonstantin Belousov __asm volatile("int3;movl\t$11,%%eax;" 1354072ae4eSKonstantin Belousov "movl\t%0,%%esp;popl\t%%ss;bound\t%1,%%eax" 1364072ae4eSKonstantin Belousov : : "r" (stk), "m" (boundx) : "memory"); 1374072ae4eSKonstantin Belousov } else if (strcmp(cmd, "int1") == 0) { 1384072ae4eSKonstantin Belousov __asm volatile(PROLOGUE ".byte 0xf1" 1394072ae4eSKonstantin Belousov : : "r" (stk) : "memory"); 1404072ae4eSKonstantin Belousov } else if (strcmp(cmd, "int3") == 0) { 1414072ae4eSKonstantin Belousov __asm volatile(PROLOGUE "int3" 1424072ae4eSKonstantin Belousov : : "r" (stk) : "memory"); 1434072ae4eSKonstantin Belousov } else if (strcmp(cmd, "into") == 0) { 1444072ae4eSKonstantin Belousov __asm volatile("int3;movl\t$0x80000000,%%eax;" 1454072ae4eSKonstantin Belousov "addl\t%%eax,%%eax;movl\t%0,%%esp;popl\t%%ss;into" 1464072ae4eSKonstantin Belousov : : "r" (stk) : "memory"); 1474072ae4eSKonstantin Belousov } else if (strcmp(cmd, "int80") == 0) { 1484072ae4eSKonstantin Belousov __asm volatile(PROLOGUE "int\t$0x80" 1494072ae4eSKonstantin Belousov : : "r" (stk) : "memory"); 1504072ae4eSKonstantin Belousov } else if (strcmp(cmd, "syscall") == 0) { 1514072ae4eSKonstantin Belousov __asm volatile(PROLOGUE "syscall" 1524072ae4eSKonstantin Belousov : : "r" (stk) : "memory"); 1534072ae4eSKonstantin Belousov } else if (strcmp(cmd, "sysenter") == 0) { 1544072ae4eSKonstantin Belousov __asm volatile(PROLOGUE "sysenter" 1554072ae4eSKonstantin Belousov : : "r" (stk) : "memory"); 1564072ae4eSKonstantin Belousov } else { 1574072ae4eSKonstantin Belousov fprintf(stderr, "unknown instruction\n"); 1584072ae4eSKonstantin Belousov exit(1); 1594072ae4eSKonstantin Belousov } 1604072ae4eSKonstantin Belousov printf("ho\n"); 1614072ae4eSKonstantin Belousov } 1624072ae4eSKonstantin Belousov 1634072ae4eSKonstantin Belousov int 1644072ae4eSKonstantin Belousov main(int argc, char *argv[]) 1654072ae4eSKonstantin Belousov { 1664072ae4eSKonstantin Belousov int child; 1674072ae4eSKonstantin Belousov 1684072ae4eSKonstantin Belousov if (argc != 2) { 1694072ae4eSKonstantin Belousov printf( 1704072ae4eSKonstantin Belousov "Usage: popss [bound|int1|int3|into|int80|syscall|sysenter]\n"); 1714072ae4eSKonstantin Belousov exit(1); 1724072ae4eSKonstantin Belousov } 1734072ae4eSKonstantin Belousov stk = &tmpstk[nitems(tmpstk) - 1]; 1744072ae4eSKonstantin Belousov child = fork(); 1754072ae4eSKonstantin Belousov if (child == -1) 1764072ae4eSKonstantin Belousov err(1, "fork"); 1774072ae4eSKonstantin Belousov if (child == 0) 1784072ae4eSKonstantin Belousov act(argv[1]); 1794072ae4eSKonstantin Belousov else 1804072ae4eSKonstantin Belousov setup(child); 1814072ae4eSKonstantin Belousov } 182