Label the filesystem for SELinux at build time
All checks were successful
build image / build (push) Successful in 25m5s
All checks were successful
build image / build (push) Successful in 25m5s
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) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XWRjNJMistCy6ngXH5aJLS
This commit is contained in:
41
README.md
41
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.
|
||||
|
||||
@@ -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" <<EOF
|
||||
# SELINUXTYPE= can take one of these values: targeted, minimum, mls
|
||||
SELINUXTYPE=targeted
|
||||
SELINUX=${SELINUX_MODE}
|
||||
EOF
|
||||
|
||||
if [ "$LABELLED" = 1 ]; then
|
||||
# Already labelled, so skip the first-boot relabel — it is several minutes
|
||||
# of USB-speed I/O to reproduce what we just did.
|
||||
rm -f "$ROOTFS/.autorelabel"
|
||||
else
|
||||
: > "$ROOTFS/.autorelabel"
|
||||
fi
|
||||
|
||||
mv "$ROOTFS/boot" "$WORK/boot"
|
||||
mkdir -p "$ROOTFS/boot"
|
||||
rm -rf "$WORK/boot/efi"
|
||||
|
||||
@@ -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}"
|
||||
|
||||
Reference in New Issue
Block a user