2012-02-28 2 views
5

Я ожидаю, что из-за рандомизации макета адресного пространства (ALSR) процесс, выложенный из другого процесса, будет иметь разные адреса, возвращенные при вызове mmap. Но, как я узнал, это было не так. Для этой цели я сделал следующую тестовую программу. Все адреса, возвращаемые malloc, точно такие же для родителя и для ребенка. Обратите внимание, что для mallocCL1, Cl2, pl1, PL2 внутренне использует mmap, потому что они большие блоки.Рандомизация адресного пространства (ALSR) и mmap

Итак, мой вопрос: почему mmap не возвращает разные адреса даже в присутствии ALSR. Может быть, потому, что семена для рандомизации здесь одинаковы для оригинального и раздвоенного процесса. Или есть другая причина?

int main() 
{ 
    pid = fork(); 

    if (pid == 0)    // child 
    { 
    void * c1 = malloc(4096); 
    void * c2 = malloc(4096); 

    void * cl1 = malloc((long)512e3); // internally uses mmap 
    void * cl2 = malloc((long)512e3); // internally uses mmap 

    printf("c1 = %p, c2 = %p, cl1 = %p, cl2 = %p!\n", c1, c2, cl1, cl2); 
    } 
    else 
    { 
    void * p1 = malloc(4096); 
    void * p2 = malloc(4096); 

    void * pl1 = malloc((long)512e3); // internally uses mmap 
    void * pl2 = malloc((long)512e3); // internally uses mmap 

    printf("p1 = %p, p2 = %p, pl1 = %p, pl2 = %p!\n", p1, p2, pl1, pl2); 
    } 

    return 0; 
} 
+0

Я не уверен, что ASLR требует, чтобы 'mmap' возвращал разные адреса; это просто означает, что он * может * возвращать разные. И, возможно (просто догадка!), Он запускается больше с помощью 'execve', чем' fork'. Конечно, если я дважды запускаю вашу программу, я получаю разные адреса. И это может измениться с будущими ядрами, или, возможно, с включенными SELinux ... –

+2

вам может показаться полезным: http://xorl.wordpress.com/2011/01/16/linux-kernel-aslr-implementation/ – Necrolis

+0

@ Базиле: Конечно, вы будете получать разные адреса для каждого прогона, но за один прогон, когда-либо отличаются адреса обоих процессов (родительский и дочерний)? – MetallicPriest

ответ

4

Вы не можете повторно рандомизации адресного пространства ребенка - все указатели должны быть подкрашены, и это технически невозможно (среда выполнения даже не знает, какая часть ваших данных указателей).

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

Вам понадобится звонок exec*, чтобы получить новое расположение адресного пространства.

$ cat t.c 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 

int main(int argc, char **argv) 
{ 
    printf("%p\n", malloc((long)512e3)); 
    if ((argc > 1) && fork()) { 
     execl("./a.out", "./a.out", NULL); 
    } 
    return 0; 
} 
$ gcc -Wall t.c 
$ ./a.out 1 
0x7f5bf6962010 
0x7f3483044010 
$ ./a.out 1 
0x7f1ce7462010 
0x7feb2adc2010 

(И убедитесь, что /proc/sys/kernel/randomize_va_space не равен нуль тоже.)

+0

OP, похоже, не хочет отображать изображения, созданные перед вилкой, для изменения адресов, только для новых сопоставлений после того, как fork получает независимо случайные адреса. Это технически невозможно, но, как описано в моем ответе, это плохая идея. –

+0

Итак, вы имеете в виду, что каждый будущий mmap, sbrk, malloc и т. Д. Возвратят те же адреса для родительского и дочернего процессов? – MetallicPriest

+1

@MetallicPriest: если вы делаете их в одном и том же порядке, для тех же величин и без каких-либо внешних факторов (ограничения ресурсов, простой OOM и т. Д.), Возможно, да с простым ядром Linux. Могут существовать некоторые патчи для рандомизации динамических распределений, но не базового ядра. См. Ответ R .. для получения дополнительной информации об этом. – Mat

5

ASLR в основном рандомизирует расстояние от верхней части пользовательского пространства адресного пространства вниз в стек, а расстояние от нижней части Пакетирования зарезервированное пространство до первого mmap (что, вероятно, является отображением динамического компоновщика). Любая дальнейшая рандомизация будет иметь серьезные эффекты фрагментации в пространстве виртуальной памяти и, таким образом, приведет к разрыву программ, которые должны сделать большие mmap с (например, сопоставление 1-2 ГБ на 32-битной машине).

Я видел некоторые исправленные ядра ядра Linux, которые выполняют намного больше рандомизации по адресам, возвращаемым mmap. Некоторые из них даже дают вам сопоставления, перекрывающиеся с пространством, зарезервированным для стека, чтобы расширяться, а затем, когда стек растет, он сжимает ваше сопоставление (в результате получается огромная дыра в области безопасности, намного больше, чем что-либо, что могло вызвать вызванные неслучайные адреса) , Держитесь подальше от этих хаков.

+0

Итак, мы можем предположить, что mmap в раздвоенном процессе не всегда будет возвращать тот же адрес, что и в родительском? правильно? – MetallicPriest

+0

Это (обычно) истинно сегодня, но я не буду предполагать, что для будущих ядер. Ничто не указывает, что это только текущая реализация. И люди ядра могут захотеть улучшить его. –

+0

Я бы не стал делать предположения так или иначе. Например, вероятно, было бы безопасно/разумно добавить небольшое количество случайных отступов (незапечатанных страниц) перед очень большими сопоставлениями (так как процентные затраты/фрагментация обязательно были бы очень малы). –

Смежные вопросы