Question

Just got confused when I am learning the virtual memory system in Linux.

Since each process has its own virtual address space and its own page table translating its virtual address to physical address(am I right?), how can it possibly try to falsely access other process's memory? There should be no entry in the page table, right?

Was it helpful?

Solution 2

Unless specifically arranged, there should be no virtual address one process can access that will modify memory assigned to another process.

OTHER TIPS

A linux process can access another process's memory via the special file /proc/pid/mem. For example, here's a little program call poke:

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <unistd.h>

int main(int ac, char **av) {
    char    name[64];
    int             fd;
    if (ac != 3) {
        fprintf(stderr, "usage: %s pid address value\n", av[1]);
        exit(1); }
    sprintf(name, "/proc/%.10s/mem", av[1]);
    if ((fd = open(name, O_WRONLY)) < 0) {
        fprintf(stderr, "Can't access pid %s", av[1]);
        perror(":");
        exit(1); }
    lseek(fd, strtol(av[2], 0, 0), SEEK_SET);
    if (write(fd, av[3], strlen(av[3])) < 0)
        perror("write");
    return 0;
}

It will write a string into another process's memory (probably causing it to crash)...

In addition to procfs, it is also possible to access other process memory using process_vm_writev and process_vm_readv

This program will read a given nubmer of bytes from a given address of a given process (removed some error checks to improve readability):

#define _GNU_SOURCE
#include <sys/uio.h>
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>

int remote_process_read(pid_t remote_pid, void *address, char *buffer, size_t len)
{
    struct iovec local[1] = {};
    struct iovec remote[1] = {};
    int errsv = 0;
    ssize_t nread = 0;

    local[0].iov_len = len;
    local[0].iov_base = (void *)buffer;

    remote[0].iov_base = address;
    remote[0].iov_len = local[0].iov_len;

    nread = process_vm_readv(remote_pid, local, 2, remote, 1, 0);

    if (nread != local[0].iov_len)
    {
        errsv = errno;
        fprintf(stderr, "Failed reading. process_vm_readv returned: %ld. Errno: %d\n", nread, errsv);
        return errsv;
    }

    return errno;
}

enum
{
    ARG_APP_NAME = 0,
    ARG_PID,
    ARG_ADDRESS,
    ARG_BYTES_TO_READ,
    ARG_COUNT
};

int main(int argc, char *argv[])
{
    pid_t remote_pid = 0;
    size_t len = 0;
    int ret = 1;
    char *buffer = NULL;
    void *remote_address = NULL;

    if (ARG_COUNT != argc)
    {
        fprintf(stderr, "Usage: %s <PID> <address (hex)> <num of bytes to read (hex)>\n", argv[ARG_APP_NAME]);
        goto clean;
    }

    remote_pid = strtol(argv[ARG_PID], NULL, 10);
    remote_address = (void *)strtoul(argv[ARG_ADDRESS], NULL, 16);
    len = strtoul(argv[ARG_BYTES_TO_READ], NULL, 16);
    buffer = malloc(len);

    if (0 != remote_process_read(remote_pid, remote_address, buffer, len))
    {
        goto clean;
    }

    printf("Read Successfully!\n");
    for (size_t i = 0; i < len; i++)
    {
        printf("%02X", buffer[i]);
    }
    printf("\n");

    ret = 0;
clean:
    free(buffer);
    return ret;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top