From 6c3c33e4ae6122d2121701f67ec7b9124fe55ec4 Mon Sep 17 00:00:00 2001 From: Breadway Date: Sun, 14 Jun 2026 04:13:10 +0800 Subject: [PATCH] Run the live session as an unprivileged user (Hyprland won't run as root) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The live medium autologged root on tty1 and exec'd Hyprland, but Hyprland refuses to start with superuser privileges ("launched with superuser privileges, but the privileges check is not omitted") and exited before even creating a log — leaving tty1 at a blank blinking cursor. (Boot, switch-root, firstboot suppression and the bos login on other ttys were all already working.) Adopt the standard live-ISO pattern: - bos-live-setup.service (oneshot, gated on the archisobasedir cmdline so it only runs on the live medium) creates an unprivileged `liveuser`, adds it to the usual hardware groups, clears its password, and drops in a minimal live Hyprland config that auto-launches the installer. - tty1 autologin now targets liveuser instead of root. - Calamares needs root, so bos-launch-calamares runs it via passwordless sudo (/etc/sudoers.d/99-bos-live) with the Wayland env preserved, so the root installer renders on the live user's compositor. Co-Authored-By: Claude Opus 4.8 --- iso/airootfs/etc/sudoers.d/99-bos-live | 3 ++ .../etc/systemd/system/bos-live-setup.service | 14 +++++ .../getty@tty1.service.d/autologin.conf | 2 +- .../bos-live-setup.service | 1 + .../usr/local/bin/bos-launch-calamares | 7 +++ iso/airootfs/usr/local/bin/bos-live-setup | 54 +++++++++++++++++++ iso/profiledef.sh | 3 ++ 7 files changed, 83 insertions(+), 1 deletion(-) create mode 100644 iso/airootfs/etc/sudoers.d/99-bos-live create mode 100644 iso/airootfs/etc/systemd/system/bos-live-setup.service create mode 120000 iso/airootfs/etc/systemd/system/multi-user.target.wants/bos-live-setup.service create mode 100644 iso/airootfs/usr/local/bin/bos-launch-calamares create mode 100644 iso/airootfs/usr/local/bin/bos-live-setup diff --git a/iso/airootfs/etc/sudoers.d/99-bos-live b/iso/airootfs/etc/sudoers.d/99-bos-live new file mode 100644 index 0000000..591d9b9 --- /dev/null +++ b/iso/airootfs/etc/sudoers.d/99-bos-live @@ -0,0 +1,3 @@ +# Live medium only: the unprivileged live user may escalate without a password +# so the installer (Calamares) can run as root from the Wayland session. +liveuser ALL=(ALL) NOPASSWD: ALL diff --git a/iso/airootfs/etc/systemd/system/bos-live-setup.service b/iso/airootfs/etc/systemd/system/bos-live-setup.service new file mode 100644 index 0000000..22e91f5 --- /dev/null +++ b/iso/airootfs/etc/systemd/system/bos-live-setup.service @@ -0,0 +1,14 @@ +[Unit] +Description=Set up the BOS live user and session +# Only on the live medium — the installed system has no archisobasedir cmdline. +ConditionKernelCommandLine=archisobasedir +Before=getty@tty1.service +After=systemd-tmpfiles-setup.service + +[Service] +Type=oneshot +RemainAfterExit=yes +ExecStart=/usr/local/bin/bos-live-setup + +[Install] +WantedBy=multi-user.target diff --git a/iso/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf b/iso/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf index b9d22eb..b10ceb2 100644 --- a/iso/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf +++ b/iso/airootfs/etc/systemd/system/getty@tty1.service.d/autologin.conf @@ -1,3 +1,3 @@ [Service] ExecStart= -ExecStart=-/sbin/agetty -o '-p -f -- \\u' --noclear --autologin root - $TERM +ExecStart=-/sbin/agetty -o '-p -f -- \\u' --noclear --autologin liveuser - $TERM diff --git a/iso/airootfs/etc/systemd/system/multi-user.target.wants/bos-live-setup.service b/iso/airootfs/etc/systemd/system/multi-user.target.wants/bos-live-setup.service new file mode 120000 index 0000000..a8d5e7d --- /dev/null +++ b/iso/airootfs/etc/systemd/system/multi-user.target.wants/bos-live-setup.service @@ -0,0 +1 @@ +../bos-live-setup.service \ No newline at end of file diff --git a/iso/airootfs/usr/local/bin/bos-launch-calamares b/iso/airootfs/usr/local/bin/bos-launch-calamares new file mode 100644 index 0000000..d7f3fe9 --- /dev/null +++ b/iso/airootfs/usr/local/bin/bos-launch-calamares @@ -0,0 +1,7 @@ +#!/bin/sh +# Launch Calamares as root on the live user's Wayland session. +# Calamares performs partitioning/bootloader work and needs root; the live user +# has passwordless sudo (see /etc/sudoers.d/99-bos-live). We preserve the Wayland +# environment so the root process renders on the user's compositor. +export QT_QPA_PLATFORM=wayland +exec sudo --preserve-env=WAYLAND_DISPLAY,XDG_RUNTIME_DIR,QT_QPA_PLATFORM calamares diff --git a/iso/airootfs/usr/local/bin/bos-live-setup b/iso/airootfs/usr/local/bin/bos-live-setup new file mode 100644 index 0000000..8944865 --- /dev/null +++ b/iso/airootfs/usr/local/bin/bos-live-setup @@ -0,0 +1,54 @@ +#!/bin/bash +# Create the unprivileged BOS live user and its Hyprland session. +# +# Hyprland refuses to run as root (superuser-privileges check), so the live +# session must run as a normal user. Calamares — which does need root — is +# launched onto the user's Wayland socket via passwordless sudo (see +# bos-launch-calamares). Runs once at boot, before the tty1 autologin getty. +set -e + +if ! id liveuser &>/dev/null; then + useradd -m -s /bin/bash liveuser + for g in wheel video input audio storage power; do + getent group "$g" >/dev/null 2>&1 && gpasswd -a liveuser "$g" >/dev/null || true + done + passwd -d liveuser >/dev/null +fi + +install -d -m 0700 -o liveuser -g liveuser /home/liveuser/.config/hypr + +# Minimal live compositor config: auto-launch the installer. +cat >/home/liveuser/.config/hypr/hyprland.conf <<'EOF' +monitor=,preferred,auto,1 + +exec-once = bos-launch-calamares + +general { + border_size = 2 + col.active_border = rgba(88c0d0ff) + col.inactive_border = rgba(4c566aff) +} +decoration { rounding = 4 } +input { + kb_layout = us + follow_mouse = 1 +} +misc { + disable_hyprland_logo = true + disable_splash_rendering = true +} +EOF + +# Start Hyprland on tty1 login; capture output and fall back to a shell so a +# failed compositor start is visible rather than a blank looping cursor. +cat >/home/liveuser/.bash_profile <<'EOF' +if [[ "$(tty)" == /dev/tty1 ]] && [[ -z "$WAYLAND_DISPLAY" ]]; then + export WLR_RENDERER_ALLOW_SOFTWARE=1 + export WLR_NO_HARDWARE_CURSORS=1 + Hyprland &>/var/log/hyprland-live.log + echo "Hyprland exited (rc=$?). Log: /var/log/hyprland-live.log" + exec bash -i +fi +EOF + +chown -R liveuser:liveuser /home/liveuser diff --git a/iso/profiledef.sh b/iso/profiledef.sh index 0085552..1d1e595 100644 --- a/iso/profiledef.sh +++ b/iso/profiledef.sh @@ -15,5 +15,8 @@ airootfs_image_type="squashfs" airootfs_image_tool_options=('-comp' 'xz' '-Xbcj' 'x86' '-b' '1M' '-Xdict-size' '1M') file_permissions=( ["/etc/shadow"]="0:0:400" + ["/etc/sudoers.d/99-bos-live"]="0:0:440" ["/etc/calamares/post-install.sh"]="0:0:755" + ["/usr/local/bin/bos-live-setup"]="0:0:755" + ["/usr/local/bin/bos-launch-calamares"]="0:0:755" )