#include <sys/types.h>
#include <sys/ptrace.h>
#include <sys/mman.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <errno.h>
#include <err.h>
static void
usage(void)
{
fprintf(stderr, "Usage: ptrace [-bdirwI]\n");
exit(1);
}
#define MAGIC "asdfblahblahspam1235432blah"
#define MAGIC_I 0x47114217
int
main(int argc, char **argv)
{
int ch;
int bad = 0, i, write, I;
pid_t pid;
char *m;
int ps;
int status;
int ret;
ps = getpagesize();
I = 0;
i = 0;
write = 0;
while ((ch = getopt(argc, argv, "bdirwI")) != -1) {
switch (ch) {
case 'b':
bad = 1;
break;
case 'i':
i = 1;
break;
case 'd':
i = 0;
break;
case 'r':
write = 0;
break;
case 'w':
write = 1;
break;
case 'I':
I = 1;
break;
default:
usage();
}
}
m = mmap(0, ps, PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0);
if (m == MAP_FAILED)
err(1, "mmap");
if (!write) {
if (I)
memcpy(m, MAGIC, sizeof(MAGIC));
else
*(int *)m = MAGIC_I;
}
if (bad)
if (mprotect(m, ps, PROT_NONE))
err(1, "mprotect");
switch ((pid = fork())) {
case 0:
pause();
_exit(0);
case -1:
err(1, "fork");
}
ret = 0;
if (ptrace(PT_ATTACH, pid, 0, 0) == -1) {
warn("ptrace(PT_ATTACH)");
ret = -1;
goto out;
}
if (wait(&status) != pid) {
warn("wait");
ret = -1;
goto out;
}
if (!write) {
int req;
if (I) {
char foo[1024];
struct ptrace_io_desc piod;
if (i)
piod.piod_op = PIOD_READ_I;
else
piod.piod_op = PIOD_READ_D;
piod.piod_offs = m;
piod.piod_addr = &foo;
piod.piod_len = sizeof(MAGIC);
if (ptrace(PT_IO, pid, (caddr_t)&piod, 0) == -1) {
warn("ptrace(PT_IO)");
if (errno == EFAULT)
ret = 1;
else
ret = -1;
goto out;
}
if (memcmp(foo, MAGIC, sizeof(MAGIC))) {
warnx("mismatch %s != %s", foo, MAGIC);
ret = 1;
goto out;
}
} else {
if (i)
req = PT_READ_I;
else
req = PT_READ_D;
i = ptrace(req, pid, m, sizeof(i));
if (i != MAGIC_I) {
warn("ptrace(%d): %d != %d", req, i, MAGIC_I);
ret = 1;
goto out;
}
}
} else {
errx(1, "lazy bum");
}
out:
if (ret == -1) {
ret = 1;
} else if (bad) {
if (ret == 0) {
warnx("protected memory unprotected");
ret = 1;
} else {
ret = 0;
}
}
kill(pid, SIGKILL);
return ret;
}