Что такое 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 ядро часть памяти? Было бы здорово, если бы кто-нибудь смог пролить свет на эту проблему.
2 ответа
Сегменты vsyscall и vDSO - это два механизма, используемые для ускорения определенных системных вызовов в Linux. Например, 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, будет выполнен традиционный системный вызов.
Кредиты и полезные ссылки:
Я просто хочу добавить это сейчас в новых ядрах, vDSO
используется не только для "безопасных" системных вызовов, но он используется для определения того, какой механизм системного вызова является предпочтительным методом для вызова системного вызова в системе.