3、构建环境安全:使用非root用户构建、构建目录权限管理、校验源码包哈希值
好,咱们进入第三个实战环节。构建环境的安全,说白了就是「别让坏人碰你的构建过程」。我见过不少团队,Buildroot 直接拿 root 跑,目录权限全开,源码包随便下载——嗯,这种习惯一旦被利用,整个固件链都可能被污染。
今天聊三个核心点:非 root 用户构建、目录权限管理、源码包哈希校验。这三件事做好了,你的构建环境至少能挡住 80% 的常见攻击。
3.1 为什么不能用 root 构建?
你可能觉得:「我自己的机器,用 root 省事啊。」
我刚开始做嵌入式时也这么想。直到有一次,一个同事的构建脚本被植入了恶意代码,因为 root 权限跑构建,恶意脚本直接修改了系统级的 /usr/bin 下的工具链。那次事故导致整个团队花了三天排查问题。
用 root 构建的风险很直接:
- 权限过大:一旦构建脚本有漏洞,攻击者可以控制整个系统
- 文件污染:构建产物可能被篡改,而你很难发现
- 难以审计:root 做的操作,日志里很难区分是人为还是恶意
3.2 创建专用构建用户
我个人习惯是创建一个叫 builder 的普通用户,专门用来做构建。这样即使构建脚本出了问题,影响范围也仅限于这个用户的家目录。
创建用户的命令很简单:
# 创建用户,不创建家目录(我们用自定义目录)
sudo useradd -M builder
# 设置密码(可选,但建议设置)
sudo passwd builder
# 将 builder 加入必要的组(比如 docker 组,如果你用容器构建)
sudo usermod -aG docker builder
然后切换到 builder 用户:
sudo su - builder
cd /home/builder
git clone https://github.com/buildroot/buildroot.git
cd buildroot
make menuconfig
你看,所有操作都在普通用户权限下完成。即使 make 过程中有恶意脚本尝试写 /etc/passwd,它也会被系统拒绝。
umask 022,确保新创建的文件默认权限是 755(目录)或 644(文件),避免意外开放写权限。
3.3 构建目录权限管理
目录权限管理,说白了就是「谁可以读、谁可以写、谁可以执行」。Buildroot 构建过程中会生成大量中间文件,如果权限设置不当,很容易被篡改。
我建议的目录结构是这样的:
/home/builder/
├── buildroot/ # 源码目录,只读权限
├── dl/ # 下载的源码包,只读权限
├── output/ # 构建输出,读写权限
└── configs/ # 自定义配置文件,只读权限
设置权限的命令:
# 源码目录设为只读(对 builder 用户)
chmod 755 /home/builder/buildroot
chmod 755 /home/builder/dl
chmod 755 /home/builder/configs
# 输出目录设为可写
chmod 775 /home/builder/output
# 递归设置子目录
find /home/builder/buildroot -type d -exec chmod 755 {} \;
find /home/builder/output -type d -exec chmod 775 {} \;
为什么要这样分?
- 源码和配置只读:防止构建过程中被意外修改,也防止恶意脚本篡改
- 输出目录可写:构建产物需要写入,但建议定期清理
- 下载目录只读:下载完成后就锁定,防止被替换
3.4 校验源码包哈希值
这是最容易被忽视的一环。Buildroot 默认会从官方源下载源码包,但如果你用的是第三方源或者镜像站,源码包可能被篡改。
Buildroot 的哈希校验机制很简单:每个软件包在 package/<pkg>/ 目录下都有一个 .hash 文件,里面记录了源码包的 SHA256 值。
比如 package/busybox/busybox.hash:
# Locally computed:
sha256 a1d8f5a8a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5 busybox-1.36.1.tar.bz2
sha256 b2d8f5a8a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5a5 busybox-1.36.1.tar.bz2.sig
构建时,Buildroot 会自动计算下载文件的哈希值,与 .hash 文件对比。如果不匹配,构建会失败并报错。
但这里有个坑:如果你自己添加了第三方软件包,一定要手动生成 .hash 文件。我见过有人直接复制别人的 .hash 文件,结果哈希值对不上,构建失败后还以为是网络问题。
生成哈希值的命令:
# 下载源码包后,计算 SHA256
sha256sum my-package-1.0.tar.gz > package/my-package/my-package.hash
# 或者用 Buildroot 自带的工具
./support/download/dl-wrapper -p my-package -o /tmp/my-package.tar.gz
3.5 实战:配置 Buildroot 强制哈希校验
Buildroot 默认是开启哈希校验的,但你可以通过配置来加强它。我个人建议在 buildroot.conf 或 local.mk 中加入以下设置:
# 强制所有包都必须有 .hash 文件
BR2_DOWNLOAD_FORCE_CHECK_HASHES=y
# 如果哈希不匹配,直接终止构建(而不是警告)
BR2_DOWNLOAD_ABORT_ON_HASH_MISMATCH=y
# 使用更安全的哈希算法(默认是 SHA256,足够了)
BR2_TAR_OPTIONS="--no-same-owner --no-same-permissions"
然后在构建时,你可以用 make source-check 来提前检查所有源码包的哈希值:
make source-check
# 如果所有哈希都正确,会输出 "All packages OK"
# 如果有问题,会列出具体哪个包哈希不匹配
这个命令我每次构建前都会跑一遍。尤其是在使用 CI/CD 流水线时,把它作为第一步检查,能避免很多后期问题。
3.6 总结一下
构建环境安全,其实就三句话:
- 别用 root:创建一个专用构建用户,权限最小化
- 管好目录:源码只读,输出可写,下载目录锁定
- 校验哈希:每个源码包都要有对应的 .hash 文件,构建前检查一遍
这三件事做起来不难,但能挡住绝大多数供应链攻击。你想想看,如果攻击者连你的构建环境都进不去,他还怎么污染你的固件?
下一章,咱们聊聊「源码供应链安全:如何验证第三方软件包的完整性」。嗯,那个话题更有意思。