内核模块让驱动和功能可以运行时加载卸载——不需要重编内核。但模块也带来安全和兼容性挑战。
一、先看图
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
同主题继续阅读
把当前热点继续串成多页阅读,而不是停在单篇消费。
【操作系统百科】内存回收
Linux 内存回收是 VM 最复杂的子系统之一。本文讲 active/inactive LRU、kswapd 与 direct reclaim、watermark 三线、swappiness 的真实含义、MGLRU 改造、memcg 回收与 PSI。
【操作系统百科】交换
swap 还值得开吗?本文讲 swap area 基础、swap cache、zram 压缩内存、zswap 前端压缩池、swappiness 的真实含义、容器里的 swap 策略,以及为什么现代 Android 全靠 zram 不靠磁盘。
【操作系统百科】Slab/SLUB 分配器
buddy 只管页粒度(4K+),内核大多数对象只有几十到几百字节。slab/SLUB 在 buddy 之上做对象级缓存。本文讲 slab 历史、SLUB 接手、SLOB 退场、kmem_cache、per-CPU cache、KASAN 集成。
【操作系统百科】用户态分配器
glibc malloc、tcmalloc、jemalloc、mimalloc 各有哲学。本文讲 arena、thread cache、size class、madvise 返还策略、碎片与 RSS 膨胀、如何根据负载选分配器。