在 Linux 上,sysctl 通过 /proc/sys 暴露一部分内核参数。它可以观察当前运行状态;有权限的写入则能在不重启的情况下改变状态。配置文件是另一层东西:它要求某个加载器在特定时刻执行赋值。混淆这两层,就会遇到常见故障:磁盘上的配置看起来正确,内核实际使用的却是另一个值。

本文限定 Linux、procps-ng 和 systemd。BSD、macOS 也提供名为 sysctl 的命令,但接口和持久化方式不同。在 macOS 上数出多少个键,不能作为 Linux procfs 接口的验证证据。

先确认正在读取哪个接口

对普通名称来说,kernel.ostype 对应 /proc/sys/kernel/ostype;procps 也接受斜杠分隔符。若名称本身含有字面意义的点号,应遵循工具的分隔规则,不能盲目把所有点替换成斜杠。可用键取决于内核配置、已加载模块和执行环境。不同机器的键集合不保证相同,同一台机器运行期间也可能变化。

procps 的普通输出是 key = value,-n 则只打印值。一次读取成功,说明调用者在当前环境看到了这个值,并不证明持久策略已经生效。有些值还会在观察期间变化。排查时只读取所需键,不能把所有读取都当成无副作用操作:手册明确说明,读取 vm.stat_refresh 会刷新每个 CPU 的统计,因此普通枚举会跳过它。

持久化由具体加载器完成

运行时赋值不会替你生成持久配置文件;反过来,保存配置片段也不会立即改变内核。讨论优先级之前,先确定系统在启动或重载时由哪个组件应用设置。

procps 的 --system 会先根据目录优先级选出文件:高优先级目录中的同名文件遮蔽低优先级副本。选中的片段随后按文件名的字典序应用,不按目录逐层决定最终值;最后再读取 /etc/sysctl.conf。systemd 的 sysctl.d 加载器也结合目录优先级和文件名排序,但不直接读取 /etc/sysctl.conf。发行版仍可能通过配置目录中的链接把这个文件纳入加载范围,因此要检查实际安装,不能只凭路径名称下结论。

这里存在两种不同覆盖:使用相同文件名可整体替代厂商文件;使用排序更靠后的不同文件名,可覆盖其中某个参数。两者都不能阻止另一个服务在加载完成之后再次写入同一参数。启动时赋值成功,与几小时后观察到的有效值,是需要分别记录的两件事。

不要混用不同实现的错误策略

systemd 的 sysctl.d 文档把变量不存在和权限失败列为调试级、非致命情况;其他赋值错误会在处理完其余设置后让服务失败。在某条赋值前加减号,则可忽略该条赋值的失败。这是 systemd 加载器的规则,不能移植成对每次 procps 命令退出状态的保证。

procps 的 -e 专门忽略未知键错误,不等于所有格式错误或被拒绝的写入都会成功。它的配置格式也支持用前导减号忽略某条赋值错误。把一个实现的选项和另一个实现的错误分类拼在一起,无法得到可移植的诊断结论;工具返回成功,也不应替代对目标值的明确核验。

坏掉的样子

依赖模块的参数,在启动加载器运行时可能尚不存在。应先检查模块是否可用,以及加载器当时的日志,再判断后来的读取结果是否暴露配置语法问题。另一个写入者也可能覆盖已经成功应用的值。把加载器名称、文件优先级、应用时间和后续有效值分开记录,才能区分没有应用与应用后又被改动。

容器又增加了一层边界:挂载方式、权限和命名空间都会影响可见性与写入范围。必须查询具体参数的文档;仅凭 net.* 这样的前缀,不能证明一次修改被隔离在容器内。不要为了让排查命令成功而临时扩大权限或重新挂载 procfs,否则诊断本身就改变了安全边界。

快速验证

在具有 procps-ng、且 procfs 可读的 Linux 环境运行下面的只读练习。它通过两个接口比较一个普通参数,再检查故意不存在的键是否被拒绝。它不枚举未知处理器、不加载配置、不写参数,也不验证重启后的持久性。

set -eu
sysctl --version
sysctl kernel.ostype
via_tool=$(sysctl -n kernel.ostype)
via_proc=$(cat /proc/sys/kernel/ostype)
test "$via_tool" = "$via_proc"
printf 'matching kernel type: %s\n' "$via_tool"
if sysctl -n kernel.xbcatm_audit_missing_key; then
    printf '%s\n' 'unexpected: negative-control key exists' >&2
    exit 1
else
    printf '%s\n' 'unknown key rejected as expected'
fi

预期出现 kernel.ostype = Linux、值一致的提示,以及未知键诊断和预期拒绝消息。如果 procfs 不存在或读取被拒绝,应停止,不要换成写入操作来“验证”。这个练习只验证观察路径与负向对照。尤其要注意,sysctl --system 和 sysctl -p 会实际应用设置,并不是配置预览命令,因此不应放进只读检查中。

来源