it-roy-ru.com

Что такое vdso и vsyscall?

Я сделал Sudo cat /proc/1/maps -vv

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

7f3c00137000-7f3c00179000 r-xp 00000000 08:01 21233923                   /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c00179000-7f3c00379000 ---p 00042000 08:01 21233923                   /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c00379000-7f3c0037a000 r--p 00042000 08:01 21233923                   /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c0037a000-7f3c0037b000 rw-p 00043000 08:01 21233923                   /lib/x86_64-linux-gnu/libdbus-1.so.3.5.8
7f3c0037b000-7f3c00383000 r-xp 00000000 08:01 21237216                   /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00383000-7f3c00583000 ---p 00008000 08:01 21237216                   /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00583000-7f3c00584000 r--p 00008000 08:01 21237216                   /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00584000-7f3c00585000 rw-p 00009000 08:01 21237216                   /lib/x86_64-linux-gnu/libnih-dbus.so.1.0.0
7f3c00585000-7f3c0059b000 r-xp 00000000 08:01 21237220                   /lib/x86_64-linux-gnu/libnih.so.1.0.0
7f3c0059b000-7f3c0079b000 ---p 00016000 08:01 21237220                   /lib/x86_64-linux-gnu/libnih.so.1.0.0
7f3c0079b000-7f3c0079c000 r--p 00016000 08:01 21237220                   /lib/x86_64-linux-gnu/libnih.so.1.0.0

К концу есть что-то вроде

7f3c0165b000-7f3c0177e000 rw-p 00000000 00:00 0                          [heap]
7fff97863000-7fff97884000 rw-p 00000000 00:00 0                          [stack]
7fff97945000-7fff97946000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]

Что означают vdso и vsyscall? vsyscall ядро ​​часть памяти? Было бы здорово, если бы кто-нибудь смог пролить свет на эту проблему.

76
liv2hak

Сегменты vsyscall и vDSO являются двумя механизмами, используемыми для ускорения определенных системных вызовов. в линуксе Например, gettimeofday обычно вызывается через этот механизм. Первым введенным механизмом был vsyscall , который был добавлен в качестве способа выполнения определенных системных вызовов, которым не требуется какой-либо реальный уровень привилегий для запуска, чтобы уменьшить затраты системных вызовов. Следуя предыдущему примеру, все, что нужно сделать gettimeofday, это прочитать текущее время ядра. Существуют приложения, которые часто вызывают gettimeofday (например, для генерации меток времени), в том смысле, что им небезразлично даже небольшое количество накладных расходов. Чтобы решить эту проблему, ядро ​​отображает в пространство пользователя страницу, содержащую текущее время и быструю реализацию gettimeofday (т.е. просто функцию, которая считывает время, сохраненное в vsyscall ). Используя этот виртуальный системный вызов, библиотека C может предоставить быстрое gettimeofday, которое не имеет издержек, связанных с переключением контекста между пространством ядра и пространством пользователя, обычно вводимым классической моделью системных вызовов INT 0x80 или SYSCALL.

Однако этот механизм vsyscall имеет некоторые ограничения: выделенная память мала и допускает только 4 системных вызова, и, что более важно и серьезно, страница vsyscall статически выделяется для одного и того же адреса в каждом процессе, поскольку местоположение vsyscall страница прибита в ядро ​​ABI. Такое статическое распределение vsyscall сводит на нет преимущества, которые дает рандомизация пространства памяти, обычно используемая в Linux. Злоумышленник, скомпрометировав приложение путем использования переполнения стека, может вызвать системный вызов со страницы vsyscall с произвольными параметрами. Все, что ему нужно, это адрес системного вызова, который легко предсказать, так как он статически распределен (если вы попытаетесь снова запустить вашу команду даже с другими приложениями, вы заметите, что адрес vsyscall не меняется). Было бы неплохо удалить или хотя бы рандомизировать расположение страницы vsyscall, чтобы помешать этому типу атаки. К сожалению, приложения зависят от существования и точного адреса этой страницы, поэтому ничего не поделаешь.

Эта проблема безопасности была решена путем замены всех инструкций системного вызова по фиксированным адресам специальной инструкцией прерывания. Приложение, пытающееся вызвать страницу vsyscall , попадет в ядро, которое затем будет эмулировать требуемый виртуальный системный вызов в пространстве ядра. В результате получается системный вызов ядра, эмулирующий виртуальный системный вызов, который был помещен туда, чтобы в первую очередь избежать системного вызова ядра. Результатом является vsyscall , выполнение которого занимает больше времени, но, что важно, не нарушает существующий ABI. В любом случае замедление будет наблюдаться только в том случае, если приложение пытается использовать страницу vsyscall вместо vDSO .

vDSO предлагает те же функции, что и vsyscall, но преодолевает его ограничения. VDSO (виртуальные динамически связанные общие объекты) - это область памяти, выделенная в пользовательском пространстве, которая безопасно раскрывает некоторые функциональные возможности ядра в пользовательском пространстве. Это было введено для устранения угроз безопасности, вызванных vsyscall. VDSO выделяется динамически, что решает проблемы безопасности и может иметь более 4 системных вызовов. Ссылки vDSO предоставляются через библиотеку glibc. Компоновщик будет ссылаться в функциональности glibc vDSO при условии, что такая подпрограмма имеет сопровождающий vDSO версия, такая как gettimeofday. Когда ваша программа выполняется, если ваше ядро ​​не поддерживает vDSO , будет выполнен традиционный системный вызов.

Кредиты и полезные ссылки:

132
Giuseppe Pes

Я просто хочу добавить, что теперь в новых ядрах vDSO не используется только для "безопасных" системных вызовов, а используется для определения, какой механизм системного вызова является предпочтительным методом для вызова системного вызова в системе.

7
incompetent