Может ли мой процесс попасть в другой участок памяти?

Происходит трансляция адресов через MMU. Получается, в селектор записывается номер дескриптора и смещение, потом в таблице GDT (LDT) находится нужная запись например с правами и прочее, дальше страничное отображение памяти на физическую. А, предположим, я узнал, где у другого процесса что лежит и через селектор сделаю запрос, чтобы он выдал тот участок памяти. Может быть такое или я что-то не понимаю в этой логике отображение виртуального адреса на физический и прав доступа?


Ответы (2 шт):

Автор решения: gbg

У вас не получится. Операционная система при первом обращении к этой памяти перехватит управление и проверит, принадлежит ли она вашему процессу, и если нет - процесс получит SEGFAULT и будет прекращен.

→ Ссылка
Автор решения: eanmos

Обращение к виртуальной памяти абсолютно прозрачно для процесса и проходит под контролем ОС, которая просто не даст вам выйти из вашего кусочка памяти. В то же время, любые инструкции CPU, которые могли бы эту прозрачность нарушить являются привилегированными и обычным процессам не доступны.

Однако ОС может нам и помочь. Например, в Linux, если ваш процесс запускается под root, есть целых два варианта заглянуть в память другого процесса:

  1. Linux предоставляет доступ ко всей физической памяти через устройство /dev/mem, с которыми можно обращаться, как с обычными файлами. Таким образом можно сделать полный дамп физической памяти с помощью dd и копаться уже в нем.

  2. Также Linux предоставляет доступ ко всему виртуальному адресному пространству каждого процесса через файл /proc/[PID]/mem, а карта отображения лежит в файле /proc/[PID]/maps. Таким образом можно сделать дамп нужной секции или всей памяти отдельного процесса.


Пример

Напишем небольшую программу, которая будет исполнять роль жертвы:

#include <stdio.h>
#include <unistd.h>

static const char haystack[] = "haystack";

int
main(void)
{
    while (1) {
        puts(haystack);
        sleep(5);
    }
}

Скомпилируем её и запустим:

gcc -O0 -g victim.c -o victim && ./victim

Она будет выводить строку haystack каждые 5 секунд. Теперь давайте попробуем изменить строку, которую выводит жертва путем изменения данных в ее виртуальном адресном пространстве.

Для начала найдем PID жертвы:

$ pgrep victim
4595

Теперь подключим к запущенному процессу GDB и найдем адрес переменной haystack:

$ yes | sudo gdb -p 4595 -ex "p &haystack" -ex "quit" | grep haystack
$1 = (const char (*)[9]) 0x558f2b2ae008 <haystack>

Теперь самое интересное. Напишем программу, которая будет писать несколько байт по определенному адресу в виртуальном адресном пространстве жертвы. Для этого откроем файл /proc/4595/mem, сместимся до нужного нам адреса и выполним write:

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

#define PID "4595"
#define OFFSET 0x558f2b2ae008
#define DATA "dragons"

int
main(void) {
    /* Открываем файл. */
    int f = open("/proc/" PID "/mem", O_WRONLY);

    /* Смещаемся до нужного адреса. */
    lseek(f, OFFSET, SEEK_SET);

    /* Пишем нужные байты. */
    write(f, DATA, sizeof(DATA));
}

Если запустить программу под root и подождать несколько секунд до следующего вывода жертвы, то увидим что теперь жертва выводит dragons. Кажется, у нас получилось?


Для наглядности сделал скриншот работы программ, который можно найти здесь.

Интересно, что man 5 proc пишет, что к файлам /proc/[PID]/mem можно обратиться только через open, read и lseek, т. е. писать в них нельзя. Видимо, эта страница мануала устарела, потому что запрет на запись в /proc/[PID]/mem был отменен в этом коммите ядра. Хотя, может быть, проверку вернули — в общем случае запись в /proc/[PID]/mem будет зависеть от версии ядра. Также смотрите статью на LWN про эту уязвимость и связанный ответ на SO.

→ Ссылка