Hi all,

I'm having some strange time with /proc/<pid>/mem. The manual page says:
       /proc/[number]/mem
This file can be used to access the pages of a process's memory through open(2), read(2), and lseek(2).
Some digging through the internet reveals that that is, indeed, the case, but the process doing the reading must be attached to the process whose memory is being accessed as a debugger. Well, so far so good.

However, when I go out to actually try it out (program at end of mail), I can access the file as neither read nor write. Any attempt to read from the file OR mmap it (PROT_READ or otherwise) results in "invalid argument".

I am running Debian Lenny with kernel 2.6.22-3-686.

Any help appreciated.

Thanks,
Shachar

#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <sys/stat.h>

#include <unistd.h>
#include <signal.h>
#include <fcntl.h>

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main()
{
    char *memory=mmap( NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, 0, 0 );

    if( memory==MAP_FAILED ) {
        perror("mmap failed");

        exit(1);
    }

    strcpy(memory, "String1");

    if( mprotect(memory, 4096, PROT_READ)!=0 ) {
        perror("mprotect failed");

        exit(1);
    }

    pid_t son=fork();

    if( son==-1 ) {
        perror("fork failed");

        exit(1);
    }

    if( son==0 ) {
        // We are the child
        if( ptrace(PTRACE_TRACEME)==-1 ) {
            perror("ptrace(TRACEME) failed");

            exit(1);
        }

        kill(getpid(), SIGSTOP);

        printf("Content of memory is \"%s\"\n", memory);

        return 0;
    } else {
        // We are the parent
        printf("Created child %d\n", son);

        if( munmap( memory, 4096 )!=0 ) {
            perror("munmap failed");

            kill(son, SIGKILL);
            exit(1);
        }

        int status;
        pid_t waiting=wait(&status);

        if( waiting!=son || !WIFSTOPPED(status) || WSTOPSIG(status)!=SIGSTOP ) {
            fprintf(stderr, "Something is out of sync. Status is %x and child is %d\n", status, waiting);

            kill(son, SIGKILL);

            exit(1);
        }

        char filename[PATH_MAX];
        sprintf(filename, "/proc/%d/mem", son);
        int fd=open(filename, O_RDONLY);

        if( fd==-1 ) {
            perror("open /proc/son/mem failed");

            ptrace(PTRACE_KILL, son);

            exit(1);
        }

        if( lseek(fd, (off_t)memory, SEEK_SET)==-1 ) {
            perror("seek into memory failed");

            ptrace(PTRACE_KILL, son);

            exit(1);
        }

        char buffer[4096];
        ssize_t numread=read(fd, buffer, 4096);

        if( numread==-1 ) {
            perror("read memory failed");

            ptrace(PTRACE_KILL, son);

            exit(1);
        }

        if( numread!=4096 ) {
            fprintf(stderr, "warning: read read only %d bytes instead of 4096\n", numread );
        }

        printf("Memory dump contains \"%s\"\n", buffer);

        char *memory2=mmap( NULL, 4096, PROT_READ, MAP_SHARED, fd, (off_t)memory );
        if( memory2==MAP_FAILED ) {
            perror("mmap(/proc/son/mem) failed");

            ptrace(PTRACE_KILL, son);

            exit(1);
        }

        strcpy(memory2, "2 and more");

        ptrace(PTRACE_CONT, son, 0, 0);

        waiting=wait(&status);
        if( waiting!=son || !WIFEXITED(status) ) {
            fprintf(stderr, "Something is out of sync(2). Status is %x and child is %d\n", status, waiting);

            kill(son, SIGKILL);

            exit(1);
        }

        return WEXITSTATUS(status);
    }

    return 0;
}

Reply via email to