Что такое 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 - часть ядра в памяти? Было бы здорово, если бы кто-нибудь мог рассказать о проблеме.

Ответ 1

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

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

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

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

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

Ответ 2

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