Введение
Динамически загружаемый модуль, расширяющий ядро работающей операционной системы. В вычислительной технике загружаемый модуль ядра (LKM) представляет собой объектный файл, содержащий код для расширения работающего ядра, или так называемого базового ядра, операционной системы. LKM обычно используются для добавления поддержки нового оборудования (в виде драйверов устройств) и/или файловых систем, либо для добавления системных вызовов. Когда функциональность, предоставляемая LKM, больше не требуется, её можно выгрузить для освобождения памяти и других ресурсов. Большинство современных Unix-подобных систем и Microsoft Windows поддерживают загружаемые модули ядра под различными названиями, такими как загружаемый модуль ядра (kld) в FreeBSD, расширение ядра (kext) в macOS (хотя поддержка модулей сторонних разработчиков прекращается), модуль расширения ядра в AIX, динамически загружаемый модуль ядра в HP-UX, драйвер в режиме ядра в Windows NT и загружаемый модуль ядра (DKM) в VxWorks. Они также известны как загружаемые модули ядра (или KLM) и просто как модули ядра (KMOD).
In computing, a loadable kernel module (LKM) is an object file that contains code to extend the running kernel, or so called base kernel, of an operating system. LKMs are typically used to add support for new hardware (as device drivers) and/or filesystems, or for adding system calls. When the functionality provided by an LKM is no longer required, it can be unloaded in order to free memory and other resources. Most current Unix like systems and Microsoft Windows support loadable kernel modules under different names, such as kernel loadable module (kld) in FreeBSD, kernel extension (kext) in macOS (although support for third party modules is being dropped), kernel extension module in AIX, dynamically loadable kernel module in HP UX, kernel mode driver in Windows NT and downloadable kernel module (DKM) in VxWorks. They are also known as kernel loadable modules (or KLM), and simply as kernel modules (KMOD).
Преимущества
Без загружаемых модулей ядра операционная система должна была бы включать в себя все возможные предполагаемые функции, скомпилированные непосредственно в базовое ядро. Большая часть этих функций оставалась бы в памяти неиспользуемой, расходуя память, и требовала бы от пользователей перекомпиляции и перезагрузки базового ядра каждый раз, когда им потребуется новая функциональность.
Недостатки
Одной из незначительных критических замечаний в пользу модульного ядра по сравнению со статическим является так называемая плата за фрагментацию. Базовое ядро всегда распаковывается в физически непрерывную память процедурами инициализации; таким образом, код базового ядра никогда не фрагментируется. Как только система переходит в состояние, в котором возможна загрузка модулей, например, после монтирования файловых систем, содержащих эти модули, любое последующее добавление кода ядра, вероятно, приведет к фрагментации ядра, что повлечет за собой небольшое снижение производительности из-за увеличения числа записей TLB и, как следствие, большего числа промахов TLB.
Линукс
Загружаемые модули ядра в Linux загружаются (и выгружаются) командой modprobe. Они находятся в каталогах /lib/modules или /usr/lib/modules и имеют расширение ko ("объект ядра") начиная с версии 2.6 (в более ранних версиях использовалось расширение o). Команда lsmod выводит список загруженных модулей ядра. В аварийных ситуациях, когда система не загружается из-за, например, неисправных модулей, отдельные модули можно включить или отключить, изменив список параметров загрузки ядра (например, при использовании GRUB, нажав 'e' в меню загрузки GRUB, а затем отредактировав строку параметров ядра).
Лицензии
По мнению сопровождающих Linux, LKM являются производными работами ядра. Сопровождающие Linux допускают распространение проприетарных модулей, но позволяют помечать символы как доступные только для модулей GNU General Public License (GPL). Загрузка проприетарного или несовместимого с GPL модуля установит флаг "taint" в работающем ядре, что означает, что любые возникающие проблемы или ошибки будут с меньшей вероятностью исследоваться сопровождающими. LKM фактически становятся частью работающего ядра, поэтому могут приводить к повреждению структур данных ядра и вызывать ошибки, которые может быть невозможно исследовать, если модуль действительно является проприетарным.
FreeBSD
Модули ядра для FreeBSD хранятся в /boot/kernel/ для модулей, распространяемых вместе с операционной системой, или, как правило, в /boot/modules/ для модулей, установленных из портов FreeBSD или пакетов FreeBSD, а также для проприетарных или других модулей, доступных только в бинарном виде. Модули ядра FreeBSD обычно имеют расширение ko. После загрузки системы их можно загрузить командой kldload, выгрузить командой kldunload и просмотреть список с помощью kldstat. Модули также могут быть загружены загрузчиком до запуска ядра, либо автоматически (через /boot/loader.conf), либо вручную.
macOS
Некоторые загружаемые модули ядра в macOS могут загружаться автоматически. Загружаемые модули ядра также можно загрузить с помощью команды kextload. Список загруженных модулей можно получить с помощью команды kextstat. Загружаемые модули ядра хранятся в пакетах с расширением kext. Модули, поставляемые с операционной системой, находятся в каталоге /System/Library/Extensions, а модули, поставляемые сторонними разработчиками, – в различных других каталогах.
NetWare
Модуль ядра NetWare называется загружаемым модулем NetWare (NLM). NLM загружаются в ядро NetWare командой LOAD и удаляются командой UNLOAD; команда modules отображает список текущих модулей ядра. NLM могут располагаться в любом допустимом пути поиска, настроенном на сервере NetWare, и имеют расширение имени файла NLM.
VxWorks
Проект типа загружаемого модуля ядра (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 требуются повышенные привилегии; они лишь упрощают атакующему сокрытие факта взлома.
Линукс
Linux позволяет отключить загрузку модулей с помощью опции sysctl /proc/sys/kernel/modules disabled. Система initramfs может загружать определенные модули, необходимые для загрузки машины, а затем отключать загрузку модулей. Это значительно повышает безопасность, приближая её к уровню монолитного ядра. Если злоумышленнику удастся изменить initramfs, он сможет изменить двоичный код ядра.
macOS
В OS X Yosemite и более поздних версиях расширение ядра должно быть подписано кодом с использованием сертификата разработчика, обладающего определенным "правом". Такой сертификат разработчика предоставляется Apple только по запросу и не выдается автоматически участникам программы Apple Developer. Эта функция, называемая "kext signing", включена по умолчанию и предписывает ядру прекращать загрузку, если обнаружены неподписанные расширения ядра. В OS X El Capitan и более поздних версиях она является частью защиты системной целостности (System Integrity Protection). В более старых версиях macOS или при отключенной подписи kext, загружаемый модуль ядра в пакете расширения ядра может быть загружен пользователями без прав root, если свойство OSBundleAllowUserLoad установлено в True в списке свойств пакета. Однако, если какой-либо из файлов в пакете, включая исполняемый код, не принадлежит пользователю root и группе wheel, или доступен для записи группе или другим пользователям, попытка загрузки загружаемого модуля ядра завершится неудачей.
Солярис
Модули ядра могут опционально содержать секцию ELF с криптографической подписью, которая проверяется при загрузке в соответствии с настройками политики Verified Boot. Ядро может требовать, чтобы модули были криптографически подписаны набором доверенных сертификатов; список доверенных сертификатов хранится вне операционной системы в ILOM на некоторых платформах на базе SPARC. Загрузка модулей ядра, инициированная из пользовательского пространства, возможна только через Доверенный путь при работе системы с включенной функцией Неизменной глобальной зоны.