# Kernel modules - LKM, modprobe, signing, DKMS _Процессы и ресурсы · LinuxLab Knowledge Base_ **TL;DR:** LKM - код, динамически загружаемый в kernel. modprobe резолвит зависимости через depmod. Подпись модуля для Secure Boot. DKMS пересобирает out-of-tree модули после kernel-upgrade. Lockdown mode запрещает загрузку неподписанных. ## Зачем kernel modules Linux kernel - монолит, но не статический. **Loadable Kernel Module (LKM)** - объектный файл (`.ko`), который можно подгрузить в работающий kernel и выгрузить без ребута. Это даёт: - **Драйверы железа подключаются по факту** - USB-стик воткнули, `usb_storage` загрузился - **Модульный kernel** - дистрибутивы строят минимальный vmlinuz, остальное - модули. RHEL/Ubuntu kernel - ~20 МБ vmlinuz + сотни МБ модулей в `/lib/modules/` - **Опциональный функционал** - `nf_nat`, `vfat`, `nvidia.ko` - грузятся только когда нужны - **Out-of-tree модули** - проприетарные драйверы (NVIDIA, ZFS, VirtualBox) без патча в mainline Альтернативы LKM: - **eBPF** ([ebpf-basics](/kb/ebpf-basics.md)) - sandboxed, без ring0-доверия. Но не может всё что может модуль (новый driver, новый syscall) - **Userspace driver** через uio/vfio - для NIC (DPDK), accelerator'ов ## Загрузка/выгрузка Три уровня абстракции: ### insmod / rmmod (raw) ``` insmod /lib/modules/$(uname -r)/kernel/fs/vfat/vfat.ko rmmod vfat ``` Не резолвит зависимости. Если модуль `A.ko` требует `B.ko`, и `B` не загружен - ошибка `Unknown symbol in module`. Использовать редко, только для отладки. ### modprobe (с зависимостями) ``` modprobe vfat modprobe -r vfat # remove modprobe -v nf_nat # verbose modprobe --first-time vfat # error if already loaded ``` Резолвит зависимости через `modules.dep` (созданный `depmod`). Сначала загрузит `fat` (зависимость), потом `vfat`. Параметры модуля: ``` modprobe nvidia NVreg_PreserveVideoMemoryAllocations=1 ``` Постоянные параметры - в `/etc/modprobe.d/.conf`: ``` options nvidia NVreg_PreserveVideoMemoryAllocations=1 blacklist nouveau ``` `blacklist` - модуль не загрузится автоматически, но можно вручную. Чтобы вообще не загружался - `install /bin/false`. ### depmod - дерево зависимостей ``` depmod -a ``` Сканирует `/lib/modules/$(uname -r)/`, читает symbols из каждого `.ko`, строит: - `modules.dep` - "A зависит от B,C" - `modules.symbols` - "symbol foo находится в A.ko" - `modules.alias` - "alias 'pci:v0x8086d0x10b8*' = e1000.ko" - `modules.builtin` - что вкомпилено в vmlinuz Запускается автоматически при `make modules_install` и при установке пакета linux-image. Руками - редко. ### Автоматическая загрузка Modern systemd-udev делает это сам через **alias matching**: - PCI устройство имеет vendor/device ID - kernel/udev генерирует MODALIAS string - matched через `modules.alias` → загружается соответствующий модуль Убедиться: ``` udevadm test /sys/class/net/eth0 # что matchится ``` Для USB то же. Для FS - kernel пытается загрузить модуль когда `mount -t vfat ...`. ## modinfo - инфа о модуле ``` modinfo nvidia filename: /lib/modules/.../nvidia.ko version: 535.183.01 license: NVIDIA description: NVIDIA Driver author: NVIDIA Corporation depends: ... retpoline: Y intree: N vermagic: 6.5.0-44-generic SMP preempt mod_unload parm: NVreg_OpenRmEnableUnsupportedGpus:int ... ``` Полезно для: - `vermagic` - под какой kernel собран (если не совпадает - не загрузится без `modprobe --force`) - `intree: N` - out-of-tree (см. ниже про taint) - `parm:` - доступные параметры ## /proc/modules и lsmod ``` lsmod | head Module Size Used by nvidia_uvm 1810432 0 nf_conntrack_netlink 65536 0 nf_nat 57344 0 nf_conntrack 196608 2 nf_nat,nf_conntrack_netlink ``` Колонки: имя, размер в памяти, refcount + кто использует. Если refcount > 0 - выгрузить нельзя: ``` rmmod: ERROR: Module nf_conntrack is in use by: nf_nat,nf_conntrack_netlink ``` Выгружать в правильном порядке (сначала зависящие). ## Module signing - подпись С версии 3.7 kernel поддерживает signing модулей. На UEFI Secure Boot система обычно **enforced**: незаподписанный модуль не загрузится. Подпись: ``` /usr/src/linux-headers-$(uname -r)/scripts/sign-file sha256 \ MOK_PRIVATE_KEY.pem MOK_CERT.x509 my_module.ko ``` Сертификат должен быть в kernel keyring или в **MOK (Machine Owner Key)**: ``` mokutil --import my_cert.der # ребут, в shim mokmanager - enroll, ввести password ``` После enroll - kernel доверяет этому сертификату. Состояние signing: ``` cat /proc/sys/kernel/modules_disabled # 1 = вообще нельзя грузить cat /sys/module//sections/.signature 2>/dev/null # подписан? ``` ## Lockdown mode Kernel 5.4+ имеет **lockdown** LSM: - **none** - полный доступ root к kernel-памяти, MSR, kexec, /dev/mem - **integrity** - запрет модификаций kernel (writeable text), но чтение разрешено - **confidentiality** - запрет также чтения (sensitive ключи нельзя sniff'ить) Включается: - В UEFI Secure Boot обычно integrity по умолчанию - Или вручную: kernel cmdline `lockdown=integrity` - Или `echo integrity > /sys/kernel/security/lockdown` Эффект: - Незаподписанные модули не грузятся - kexec без подписи - запрещён - /dev/mem read - запрещён - Некоторые ioctl'и (`SET_KERNEL`, ftrace marker) - запрещены Используется в hardened-системах (Federal POS, ChromeOS, Tails). ## Out-of-tree модули и DKMS Некоторые модули не в mainline kernel: NVIDIA, ZFS, VirtualBox, WireGuard до 5.6. После каждого kernel-upgrade такие модули нужно пересобирать. **DKMS (Dynamic Kernel Module Support)** автоматизирует: 1. Источник модуля и spec лежат в `/usr/src/-/` 2. При установке нового kernel-headers - DKMS пересобирает все зарегистрированные модули 3. Кладёт `.ko` в `/lib/modules/$(new_kernel)/updates/dkms/` 4. `depmod` запускается автоматически Регистрация: ``` dkms add -m my-driver -v 1.0 dkms build -m my-driver -v 1.0 dkms install -m my-driver -v 1.0 dkms status ``` Без DKMS - после `apt upgrade && reboot` теряешь NVIDIA → noir экран. ## Kernel taint Когда грузится "плохой" модуль, kernel помечает себя **tainted**: ``` cat /proc/sys/kernel/tainted ``` Битмап: - `1` (P) - proprietary module loaded (NVIDIA) - `2` (F) - module force-loaded (modprobe --force) - `4` (S) - SMP w/ non-SMP-capable cpu - `512` (W) - WARN_ON triggered - `4096` (K) - kernel was live-patched - `8192` (X) - external/unsupported module - `32768` (E) - unsigned module loaded В bug-report'ах maintainers первым делом смотрят на taint - если P, никакой поддержки не будет (NVIDIA - твоя проблема). Расшифровка: ``` cat /proc/sys/kernel/tainted # или dmesg | grep -i taint ``` ## Module init/exit Каждый модуль имеет: ```c static int __init my_init(void) { pr_info("loaded\n"); return 0; } static void __exit my_exit(void) { pr_info("unloaded\n"); } module_init(my_init); module_exit(my_exit); MODULE_LICENSE("GPL"); MODULE_AUTHOR("..."); ``` При insmod вызывается `module_init`. Если init возвращает не 0 - модуль выгружается (без вызова `module_exit`). При rmmod - `module_exit`. Логи `pr_info` (= `printk(KERN_INFO ...)`) видны через [[cmd-dmesg|dmesg]] или `journalctl -k`. ## Когда что-то пошло не так - **`Required key not available`** - Secure Boot включён, модуль не подписан. Подписать или disable Secure Boot (на свой риск). - **`Exec format error`** - vermagic не совпадает. Модуль собран под другой kernel. Пересобрать. - **`Unknown symbol in module`** - зависимость не загружена. `modprobe` вместо `insmod`. Или dependency не существует (типичная боль с out-of-tree модулями). - **Нельзя rmmod** - `Module is in use`. Найди что использует (`lsmod | grep `), выгрузи зависящие сначала. - **Kernel panic при load** - модуль кривой. Загрузи с другого initramfs, удали `.ko` из `/lib/modules/.../updates/`. - **DKMS не пересобирает после upgrade** - `dkms autoinstall` руками, проверь логи в `/var/lib/dkms///build/make.log`. - **Lockdown сообщение `Lockdown: ... is restricted`** - lockdown режим запрещает действие. Проверь `dmesg | grep -i lockdown`. ## Команды ```bash lsmod ``` Список загруженных модулей с refcount и зависимостями ```bash modprobe nf_conntrack ``` Загрузить модуль с авторезолвом зависимостей ```bash modprobe -r nf_conntrack ``` Выгрузить - провалится если refcount > 0 ```bash modinfo nvidia ``` Метаданные модуля: vermagic, параметры, лицензия, intree/oot ```bash depmod -a ``` Перестроить modules.dep + symbols + alias - после ручного копирования .ko ```bash cat /proc/sys/kernel/tainted ``` Битмап taint - что 'грязного' было загружено ```bash dkms status ``` Все DKMS-модули и под какие kernel они собраны ```bash echo integrity > /sys/kernel/security/lockdown ``` Включить lockdown integrity-mode (можно только повышать уровень, не понижать) ## См. также - [dmesg - kernel ring buffer](/kb/cmd-dmesg.md) - [sysctl - крутилки ядра](/kb/cmd-sysctl.md) - [BPF CO-RE - Compile Once Run Everywhere](/kb/bpf-co-re.md) - [SELinux и AppArmor - Mandatory Access Control](/kb/selinux-apparmor.md) - [systemd - init и менеджер сервисов](/kb/systemd.md) - [Linux capabilities - биты привилегий](/kb/capabilities.md)