Mount the rootfs read-only on both images

The rootfs mounted read-write, so a slot ran with its own files open to
change, and the factory-slot mounts rode along on the release image.
Both images now carry the read-only-rootfs feature: the ro root line and
the rcS default, the volatile links made at rootfs time, a writable copy
of /var/lib at boot, a build failure for a post-install that needs the
machine, and the removal of shadow, base-passwd, update-rc.d and
update-alternatives.

What must last or change at run time is handled file by file:

- forgefirm-users renders the four account files from the record into
  /run/forgefirm/accounts and bind-mounts each copy over its /etc file
  (useradd and the rest are gone with shadow); a render writes through
  the mount, and the image's own files apply until the first render.
- forgefirm-banner bind-mounts a copy of /etc/issue and writes the
  address block through it.
- sshd keeps its host keys under /data/forgefirm/ssh, so the fingerprint
  survives updates; both sshd configs carry the same HostKey lines.
- forgefirm-logging passes logrotate a state file under /var/run
  (logrotate refuses to run without one).
- forgefirm-persist points the boot timestamp and the random seed at
  /data/forgefirm.

The dev image appends the /factory slot mounts, without nofail (busybox
mount hands it to the kernel, which rejects it). The rootfs command
entries lose their semicolons: on scarthgap the value is the task's
vardeps, split on whitespace, so "name;" left the function body out of
the signature and a changed body did not remake the rootfs; with the
bodies tracked, the dev image's DATETIME string needs a vardepsexclude.
release.sh gains the read-only gate (root ro, no /factory line,
ROOTFS_READ_ONLY=yes, host keys on /data). image.health checks the
mounts, the account binds, the banner bind, the host keys and the
dev-only /factory mounts.

Proven on the bench reference (dev image 20260909140901): / ro, /data
rw, /var/lib a tmpfs copy, the four account files and /etc/issue bound
from tmpfs, the host keys in /data/forgefirm/ssh, no "Read-only file
system" line in any log; forgectrl.auth and commission.account-login (a
temporary account rendered, logged in over HTTPS and removed again),
kernel.latch-locked-idle and motion.liveness-probe PASS; logrotate runs
with the volatile state. forgetest unit tests 335 OK; both images build
clean, and debugfs on the built rootfs shows every setting above.
This commit is contained in:
ScottW514
2026-09-09 11:02:10 -04:00
parent 2936890eaa
commit 8af8b197ee
14 changed files with 309 additions and 79 deletions
@@ -43,6 +43,10 @@ IMAGE_ROOTFS_EXTRA_SPACE = "262144"
# Dev builds identify by build timestamp (matches the artifact name),
# tagged so a bench machine is never mistaken for a release.
FORGEFIRM_VERSION_STRING = "${DATETIME} (dev)"
# The rootfs functions that write the string are in the do_rootfs
# signature; DATETIME must not be, or the basehash changes at every parse
# and bitbake refuses the build as non-deterministic.
FORGEFIRM_VERSION_STRING[vardepsexclude] += "DATETIME"
# /etc/forgefirm-dev marks a dev image on the rootfs; its content is the
# version string. The sshd init script starts sshd on a dev image without
@@ -52,4 +56,20 @@ write_forgefirm_dev_marker() {
echo "${FORGEFIRM_VERSION_STRING}" > ${IMAGE_ROOTFS}${sysconfdir}/forgefirm-dev
}
write_forgefirm_dev_marker[vardepsexclude] += "DATETIME"
ROOTFS_POSTPROCESS_COMMAND += "write_forgefirm_dev_marker;"
ROOTFS_POSTPROCESS_COMMAND += "write_forgefirm_dev_marker "
# The two factory rootfs slots, read-only under /factory/img1 and
# /factory/img2: a bench convenience for reading a factory image in place
# (the ffboot inventory reuses the mounts). The release image mounts no
# factory slot; it reads one through a temporary read-only mount when it
# needs to (ffboot -l). No nofail: busybox mount hands it to the kernel
# as a filesystem parameter, which the kernel rejects (the mount fails
# with EINVAL); mount -a goes on past a slot that does not mount anyway.
add_factory_slot_mounts() {
install -d ${IMAGE_ROOTFS}/factory/img1 ${IMAGE_ROOTFS}/factory/img2
printf '%s\n' \
'/dev/mmcblk2p1 /factory/img1 auto ro,noatime 0 0' \
'/dev/mmcblk2p2 /factory/img2 auto ro,noatime 0 0' \
>> ${IMAGE_ROOTFS}${sysconfdir}/fstab
}
ROOTFS_POSTPROCESS_COMMAND += "add_factory_slot_mounts "