Как процесс может попытаться получить доступ к памяти другого процесса в системе виртуальной памяти Linux

Просто запутался, когда изучаю систему виртуальной памяти в Linux.

Поскольку каждый процесс имеет свое собственное виртуальное адресное пространство и свою собственную таблицу страниц, преобразующую свой виртуальный адрес в физический адрес (правильно ли я?), как он может попытаться получить ложный доступ к памяти другого процесса? В таблице страниц не должно быть записи, верно?


person Hao Shen    schedule 26.12.2013    source источник


Ответы (3)


Если это специально не оговорено, не должно быть виртуального адреса, к которому может получить доступ один процесс и который будет изменять память, назначенную другому процессу.

person David Schwartz    schedule 26.12.2013

Процесс Linux может получить доступ к памяти другого процесса через специальный файл /proc/pid/mem. Например, вот небольшой вызов программы 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;
}

Он запишет строку в память другого процесса (вероятно, вызвав его сбой)...

person Chris Dodd    schedule 28.12.2013
comment
Обратите внимание, что это работает только в том случае, если процесс, выполняющий этот код, имеет доступ на запись к /proc/pid/mem. В моей системе /proc и его содержимое принадлежат пользователю root и помечены как доступные только для чтения, поэтому большинству процессов это запрещено. Базовые требования безопасности и надежности ОС требуют, чтобы процессы не могли взаимодействовать друг с другом, если у них нет специального разрешения или привилегий на уровне ОС. - person keshlam; 29.12.2013
comment
@keshlam: да, открытие может завершиться ошибкой, поэтому важно проверять возвращаемое значение на наличие ошибок... - person Chris Dodd; 02.01.2014

В дополнение к procfs также можно получить доступ к другой памяти процесса, используя process_vm_writev и process_vm_readv

Эта программа будет читать заданное количество байтов с заданного адреса данного процесса (удалены некоторые проверки ошибок для улучшения читаемости):

#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;
}
person Yosef Arbiv    schedule 19.10.2019