xref: /openbsd/regress/sys/kern/ptrace/ptrace.c (revision 3d8817e4)
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