Зачем 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) - 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/<name>.conf:
options nvidia NVreg_PreserveVideoMemoryAllocations=1
blacklist nouveau
blacklist - модуль не загрузится автоматически, но можно вручную.
Чтобы вообще не загружался - install <module> /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/<m>/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) автоматизирует:
- Источник модуля и spec лежат в
/usr/src/<module>-<version>/ - При установке нового kernel-headers - DKMS пересобирает все зарегистрированные модули
- Кладёт
.koв/lib/modules/$(new_kernel)/updates/dkms/ 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 cpu512(W) - WARN_ON triggered4096(K) - kernel was live-patched8192(X) - external/unsupported module32768(E) - unsigned module loaded
В bug-report'ах maintainers первым делом смотрят на taint - если P, никакой поддержки не будет (NVIDIA - твоя проблема). Расшифровка:
cat /proc/sys/kernel/tainted
# или
dmesg | grep -i taint
Module init/exit
Каждый модуль имеет:
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 <name>), выгрузи зависящие сначала. - Kernel panic при load - модуль кривой. Загрузи с другого
initramfs, удали
.koиз/lib/modules/.../updates/. - DKMS не пересобирает после upgrade -
dkms autoinstallруками, проверь логи в/var/lib/dkms/<module>/<ver>/build/make.log. - Lockdown сообщение
Lockdown: ... is restricted- lockdown режим запрещает действие. Проверьdmesg | grep -i lockdown.