Вопрос или проблема
Я написал простой скрипт на Python, чтобы проверить /proc/{pid}/maps
на наличие областей, которые одновременно доступны для записи и исполнения на моем компьютере. Удивительно, но некоторые из них обнаружились, все приватные и анонимные. Задумываюсь, зачем программе в наши дни может понадобиться область, доступная для записи и исполнения? Для чего они используются?
/proc/1286/maps
['/usr/lib/xorg/Xorg\x00:0\x00-seat\x00seat0\x00-auth\x00/var/run/lightdm/root/:0\x00-nolisten\x00tcp\x00vt7\x00-novtswitch\x00']
7f5860c03000-7f5860c04000 rwxp 00000000 00:00 0
/proc/2659/maps
['xfwm4\x00--display\x00:0.0\x00--sm-client-id\x002c1781f72-47a5-494a-a3e7-32424563\x00']
7ffb7d804000-7ffb7d805000 rwxp 00000000 00:00 0
/proc/404436/maps
['xfce4-terminal\x00--geometry=180x56-0-0\x00']
7f44aa15a000-7f44aa18a000 rwxp 00000000 00:00 0
/proc/404436/maps
['xfce4-terminal\x00--geometry=180x56-0-0\x00']
7f44aa19b000-7f44aa1fb000 rwxp 00000000 00:00 0
/proc/404436/maps
['xfce4-terminal\x00--geometry=180x56-0-0\x00']
7f44aaa5c000-7f44aaa7c000 rwxp 00000000 00:00 0
/proc/404436/maps
['xfce4-terminal\x00--geometry=180x56-0-0\x00']
7f44aabba000-7f44aabca000 rwxp 00000000 00:00 0
/proc/404436/maps
['xfce4-terminal\x00--geometry=180x56-0-0\x00']
7f44ac736000-7f44ac766000 rwxp 00000000 00:00 0
/proc/407109/maps
['/usr/lib/firefox-esr/firefox-esr\x00-contentproc\x00-childID\x001\x00-isForBrowser\x00-prefsLen\x0037585\x00-prefMapSize\x00265304...']
10737c04c000-10737c05c000 rwxp 00000000 00:00 0
Скрипт:
#!/usr/bin/env python3
import sys
import os
import re
import glob
from os.path import dirname, join
def main():
map_files = list(filter(lambda f: re.match(r'^\d+$', f.split("https://unix.stackexchange.com/")[2]), glob.glob('/proc/*/maps')))
for map_file in map_files:
with open(map_file, 'r') as map_f:
for line in map_f.readlines(): # для каждой отображаемой области
[start, end, perms, offset, dev, inode, pathname] = parse_maps_line(line)
if 'x' in perms and 'w' in perms:
print(map_file)
with open(join(dirname(map_file), 'cmdline'), 'r') as cmd_f:
print('\t', cmd_f.readlines())
print('\t', line.strip())
def parse_maps_line(line):
''' Формат файла:
address perms offset dev inode pathname
00400000-00452000 r-xp 00000000 08:02 173521 /usr/bin/dbus-daemon
'''
[address, perms, offset, dev, inode, pathname] = re.split(r'\s+', line, 5)
[start, end] = address.split('-')
return [int(start, 16), int(end, 16), perms, int(offset, 16), dev, inode, pathname]
if __name__ == "__main__":
main()
Системы, которые позволяют программирование на основе образов
, где компилятор является частью образа
, обычно требуют, чтобы некоторые области памяти были одновременно доступными для записи и исполнения, но это может быть не одновременно. Это необходимо для того, чтобы компилировать новый код и затем выполнять его. Если они компилируют только в байт-код, они могут обойтись без разрешения на выполнение, но высокопроизводительные системы, которые компилируют в нативный код, будут требовать этого.
Динамически подключаемые библиотеки могут нуждаться в таблице переходов, которая заполняется во время выполнения для указания на функции.
Наличие областей, которые одновременно доступны для записи и исполнения, требует тщательного программирования, так как процессоры часто имеют отдельные кэши инструкций и данных, которые могут не обновляться корректно аппаратной поддержкой. Это может быть более значительной проблемой, если в системе несколько процессоров.
Ответ или решение
В современном программировании и операционных системах управление памятью включает в себя множество аспектов, связанных с безопасностью и производительностью. Одним из таких аспектов является наличие регионов памяти, которые одновременно и записываемые, и исполняемые. На первый взгляд это может показаться странным, особенно учитывая современный подход к безопасности, который стремится свести к минимуму возможность выполнения случайного или вредоносного кода. Попробуем рассмотреть причину существования таких регионов и их применение.
### Теория
Во-первых, стоит отметить важность как записи, так и исполнения кода в определенных сценариях. Некоторые системы программирования реализуют подход, который называется “образ пpограммирования” (image-based programming). В таких системах компилятор встроен в сам image, что позволяет компилировать и исполнять код во время выполнения. Для этого необходимо, чтобы некоторые регионы памяти могли быть и записываемыми, и исполняемыми.
Вторая распространенная причина — механизмы, которые используются в динамических библиотеках. При динамической линковке может потребоваться таблица переходов (jump table), которая заполняется во время выполнения программы для правильного адресации функций. В таких случаях требуется регион памяти, который будет одновременно записываемым и исполняемым.
### Пример
Посмотрим на вывод Python-скрипта, часть которого вы представили. Некоторые процессы, такие как ‘Xorg’, ‘xfwm4’ и ‘firefox-esr’, используют такие регионы памяти. Это может быть вызвано необходимостью в реалокации исполняемых частей кода или же применением особых архитектурных подходов, где динамическая изменяемость кода является нормой.
### Применение
Однако, несмотря на вышесказанное, возможность исполнения записываемого кода несет в себе риски. Такие регионы могут быть целью атак, таких как внедрение и выполнение вредоносного кода. В связи с этим система должна предусматривать механизмы контроля и очистки данных кеша процессора, особенно в многопроцессорных системах.
Для повышения безопасности, многие современные ОС и среды исполнения используют такие подходы, как Data Execution Prevention (DEP) или Address Space Layout Randomization (ASLR), чтобы минимизировать риски. При проектировании систем и программ нужно тщательно оценивать необходимость использования записываемых и исполняемых регионов памяти, а также предусматривать дополнительные меры по защите.
Таким образом, наличие записываемых и исполняемых регионов памяти может быть обусловлено необходимостью в системах, где динамическое изменение кода является частью архитектуры. Однако это требует тщательной разработки и внедрения мер безопасности для предотвращения потенциальных уязвимостей.