内核模块让驱动和功能可以运行时加载卸载——不需要重编内核。但模块也带来安全和兼容性挑战。
一、先看图
flowchart TD
SRC[模块源码<br/>.c + Makefile] --> BUILD[编译<br/>make -C /lib/modules/...]
BUILD --> KO[module.ko]
KO --> SIGN[签名<br/>sign-file]
SIGN --> LOAD[insmod / modprobe]
LOAD --> VERIFY{Secure Boot<br/>验证签名?}
VERIFY -- 通过 --> INIT[module_init<br/>初始化]
VERIFY -- 失败 --> REJECT[拒绝加载]
classDef build fill:#388bfd22,stroke:#388bfd,color:#adbac7;
classDef sec fill:#f0883e22,stroke:#f0883e,color:#adbac7;
class SRC,BUILD,KO build
class SIGN,LOAD,VERIFY,INIT,REJECT sec
二、模块加载
insmod /path/to/module.ko # 直接加载
modprobe my_module # 自动处理依赖
modprobe -r my_module # 卸载内核内部:
// kernel/module/main.c
SYSCALL_DEFINE3(init_module, void __user *, umod, unsigned long, len, const char __user *, uargs)加载 → 解析 ELF → 重定位 → 检查签名 → 调用
module_init()。
三、符号版本(modversions)
CONFIG_MODVERSIONS=y
每个导出符号附加 CRC → 模块加载时检查 CRC 匹配 → 防止内核更新后加载不兼容模块。
不匹配 →
insmod: ERROR: could not insert module: Invalid module format。
四、模块签名
# 编译时签名
CONFIG_MODULE_SIG=y
CONFIG_MODULE_SIG_FORCE=y
# 手动签名
scripts/sign-file sha256 signing_key.pem signing_key.x509 module.koSecure Boot 环境:未签名模块 → 拒绝加载。
五、DKMS
Dynamic Kernel Module Support:
dkms add ./module-source
dkms build -m mymodule -v 1.0 -k $(uname -r)
dkms install -m mymodule -v 1.0内核更新时自动重新编译 out-of-tree 模块。
常见用户:NVIDIA 驱动、VirtualBox、ZFS。
六、Lockdown
CONFIG_SECURITY_LOCKDOWN_LSM=y
lockdown 模式限制 root 权限:
- integrity:禁止修改内核(/dev/mem、kexec unsigned)
- confidentiality:禁止读取内核数据(/dev/kmem、perf)
未签名模块在 lockdown 模式下无法加载。
七、Module Taint
cat /proc/sys/kernel/tainted加载某些模块会 taint 内核:
| taint 标志 | 含义 |
|---|---|
| P | 专有模块(proprietary) |
| O | out-of-tree 模块 |
| E | 未签名模块 |
| C | staging 驱动 |
Tainted 内核 → bug 报告可能被内核开发者忽略。
八、livepatch
不重启修复内核 bug:
# kpatch
kpatch load my-fix.ko
# 内核原生
echo 1 > /sys/kernel/livepatch/my_patch/enabled8.1 原理
ftrace + 函数替换:
- 编译补丁函数
- 用 ftrace 替换原函数入口 → 跳转到新函数
- 等所有线程离开旧函数(一致性模型)
8.2 限制
- 只能替换函数级别
- 数据结构变更不支持
- 需要
CONFIG_LIVEPATCH=y
九、观察
lsmod # 已加载模块
modinfo my_module # 模块信息
cat /proc/modules # 原始格式
cat /sys/module/my_module/taint # taint 状态
# 模块依赖
modprobe --show-depends my_module
# 签名验证
modinfo -F sig_hashalgo my_module.ko十、小结
- 模块是可加载的内核扩展 → 灵活但有安全风险
- modversions 防止 ABI 不匹配
- Secure Boot + 签名强制 → 只加载受信任模块
- DKMS 解决 out-of-tree 模块的编译问题
- livepatch 允许不重启修复内核 bug
参考文献
kernel/module/Documentation/admin-guide/module-signing.rstDocumentation/livepatch/- DKMS documentation
工具
modprobe/insmod/rmmodmodinfodkmskpatch
文章导航
读完这篇,下一步读什么
优先读同系列或同问题的下一篇,把单篇消费变成主题集群。
CPU 调度:CFS 的虚拟运行时间与 EEVDF 的虚拟截止期
从比例份额调度的论文谱系出发,对照 Linux v6.6 与 v6.12 fair.c 源码,解释 CFS 的 vruntime、EEVDF 的 lag/eligible/deadline,并用确定性模拟复现延迟与 lag 的差异。
I/O 调度:在寻道、队列深度与公平性之间取舍
从电梯算法到 blk-mq,解释 Linux I/O 调度器为何在 HDD 上排序、在共享设备上保公平、在 NVMe 上常选择 none,并用确定性模拟展示寻道距离与队列尾延迟的取舍。
用户态内存分配器:size class、线程缓存与碎片边界
从 Wilson 分配器综述到 jemalloc、gperftools tcmalloc 与 mimalloc 的源码路径,解释 size class、线程缓存、跨线程释放和 RSS 碎片;用可复现实验说明不能只凭 allocator 名字下结论。
伙伴系统与 SLUB:Linux 物理页和小对象分配的边界
以 Linux v6.6 源码和确定性模拟为准,解释伙伴系统的 split/coalesce、migratetype 反碎片策略,以及 SLUB 的 per-CPU freelist、partial list 与安全加固。