1/*	$OpenBSD: ptrace.c,v 1.5 2017/09/16 02:03:40 guenther 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 <string.h>
25#include <unistd.h>
26#include <signal.h>
27#include <errno.h>
28#include <err.h>
29
30static void
31usage(void)
32{
33	fprintf(stderr, "Usage: ptrace [-bdirwI]\n");
34	exit(1);
35}
36
37#define MAGIC	"asdfblahblahspam1235432blah"
38#define MAGIC_I	0x47114217
39
40int
41main(int argc, char **argv)
42{
43	int ch;
44	int bad = 0, i, write, I;
45	pid_t pid;
46	char *m;
47	int ps;
48	int status;
49	int ret;
50
51	ps = getpagesize();
52
53	I = 0;
54	i = 0;
55	write = 0;
56
57	while ((ch = getopt(argc, argv, "bdirwI")) != -1) {
58		switch (ch) {
59		case 'b':
60			bad = 1;
61			break;
62		case 'i':
63			i = 1;
64			break;
65		case 'd':
66			i = 0;
67			break;
68		case 'r':
69			write = 0;
70			break;
71		case 'w':
72			write = 1;
73			break;
74		case 'I':
75			I = 1;
76			break;
77		default:
78			usage();
79		}
80	}
81
82	m = mmap(0, ps, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
83	if (m == MAP_FAILED)
84		err(1, "mmap");
85
86	if (!write) {
87		if (I)
88			memcpy(m, MAGIC, sizeof(MAGIC));
89		else
90			*(int *)m = MAGIC_I;
91	}
92	if (bad)
93		if (mprotect(m, ps, PROT_NONE))
94			err(1, "mprotect");
95
96	switch ((pid = fork())) {
97	case 0:
98		pause();
99		_exit(0);
100	case -1:
101		err(1, "fork");
102	}
103
104	ret = 0;
105
106	if (ptrace(PT_ATTACH, pid, 0, 0) == -1) {
107		warn("ptrace(PT_ATTACH)");
108		ret = -1;
109		goto out;
110	}
111
112	if (wait(&status) != pid) {
113		warn("wait");
114		ret = -1;
115		goto out;
116	}
117
118	if (!write) {
119		int req;
120
121		if (I) {
122			char foo[1024];
123			struct ptrace_io_desc piod;
124
125			if (i)
126				piod.piod_op = PIOD_READ_I;
127			else
128				piod.piod_op = PIOD_READ_D;
129			piod.piod_offs = m;
130			piod.piod_addr = &foo;
131			piod.piod_len = sizeof(MAGIC);
132
133			if (ptrace(PT_IO, pid, (caddr_t)&piod, 0) == -1) {
134				warn("ptrace(PT_IO)");
135				if (errno == EFAULT)
136					ret = 1;
137				else
138					ret = -1;
139				goto out;
140			}
141
142			if (memcmp(foo, MAGIC, sizeof(MAGIC))) {
143				warnx("mismatch %s != %s", foo, MAGIC);
144				ret = 1;
145				goto out;
146			}
147		} else {
148			if (i)
149				req = PT_READ_I;
150			else
151				req = PT_READ_D;
152
153			i = ptrace(req, pid, m, sizeof(i));
154			if (i != MAGIC_I) {
155				warn("ptrace(%d): %d != %d", req, i, MAGIC_I);
156				ret = 1;
157				goto out;
158			}
159		}
160	} else {
161		errx(1, "lazy bum");
162	}
163
164out:
165	if (ret == -1) {
166		/* other errors */
167		ret = 1;
168	} else if (bad) {
169		if (ret == 0) {
170			warnx("protected memory unprotected");
171			ret = 1;
172		} else {
173			ret = 0;
174		}
175	}
176
177	kill(pid, SIGKILL);
178
179	return ret;
180}
181