Hacktoberfest 2026:メンテナが10月に向けて印を付けた、オープンで初心者向けの issue。 Hacktoberfest の issue を見る

holo-chroot/steamos-chroot: unguarded rmdir in the EXIT trap discards the chrooted command's exit status

オープン 初心者向け
#2,927 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

まだ誰も着手していません。

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
72/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
bash, linux, shell

調査の方向性

修正箇所は /usr/bin/holo-chroot の cleanup_chroot_at() 関数、246行目付近です。281行目の最後の rmdir $dir だけが保護されておらず、他のすべてのコマンドは || : で保護されています。chroot の /efi 配下でビジーなマウントポイントを開いたままchroot内のコマンドを実行して再現し、成功したにもかかわらず終了ステータスが 1 になることを確認してください。その場合にchroot内コマンドの終了ステータスが保持され、ディレクトリが残されたときにオプションで警告が表示されれば完了です。

索引モデルが issue の本文から書いたものです。

説明

Your system information
  • Steam client version: n/a — this is a defect in a shell script shipped in steamos-customizations-jupiter, not in the client
  • SteamOS version: reproduced by inspection against steamos-customizations-jupiter 20260916.1-1, the newest build in jupiter-main at time of writing. Observed in the wild on a steamdeck-oobe-repair recovery image (linux-neptune-616, e2fsprogs 1.47.3)
  • Opted into Steam client beta?: No
  • Opted into SteamOS beta?: No
  • Have you checked for updates in Settings > System?: Yes — the affected line is unchanged in the latest package
Please describe your issue in as much detail as possible

holo-chroot (steamos-chroot) can exit 1 after the chrooted command has fully succeeded, because the final rmdir in its EXIT trap is unguarded.

/usr/bin/holo-chroot runs under set -euo pipefail (line 17) and does its teardown from an EXIT trap:

284  CHROOTDIR=$(mktemp -d)
285  trap "cleanup_chroot_at $CHROOTDIR" EXIT
286
287  prepare_chroot_at $CHROOTDIR
288  chroot $CHROOTDIR "$@"

Inside cleanup_chroot_at() (line 246) every single command is guarded with || : — all eleven umounts, the flocks, and even the other rmdir at line 263:

263                  rmdir "$DEV_DIR" || :
...
270      umount $dir/var  || :
271      umount $dir/esp  || :
272      umount $dir/efi  || :
273      umount $dir/tmp  || :
274      umount $dir/sys/firmware/efi/efivars || :
275      umount -R $dir/sys  || :
276      umount $dir/run  || :
277      umount -R $dir/proc || :
278      umount $dir/dev  || :
279      umount $dir      || :
280
281      rmdir $dir          # <-- the only unguarded command in the function

So if any of those mountpoints is busy at teardown time, the umounts are tolerated as intended, but $dir is then necessarily non-empty, rmdir fails, and — because the script runs under set -e — errexit fires from inside the EXIT trap. The shell exits with rmdir's status and the exit status of chroot $CHROOTDIR "$@" is discarded.

The consequence is that any caller which checks steamos-chroot's exit status sees a spurious failure for work that actually completed. Here is a real instance, where update-grub demonstrably succeeded and steamos-chroot still exited 1:

+ steamos-chroot --no-overlay --disk /dev/sdb --partset A -- update-grub
Generating grub configuration file ...
Found linux image: /boot/vmlinuz-linux-neptune-616
Found initrd image: /boot/amd-ucode.img /boot/initramfs-linux-neptune-616.img
Adding boot menu entry for UEFI Firmware Settings ...
done
Installing grub configuration file at /efi/EFI/steamos/grub.cfg
umount: /tmp/tmp.h5fd9aSs2I/efi: target is busy.
umount: /tmp/tmp.h5fd9aSs2I: target is busy.
rmdir: failed to remove '/tmp/tmp.h5fd9aSs2I': Device or resource busy

update-grub wrote its config and reported done; the only failures are in the teardown. An installer calling this in a sequence of steps aborts here, mid-install.

That set -e-inside-a-trap behaviour is easy to miss, so to be explicit about the mechanism:

$ bash -c 'set -e; cleanup() { rmdir /nonexistent; echo AFTER; }; trap cleanup EXIT; true'; echo $?
rmdir: failed to remove '/nonexistent': No such file or directory
1

AFTER never prints — errexit aborts from within the trap — and the script's status becomes 1 despite the body having succeeded. Removing set -e, or adding || :, both yield 0.

Steps for reproducing this issue
  1. Arrange for one of the chroot's mountpoints to be busy at teardown. Any of them will do; the simplest synthetic version is to hold a reference open while the chroot exits, e.g. run steamos-chroot --no-overlay --disk $DISK --partset A -- update-grub while another process has a file open under the chroot's /efi.
  2. Observe that the chrooted command completes and prints its normal success output.
  3. Observe that steamos-chroot nonetheless exits 1, with the only errors being umount: ... target is busy followed by rmdir: failed to remove ...: Device or resource busy.
Suggested fix

Guard it like everything else in the function, which also keeps it consistent with line 263:

-    rmdir $dir
+    rmdir $dir || :

Optionally warn so the leftover directory isn't silently abandoned:

rmdir $dir || echo >&2 "warning: left $dir behind; something is still using it"

Either way the exit status of the chrooted command is preserved, which is what callers rely on.

Note that why a mountpoint is busy is a separate question, and arguably a legitimate thing for a caller to have to deal with. This report is only about the teardown clobbering an otherwise successful exit status — a busy mountpoint shouldn't turn a completed operation into a failed one.


Found via a third-party SteamOS installer that calls steamos-chroot in sequence and checks each step: louij2/steamos_custom_install#12. Happy to supply more detail if useful.

主要言語
言語のデータがありません
スター
2.6k
フォーク
85
PR マージ指標
30日以内にマージされた PR はありません

環境構築

このプロジェクトには開発コンテナ、Dockerfile、コントリビューションガイドがありません。まず README を読み、一般的な手順ははじめてのコントリビューションガイドを参照してください。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

ValveSoftware/SteamOS のほかの issue

ValveSoftware/SteamOS の issue をすべて見る

似ている issue

CLI の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。