В вычислительной технике загружаемый модуль ядра ( LKM ) — это объектный файл , содержащий код для расширения работающего ядра , или так называемого базового ядра , операционной системы . LKM обычно используются для добавления поддержки нового оборудования (например, драйверов устройств ) и/или файловых систем , или для добавления системных вызовов . Когда функциональность, предоставляемая LKM, больше не требуется, его можно выгрузить, чтобы освободить память и другие ресурсы.
Большинство современных Unix-подобных систем и Microsoft Windows поддерживают загружаемые модули ядра под разными названиями, например, загружаемый модуль ядра ( kld ) в FreeBSD , расширение ядра ( kext ) в macOS (хотя поддержка сторонних модулей прекращается [1] ), [2] модуль расширения ядра в AIX , динамически загружаемый модуль ядра в HP-UX , [3] драйвер режима ядра в Windows NT [4] и загружаемый модуль ядра ( DKM ) в VxWorks . Они также известны как загружаемые модули ядра (или KLM ) и просто как модули ядра ( KMOD ).
Без загружаемых модулей ядра операционная система должна была бы включать все возможные ожидаемые функции, скомпилированные непосредственно в базовое ядро. Большая часть этой функциональности находилась бы в памяти без использования, тратя память [ нужна цитата ] и требовала бы, чтобы пользователи перестраивали и перезапускали базовое ядро каждый раз, когда им требуется новая функциональность.
Одной из незначительных критических замечаний по поводу предпочтения модульного ядра статическому ядру является так называемый штраф за фрагментацию . Базовое ядро всегда распаковывается в реальную непрерывную память своими процедурами настройки; таким образом, базовый код ядра никогда не фрагментируется. Как только система находится в состоянии, в котором могут быть вставлены модули, например, после монтирования файловых систем , содержащих модули, вполне вероятно, что любая новая вставка кода ядра приведет к фрагментации ядра, тем самым внося незначительный штраф за производительность из-за использования большего количества записей TLB , что приводит к большему количеству промахов TLB. [ необходима цитата ]
Загружаемые модули ядра в Linux загружаются (и выгружаются) командой modprobe
. Они находятся в /lib/modules
или /usr/lib/modules
и имеют расширение .ko
(«объект ядра») с версии 2.6 (предыдущие версии использовали .o
расширение). [5] Команда lsmod
выводит список загруженных модулей ядра. В экстренных случаях, когда система не загружается из-за, например, сломанных модулей, определенные модули можно включить или отключить, изменив список параметров загрузки ядра (например, если используется GRUB , нажав «e» в стартовом меню GRUB, а затем отредактировав строку параметров ядра).
По мнению разработчиков Linux, LKM являются производными от ядра [ требуется ссылка ] . Разработчики Linux допускают распространение проприетарных модулей [ требуется ссылка ], но позволяют отмечать символы как доступные только для модулей GNU General Public License (GPL).
Загрузка проприетарного или несовместимого с GPL модуля установит флаг «небезопасности» [6] [7] в работающем ядре, что означает, что любые возникшие проблемы или ошибки с меньшей вероятностью будут расследованы сопровождающими. [8] [9] LKM фактически становятся частью работающего ядра, поэтому могут повредить структуры данных ядра и привести к ошибкам, которые невозможно будет расследовать, если модуль действительно является проприетарным.
В 2004 году Linuxant, консалтинговая компания, выпускающая фирменные драйверы устройств в виде загружаемых модулей ядра, попыталась злоупотребить нулевым терминатором в своих файлах MODULE_LICENSE
, как видно из следующего фрагмента кода:
MODULE_LICENSE ( "GPL \0 для файлов в каталоге \" GPL \" ; для остальных применяется только файл LICENSE" );
Код сравнения строк, используемый ядром в то время, пытался определить, имеет ли модуль лицензию GPL, и останавливался, когда достигал нулевого символа ( \0
), поэтому его обманывали, заставляя думать, что модуль объявляет свою лицензию просто «GPL». [10]
Модули ядра для FreeBSD хранятся в /boot/kernel/
для модулей, распространяемых с операционной системой , или обычно /boot/modules/
для модулей, установленных из портов FreeBSD или пакетов FreeBSD , или для фирменных или иных двоичных модулей. Модули ядра FreeBSD обычно имеют расширение .ko
. После загрузки машины их можно загрузить с помощью kldload
команды , выгрузить с помощью kldunload
и просмотреть с помощью kldstat
. Модули также можно загрузить из загрузчика до запуска ядра, как автоматически (через /boot/loader.conf
), так и вручную.
Некоторые загружаемые модули ядра в macOS могут быть загружены автоматически. Загружаемые модули ядра также могут быть загружены командой kextload
. Их можно перечислить командой kextstat
. Загружаемые модули ядра находятся в пакетах с расширением .kext
. Модули, поставляемые с операционной системой, хранятся в /System/Library/Extensions
каталоге; модули, поставляемые третьими лицами, находятся в различных других каталогах.
Модуль ядра NetWare называется загружаемым модулем NetWare (NLM). NLM вставляются в ядро NetWare с помощью команды LOAD и удаляются с помощью команды UNLOAD; modules
команда выводит список загруженных в данный момент модулей ядра. NLM могут находиться в любом допустимом пути поиска, назначенном на сервере NetWare, и они имеют .NLM
расширение имени файла.
Проект типа загружаемого модуля ядра (DKM) может быть создан для генерации файла ".out", который затем может быть загружен в пространство ядра с помощью команды "ld". Этот загружаемый модуль ядра может быть выгружен с помощью команды "unld".
Solaris имеет настраиваемый путь загрузки модулей ядра, который по умолчанию равен /platform/platform-name/kernel /kernel /usr/kernel
. Большинство модулей ядра находятся в подкаталогах в /kernel
; те, которые не считаются необходимыми для загрузки системы до точки, когда может запуститься init, часто (но не всегда) находятся в /usr/kernel
. При запуске сборки ядра DEBUG система активно пытается выгрузить модули.
Linux не предоставляет стабильный API или ABI для модулей ядра. Это означает, что существуют различия во внутренней структуре и функциях между различными версиями ядра, что может вызвать проблемы совместимости. В попытке бороться с этими проблемами данные о версиях символов помещаются в .modinfo
раздел загружаемых модулей ELF . Эту информацию о версиях можно сравнить с информацией о версиях работающего ядра перед загрузкой модуля; если версии несовместимы, модуль не будет загружен.
Другие операционные системы, такие как Solaris , FreeBSD , macOS и Windows , сохраняют API и ABI ядра относительно стабильными, тем самым избегая этой проблемы. Например, модули ядра FreeBSD , скомпилированные с версией ядра 6.0, будут работать без перекомпиляции на любой другой версии FreeBSD 6.x, например, 6.4. Однако они несовместимы с другими основными версиями и должны быть перекомпилированы для использования с FreeBSD 7.x, поскольку совместимость API и ABI поддерживается только в пределах ветви.
Хотя загружаемые модули ядра являются удобным методом изменения работающего ядра, это может быть использовано злоумышленниками на скомпрометированной системе для предотвращения обнаружения их процессов или файлов , что позволяет им сохранять контроль над системой. Многие руткиты используют LKM таким образом. Обратите внимание, что в большинстве операционных систем модули никак не помогают повышению привилегий , поскольку для загрузки LKM требуются повышенные привилегии; они просто облегчают злоумышленнику задачу сокрытия взлома. [11]
Linux позволяет отключать загрузку модулей через опцию sysctl/proc/sys/kernel/modules_disabled
. [12] [13] Система initramfs может загружать определенные модули, необходимые для машины при загрузке, а затем отключать загрузку модулей. Это делает безопасность очень похожей на монолитное ядро. Если злоумышленник может изменить initramfs, он может изменить двоичный файл ядра.
В OS X Yosemite и более поздних выпусках расширение ядра должно быть подписано кодом с сертификатом разработчика, который содержит определенное «право». Такой сертификат разработчика предоставляется Apple только по запросу и не выдается автоматически членам Apple Developer . Эта функция, называемая «подписанием kext», включена по умолчанию и предписывает ядру прекратить загрузку, если присутствуют неподписанные расширения ядра. [14] В OS X El Capitan и более поздних выпусках она является частью System Integrity Protection .
В старых версиях macOS или если отключена подпись kext, загружаемый модуль ядра в пакете расширений ядра может быть загружен пользователями без прав root, если свойство OSBundleAllowUserLoad установлено в значение True в списке свойств пакета. [15] Однако, если какой-либо из файлов в пакете, включая файл исполняемого кода, не принадлежит пользователю root и группе wheel или доступен для записи группе или «другим», попытка загрузить загружаемый модуль ядра завершится неудачей. [16]
Модули ядра могут опционально иметь раздел ELF криптографической подписи, который проверяется при загрузке в зависимости от настроек политики Verified Boot. Ядро может обеспечить криптографическую подпись модулей набором доверенных сертификатов; список доверенных сертификатов хранится вне ОС в ILOM на некоторых платформах на базе SPARC. Загрузка модуля ядра, инициированная пользовательским пространством, возможна только из доверенного пути, когда система работает с включенной функцией Immutable Global Zone.