fix(kiosk): stop GDM covering the wall with a greeter after auto-login

Auto-login succeeded and the wall kept streaming, but about ten seconds
after the kiosk session came up GDM autospawned a greeter on the same GPU
and a login screen covered it. gnome-kiosk ships X-GDM-SessionRegisters=false,
so nothing ever registers and GDM concludes the display is still free — which
is why every remote check (loginctl, the mirror roster) stayed green while
the physical screen showed a password prompt.

Override that session file with the flag set to true, keeping the file name
and session id identical: inventing an id makes GDM quietly fall back to the
plain GNOME session, top bar and all.

Add a per-minute guard that reclaims the foreground VT, because this class
of failure is invisible from the outside, and have the checker assert both
the foreground VT and the greeter-session count. That count had a silent
false green: journalctl has no --no-legend, so the check read an empty
stream and passed unconditionally.

Also keep a copy of the payload in /usr/local/share/mirror-kiosk. /tmp is
cleared at every boot, which deletes the checker just after the one event
you are most likely to want to re-run it for.

Verified on the reference client: a cold boot now creates no greeter session
at all, the kiosk compositor and Firefox come up undisturbed, and a console
stolen with chvt is taken back within a minute.

LLM-Generated: true
This commit is contained in:
2026-11-01 19:46:17 -05:00
parent 32c6bc272b
commit 7d4bcf7e23
8 changed files with 254 additions and 20 deletions
+43 -8
View File
@@ -58,7 +58,7 @@ for c in rpm getent restorecon useradd sed awk grep install; do need "$c"; done
[ -f /etc/os-release ] && grep -q '^ID=fedora' /etc/os-release ||
say "warning: this does not look like Fedora; continuing anyway"
say "== 1/6 packages =="
say "== 1/7 packages =="
if rpm -q gnome-kiosk gnome-kiosk-script-session >/dev/null 2>&1; then
say "gnome-kiosk + gnome-kiosk-script-session already present"
else
@@ -69,7 +69,7 @@ else
say "layered the kiosk packages — a reboot is required before they exist"
fi
say "== 2/6 kiosk user =="
say "== 2/7 kiosk user =="
if id -u "$KIOSK_USER" >/dev/null 2>&1; then
HOME_DIR=$(getent passwd "$KIOSK_USER" | cut -d: -f6)
else
@@ -81,7 +81,7 @@ fi
KIOSK_GROUP=$(getent passwd "$KIOSK_USER" | cut -d: -f4)
say "user $KIOSK_USER uid=$(id -u "$KIOSK_USER") home=$HOME_DIR"
say "== 3/6 payload =="
say "== 3/7 payload =="
# Firefox enterprise policy: no update prompts, no account/sync, no telemetry,
# no first-run pages. /etc is mutable on Silverblue and survives upgrades.
install -D -m 0644 "$HERE/policies.json" /etc/firefox/policies/policies.json
@@ -93,6 +93,18 @@ say " /etc/firefox/policies/policies.json"
install -D -m 0644 "$HERE/window-config.ini" /usr/local/share/gnome-kiosk/window-config.ini
say " /usr/local/share/gnome-kiosk/window-config.ini"
# THE GREETER FIX. The shipped gnome-kiosk session sets X-GDM-SessionRegisters=
# false, so nothing ever registers with GDM and GDM concludes the display is
# still free: about eight seconds after auto-login it autospawns a full greeter
# session on the same GPU and a login screen covers the wall. The kiosk keeps
# running underneath, so loginctl and the mirror roster both still look healthy.
# Registering makes GDM treat the session as the display's owner. Keep the file
# name identical to the shipped one and change only that key — inventing a new
# session id makes GDM quietly fall back to the plain GNOME session.
install -D -m 0644 "$HERE/gnome-kiosk-script-wayland.desktop" \
/usr/local/share/wayland-sessions/gnome-kiosk-script-wayland.desktop
say " /usr/local/share/wayland-sessions/gnome-kiosk-script-wayland.desktop (registers with GDM)"
# `install -d` creates missing parents but leaves them owned by whoever is
# running the installer, which is how a kiosk ends up with a root-owned
# ~/.local and then spends its life logging "Permission denied" about
@@ -117,7 +129,7 @@ say " $HOME_DIR/.config/mirror/kiosk.conf -> $KIOSK_URL"
install -m 0644 -o "$KIOSK_USER" -g "$KIOSK_GROUP" /dev/null \
"$HOME_DIR/.config/gnome-initial-setup-done"
say "== 4/6 default session =="
say "== 4/7 default session =="
ACCT="/var/lib/AccountsService/users/$KIOSK_USER"
if [ -f "$ACCT" ]; then
set_ini "$ACCT" User Session "$KIOSK_SESSION"
@@ -129,7 +141,7 @@ fi
systemctl restart accounts-daemon.service 2>/dev/null || :
say " $ACCT Session=$KIOSK_SESSION"
say "== 5/6 auto-login =="
say "== 5/7 auto-login =="
if [ ! -d /etc/gdm ]; then
say " gdm is not installed — installing it"
rpm-ostree install gdm
@@ -144,13 +156,36 @@ if [ -d /etc/gdm ]; then
say " /etc/gdm/custom.conf: AutomaticLogin=$KIOSK_USER"
fi
say "== 6/6 selinux labels =="
say "== 6/7 console guard =="
# Cheap insurance against the class of bug above: if the kiosk session exists but
# something else holds the foreground VT, bring the wall back. Stops short of
# ever restarting gdm. Pause it while debugging the console with:
# sudo systemctl stop mirror-kiosk-console-guard.timer
install -D -m 0755 "$HERE/mirror-kiosk-console-guard" /usr/local/libexec/mirror-kiosk-console-guard
install -D -m 0644 "$HERE/mirror-kiosk-console-guard.service" /etc/systemd/system/mirror-kiosk-console-guard.service
install -D -m 0644 "$HERE/mirror-kiosk-console-guard.timer" /etc/systemd/system/mirror-kiosk-console-guard.timer
systemctl daemon-reload
systemctl enable --now mirror-kiosk-console-guard.timer
say " mirror-kiosk-console-guard.timer enabled"
# Keep a copy of the payload on the box. /tmp is cleared at every boot, so a
# checker staged there is gone precisely when you want to run it again — after a
# reboot, or from a rescue session hours later.
if [ "$HERE" != "/usr/local/share/mirror-kiosk" ]; then
install -d -m 0755 /usr/local/share/mirror-kiosk
cp -a "$HERE"/. /usr/local/share/mirror-kiosk/
say " /usr/local/share/mirror-kiosk (survives reboot; run check-kiosk.sh from here)"
fi
say "== 7/7 selinux labels =="
restorecon -RF "$HOME_DIR/.local" "$HOME_DIR/.config" 2>/dev/null || :
restorecon -RF /etc/firefox /usr/local/share/gnome-kiosk 2>/dev/null || :
restorecon -RF /etc/firefox /usr/local/share/gnome-kiosk /usr/local/share/wayland-sessions \
/usr/local/libexec 2>/dev/null || :
say ""
say "Installed."
[ "$NEED_REBOOT" -eq 1 ] && say "NEXT: sudo reboot (new RPMs are only in the new deployment)"
say "Then, to start the kiosk now (this closes anything on the console):"
say " sudo systemctl restart gdm"
say "Check it with: sh check-kiosk.sh"
say "Check it with (this path survives reboots):"
say " sudo sh /usr/local/share/mirror-kiosk/check-kiosk.sh"