Вопрос или проблема
На одной из наших машин Red Hat, с /proc/sys/kernel/randomize_va_space
на уровне 2, я исследовал распределение памяти нашего процесса, пытаясь понять в деталях, как распределяется память и т. д., и что-то привлекло мое внимание:
ADDR PERM VM RSS SWAP LAZYFREE VMFLAGS MAPPING
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 3.13G 2.33G 353.91M 0K {TOTALS} │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 4.00M r-xp 7.48M 1.14M 0K 0K rd ex mr mw me dw sd OurBinary │
│-------------------------------------------------------------------------------------------------------------│
│ 11.48M 7.48M 1.14M 0K 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 13.48M r--p 4K 4K 0K 0K rd mr mw me dw ac sd OurBinary │
│ rw-p 24K 12K 0K 0K rd wr mr mw me dw ac sd OurBinary │
│ rw-p 5.20M 8K 20K 0K rd wr mr mw me ac sd │
│-------------------------------------------------------------------------------------------------------------│
│ 18.71M 5.22M 24K 20K 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 21.36M rw-p 2.56G 2.26G 309.06M 0K rd wr mr mw me ac sd [heap] │
│-------------------------------------------------------------------------------------------------------------│
│ 2.58G 2.56G 2.26G 309.06M 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 127.14T rw-p 45.78M 28.01M 17.77M 0K rd wr mr mw me ac sd │
│ rw-p 132K 20K 0K 0K rd wr mr mw me nr sd │
│ ---p 63.87M 0K 0K 0K mr mw me nr sd │
│ rw-p 132K 0K 8K 0K rd wr mr mw me nr sd │
│ ---p 63.87M 0K 0K 0K mr mw me nr sd │
│ rw-p 1.23M 208K 748K 0K rd wr mr mw me nr sd │
│ ---p 62.77M 0K 0K 0K mr mw me nr sd │
│ rw-p 132K 32K 0K 0K rd wr mr mw me nr sd │
│ ---p 63.87M 0K 0K 0K mr mw me nr sd │
│ rw-p 132K 0K 8K 0K rd wr mr mw me nr sd │
│ ---p 63.87M 0K 0K 0K mr mw me nr sd │
│-------------------------------------------------------------------------------------------------------------│
│ 127.14T 365.78M 28.27M 18.52M 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 127.14T rw-p 15.42M 10.07M 68K 0K rd wr mr mw me ac sd │
│ r-xp 12K 8K 0K 0K rd ex mr mw me sd libnque19.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libnque19.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libnque19.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libnque19.so │
│ r-xp 44K 40K 0K 0K rd ex mr mw me sd libnuma.so.1.0.0 │
│ ---p 2.00M 0K 0K 0K mr mw me sd libnuma.so.1.0.0 │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libnuma.so.1.0.0 │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libnuma.so.1.0.0 │
│ r--p 772K 64K 0K 0K rd mr mw me nr sd timezlrg_32.dat │
│ ---p 4K 0K 0K 0K mr mw me sd │
│ rw-p 8.00M 0K 56K 0K rd wr mr mw me ac sd │
│ ---p 4K 0K 0K 0K mr mw me sd │
│ rw-p 8.48M 372K 84K 0K rd wr mr mw me ac sd │
│ r-xp 44K 44K 0K 0K rd ex mr mw me sd libnss_files-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libnss_files-2.28.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libnss_files-2.28.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libnss_files-2.28.so │
│ rw-p 24K 0K 0K 0K rd wr mr mw me ac sd │
│ ---p 4K 0K 0K 0K mr mw me sd │
│ rw-p 8.00M 20K 40K 0K rd wr mr mw me ac sd │
│ ---p 4K 0K 0K 0K mr mw me sd │
│ rw-p 8.00M 0K 60K 0K rd wr mr mw me ac sd │
│ ---p 4K 0K 0K 0K mr mw me sd │
│ rw-p 46.64M 15.05M 23.65M 0K rd wr mr mw me ac sd │
│ r-xp 4.85M 2.66M 0K 0K rd ex mr mw me sd libnnz19.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libnnz19.so │
│ r--p 184K 0K 184K 0K rd mr mw me ac sd libnnz19.so │
│ rw-p 252K 40K 92K 0K rd wr mr mw me ac sd libnnz19.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd │
│ r-xp 1.80M 1.58M 0K 0K rd ex mr mw me sd libc-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libc-2.28.so │
│ r--p 16K 12K 4K 0K rd mr mw me ac sd libc-2.28.so │
│ rw-p 8K 8K 0K 0K rd wr mr mw me ac sd libc-2.28.so │
│ rw-p 16K 12K 4K 0K rd wr mr mw me ac sd │
│ r-xp 92K 88K 0K 0K rd ex mr mw me sd libgcc_s-8-20210514.so.1 │
│ ---p 2.00M 0K 0K 0K mr mw me sd libgcc_s-8-20210514.so.1 │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libgcc_s-8-20210514.so.1 │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libgcc_s-8-20210514.so.1 │
│ r-xp 1.52M 1.18M 0K 0K rd ex mr mw me sd libstdc++.so.6.0.25 │
│ ---p 2.00M 0K 0K 0K mr mw me sd libstdc++.so.6.0.25 │
│ r--p 48K 4K 44K 0K rd mr mw me ac sd libstdc++.so.6.0.25 │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libstdc++.so.6.0.25 │
│ rw-p 12K 0K 12K 0K rd wr mr mw me ac sd │
│ r-xp 1.50M 312K 0K 0K rd ex mr mw me sd libm-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libm-2.28.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libm-2.28.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libm-2.28.so │
│ r-xp 80K 60K 0K 0K rd ex mr mw me sd libresolv-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libresolv-2.28.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libresolv-2.28.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libresolv-2.28.so │
│ rw-p 8K 0K 0K 0K rd wr mr mw me ac sd │
│ r-xp 8K 8K 0K 0K rd ex mr mw me sd libaio.so.1.0.1 │
│ ---p 2.00M 0K 0K 0K mr mw me sd libaio.so.1.0.1 │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libaio.so.1.0.1 │
│ rw-p 4K 0K 0K 0K rd wr mr mw me ac sd │
│ r-xp 28K 28K 0K 0K rd ex mr mw me sd librt-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd librt-2.28.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd librt-2.28.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd librt-2.28.so │
│ r-xp 88K 64K 0K 0K rd ex mr mw me sd libnsl-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libnsl-2.28.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libnsl-2.28.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libnsl-2.28.so │
│ rw-p 8K 0K 0K 0K rd wr mr mw me ac sd │
│ r-xp 108K 88K 0K 0K rd ex mr mw me sd libpthread-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libpthread-2.28.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libpthread-2.28.so │
│ rw-p 4K 4K 0K 0K rd wr mr mw me ac sd libpthread-2.28.so │
│ rw-p 16K 4K 0K 0K rd wr mr mw me ac sd │
│ r-xp 12K 12K 0K 0K rd ex mr mw me sd libdl-2.28.so │
│ ---p 2.00M 0K 0K 0K mr mw me sd libdl-2.28.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libdl-2.28.so │
│ rw-p 4K 0K 4K 0K rd wr mr mw me ac sd libdl-2.28.so │
│ r-xp 3.52M 1.76M 0K 0K rd ex mr mw me sd libclntshcore.so.19.1 │
│ ---p 2.00M 0K 0K 0K mr mw me sd libclntshcore.so.19.1 │
│ r--p 24K 0K 24K 0K rd mr mw me ac sd libclntshcore.so.19.1 │
│ rw-p 20K 0K 20K 0K rd wr mr mw me ac sd libclntshcore.so.19.1 │
│ rw-p 64K 0K 52K 0K rd wr mr mw me ac sd │
│ r-xp 60.16M 11.69M 0K 0K rd ex mr mw me sd libclntsh.so.19.1 │
│ ---p 2.00M 0K 0K 0K mr mw me sd libclntsh.so.19.1 │
│ r--p 1.44M 0K 1.42M 0K rd mr mw me ac sd libclntsh.so.19.1 │
│ rw-p 264K 4K 188K 0K rd wr mr mw me ac sd libclntsh.so.19.1 │
│ rw-p 156K 4K 36K 0K rd wr mr mw me ac sd │
│ r-xp 188K 188K 0K 0K rd ex mr mw me dw sd ld-2.28.so │
│-------------------------------------------------------------------------------------------------------------│
│ 127.14T 203.95M 45.44M 26.10M 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 127.14T ---p 4K 0K 0K 0K mr mw me sd │
│ rw-p 760K 412K 112K 0K rd wr mr mw me ac sd │
│ r--p 96K 92K 0K 0K rd mr mw me sd libtibrv.so │
│ r-xp 316K 64K 0K 0K rd ex mr mw me sd libtibrv.so │
│ r--p 108K 0K 0K 0K rd mr mw me sd libtibrv.so │
│ r--p 4K 0K 4K 0K rd mr mw me ac sd libtibrv.so │
│ rw-p 16K 0K 16K 0K rd wr mr mw me ac sd libtibrv.so │
│ rw-p 12K 0K 8K 0K rd wr mr mw me ac sd │
│-------------------------------------------------------------------------------------------------------------│
│ 127.14T 1.29M 568K 140K 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 127.14T rw-p 8K 0K 8K 0K rd wr mr mw me ac sd │
│ r--p 96K 92K 0K 0K rd mr mw me sd libtibrv64.so │
│ r-xp 316K 316K 0K 0K rd ex mr mw me sd libtibrv64.so │
│ r--p 108K 64K 0K 0K rd mr mw me sd libtibrv64.so │
│ r--p 4K 4K 0K 0K rd mr mw me dw ac sd libtibrv64.so │
│ rw-p 16K 16K 0K 0K rd wr mr mw me ac sd libtibrv64.so │
│ rw-p 4K 4K 0K 0K rd wr mr mw me ac sd │
│ r--p 28K 28K 0K 0K rd mr mw me sd libtibrvcm64.so │
│ r-xp 72K 72K 0K 0K rd ex mr mw me sd libtibrvcm64.so │
│ r--p 16K 16K 0K 0K rd mr mw me sd libtibrvcm64.so │
│ ---p 4K 0K 0K 0K mr mw me sd libtibrvcm64.so │
│ r--p 4K 4K 0K 0K rd mr mw me ac sd libtibrvcm64.so │
│ rw-p 4K 4K 0K 0K rd wr mr mw me ac sd libtibrvcm64.so │
│ rw-p 8K 4K 4K 0K rd wr mr mw me ac sd │
│ r--p 4K 4K 0K 0K rd mr mw me dw ac sd ld-2.28.so │
│ rw-p 8K 8K 0K 0K rd wr mr mw me dw ac sd ld-2.28.so │
│-------------------------------------------------------------------------------------------------------------│
│ 127.14T 700K 636K 12K 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 127.99T rw-p 136K 36K 76K 0K rd wr mr mw me gd ac [stack] │
│-------------------------------------------------------------------------------------------------------------│
│ 127.99T 136K 36K 76K 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 127.99T r--p 16K 0K 0K 0K rd mr pf io de dd sd [vvar] │
│ r-xp 8K 4K 0K 0K rd ex mr mw me de sd [vdso] │
│-------------------------------------------------------------------------------------------------------------│
│ 127.99T 24K 4K 0K 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────────────────────────────────────────────────────┐
│ 16.00E r-xp 4K 0K 0K 0K rd ex [vsyscall] │
│-------------------------------------------------------------------------------------------------------------│
│ 16.00E 4K 0K 0K 0K │
└─────────────────────────────────────────────────────────────────────────────────────────────────────────────┘
Эти блоки исходят от моего скрипта, который исследует VMA (области виртуальной памяти) процесса, находит непрерывные области памяти и рисует вокруг них рамки (а также показывает адрес в удобочитаемом формате, чтобы получить представление о промежутках между областями).
Я знаю, что бинарный файл всегда начинается на границах 4 МБ, поэтому начальный адрес бинарного файла не рандомизирован, что [heap]
рандомизирован в конце карты бинарного файла и следующих 8 МБ, а [stack]
также рандомизирован.
Но кроме этого, что еще рандомизировано? Вы можете увидеть, что все подкучи malloc различных потоков идут одна за другой, а также что все библиотеки идут одна за другой в соседних областях, однако иногда между отображениями библиотек также есть промежутки.
Тем не менее, в некоторых других процессах я наблюдал подкучи malloc внутри областей, которые в основном доминируют над отображениями библиотек.
Так какой “алгоритм” следует ядру, чтобы решить, что рандомизировать, а что нет (кроме VSDO, [stack]
и [heap]
, которые явно задокументированы как рандомизированные)? Также, почему начальный адрес самого бинарного файла тоже не рандомизирован? Это имеет смысл, чтобы защитить его от атак, не так ли?
Ответ или решение
Виртуальные области памяти и их рандомизация в Linux
Ваша наблюдательность при работе с виртуальными областями памяти (VMA) вашего процесса на Red Hat с настройкой /proc/sys/kernel/randomize_va_space
на уровне 2 заслуживает похвалы. Рассмотрим, какие области памяти рандомизируются и в каких условиях это происходит.
Основные области, подлежащие рандомизации
-
Стек (stack): Стек каждого потока рандомизируется при каждом запуске процесса. Это предотвращает угон адресов и устойчивость к атакам типа «переполнение стека».
-
Куча (heap): Куча представляет собой область памяти, выделяемую для динамического распределения памяти. При этом располагается в диапазоне от конца области бинарного файла до следующей границы, которая также рандомизируется, чтобы ограничить возможность предсказания на основе стандартных паттернов распределения памяти.
-
Виртуальное пространство динамической загрузки (VDSO) и временные переменные (vvar) также могут подвергаться рандомизации, но их поведение будет зависеть от конкретной реализации ядра.
Алгоритмы рандомизации
Рандомизация виртуальных адресов в Linux, как и в других Unix-подобных системах, осуществляется с использованием следующих алгоритмических подходов:
-
Стратегии распределения: В зависимости от значений, доступных в VMA, распределяются адреса для динамически выделенной памяти и стеков. Это делается с целью уменьшения предсказуемости расположения объектов в памяти, что затрудняет эксплуатацию уязвимостей.
-
Границы выделений: Для бинарных файлов используется фиксированная точка начала (например, 4Мб), чтобы обеспечить предсказуемую базу для загружаемых либ и других областей, необходимых для корректного функционирования приложений, что упрощает совместимость. Это делает бинарный файл предсказуемым и стабильным.
-
Сегментация по типам памяти: В типичной распределенной памяти свободные области для библиотек могут также совпадать, но это не всегда так. Этому в значительной степени способствуют обстоятельства, такие как загрузка дополнительных библиотек или модулей, которые могут использовать места в разных областях при их динамическом распределении.
Причины, по которым бинарный файл не рандомизируется
Стартовый адрес бинарного файла (обычно на границе 4Мб) не рандомизируется по нескольким причинам:
-
Совместимость: Это упрощает работу различных систем и инструментов, требующих фиксированных точек для взаимодействия с бинарными файлами.
-
Качество и стабильность работы приложений: Это позволяет многим приложениям правильно управлять ресурсами и использованием библиотек, минимизируя вероятность возникновения сбоев.
-
Безопасность через предсказуемость: Хотя предсказуемость может звучать, как потенциальная уязвимость, в действительности, эта фиксированная часть памяти также служит областью, где присутствуют хорошо изученные и защищенные механизмы, такие как системы контроля доступа и разрешений.
Заключение
Рандомизация виртуальных адресов в Linux (в частности, в дистрибутивах, таких как Red Hat) реализуется с целью повышения безопасности и сложности эксплуатации уязвимостей. Несмотря на то что стеки и кучи подлежат рандомизации, существуют обоснованные причины для оставления стартового адреса бинарного файла предсказуемым, чтобы обеспечить оптимальную производительность и совместимость программного обеспечения.
Эти аспекты подчеркивают важность понимания работы с памятью на низком уровне, что является критически важным для разработки безопасных и устойчивых приложений.