Devtools chroot 被用户 run 目录污染事件
概况
2019年12月1日凌晨一点,lilydjwg 收到多封 lilac 的报错。错误信息如下:
==> ERROR: '/var/lib/archbuild/extra-x86_64/root' does not appear to be an Arch chroot.
==> ERROR: Aborting...
随后发现几乎所有 lilac 包都遇到此错误。调查发现 /var/lib/archbuild/extra-x86_64/root 下有一个已挂载的系统 /run 目录,里边包含一些用户 run 目录的挂载。
事故调查
根据目录中残留的文件确定时间戳:
1712 (archlinuxcn-build-e5) /var/lib/archbuild/extra-x86_64
### stat root
文件:root
大小:60 块:0 IO 块:4096 目录
设备:2dh/45d Inode:66952 硬链接:3
权限:(0755/drwxr-xr-x) Uid:( 0/ root) Gid:( 0/ root)
最近访问:2019-11-30 23:43:32.647435418 +0800
最近更改:2019-11-30 23:43:11.560712233 +0800
最近改动:2019-11-30 23:43:11.560712233 +0800
创建时间:-
1713 (archlinuxcn-build-e5) /var/lib/archbuild/extra-x86_64
### stat root.lock
文件:root.lock
大小:0 块:0 IO 块:4096 普通空文件
设备:2dh/45d Inode:70381120 硬链接:1
权限:(0644/-rw-r--r--) Uid:( 0/ root) Gid:( 0/ root)
最近访问:2019-11-30 23:43:36.414112131 +0800
最近更改:2019-12-01 01:47:50.312800053 +0800
最近改动:2019-12-01 01:47:50.312800053 +0800
创建时间:-
然后分析 journalctl 日志。
事件线
- Nov 25 20:46:27 system boot
- Nov 25 20:50:41 megumifox extra-x86_64-build
- Nov 25 20:51:04 megumifox initilizing root chroot
- Nov 25 20:51:04 a-wing run acquire
- Nov 25 20:51:09 a-wing run release
- Nov 25 20:51:09 root chroot release, axionl sees umount of run, others see umount of a-wing's run
- Nov 25 22:22:34 yan12125 run release, root/run already polluted
- Nov 30 23:42:32 dctxmei login
- Nov 30 23:43:11 dctxmei extra-x86_64-build -c
- Nov 30 23:43:32 dctxmei extra-x86_64-build -c
run acquire 表示用户的 run 目录被挂载,run release 表示被卸载。
在开机后不久,由于 /var/lib/archbuild 目录为空,devtools 会开始建立新的 root chroot。这时刚好 a-wing 登录,导致 run 目录的挂载事件被扩散到 chroot 内。数天后,dctxmei 使用 -c 参数重建 root chroot 时失败,问题显现。
解决方案
临时
umount -l 有问题的 run 目录,然后 rm -r --one-file-system 删除整个 extra-x86_64。
长期
修改 devtools-archlinuxcn 中的 mkarchroot 脚本,在调用 pacstrap 时使用 unshare 以避免系统的挂载扩散进去。
diff -Naur a/usr/bin/mkarchroot b/usr/bin/mkarchroot
--- a/usr/bin/mkarchroot 2019-11-19 16:26:19.000000000 +0800
+++ b/usr/bin/mkarchroot 2019-12-01 18:04:51.762383615 +0800
@@ -332,7 +332,7 @@
cp "$file" "$working_dir$file"
done
-pacstrap -Mcd ${pac_conf:+-C "$pac_conf"} "$working_dir" \
+unshare -m pacstrap -Mcd ${pac_conf:+-C "$pac_conf"} "$working_dir" \
"${cache_dirs[@]/#/--cachedir=}" "$@" || die 'Failed to install all packages'
printf '%s.UTF-8 UTF-8\n' en_US de_DE > "$working_dir/etc/locale.gen"
类似事故
前不久发现过一起类似的事故,由于当时 build-cleaner 清理脚本未做跨文件系统的检查,直接导致 system D-Bus 的 socket 文件被删除,进而计划重启。
- Nov 18 21:30:10 felix run acquire
- Nov 18 22:02:32 felix extra-x86_64-build start
- Nov 18 22:06:20 felix extra-x86_64-build end
- Nov 18 22:14:23 felixonmars2 run acquire
- Nov 18 22:22:06 felix chroot release without /run
- Nov 18 22:27:16 yan12125 run acquire
- Nov 18 22:31:45 yan12125 run release, felixonmars2/run & felix/run already polluted
- Nov 18 22:57 felixonmars2 chroot known broken with tmp
- Nov 19 01:41:33 yan12125 run acquire
- Nov 19 02:48:52 yan12125 run release
- Nov 19 09:42:57 felixonmars2 chroot release
- Nov 19 09:43:07 felixonmars2 logout
- Nov 19 09:43:07 felix logout
- Nov 19 09:43:07 felix run release
- Nov 19 09:43:07 felixonmars2 run release
- Nov 19 09:57 felixonmars2 chroot recovered
- Nov 19 09:57 felix chroot known broken with /run 1053 (felixonmars3)
- Nov 20 13:29:10 felix still has processes running
- Nov 25 20:44:07 felixonmars3 logout
事故一开始是 felixonmars2 的 chroot 中包含已挂载的 tmp 目录从而清理失败。到第二天上午的时候,登出导致该 chroot 下的诸多文件系统被卸载,此 chroot 恢复正常。然而 felix chroot 依旧有问题,直接后来手工卸载。
几个疑点:
- felixonmars2 chroot 为什么隔了数小时才开始卸载?此时锁文件为什么没有被上锁?是使用该 chroot 的进程有泄漏吗?
- felix chroot 的 run 目录为什么会被挂载在外面的 mount ns?除了 root chroot 之外,用户的 chroot 应当只会通过 arch-nspawn 使用 systemd-nspawn,其挂载是私有的,也没有看到有 bind mount /run 的地方。
外部链接
- devtools 上游的 bug 报告:FS#64698