附录 D 内核配置 (Kernel Configuration)
核心结论
-
Linux 内核功能按需编译:每个内核子系统可在编译时
=y/=m/=n;可减少内核二进制大小、节省内存、避免不需要的代码进入漏洞评估面。 -
配置工具:
make menuconfig(curses 风格)、make xconfig(Qt 图形)、make config(文本问答);结果写入.config文件。 -
.config 文件格式:
CONFIG_NAME=value行;# CONFIG_NAME is not set表示未启用;可用 menuconfig 的 / 搜索直接定位。 -
运行内核可看 /proc/config.gz:压缩的 .config 信息;
zcat /proc/config.gz | grep CONFIG_X查当前已编译配置。 -
模块化(=m)的优点:功能不在内核体积,但可按需
modprobe加载;副作用少、升级不需重编。 -
TLPI 不指明 menu 路径——menu 层级随内核版本变化;只要知道名字 + menuconfig / 搜索就能找到。
|
附录主旨
本附录概述 Linux 内核编译配置机制。读者需掌握:(1) |
一、核心概念
本附录围绕 4 个核心概念:编译选项 y/m/n、三种配置工具、.config 格式、运行内核查配置。
| 概念 | 定义 + 重要性 | 实现提示 |
|---|---|---|
编译选项三态 |
|
§D;如 |
配置工具(menu/x/config) |
|
§D;改完 |
.config 格式 |
|
§D;可用 |
运行内核查配置 |
|
§D;`zcat /proc/config.gz |
二、详细笔记
D.1 配置文件流程
What:编译内核的标准流程(高层):
tar xvf linux-6.6.tar.xz
cd linux-6.6
make menuconfig # 选择配置
make -j$(nproc) # 编译
sudo make modules_install
sudo make install
Why:(1) TLPI 描述功能时常引用 CONFIG_* 名称——理解 .config 是配置入口的关键;(2) 调试需要时可能重编启用 CONFIG_xxx。
How:在 menuconfig 主菜单按 / 进入搜索模式,输入如 INOTIFY → 找到选项描述与路径。
When:(1) 想启用某功能但发行版默认不开;(2) 想关某功能减少 attack surface。
Example:CentOS / RHEL 默认 CONFIG_UNIX98_PTYS=n → ssh server 不能分配 pty → 编辑 /etc/sshd_config 不行,得重编或换 distro。
D.2 y / m / n 与模块管理
What:CONFIG_FOO=y 编入 vmlinux;CONFIG_FOO=m 生成 foo.ko,可按需 modprobe foo 加载;CONFIG_FOO 不存在则不编译。
Why:(1) 现代发行版默认大量 =m 模块,节约常驻内存;(2) 核心 / 启动必需的功能必须 =y(如 root fs、disk 驱动);(3) 编译失败时精确到具体选项。
How:
| 类别 | 常用选项 | 典型选择 |
|---|---|---|
启动必需 |
CONFIG_SATA_AHCI=y, CONFIG_EXT4_FS=y |
一定 y |
文件系统 |
CONFIG_NTFS_FS=m |
按需加载 |
网络协议 |
CONFIG_IPV6=m |
现代偏好 y |
安全 |
CONFIG_SECURITY_APPARMOR=m |
发行版默认 m |
调试 |
CONFIG_DEBUG_KERNEL=y |
开发用 |
性能追踪 |
CONFIG_FTRACE=y |
perf 用户 |
用户态 API |
CONFIG_EPOLL=y, CONFIG_INOTIFY=y |
When:(1) 嵌入式系统极度裁剪——绝大多数 m/n;(2) 普通服务器:核心 y、副功能 m。
Example:/lib/modules/$(uname -r)/ 列出当前内核的所有模块——modinfo e1000e 看驱动信息。
D.3 /proc/config.gz:运行内核的 build-time 配置
What:内核编译时启用 CONFIG_IKCONFIG=y + CONFIG_IKCONFIG_PROC=y → /proc/config.gz 提供 gzip(.config);运行中查询已编译功能。
Why:(1) 现场不重新编译可知道功能是否在内;(2) 调试不在系统上重现 bug 时知道对方内核配置。
How:
zcat /proc/config.gz | grep -E 'CONFIG_(EPOLL|INOTIFY|EVENTFD|SECCOMP|NAMESPACES)'
When:(1) 排查「为什么我 exec 不成功」类问题,先确认 CONFIG_xxx 在当前内核;(2) TLPI 多处引用,本附录给出兜底查询方法。
Example:CONFIG_USER_NS 限制能否建 user namespace;CONFIG_CGROUP_* 决定有哪些 cgroup 子系统可用。
D.4 间接配置路径(如 /proc/sys)
What:很多内核选项不仅有 .config / module 开关;运行时可通过 /proc/sys/ 调整参数(如 pty/max、tcp_ecn)。
Why:与 .config 静态编译选项不同,/proc/sys 暴露运行时可调的运行时参数。
How:
sysctl kernel.pty.max # 动态查
sysctl -w kernel.pty.max=8192
cat /proc/sys/kernel/pty/max
When:(1) 调 socket 缓存、文件数限制;(2) 调 pty 数量;(3) 调 TCP 拥塞控制算法。
Example:TLPI 9 章 CAP_NET_BIND_SERVICE 与 capabilities 配合 /proc/sys/kernel/yama/ptrace_scope 等。
D.5 进一步:编译 / 调试 / 升级
What:典型编译内核的后续步骤:
make -j$(nproc) bzImage modules
sudo make modules_install install
sudo update-grub # Debian/Ubuntu
sudo grub2-mkconfig -o /boot/grub2/grub.cfg # RHEL
sudo reboot
Why:TLPI 不强求编译内核,但排除某个功能未启用问题时常需重编。
How:
| 步骤 | 目的 | 工具 |
|---|---|---|
make mrproper |
清旧 .config + 缓存 |
make |
make defconfig |
使用 arch 默认 |
|
make |
make olddefconfig |
|
移植旧 .config |
make |
|
make localmodconfig |
仅编译当前 loaded modules |
make |
make modules_install |
装到 |
When:(1) 升级内核;(2) 定制功能性关闭;(3) 加 patch 后重编。
Example:make localmodconfig 仅编译当前 loaded modules,最小化编译时间但避免新硬件无驱动。
三、关键图表
|
TLPI 引用的关键 CONFIG 选项
|
|
.config 语法
|
四、思维导图
mindmap
root((附录 D kernel 配置))
编译选项
y 编入
m 模块
n not set
string 数字
配置工具
menuconfig ncurses
xconfig Qt
gconfig GTK
config 文本
config 文件
CONFIG NAME value
not set 注释
menuconfig 生成
旧版本兼容
运行查配置
proc config gz
ikconfig y
zcat 查询
运行时参数
proc sys
sysctl 修改
持久化 etc sysctl
编译流程
mrproper
defconfig
olddefconfig
localmodconfig
modules_install
五、重点与易错点
-
TLPI 引用 CONFIG_xxx 时常用
/proc/config.gz | grep查运行内核是否启用——比改 menuconfig 重编高效。 -
module
=m与=y区别:模块可按需 modprobe 节省内存;启动必需功能必须 y。 -
menuconfig 按
/搜索——不必死记路径;版本间菜单变化大。 -
localmodconfig 减少编译时间——只编译当前 loaded 的模块,避免冗余;但加新硬件时需重新编译。
-
重编内核不会自动生效——必须
make install+ 重启;旧内核仍可用 GRUB 选。 -
发行版内核常禁 CONFIG_IKCONFIG=y——/proc/config.gz 可能为空;只能用
/proc/version、/proc/sys/间接推断。 -
CONFIG_UNIX98_PTYS 自 2.6.4 起被替代——通过
/proc/sys/kernel/pty/max控制,参数非编时选项。 -
modprobe 加载模块:
/etc/modprobe.d/控制系统启动时加载;modprobe -r foo卸载。 -
CONFIG_xxx 模块化的副作用——内核升级后可能要求重编模块(
dkms自动维护)。 -
改 .config 后务必 make olddefconfig——避免新内核新增选项被设为 n 而 missing。
-
CONFIG_PREEMPT / CONFIG_PREEMPT_RT——影响调度延迟;桌面选 PREEMPT_VOLUNTARY、实时系统选 PREEMPT_RT(需打 patch)。
-
CONFIG_CGROUP_xyz——多个子系统分别编译;CONFIG_CGROUP_SCHED/CPUSET/…;cat /proc/cgroups 查启用列表。
-
CONFIG_SECCOMP 是现代容器 / firefox 沙箱的基础——常被加严配合 seccomp filter (BPF)。
-
CONFIG_USER_NS 必需——Docker/k8s 必备;用户 namespace 提供非 root 容器隔离。
-
CONFIG_DEBUG_KERNEL / CONFIG_DEBUG_INFO 启用会让内核 + 应用大很多——生产前关闭节省内存。
-
跨章衔接:本章被第 9 章 capabilities / 第 33 章线程 / 第 46 章 SysV IPC / 第 50 章 mmap / 第 53 章 POSIX semaphore / 第 62 章 terminal / 第 64 章 pty 等多章引用,是 TLPI 系统编程中「功能是否启用」的兜底检查。