From 482c5d9c9a336c0bcd3d7e566a3fa7db1a8d0900 Mon Sep 17 00:00:00 2001 From: rob thijssen Date: Mon, 27 Jul 2026 18:05:28 +0300 Subject: [PATCH] Label the filesystem for SELinux at build time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The image booted. Kernel came up, the device tree loaded — UFS, display, WiFi and IPA all probed as platform devices — framebuffer console came up, root mounted off USB and systemd started. Then: systemd[1]: Unable to fix SELinux security context of /dev/tty..: Permission denied (x hundreds) systemd[1]: Too many messages being logged to kmsg, ignoring [!!!!!!] Failed to allocate manager object. The filesystem had no SELinux labels. mke2fs -d carries security.* xattrs across faithfully, but nothing had ever set them: the tree came from dnf, not from a running SELinux system. I had relied on /.autorelabel, which cannot work here — PID 1 dies long before anything acts on the flag. Label the tree with setfiles instead, after the bind mounts are torn down (or it would walk the builder's /proc) and before /boot is split out, so /boot's files are labelled along with everything else. Verified in a privileged container beforehand that security.selinux xattrs can actually be written through a bind mount, rather than assuming it. I had listed policycoreutils in the gongfoo build base for exactly this and then never called setfiles. It is now also in stage2's fallback toolchain, so the stock-Fedora path works too. Ship permissive regardless. The labels make enforcing viable, but the failure mode is unusually punishing — no login prompt, no shell, nothing to repair from — and on a machine this awkward to reach that is not a default worth choosing. SELINUX_MODE in config/device.env flips it. Co-Authored-By: Claude Opus 5 (1M context) Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS --- README.md | 41 +++++++++++++++++++++++++++++++++------ build/stage2.sh | 49 +++++++++++++++++++++++++++++++++++++++++++---- config/device.env | 9 +++++++++ 3 files changed, 89 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index e4940dc..ff1a6fd 100644 --- a/README.md +++ b/README.md @@ -122,11 +122,40 @@ docs/ Installation, firmware, runner setup - [docs/firmware.md](docs/firmware.md) — what needs extracting from Windows and why - [docs/runner-setup.md](docs/runner-setup.md) — one-time Gitea runner preparation +## Boot status + +Confirmed on hardware, from a USB stick: + +- GRUB loads the kernel and the device tree +- The kernel comes up and probes the SDM850 — UFS controller, display + subsystem, WiFi and IPA all appear as platform devices, so + `DEVICE_CMDLINE` and the DTB are right +- The framebuffer console works (`simple-framebuffer`, 240x67) +- The root filesystem mounts and systemd starts + +Not yet confirmed: reaching a login prompt, and anything past it. SELinux is +shipped permissive — see below. + +### SELinux + +The build labels the filesystem offline with `setfiles`, so enforcing should +work. It ships **permissive** anyway, because the failure mode is unusually +punishing: an unlabelled root takes PID 1 down with `Failed to allocate manager +object` before anything can be logged into and repaired, and `/.autorelabel` +cannot save it because nothing survives long enough to act on the flag. + +Once the machine is up and you are happy with it: + +```sh +sudo setenforce 1 # try it for this boot +sudo sed -i 's/^SELINUX=.*/SELINUX=enforcing/' /etc/selinux/config +``` + +Or set `SELINUX_MODE=enforcing` in `config/device.env` and rebuild. + ## Caveats -The build has not yet been confirmed to boot on real hardware. The device tree, -kernel command line and firmware layout are taken from Fedora's Snapdragon WoA -documentation and the aarch64-laptops project; the parts specific to the C630's -older SDM850 are reasoned from those rather than tested. Expect to spend a boot -or two adjusting `DEVICE_CMDLINE` in `config/device.env`. Findings belong in -this README. +The kernel command line and firmware layout are taken from Fedora's Snapdragon +WoA documentation and the aarch64-laptops project; the parts specific to the +C630's older SDM850 are reasoned from those rather than derived from +documentation for this machine. Findings belong in this README. diff --git a/build/stage2.sh b/build/stage2.sh index ebd2196..f8b373c 100755 --- a/build/stage2.sh +++ b/build/stage2.sh @@ -73,13 +73,14 @@ find "$WORK" -mindepth 1 -maxdepth 1 \ # becomes a no-op. Only a stock Fedora image pays for it. # --------------------------------------------------------------------------- if command -v mke2fs >/dev/null && command -v mcopy >/dev/null \ - && command -v sgdisk >/dev/null && command -v zstd >/dev/null; then + && command -v sgdisk >/dev/null && command -v setfiles >/dev/null; then echo "build tooling already present in the container image" else log "Installing build tooling into the container" dnf -y install --setopt=install_weak_deps=False \ --setopt=cachedir="$DNF_CACHE" --setopt=keepcache=1 \ e2fsprogs dosfstools mtools gdisk util-linux rsync zstd findutils \ + policycoreutils \ >/dev/null fi @@ -261,9 +262,8 @@ printf 'root=UUID=%s ro %s\n' "$ROOT_UUID" "$DEVICE_CMDLINE" \ ln -sf ../run/systemd/resolve/stub-resolv.conf "$ROOTFS/etc/resolv.conf" echo "$DEVICE_NAME" > "$ROOTFS/etc/hostname" -# mke2fs -d does not reliably carry SELinux labels across, and the builder has -# no policy loaded anyway. Relabel on first boot. -: > "$ROOTFS/.autorelabel" +# SELinux labelling happens later, once the bind mounts are gone — see +# "Labelling the filesystem for SELinux" below. # --------------------------------------------------------------------------- log "Configuring the target system" @@ -399,6 +399,47 @@ for d in dev/pts dev sys proc; do fi done +# --------------------------------------------------------------------------- +log "Labelling the filesystem for SELinux" +# --------------------------------------------------------------------------- +# mke2fs -d builds the filesystem from a directory tree and carries security.* +# xattrs across, but nothing has set them: the tree came out of dnf, not out of +# a running SELinux system. Boot an unlabelled root and systemd cannot set a +# context on anything under /dev, logs a screenful of "Permission denied", and +# dies with "Failed to allocate manager object". /.autorelabel does not rescue +# it — PID 1 never survives long enough to act on the flag. +# +# So label it here, after the bind mounts are gone (or setfiles would walk the +# builder's /proc) and before /boot is split out, so /boot's files are labelled +# with everything else. +FILE_CONTEXTS="$ROOTFS/etc/selinux/targeted/contexts/files/file_contexts" +LABELLED=0 +if [ -f "$FILE_CONTEXTS" ] && command -v setfiles >/dev/null; then + if setfiles -F -r "$ROOTFS" "$FILE_CONTEXTS" "$ROOTFS"; then + LABELLED=1 + echo "filesystem labelled" + else + echo "warning: setfiles failed — falling back to a first-boot relabel" >&2 + fi +else + echo "warning: no SELinux policy or no setfiles in this container" >&2 +fi + +mkdir -p "$ROOTFS/etc/selinux" +cat > "$ROOTFS/etc/selinux/config" < "$ROOTFS/.autorelabel" +fi + mv "$ROOTFS/boot" "$WORK/boot" mkdir -p "$ROOTFS/boot" rm -rf "$WORK/boot/efi" diff --git a/config/device.env b/config/device.env index 5a6fbcb..59bf53f 100644 --- a/config/device.env +++ b/config/device.env @@ -44,6 +44,15 @@ : "${FEDORA_RELEASE:=44}" : "${TARGET_ARCH:=aarch64}" +# --- selinux ------------------------------------------------------------ +# The build labels the filesystem offline with setfiles, so enforcing is +# viable. It ships permissive anyway: an unlabelled or mislabelled filesystem +# takes PID 1 down with "Failed to allocate manager object" before anything can +# be logged in and fixed, and on a machine this awkward to debug that trade is +# not worth making by default. Switch with `sudo setenforce 1` once it is up, +# or set this to enforcing and rebuild. +: "${SELINUX_MODE:=permissive}" + # --- default account ---------------------------------------------------- # Password is expired at first login, so it must be changed immediately. : "${DEFAULT_USER:=fedora}"