Разве не позволяет программе пользовательского режима получать доступ к памяти пространства ядра и выполнять инструкции IN и OUT, что не мешает использованию режимов ЦП?

19

Когда ЦП находится в режиме пользователя, ЦП не может выполнять привилегированные инструкции и не может получить доступ к памяти пространства ядра.

А когда процессор находится в режиме ядра, он может выполнять все инструкции и получать доступ ко всей памяти.

Теперь в Linux программа в режиме пользователя может получить доступ ко всей памяти (используя /dev/mem) и может выполнить две привилегированные инструкции INи OUT(используя, iopl()я думаю).

Таким образом, программа в пользовательском режиме в Linux может делать большинство вещей (я думаю, большинство вещей), которые можно делать в режиме ядра.

Разве не позволение программе пользовательского режима иметь всю эту мощь не противоречит цели использования режимов ЦП?

user341099
источник

Ответы:

23

Таким образом, программа в пользовательском режиме в Linux может делать большинство вещей (я думаю, большинство вещей), которые можно делать в режиме ядра.

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

/dev/memзащищен обычными правами доступа к файловой системе и CAP_SYS_RAWIOвозможностью. iopl()и ioperm()также ограничены через ту же возможность.

/dev/memтакже может быть скомпилирован из ядра ( CONFIG_DEVMEM).

Разве не позволение программе пользовательского режима иметь всю эту мощь не противоречит цели использования режимов ЦП?

Что же, может быть. Это зависит от того, что вы хотите, чтобы привилегированные процессы пользовательского пространства могли выполнять. Процессы пользовательского пространства также могут уничтожить весь жесткий диск, если у них есть доступ /dev/sda(или эквивалент), даже если это противоречит цели иметь драйвер файловой системы для управления доступом к хранилищу.

(Также существует тот факт, что он iopl()работает с использованием режимов привилегий ЦП на i386, поэтому нельзя сказать, что он побеждает их назначение.)

ilkkachu
источник
2
Даже ioplне разрешает все привилегированные инструкции, поэтому все равно полезно убедиться, что ошибочная программа пользовательского пространства не запускается случайно invd, перепрыгивая через поврежденный указатель функции, который указывает на исполняемую память, начиная с 0F 08байтов. Я добавил ответ с некоторыми причинами, не связанными с безопасностью, почему полезно, чтобы процессы в пользовательском пространстве повышали свои привилегии.
Питер Кордес
16

Только так же, как modprobe«побеждает» безопасность, загружая новый код в ядро.

По разным причинам иногда имеет смысл иметь полу-привилегированный код (например, графические драйверы внутри X-сервера), работающий в пользовательском пространстве, а не в потоке ядра.

  • Быть способным к killэтому легче, если это не запирает HW.
  • Наличие этого по требованию страницы его код / ​​данные из файлов в файловой системе. (Ядро памяти не является страничным)
  • Предоставляя ему свое собственное виртуальное адресное пространство, где ошибки в X-сервере могут просто привести к сбою X-сервера, не разрушая ядро.

Это мало что делает для безопасности, но имеет большие преимущества в надежности и архитектуре программного обеспечения.

Внедрение графических драйверов в ядро ​​может уменьшить переключение контекста между X-клиентами и X-сервером, например, всего лишь на один пользователь-> ядро-> пользователь, вместо того, чтобы загружать данные в другой процесс пространства использования, но исторически X-серверы слишком велики и слишком глючны. хотеть их полностью в ядре.


Да, вредоносный код с этими привилегиями мог бы захватить ядро, если бы захотел, используя /dev/memдля модификации кода ядра.

Или на x86, например, запустите cliинструкцию для отключения прерываний на этом ядре после выполнения ioplсистемного вызова, чтобы установить уровень привилегий ввода-вывода в 0.

Но даже x86 iopl"only" предоставляет доступ к некоторым инструкциям : in / out (и строковые версии in / outs) и cli / sti. Он не позволяет вам использовать rdmsrили wrmsrдля чтения или записи «регистров, специфичных для модели» (например, IA32_LSTARкоторые задают адрес точки входа ядра для syscallинструкции x86-64 ), или lidtдля замены таблицы дескрипторов прерываний (что позволит вам полностью принять на машине из существующего ядра, по крайней мере, на этом ядре.)

Вы даже не можете читать управляющие регистры (например, CR3, который содержит физический адрес каталога страниц верхнего уровня, который атакующий процесс может счесть полезным в качестве смещения /dev/memдля изменения своих собственных таблиц страниц в качестве альтернативы mmapбольшему количеству /dev/mem. )

invd(аннулируйте все кеши без обратной записи !! ( используйте вариант = ранний BIOS до того, как сконфигурирована RAM)) - еще один забавный, который всегда требует полного CPL 0 (текущий уровень привилегий), а не только IOPL. Даже wbinvdпривилегирован, потому что он очень медленный (и не прерываемый) и должен сбрасывать все кэши во всех ядрах. (См Есть ли способ , чтобы очистить весь кэш процессора , связанный с программой? И использование инструкции WBINVD )

Ошибки, которые приводят к переходу на неверный адрес, выполняющий данные как код, таким образом, не могут выполнить любую из этих инструкций случайно на X-сервере пользовательского пространства.


Текущий уровень привилегий (в защищенном и длинном режиме) - младшие 2 бита cs(селектор сегмента кода) . mov eax, cs/ and eax, 3работает в любом режиме для чтения уровня привилегий.

Чтобы записать уровень привилегий, вы должны сделать a jmp farили call farустановить CS:RIP(но запись GDT / LDT для целевого сегмента может ограничить его на основе старого уровня привилегий, поэтому пользовательское пространство не может сделать это, чтобы поднять себя). Или вы используете intили syscallдля переключения на кольцо 0 в точке входа в ядро.

Питер Кордес
источник
На самом деле, я почти уверен, что это просто «селектор» кода в Intel parlace. Это был сегмент в 8086/8088, возможно, в 80186, но в 80286 его называли селектором, и я не думаю, что они официально изменили эту терминологию с тех пор.
CVN