Hacktoberfest 2026: le issue che i maintainer hanno segnato per ottobre, aperte e adatte ai principianti. Sfoglia le issue Hacktoberfest

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

Aperta Adatta ai principianti
#2,927 0 commenti 0 reazioni 0 assegnatari Vedi su GitHub

Nessuno ha ancora preso questa issue.

Valutazione

Difficoltà
2/5
Tempo stimato
1-3 ore
Idoneità per principianti
72/100
Tipo di issue
Bug
Chiarezza
Specificata chiaramente
Stato di attività
Attiva
Stack tecnologico
bash, linux, shell

Direzione di ricerca

La correzione si trova nella funzione cleanup_chroot_at() in /usr/bin/holo-chroot, intorno alla riga 246, dove l'ultimo rmdir $dir, alla riga 281, non è protetto mentre tutti gli altri comandi usano || :. Riproduci il problema con un mountpoint occupato sotto /efi del chroot mentre viene eseguito il comando nel chroot, quindi verifica che lo stato di uscita sia 1 nonostante il successo. È completato quando, in quel caso, lo stato di uscita del comando eseguito nel chroot viene preservato e, facoltativamente, viene stampato un avviso quando la directory rimane presente.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Descrizione

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.

Lingua principale
Nessun dato sulla lingua
Stelle
2.6k
Fork
85
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Preparare l'ambiente

Questo progetto non fornisce container di sviluppo, Dockerfile né guida per i contributori, quindi l'ambiente è a tuo carico: parti dal suo README e consulta la nostra guida al primo contributo per i passaggi generali.

Come iniziare

  1. Leggi tutta la issue e poi la guida ai contributi del progetto.
  2. Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
  3. Fai un fork del repository e lavora su un branch.
  4. Apri una pull request che faccia riferimento al numero della issue.

Altre issue di ValveSoftware/SteamOS

Tutte le issue di ValveSoftware/SteamOS

Issue simili

Altre issue su CLI

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.