Hacktoberfest 2026: los issues que los mantenedores marcaron para octubre, abiertos y aptos para principiantes. Explorar issues de Hacktoberfest

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

Abierto Apto para principiantes
#2,927 0 comentarios 0 reacciones 0 asignados Ver en GitHub

Nadie ha tomado este issue todavía.

Evaluación

Dificultad
2/5
Tiempo estimado
1-3 horas
Aptitud para principiantes
72/100
Tipo de issue
Error
Claridad
Bien especificado
Estado de actividad
Activo
Stack tecnológico
bash, linux, shell

Línea de trabajo

La corrección está en la función cleanup_chroot_at() de /usr/bin/holo-chroot, alrededor de la línea 246, donde el rmdir $dir final de la línea 281 no está protegido, mientras que todos los demás comandos usan || :. Reproduce el problema con un punto de montaje ocupado bajo /efi del chroot mientras se ejecuta el comando dentro del chroot, y luego confirma que el código de salida es 1 a pesar del éxito. Está terminado cuando el código de salida del comando dentro del chroot se conserva en ese caso y se imprime una advertencia opcional cuando el directorio queda sin eliminar.

Escrito por el modelo de indexación a partir del texto del issue.

Descripción

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.

Lenguaje dominante
Sin datos de lenguaje
Estrellas
2.6k
Forks
85
Métricas de merge de PR
Sin PR fusionados en 30 d

Preparar el entorno

Este proyecto no incluye contenedor de desarrollo, Dockerfile ni guía de contribución, así que la configuración corre por tu cuenta: empieza por su README y consulta nuestra guía para la primera contribución para los pasos generales.

Primeros pasos

  1. Lee el issue completo y luego la guía de contribución del proyecto.
  2. Comenta en el issue que vas a ocuparte — evita que dos personas hagan lo mismo.
  3. Haz un fork del repositorio y trabaja en una rama.
  4. Abre un pull request que haga referencia al número del issue.

Más de ValveSoftware/SteamOS

Todos los issues de ValveSoftware/SteamOS

Issues similares

Más issues de CLI

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.