1 /* $OpenBSD: ptrace.c,v 1.2 2005/07/20 16:16:04 art Exp $ */ 2 /* 3 * Copyright (c) 2005 Artur Grabowski <art@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18 #include <sys/types.h> 19 #include <sys/ptrace.h> 20 #include <sys/mman.h> 21 #include <sys/wait.h> 22 #include <stdlib.h> 23 #include <stdio.h> 24 #include <unistd.h> 25 #include <signal.h> 26 #include <errno.h> 27 28 static void 29 usage(void) 30 { 31 fprintf(stderr, "Usage: ptrace [-bdirwI]\n"); 32 exit(1); 33 } 34 35 #define MAGIC "asdfblahblahspam1235432blah" 36 #define MAGIC_I 0x47114217 37 38 int 39 main(int argc, char **argv) 40 { 41 int ch; 42 int bad = 0, i, write, I; 43 pid_t pid; 44 char *m; 45 int ps; 46 int status, req; 47 int ret; 48 49 ps = getpagesize(); 50 51 I = 0; 52 i = 0; 53 write = 0; 54 55 while ((ch = getopt(argc, argv, "bdirwI")) != -1) { 56 switch (ch) { 57 case 'b': 58 bad = 1; 59 break; 60 case 'i': 61 i = 1; 62 break; 63 case 'd': 64 i = 0; 65 break; 66 case 'r': 67 write = 0; 68 break; 69 case 'w': 70 write = 1; 71 break; 72 case 'I': 73 I = 1; 74 break; 75 default: 76 usage(); 77 } 78 } 79 80 m = mmap(0, ps, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); 81 if (m == MAP_FAILED) 82 err(1, "mmap"); 83 84 if (!write) { 85 if (I) 86 memcpy(m, MAGIC, sizeof(MAGIC)); 87 else 88 *(int *)m = MAGIC_I; 89 } 90 if (bad) 91 if (mprotect(m, ps, PROT_NONE)) 92 err(1, "mprotect"); 93 94 switch ((pid = fork())) { 95 case 0: 96 pause(); 97 _exit(0); 98 case -1: 99 err(1, "fork"); 100 } 101 102 ret = 0; 103 104 if (ptrace(PT_ATTACH, pid, 0, 0) == -1) { 105 warn("ptrace(PT_ATTACH)"); 106 ret = -1; 107 goto out; 108 } 109 110 if (wait(&status) != pid) { 111 warn("wait"); 112 ret = -1; 113 goto out; 114 } 115 116 if (!write) { 117 int i, req; 118 119 if (I) { 120 char foo[1024]; 121 struct ptrace_io_desc piod; 122 123 if (i) 124 piod.piod_op = PIOD_READ_I; 125 else 126 piod.piod_op = PIOD_READ_D; 127 piod.piod_offs = m; 128 piod.piod_addr = &foo; 129 piod.piod_len = sizeof(MAGIC); 130 131 if (ptrace(PT_IO, pid, (caddr_t)&piod, 0) == -1) { 132 warn("ptrace(PT_IO)"); 133 if (errno == EFAULT) 134 ret = 1; 135 else 136 ret = -1; 137 goto out; 138 } 139 140 if (memcmp(foo, MAGIC, sizeof(MAGIC))) { 141 warnx("mismatch %s != %s", foo, MAGIC); 142 ret = 1; 143 goto out; 144 } 145 } else { 146 if (i) 147 req = PT_READ_I; 148 else 149 req = PT_READ_D; 150 151 i = ptrace(req, pid, m, sizeof(i)); 152 if (i != MAGIC_I) { 153 warn("ptrace(%d): %d != %d", req, i, MAGIC_I); 154 ret = 1; 155 goto out; 156 } 157 } 158 } else { 159 errx(1, "lazy bum"); 160 } 161 162 out: 163 if (ret == -1) { 164 /* other errors */ 165 ret = 1; 166 } else if (bad) { 167 if (ret == 0) { 168 warnx("protected memory unprotected"); 169 ret = 1; 170 } else { 171 ret = 0; 172 } 173 } 174 175 kill(pid, SIGKILL); 176 177 return ret; 178 } 179