[PATCH 0/2] Move verity and EFI creation to separate Nix derivations
This doesn't have any functional change, other than to use the read builtin instead of a cat command in a shell script. However, it does make the code much cleaner and more reusable. For instance, one can easily build just the verity image or just the UKI. This will be used by the Nix code that generates an update package. The update package needs the root filesystem, the verity superblock, and the UKI. It doesn't need the installer or the live image. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Demi Marie Obenour (2): Create Nix derivation for building verity images Move UKI creation to a separate derivation host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ host/initramfs/Makefile | 25 +++++-------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 24 +++++------------------- host/rootfs/shell.nix | 3 +++ host/verity.nix | 19 +++++++++++++++++++ lib/common.mk | 1 - pkgs/default.nix | 2 ++ release/live/Makefile | 37 +++++-------------------------------- release/live/default.nix | 22 +++++++--------------- 10 files changed, 95 insertions(+), 88 deletions(-) --- base-commit: 43a8c81c58d73967635f57fdd84734d44120bc39 change-id: 20251105-refactor-verity-9c8ca37e021a -- Sincerely, Demi Marie Obenour (she/her/hers)
This gets rid of a lot of duplicated code and allows building the verity roothash and superblock only when needed. It also removes a hack used to work around make limitations. Furthermore, 'veritysetup --root-hash-file' is used to avoid an awk script. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- nix-shell --pure --run 'make run' in host/initramfs fails. This is a preexisting bug and I will send a separate patch for it. --- host/initramfs/Makefile | 25 +++++-------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 24 +++++------------------- host/rootfs/shell.nix | 3 +++ host/verity.nix | 19 +++++++++++++++++++ lib/common.mk | 1 - pkgs/default.nix | 1 + release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 9 files changed, 44 insertions(+), 63 deletions(-) diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..5c8c0eb2e50efcef33d78f91b562d8e79a76a900 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,11 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@ build/loop.tar: build/live.img @@ -69,12 +54,12 @@ clean: rm -rf build .PHONY: clean -run: $(dest) build/rootfs.verity.roothash $(RUN_IMAGE) +run: $(dest) $(RUN_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) @../../scripts/run-qemu.sh -m 4G \ -machine virtualization=on \ -kernel $(KERNEL) \ -initrd $(dest) \ - -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< build/rootfs.verity.roothash) nokaslr" \ + -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") nokaslr" \ -cpu max \ -gdb unix:build/gdb.sock,server,nowait \ -parallel none \ diff --git a/host/initramfs/shell.nix b/host/initramfs/shell.nix index eeba865e3ac793f67ae1808a92cf5eb1b37d57af..3e2abd17d2a989aa056d6f20633c624717e6b775 100644 --- a/host/initramfs/shell.nix +++ b/host/initramfs/shell.nix @@ -3,7 +3,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, rootfs, pkgsStatic, stdenv -, cryptsetup, qemu_kvm, tar2ext4, util-linux +, cryptsetup, qemu_kvm, tar2ext4, util-linux, verity }: let @@ -18,5 +18,7 @@ initramfs.overrideAttrs ({ nativeBuildInputs ? [], env ? {}, ... }: { env = env // { KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; ROOT_FS = rootfs; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; }; })) (_: {}) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 00d125774bb7b98736d0928c69cb307740cee034..bb602e2745fb5873204f453b35fc529c5c96f64a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -82,25 +82,11 @@ clean: rm -rf build .PHONY: clean -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(dest) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@ debug: @@ -110,7 +96,7 @@ debug: $(VMLINUX) .PHONY: debug -run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img $(EXT_FS) $(ROOT_FS_VERITY_ROOTHASH) @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -131,7 +117,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..f16e4905adfbc8faebde19d0a1364ad9df90219b 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -5,6 +5,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, rootfs, pkgsStatic, srcOnly, stdenv , btrfs-progs, cryptsetup, jq, netcat, qemu_kvm, reuse, util-linux +, verity }: rootfs.overrideAttrs ( @@ -20,5 +21,7 @@ rootfs.overrideAttrs ( KERNEL = "${passthru.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; LINUX_SRC = srcOnly passthru.kernel.configfile; VMLINUX = "${passthru.kernel.dev}/vmlinux"; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; }; })) (_: {}) diff --git a/host/verity.nix b/host/verity.nix new file mode 100644 index 0000000000000000000000000000000000000000..b144c4e270e8aa874b38c0aec69b6d99393a14b9 --- /dev/null +++ b/host/verity.nix @@ -0,0 +1,19 @@ +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ({ cryptsetup, runCommand, rootfs }: +runCommand "spectrum-verity" { + nativeBuildInputs = [ cryptsetup ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + env = { ROOTFS = rootfs; }; +} '' + mkdir -- "$out" + veritysetup format "--root-hash-file=$out/rootfs.verity.roothash" \ + -- "$ROOTFS" "$out/rootfs.verity.superblock" + # veritysetup doesn't append a newline, so the shell read command fails + echo >> "$out/rootfs.verity.roothash" + '' +) (_: {}) diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..f4aa15ef8fc053ae61a8d875eac4fc6a094411c6 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -15,7 +15,6 @@ S6_IPCSERVER_SOCKETBINDER = s6-ipcserver-socketbinder TAR = tar TRUNCATE = truncate UKIFY = ukify -VERITYSETUP = veritysetup VIRTIOFSD = virtiofsd PACKAGES_FILE != \ diff --git a/pkgs/default.nix b/pkgs/default.nix index cc60228a10cddcb70e5ab9faa1bab7d74f3ebb35..bc02f6b2f532f3ee1a2ea3aa45de3c9561bbb6ab 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -36,6 +36,7 @@ let path: (import path { inherit (self) callPackage; }).override; rootfs = self.callSpectrumPackage ../host/rootfs {}; + verity = self.callSpectrumPackage ../host/verity.nix {}; spectrum-build-tools = self.callSpectrumPackage ../tools { appSupport = false; buildSupport = true; diff --git a/release/live/Makefile b/release/live/Makefile index 6dcbdeedda5d6ccf293f60dc62043f46c81ecf83..191b44944af0adf965e1d5f2785719b236bfd99c 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -9,17 +9,17 @@ DTBS ?= build/empty dest = build/live.img -$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY":verity:$$(../../scripts/format-uuid.sh "$$(dd if="$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@ build/empty: mkdir -p $@ -build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) +build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) { \ printf "[UKI]\nDeviceTreeAuto=" && \ find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ @@ -29,7 +29,7 @@ build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) --linux $(KERNEL) \ --initrd $(INITRAMFS) \ --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat build/rootfs.verity.roothash)" + --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(TRUNCATE) -s 440401920 $@ @@ -38,22 +38,6 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - clean: rm -rf build .PHONY: clean diff --git a/release/live/default.nix b/release/live/default.nix index 2a1dc3e1dd939f21edac582bf39737eb4d46eb0c..32901f00a270f6dae005563b2e4082ad225c61e1 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -6,7 +6,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, spectrum-build-tools, rootfs, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify +, systemdUkify, verity }: let @@ -47,6 +47,8 @@ stdenv.mkDerivation { INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; ROOT_FS = rootfs; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; EFINAME = "BOOT${toUpper efiArch}.EFI"; } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { -- 2.51.2
Demi Marie Obenour <demiobenour@gmail.com> writes:
This gets rid of a lot of duplicated code and allows building the verity roothash and superblock only when needed. It also removes a hack used to work around make limitations. Furthermore, 'veritysetup --root-hash-file' is used to avoid an awk script.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- nix-shell --pure --run 'make run' in host/initramfs fails. This is a preexisting bug and I will send a separate patch for it. --- host/initramfs/Makefile | 25 +++++-------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 24 +++++------------------- host/rootfs/shell.nix | 3 +++ host/verity.nix | 19 +++++++++++++++++++ lib/common.mk | 1 - pkgs/default.nix | 1 + release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 9 files changed, 44 insertions(+), 63 deletions(-)
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 00d125774bb7b98736d0928c69cb307740cee034..bb602e2745fb5873204f453b35fc529c5c96f64a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -82,25 +82,11 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@
-build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(dest) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@
debug: @@ -110,7 +96,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img $(EXT_FS) $(ROOT_FS_VERITY_ROOTHASH) @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -131,7 +117,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..f16e4905adfbc8faebde19d0a1364ad9df90219b 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -5,6 +5,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, rootfs, pkgsStatic, srcOnly, stdenv , btrfs-progs, cryptsetup, jq, netcat, qemu_kvm, reuse, util-linux +, verity }:
rootfs.overrideAttrs ( @@ -20,5 +21,7 @@ rootfs.overrideAttrs ( KERNEL = "${passthru.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; LINUX_SRC = srcOnly passthru.kernel.configfile; VMLINUX = "${passthru.kernel.dev}/vmlinux"; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; }; })) (_: {})
Surely this would break interactive development of the rootfs? If I'm in a Nix shell, and make a change to any part of the rootfs, the verity data in the environment will be out of date. I'd have to leave and re-enter the Nix shell after /any/ change, waiting for an evaluation each time, as opposed to the current situation where that's only necessary when modifying Nix code or other Spectrum components.
On 11/6/25 05:20, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
This gets rid of a lot of duplicated code and allows building the verity roothash and superblock only when needed. It also removes a hack used to work around make limitations. Furthermore, 'veritysetup --root-hash-file' is used to avoid an awk script.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- nix-shell --pure --run 'make run' in host/initramfs fails. This is a preexisting bug and I will send a separate patch for it. --- host/initramfs/Makefile | 25 +++++-------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 24 +++++------------------- host/rootfs/shell.nix | 3 +++ host/verity.nix | 19 +++++++++++++++++++ lib/common.mk | 1 - pkgs/default.nix | 1 + release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 9 files changed, 44 insertions(+), 63 deletions(-)
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 00d125774bb7b98736d0928c69cb307740cee034..bb602e2745fb5873204f453b35fc529c5c96f64a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -82,25 +82,11 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@
-build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(dest) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@
debug: @@ -110,7 +96,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img $(EXT_FS) $(ROOT_FS_VERITY_ROOTHASH) @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -131,7 +117,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..f16e4905adfbc8faebde19d0a1364ad9df90219b 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -5,6 +5,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, rootfs, pkgsStatic, srcOnly, stdenv , btrfs-progs, cryptsetup, jq, netcat, qemu_kvm, reuse, util-linux +, verity }:
rootfs.overrideAttrs ( @@ -20,5 +21,7 @@ rootfs.overrideAttrs ( KERNEL = "${passthru.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; LINUX_SRC = srcOnly passthru.kernel.configfile; VMLINUX = "${passthru.kernel.dev}/vmlinux"; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; }; })) (_: {})
Surely this would break interactive development of the rootfs? If I'm in a Nix shell, and make a change to any part of the rootfs, the verity data in the environment will be out of date. I'd have to leave and re-enter the Nix shell after /any/ change, waiting for an evaluation each time, as opposed to the current situation where that's only necessary when modifying Nix code or other Spectrum components.
It would. Are there alternatives you can recommend? I don't want the updater and the installer to have to use two different copies. -- Sincerely, Demi Marie Obenour (she/her/hers)
Demi Marie Obenour <demiobenour@gmail.com> writes:
On 11/6/25 05:20, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
This gets rid of a lot of duplicated code and allows building the verity roothash and superblock only when needed. It also removes a hack used to work around make limitations. Furthermore, 'veritysetup --root-hash-file' is used to avoid an awk script.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- nix-shell --pure --run 'make run' in host/initramfs fails. This is a preexisting bug and I will send a separate patch for it. --- host/initramfs/Makefile | 25 +++++-------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 24 +++++------------------- host/rootfs/shell.nix | 3 +++ host/verity.nix | 19 +++++++++++++++++++ lib/common.mk | 1 - pkgs/default.nix | 1 + release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 9 files changed, 44 insertions(+), 63 deletions(-)
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 00d125774bb7b98736d0928c69cb307740cee034..bb602e2745fb5873204f453b35fc529c5c96f64a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -82,25 +82,11 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@
-build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(dest) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@
debug: @@ -110,7 +96,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img $(EXT_FS) $(ROOT_FS_VERITY_ROOTHASH) @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -131,7 +117,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..f16e4905adfbc8faebde19d0a1364ad9df90219b 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -5,6 +5,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, rootfs, pkgsStatic, srcOnly, stdenv , btrfs-progs, cryptsetup, jq, netcat, qemu_kvm, reuse, util-linux +, verity }:
rootfs.overrideAttrs ( @@ -20,5 +21,7 @@ rootfs.overrideAttrs ( KERNEL = "${passthru.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; LINUX_SRC = srcOnly passthru.kernel.configfile; VMLINUX = "${passthru.kernel.dev}/vmlinux"; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; }; })) (_: {})
Surely this would break interactive development of the rootfs? If I'm in a Nix shell, and make a change to any part of the rootfs, the verity data in the environment will be out of date. I'd have to leave and re-enter the Nix shell after /any/ change, waiting for an evaluation each time, as opposed to the current situation where that's only necessary when modifying Nix code or other Spectrum components.
It would. Are there alternatives you can recommend? I don't want the updater and the installer to have to use two different copies.
Have the host/rootfs derivation install the verity files alongside the rootfs image. Then host/rootfs/Makefile is the single place we generate the verity images, and it will still be regenerated by make when in a Nix shell.
On 11/6/25 06:44, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
On 11/6/25 05:20, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
This gets rid of a lot of duplicated code and allows building the verity roothash and superblock only when needed. It also removes a hack used to work around make limitations. Furthermore, 'veritysetup --root-hash-file' is used to avoid an awk script.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- nix-shell --pure --run 'make run' in host/initramfs fails. This is a preexisting bug and I will send a separate patch for it. --- host/initramfs/Makefile | 25 +++++-------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 24 +++++------------------- host/rootfs/shell.nix | 3 +++ host/verity.nix | 19 +++++++++++++++++++ lib/common.mk | 1 - pkgs/default.nix | 1 + release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 9 files changed, 44 insertions(+), 63 deletions(-)
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 00d125774bb7b98736d0928c69cb307740cee034..bb602e2745fb5873204f453b35fc529c5c96f64a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -82,25 +82,11 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@
-build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(dest) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@
debug: @@ -110,7 +96,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img $(EXT_FS) $(ROOT_FS_VERITY_ROOTHASH) @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -131,7 +117,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..f16e4905adfbc8faebde19d0a1364ad9df90219b 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -5,6 +5,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, rootfs, pkgsStatic, srcOnly, stdenv , btrfs-progs, cryptsetup, jq, netcat, qemu_kvm, reuse, util-linux +, verity }:
rootfs.overrideAttrs ( @@ -20,5 +21,7 @@ rootfs.overrideAttrs ( KERNEL = "${passthru.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; LINUX_SRC = srcOnly passthru.kernel.configfile; VMLINUX = "${passthru.kernel.dev}/vmlinux"; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; }; })) (_: {})
Surely this would break interactive development of the rootfs? If I'm in a Nix shell, and make a change to any part of the rootfs, the verity data in the environment will be out of date. I'd have to leave and re-enter the Nix shell after /any/ change, waiting for an evaluation each time, as opposed to the current situation where that's only necessary when modifying Nix code or other Spectrum components.
It would. Are there alternatives you can recommend? I don't want the updater and the installer to have to use two different copies.
Have the host/rootfs derivation install the verity files alongside the rootfs image. Then host/rootfs/Makefile is the single place we generate the verity images, and it will still be regenerated by make when in a Nix shell.
Is it okay to instead remove dm-verity protection for the verity images? Given that we discussed using virtiofs for live development, I don't think the verity protection is necessary. It also slows down live development. -- Sincerely, Demi Marie Obenour (she/her/hers)
Demi Marie Obenour <demiobenour@gmail.com> writes:
On 11/6/25 06:44, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
On 11/6/25 05:20, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
This gets rid of a lot of duplicated code and allows building the verity roothash and superblock only when needed. It also removes a hack used to work around make limitations. Furthermore, 'veritysetup --root-hash-file' is used to avoid an awk script.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- nix-shell --pure --run 'make run' in host/initramfs fails. This is a preexisting bug and I will send a separate patch for it. --- host/initramfs/Makefile | 25 +++++-------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 24 +++++------------------- host/rootfs/shell.nix | 3 +++ host/verity.nix | 19 +++++++++++++++++++ lib/common.mk | 1 - pkgs/default.nix | 1 + release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 9 files changed, 44 insertions(+), 63 deletions(-)
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 00d125774bb7b98736d0928c69cb307740cee034..bb602e2745fb5873204f453b35fc529c5c96f64a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -82,25 +82,11 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@
-build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(dest) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@
debug: @@ -110,7 +96,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img $(EXT_FS) $(ROOT_FS_VERITY_ROOTHASH) @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -131,7 +117,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..f16e4905adfbc8faebde19d0a1364ad9df90219b 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -5,6 +5,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, rootfs, pkgsStatic, srcOnly, stdenv , btrfs-progs, cryptsetup, jq, netcat, qemu_kvm, reuse, util-linux +, verity }:
rootfs.overrideAttrs ( @@ -20,5 +21,7 @@ rootfs.overrideAttrs ( KERNEL = "${passthru.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; LINUX_SRC = srcOnly passthru.kernel.configfile; VMLINUX = "${passthru.kernel.dev}/vmlinux"; + ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; }; })) (_: {})
Surely this would break interactive development of the rootfs? If I'm in a Nix shell, and make a change to any part of the rootfs, the verity data in the environment will be out of date. I'd have to leave and re-enter the Nix shell after /any/ change, waiting for an evaluation each time, as opposed to the current situation where that's only necessary when modifying Nix code or other Spectrum components.
It would. Are there alternatives you can recommend? I don't want the updater and the installer to have to use two different copies.
Have the host/rootfs derivation install the verity files alongside the rootfs image. Then host/rootfs/Makefile is the single place we generate the verity images, and it will still be regenerated by make when in a Nix shell.
Is it okay to instead remove dm-verity protection for the verity images? Given that we discussed using virtiofs for live development, I don't think the verity protection is necessary. It also slows down live development.
If you can do it in a way that doesn't require modifying the rootfs image. I don't want it to have to do anything special to support development builds that don't work like the real thing.
It will be used by the update code later. No functional change intended, other than a trivial shell script refactoring. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ pkgs/default.nix | 1 + release/live/Makefile | 15 ++------------- release/live/default.nix | 20 +++++--------------- 4 files changed, 54 insertions(+), 28 deletions(-) diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..45c76e4f37f52a62744318df3590dd429c005fe9 --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ bash, callSpectrumPackage, cryptsetup, runCommand +, stdenv, systemdUkify, rootfs, verity +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd bash ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit systemd; }; + env = { + DTBS = "${rootfs.kernel}/dtbs"; + KERNEL = kernel; + INITRAMFS = initramfs; + VERITY = verity; + }; +} '' + read -r roothash < "$VERITY/rootfs.verity.roothash" + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d "$DTBS" ]; then + find "$DTBS" -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux "$KERNEL" \ + --initrd "$INITRAMFS" \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/pkgs/default.nix b/pkgs/default.nix index bc02f6b2f532f3ee1a2ea3aa45de3c9561bbb6ab..95f431f560f6bf61dd56141a349210526a519838 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -37,6 +37,7 @@ let rootfs = self.callSpectrumPackage ../host/rootfs {}; verity = self.callSpectrumPackage ../host/verity.nix {}; + efi = self.callSpectrumPackage ../host/efi.nix {}; spectrum-build-tools = self.callSpectrumPackage ../tools { appSupport = false; buildSupport = true; diff --git a/release/live/Makefile b/release/live/Makefile index 191b44944af0adf965e1d5f2785719b236bfd99c..4de8743f42dec65aa863c3020cd70124316a6118 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,19 +19,8 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@ -build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty + ln -sf -- "$$EFI_IMAGE" build/spectrum.efi $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux diff --git a/release/live/default.nix b/release/live/default.nix index 32901f00a270f6dae005563b2e4082ad225c61e1..8b9f48997963608db86a1d3346bfe2b66f55adf5 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -6,7 +6,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, spectrum-build-tools, rootfs, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify, verity +, verity, efi }: let @@ -14,13 +14,6 @@ let stdenv = stdenvNoCC; - systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; in @@ -40,19 +33,16 @@ stdenv.mkDerivation { sourceRoot = "source/release/live"; nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ]; env = { - INITRAMFS = initramfs; - KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; ROOT_FS = rootfs; ROOT_FS_VERITY = "${verity}/rootfs.verity.superblock"; ROOT_FS_VERITY_ROOTHASH = "${verity}/rootfs.verity.roothash"; - SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + SYSTEMD_BOOT_EFI = "${efi.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; }; buildFlags = [ "dest=$(out)" ]; @@ -65,6 +55,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true; - passthru = { inherit initramfs rootfs; }; + passthru = { inherit rootfs; }; } ) (_: {}) -- 2.51.2
This doesn't have any functional change, other than to use the read builtin instead of a cat command in a shell script. However, it does make the code much cleaner and more reusable. For instance, one can easily build just the verity image or just the UKI. This will be used by the Nix code that generates an update package. The update package needs the root filesystem, the verity superblock, and the UKI. It doesn't need the installer or the live image. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes in v2: - Do not break interactive rootfs development. - Link to v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251105-refactor-veri... --- Demi Marie Obenour (2): Build verity images in rootfs Nix derivation Move UKI creation to a separate derivation host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 44 +++++++++++++++++++++----------------------- host/rootfs/default.nix | 2 +- host/rootfs/shell.nix | 2 +- pkgs/default.nix | 1 + release/live/Makefile | 37 +++++-------------------------------- release/live/default.nix | 23 ++++++++--------------- 9 files changed, 91 insertions(+), 94 deletions(-) --- base-commit: 464d69599922a2b233804559c93ccea10fa3dc44 change-id: 20251105-refactor-verity-9c8ca37e021a -- Sincerely, Demi Marie Obenour (she/her/hers)
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 44 +++++++++++++++++++++----------------------- host/rootfs/default.nix | 2 +- host/rootfs/shell.nix | 2 +- release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 7 files changed, 39 insertions(+), 69 deletions(-) diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..102870ecba4456303414e2531ea592473ddfc1cf 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@ build/loop.tar: build/live.img @@ -69,12 +53,12 @@ clean: rm -rf build .PHONY: clean -run: $(dest) build/rootfs.verity.roothash $(RUN_IMAGE) +run: $(dest) $(RUN_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) @../../scripts/run-qemu.sh -m 4G \ -machine virtualization=on \ -kernel $(KERNEL) \ -initrd $(dest) \ - -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< build/rootfs.verity.roothash) nokaslr" \ + -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") nokaslr" \ -cpu max \ -gdb unix:build/gdb.sock,server,nowait \ -parallel none \ diff --git a/host/initramfs/shell.nix b/host/initramfs/shell.nix index 8b47aa53bc19a818ebf563e281f22e82202a8ea5..fef8198685564bef2d8d673e0dc9403ee9c9a444 100644 --- a/host/initramfs/shell.nix +++ b/host/initramfs/shell.nix @@ -17,6 +17,8 @@ initramfs.overrideAttrs ({ nativeBuildInputs ? [], env ? {}, ... }: { env = env // { KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS = "${rootfs}/rootfs"; + ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash"; }; })) (_: {}) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 00d125774bb7b98736d0928c69cb307740cee034..d7764d9b796f1773b4bebd0d50eec52b9be29e42 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -6,7 +6,7 @@ include ../../lib/common.mk include file-list.mk -dest = build/rootfs.erofs +dest = build DIRS = \ dev \ @@ -46,14 +46,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc -$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +$(dest)/timestamp: ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk $(dest) { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(dest)/rootfs + $(VERITYSETUP) format \ + --root-hash-file $(dest)/rootfs.verity.roothash \ + -- $(dest)/rootfs $(dest)/rootfs.verity.superblock + # Add trailing newline + echo >> $(dest)/rootfs.verity.roothash + touch -- $(dest)/timestamp + +$(dest): + mkdir -p $(dest) build/fifo: mkdir -p build @@ -82,25 +95,10 @@ clean: rm -rf build .PHONY: clean -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(dest)/timestamp ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(dest)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(dest)/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ + $(dest)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(dest)/rootfs.verity.roothash)") mv $@.tmp $@ debug: @@ -110,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug -run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -131,7 +129,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(dest)/rootfs.verity.roothash) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 0d79f7ca54ccc86eb0fa6e743f2011237d365f24..453629d03d4b2b7e6bc49de5419321fc6b27f431 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -145,7 +145,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs"; - nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ]; env = { PACKAGES = runCommand "packages" {} '' diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs ( { nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ]; env = env // { diff --git a/release/live/Makefile b/release/live/Makefile index 6dcbdeedda5d6ccf293f60dc62043f46c81ecf83..191b44944af0adf965e1d5f2785719b236bfd99c 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -9,17 +9,17 @@ DTBS ?= build/empty dest = build/live.img -$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY":verity:$$(../../scripts/format-uuid.sh "$$(dd if="$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@ build/empty: mkdir -p $@ -build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) +build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) { \ printf "[UKI]\nDeviceTreeAuto=" && \ find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ @@ -29,7 +29,7 @@ build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) --linux $(KERNEL) \ --initrd $(INITRAMFS) \ --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat build/rootfs.verity.roothash)" + --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(TRUNCATE) -s 440401920 $@ @@ -38,22 +38,6 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - clean: rm -rf build .PHONY: clean diff --git a/release/live/default.nix b/release/live/default.nix index 2a1dc3e1dd939f21edac582bf39737eb4d46eb0c..9a62d4da9cfea11d94d2a1d5764d41587efd5ad5 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -46,7 +46,9 @@ stdenv.mkDerivation { env = { INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS = "${rootfs}/rootfs"; + ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash"; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; EFINAME = "BOOT${toUpper efiArch}.EFI"; } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { -- 2.51.2
It will be used by the update code later. No functional change intended, other than a trivial shell script refactoring. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ pkgs/default.nix | 1 + release/live/Makefile | 15 ++------------- release/live/default.nix | 19 +++++-------------- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..a2b47fd050fbf00050473a0d5a1373eb96c341b5 --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ bash, callSpectrumPackage, cryptsetup, runCommand +, stdenv, systemdUkify, rootfs +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd bash ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit systemd; }; + env = { + DTBS = "${rootfs.kernel}/dtbs"; + KERNEL = kernel; + INITRAMFS = initramfs; + ROOTFS = rootfs; + }; +} '' + read -r roothash < "$ROOTFS/rootfs.verity.roothash" + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d "$DTBS" ]; then + find "$DTBS" -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux "$KERNEL" \ + --initrd "$INITRAMFS" \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/pkgs/default.nix b/pkgs/default.nix index cc60228a10cddcb70e5ab9faa1bab7d74f3ebb35..c9f6dcfad9369567468b30d1c5697e3551a7b236 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -36,6 +36,7 @@ let path: (import path { inherit (self) callPackage; }).override; rootfs = self.callSpectrumPackage ../host/rootfs {}; + efi = self.callSpectrumPackage ../host/efi.nix {}; spectrum-build-tools = self.callSpectrumPackage ../tools { appSupport = false; buildSupport = true; diff --git a/release/live/Makefile b/release/live/Makefile index 191b44944af0adf965e1d5f2785719b236bfd99c..4de8743f42dec65aa863c3020cd70124316a6118 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,19 +19,8 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@ -build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty + ln -sf -- "$$EFI_IMAGE" build/spectrum.efi $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux diff --git a/release/live/default.nix b/release/live/default.nix index 9a62d4da9cfea11d94d2a1d5764d41587efd5ad5..c234d87e62cc9ae65ba60f94bab6e58b43beddbc 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -6,7 +6,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, spectrum-build-tools, rootfs, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify +, systemdUkify, efi }: let @@ -14,13 +14,6 @@ let stdenv = stdenvNoCC; - systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; in @@ -40,19 +33,17 @@ stdenv.mkDerivation { sourceRoot = "source/release/live"; nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ]; env = { - INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; ROOT_FS = "${rootfs}/rootfs"; ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash"; - SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + SYSTEMD_BOOT_EFI = "${efi.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; }; buildFlags = [ "dest=$(out)" ]; @@ -65,6 +56,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true; - passthru = { inherit initramfs rootfs; }; + passthru = { inherit rootfs; }; } ) (_: {}) -- 2.51.2
This doesn't have any functional change, other than to use the read builtin instead of a cat command in a shell script. However, it does make the code much cleaner and more reusable. For instance, one can easily build just the verity image or just the UKI. This will be used by the Nix code that generates an update package. The update package needs the root filesystem, the verity superblock, and the UKI. It doesn't need the installer or the live image. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes in v3: - Rebase on main - Link to v2: https://spectrum-os.org/lists/archives/spectrum-devel/20251107-refactor-veri... Changes in v2: - Do not break interactive rootfs development. - Link to v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251105-refactor-veri... --- Demi Marie Obenour (2): Build verity images in rootfs Nix derivation Move UKI creation to a separate derivation host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 45 +++++++++++++++++++++------------------------ host/rootfs/default.nix | 2 +- host/rootfs/shell.nix | 2 +- pkgs/default.nix | 1 + release/live/Makefile | 37 +++++-------------------------------- release/live/default.nix | 23 ++++++++--------------- 9 files changed, 91 insertions(+), 95 deletions(-) --- base-commit: 50f8db9cec022a60ea978bfdde0904a18718d161 change-id: 20251105-refactor-verity-9c8ca37e021a -- Sincerely, Demi Marie Obenour (she/her/hers)
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 45 +++++++++++++++++++++------------------------ host/rootfs/default.nix | 2 +- host/rootfs/shell.nix | 2 +- release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 7 files changed, 39 insertions(+), 70 deletions(-) diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..102870ecba4456303414e2531ea592473ddfc1cf 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \ + $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@ build/loop.tar: build/live.img @@ -69,12 +53,12 @@ clean: rm -rf build .PHONY: clean -run: $(dest) build/rootfs.verity.roothash $(RUN_IMAGE) +run: $(dest) $(RUN_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) @../../scripts/run-qemu.sh -m 4G \ -machine virtualization=on \ -kernel $(KERNEL) \ -initrd $(dest) \ - -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< build/rootfs.verity.roothash) nokaslr" \ + -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") nokaslr" \ -cpu max \ -gdb unix:build/gdb.sock,server,nowait \ -parallel none \ diff --git a/host/initramfs/shell.nix b/host/initramfs/shell.nix index 8b47aa53bc19a818ebf563e281f22e82202a8ea5..fef8198685564bef2d8d673e0dc9403ee9c9a444 100644 --- a/host/initramfs/shell.nix +++ b/host/initramfs/shell.nix @@ -17,6 +17,8 @@ initramfs.overrideAttrs ({ nativeBuildInputs ? [], env ? {}, ... }: { env = env // { KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS = "${rootfs}/rootfs"; + ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash"; }; })) (_: {}) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index f107ca44fcf1ad85af5788d87f6c772910d40072..d7764d9b796f1773b4bebd0d50eec52b9be29e42 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -6,7 +6,7 @@ include ../../lib/common.mk include file-list.mk -dest = build/rootfs.erofs +dest = build DIRS = \ dev \ @@ -46,15 +46,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc -$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +$(dest)/timestamp: ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk $(dest) { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(dest)/rootfs + $(VERITYSETUP) format \ + --root-hash-file $(dest)/rootfs.verity.roothash \ + -- $(dest)/rootfs $(dest)/rootfs.verity.superblock + # Add trailing newline + echo >> $(dest)/rootfs.verity.roothash + touch -- $(dest)/timestamp + +$(dest): + mkdir -p $(dest) build/fifo: mkdir -p build @@ -83,25 +95,10 @@ clean: rm -rf build .PHONY: clean -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(dest)/timestamp ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(dest)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(dest)/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ + $(dest)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(dest)/rootfs.verity.roothash)") mv $@.tmp $@ debug: @@ -111,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug -run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -132,7 +129,7 @@ run: build/live.img $(EXT_FS) build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(dest)/rootfs.verity.roothash) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 0ac70c7c077c0656c5820a5d8b3c7ce0e7c78e54..eb6c64067091ef3802596ce581f82f322f5bfe34 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -138,7 +138,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs"; - nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ]; env = { PACKAGES = runCommand "packages" {} '' diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs ( { nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ]; env = env // { diff --git a/release/live/Makefile b/release/live/Makefile index 6dcbdeedda5d6ccf293f60dc62043f46c81ecf83..191b44944af0adf965e1d5f2785719b236bfd99c 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -9,17 +9,17 @@ DTBS ?= build/empty dest = build/live.img -$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY":verity:$$(../../scripts/format-uuid.sh "$$(dd if="$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 "$$ROOT_FS_VERITY_ROOTHASH")") mv $@.tmp $@ build/empty: mkdir -p $@ -build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) +build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) { \ printf "[UKI]\nDeviceTreeAuto=" && \ find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ @@ -29,7 +29,7 @@ build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) --linux $(KERNEL) \ --initrd $(INITRAMFS) \ --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat build/rootfs.verity.roothash)" + --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(TRUNCATE) -s 440401920 $@ @@ -38,22 +38,6 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - clean: rm -rf build .PHONY: clean diff --git a/release/live/default.nix b/release/live/default.nix index 2a1dc3e1dd939f21edac582bf39737eb4d46eb0c..9a62d4da9cfea11d94d2a1d5764d41587efd5ad5 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -46,7 +46,9 @@ stdenv.mkDerivation { env = { INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS = "${rootfs}/rootfs"; + ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; + ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash"; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; EFINAME = "BOOT${toUpper efiArch}.EFI"; } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { -- 2.51.2
Demi Marie Obenour <demiobenour@gmail.com> writes:
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 45 +++++++++++++++++++++------------------------ host/rootfs/default.nix | 2 +- host/rootfs/shell.nix | 2 +- release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 7 files changed, 39 insertions(+), 70 deletions(-)
Looking good!
diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..102870ecba4456303414e2531ea592473ddfc1cf 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';'
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \
Indentation got messed up here. Given rootfs has a well-defined output structure, maybe we could just write $(ROOT_FS)/rootfs.verity.roothash, so we don't need to define lots of different environment variables in each component that uses the verity data. I think we should consistently use Make variable expansion rather than shell variable expansion when we're using the variable in a Make dependency line too, to avoid the possibility of them being different.
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index f107ca44fcf1ad85af5788d87f6c772910d40072..d7764d9b796f1773b4bebd0d50eec52b9be29e42 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -6,7 +6,7 @@ include ../../lib/common.mk include file-list.mk
-dest = build/rootfs.erofs +dest = build
DIRS = \ dev \ @@ -46,15 +46,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo
BUILD_FILES = build/etc/s6-rc
-$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +$(dest)/timestamp: ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk $(dest)
Semes a bit odd to install the timestamp in $(dest).
{ \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(dest)/rootfs + $(VERITYSETUP) format \ + --root-hash-file $(dest)/rootfs.verity.roothash \ + -- $(dest)/rootfs $(dest)/rootfs.verity.superblock + # Add trailing newline + echo >> $(dest)/rootfs.verity.roothash + touch -- $(dest)/timestamp
I prefer smaller independent Make rules where possible. Can't the verity data stay in a separate rule from make-erofs.sh? Either way, change deserves a copyright header IMO. :)
+ +$(dest): + mkdir -p $(dest)
Would rather this was inlined into every target in $(dest), because directories can be a bit confusing to me as Make targets. "Does the target just create the directory, or does it create the directory and everything in it?" sort of thing.
build/fifo: mkdir -p build @@ -83,25 +95,10 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(dest)/timestamp ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(dest)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(dest)/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ + $(dest)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(dest)/rootfs.verity.roothash)") mv $@.tmp $@
debug: @@ -111,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img
What happened to $(EXT_FS)?
On 11/13/25 06:46, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/shell.nix | 4 +++- host/rootfs/Makefile | 45 +++++++++++++++++++++------------------------ host/rootfs/default.nix | 2 +- host/rootfs/shell.nix | 2 +- release/live/Makefile | 26 +++++--------------------- release/live/default.nix | 4 +++- 7 files changed, 39 insertions(+), 70 deletions(-)
Looking good!
Thank you!
diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..102870ecba4456303414e2531ea592473ddfc1cf 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';'
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \
Indentation got messed up here.
Given rootfs has a well-defined output structure, maybe we could just write $(ROOT_FS)/rootfs.verity.roothash, so we don't need to define lots of different environment variables in each component that uses the verity data.
I think we should consistently use Make variable expansion rather than shell variable expansion when we're using the variable in a Make dependency line too, to avoid the possibility of them being different.
Make expansion followed by shell expansion and just Make expansion aren't even consistent with each other.
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index f107ca44fcf1ad85af5788d87f6c772910d40072..d7764d9b796f1773b4bebd0d50eec52b9be29e42 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -6,7 +6,7 @@ include ../../lib/common.mk include file-list.mk
-dest = build/rootfs.erofs +dest = build
DIRS = \ dev \ @@ -46,15 +46,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo
BUILD_FILES = build/etc/s6-rc
-$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +$(dest)/timestamp: ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk $(dest)
Semes a bit odd to install the timestamp in $(dest).
{ \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(dest)/rootfs + $(VERITYSETUP) format \ + --root-hash-file $(dest)/rootfs.verity.roothash \ + -- $(dest)/rootfs $(dest)/rootfs.verity.superblock + # Add trailing newline + echo >> $(dest)/rootfs.verity.roothash + touch -- $(dest)/timestamp
I prefer smaller independent Make rules where possible. Can't the verity data stay in a separate rule from make-erofs.sh?
Either way, change deserves a copyright header IMO. :)
+ +$(dest): + mkdir -p $(dest)
Would rather this was inlined into every target in $(dest), because directories can be a bit confusing to me as Make targets. "Does the target just create the directory, or does it create the directory and everything in it?" sort of thing.
Will fix.
build/fifo: mkdir -p build @@ -83,25 +95,10 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(dest)/timestamp ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(dest)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(dest)/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ + $(dest)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(dest)/rootfs.verity.roothash)") mv $@.tmp $@
debug: @@ -111,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img
What happened to $(EXT_FS)?
Since commit 12b64009d9cde56b5629a832086d2c2311908ebe ("host/initramfs/extfs.nix: remove") it has been unused. I deleted it while changing other stuff in this line. -- Sincerely, Demi Marie Obenour (she/her/hers)
Demi Marie Obenour <demiobenour@gmail.com> writes:
On 11/13/25 06:46, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..102870ecba4456303414e2531ea592473ddfc1cf 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';'
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_VERITY) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + "$$ROOT_FS_VERITY:verity:$$(../../scripts/format-uuid.sh "$$(dd "if=$$ROOT_FS_VERITY_ROOTHASH" bs=32 skip=1 count=1 status=none)")" \
Indentation got messed up here.
Given rootfs has a well-defined output structure, maybe we could just write $(ROOT_FS)/rootfs.verity.roothash, so we don't need to define lots of different environment variables in each component that uses the verity data.
I think we should consistently use Make variable expansion rather than shell variable expansion when we're using the variable in a Make dependency line too, to avoid the possibility of them being different.
Make expansion followed by shell expansion and just Make expansion aren't even consistent with each other.
Can you elaborate?
build/fifo: mkdir -p build @@ -83,25 +95,10 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(dest)/timestamp ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(dest)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(dest)/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ + $(dest)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(dest)/rootfs.verity.roothash)") mv $@.tmp $@
debug: @@ -111,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img $(EXT_FS) build/rootfs.verity.roothash +run: build/live.img
What happened to $(EXT_FS)?
Since commit 12b64009d9cde56b5629a832086d2c2311908ebe ("host/initramfs/extfs.nix: remove") it has been unused. I deleted it while changing other stuff in this line.
Got it. I'll just push a drop of $(EXT_FS) now then.
It will be used by the update code later. No functional change intended, other than a trivial shell script refactoring. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ pkgs/default.nix | 1 + release/live/Makefile | 15 ++------------- release/live/default.nix | 19 +++++-------------- 4 files changed, 54 insertions(+), 27 deletions(-) diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..a2b47fd050fbf00050473a0d5a1373eb96c341b5 --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: EUPL-1.2+ +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ bash, callSpectrumPackage, cryptsetup, runCommand +, stdenv, systemdUkify, rootfs +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd bash ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit systemd; }; + env = { + DTBS = "${rootfs.kernel}/dtbs"; + KERNEL = kernel; + INITRAMFS = initramfs; + ROOTFS = rootfs; + }; +} '' + read -r roothash < "$ROOTFS/rootfs.verity.roothash" + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d "$DTBS" ]; then + find "$DTBS" -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux "$KERNEL" \ + --initrd "$INITRAMFS" \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/pkgs/default.nix b/pkgs/default.nix index cc60228a10cddcb70e5ab9faa1bab7d74f3ebb35..c9f6dcfad9369567468b30d1c5697e3551a7b236 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -36,6 +36,7 @@ let path: (import path { inherit (self) callPackage; }).override; rootfs = self.callSpectrumPackage ../host/rootfs {}; + efi = self.callSpectrumPackage ../host/efi.nix {}; spectrum-build-tools = self.callSpectrumPackage ../tools { appSupport = false; buildSupport = true; diff --git a/release/live/Makefile b/release/live/Makefile index 191b44944af0adf965e1d5f2785719b236bfd99c..4de8743f42dec65aa863c3020cd70124316a6118 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,19 +19,8 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@ -build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty + ln -sf -- "$$EFI_IMAGE" build/spectrum.efi $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux diff --git a/release/live/default.nix b/release/live/default.nix index 9a62d4da9cfea11d94d2a1d5764d41587efd5ad5..c234d87e62cc9ae65ba60f94bab6e58b43beddbc 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -6,7 +6,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, spectrum-build-tools, rootfs, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify +, systemdUkify, efi }: let @@ -14,13 +14,6 @@ let stdenv = stdenvNoCC; - systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; in @@ -40,19 +33,17 @@ stdenv.mkDerivation { sourceRoot = "source/release/live"; nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ]; env = { - INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; ROOT_FS = "${rootfs}/rootfs"; ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash"; - SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + SYSTEMD_BOOT_EFI = "${efi.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; }; buildFlags = [ "dest=$(out)" ]; @@ -65,6 +56,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true; - passthru = { inherit initramfs rootfs; }; + passthru = { inherit rootfs; }; } ) (_: {}) -- 2.51.2
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ pkgs/default.nix | 1 + release/live/Makefile | 15 ++------------- release/live/default.nix | 19 +++++-------------- 4 files changed, 54 insertions(+), 27 deletions(-)
diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..a2b47fd050fbf00050473a0d5a1373eb96c341b5 --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: EUPL-1.2+
MIT for Nix files please. (Fine to take my stuff from the EUPL-1.2+ Makefile and use it in a MIT-licensed Nix file.)
+# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ bash, callSpectrumPackage, cryptsetup, runCommand +, stdenv, systemdUkify, rootfs +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd bash ];
bash?
+ __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit systemd; }; + env = { + DTBS = "${rootfs.kernel}/dtbs"; + KERNEL = kernel; + INITRAMFS = initramfs; + ROOTFS = rootfs; + };
Usually we'd just inline these via string interpolation, rather than passing them through as environment variables.
diff --git a/pkgs/default.nix b/pkgs/default.nix index cc60228a10cddcb70e5ab9faa1bab7d74f3ebb35..c9f6dcfad9369567468b30d1c5697e3551a7b236 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -36,6 +36,7 @@ let path: (import path { inherit (self) callPackage; }).override;
rootfs = self.callSpectrumPackage ../host/rootfs {}; + efi = self.callSpectrumPackage ../host/efi.nix {}; spectrum-build-tools = self.callSpectrumPackage ../tools { appSupport = false; buildSupport = true;
Generally images don't need entries here, and can just be loaded by callSpectrumPackage. There was a specific reason to make an exception for rootfs (which I've now forgotten).
diff --git a/release/live/Makefile b/release/live/Makefile index 191b44944af0adf965e1d5f2785719b236bfd99c..4de8743f42dec65aa863c3020cd70124316a6118 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,19 +19,8 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@
-build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty + ln -sf -- "$$EFI_IMAGE" build/spectrum.efi $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux
Why a symlink? Why not just replace the path we copy from?
diff --git a/release/live/default.nix b/release/live/default.nix index 9a62d4da9cfea11d94d2a1d5764d41587efd5ad5..c234d87e62cc9ae65ba60f94bab6e58b43beddbc 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -6,7 +6,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, spectrum-build-tools, rootfs, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify +, systemdUkify, efi }:
let @@ -14,13 +14,6 @@ let
stdenv = stdenvNoCC;
- systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; in
@@ -40,19 +33,17 @@ stdenv.mkDerivation { sourceRoot = "source/release/live";
nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ];
env = { - INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; ROOT_FS = "${rootfs}/rootfs"; ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash";
Since efi is tied to a specific rootfs, maybe it would be nice to use efi.rootfs here?
- SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + SYSTEMD_BOOT_EFI = "${efi.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
We can just get this from the default systemd package. Doesn't need to be efi's special overridden one.
+ EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; };
buildFlags = [ "dest=$(out)" ]; @@ -65,6 +56,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true;
- passthru = { inherit initramfs rootfs; }; + passthru = { inherit rootfs; }; } ) (_: {})
-- 2.51.2
On 11/13/25 06:57, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ pkgs/default.nix | 1 + release/live/Makefile | 15 ++------------- release/live/default.nix | 19 +++++-------------- 4 files changed, 54 insertions(+), 27 deletions(-)
diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..a2b47fd050fbf00050473a0d5a1373eb96c341b5 --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: EUPL-1.2+
MIT for Nix files please. (Fine to take my stuff from the EUPL-1.2+ Makefile and use it in a MIT-licensed Nix file.)
I think it would be best to relicense the Makefiles under MIT if we can, so that we can move code back and forth even after neither of us knows every single copyright holder. Feel free to relicense my contributions to them.
+# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ bash, callSpectrumPackage, cryptsetup, runCommand +, stdenv, systemdUkify, rootfs +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd bash ];
bash?
Will remove.
+ __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit systemd; }; + env = { + DTBS = "${rootfs.kernel}/dtbs"; + KERNEL = kernel; + INITRAMFS = initramfs; + ROOTFS = rootfs; + };
Usually we'd just inline these via string interpolation, rather than passing them through as environment variables.
Done, except for DTBS which is used more than once.
diff --git a/pkgs/default.nix b/pkgs/default.nix index cc60228a10cddcb70e5ab9faa1bab7d74f3ebb35..c9f6dcfad9369567468b30d1c5697e3551a7b236 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -36,6 +36,7 @@ let path: (import path { inherit (self) callPackage; }).override;
rootfs = self.callSpectrumPackage ../host/rootfs {}; + efi = self.callSpectrumPackage ../host/efi.nix {}; spectrum-build-tools = self.callSpectrumPackage ../tools { appSupport = false; buildSupport = true;
Generally images don't need entries here, and can just be loaded by callSpectrumPackage. There was a specific reason to make an exception for rootfs (which I've now forgotten).
What is the general rule for what should go in pkgs/default.nix? If you could add it to the docs that would be great.
diff --git a/release/live/Makefile b/release/live/Makefile index 191b44944af0adf965e1d5f2785719b236bfd99c..4de8743f42dec65aa863c3020cd70124316a6118 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,19 +19,8 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@
-build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty + ln -sf -- "$$EFI_IMAGE" build/spectrum.efi $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux
Why a symlink? Why not just replace the path we copy from?
The basename of the path is actually important. I tried using $(EFI_IMAGE) and the system didn't boot.
diff --git a/release/live/default.nix b/release/live/default.nix index 9a62d4da9cfea11d94d2a1d5764d41587efd5ad5..c234d87e62cc9ae65ba60f94bab6e58b43beddbc 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -6,7 +6,7 @@ import ../../lib/call-package.nix ( { callSpectrumPackage, spectrum-build-tools, rootfs, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify +, systemdUkify, efi }:
let @@ -14,13 +14,6 @@ let
stdenv = stdenvNoCC;
- systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; in
@@ -40,19 +33,17 @@ stdenv.mkDerivation { sourceRoot = "source/release/live";
nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ];
env = { - INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; ROOT_FS = "${rootfs}/rootfs"; ROOT_FS_VERITY = "${rootfs}/rootfs.verity.superblock"; ROOT_FS_VERITY_ROOTHASH = "${rootfs}/rootfs.verity.roothash";
Since efi is tied to a specific rootfs, maybe it would be nice to use efi.rootfs here?
Will change in v4.
- SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + SYSTEMD_BOOT_EFI = "${efi.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
We can just get this from the default systemd package. Doesn't need to be efi's special overridden one.
Would it be better to have the override in a Spectrum-wide overlay?
+ EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; };
buildFlags = [ "dest=$(out)" ]; @@ -65,6 +56,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true;
- passthru = { inherit initramfs rootfs; }; + passthru = { inherit rootfs; }; } ) (_: {})
-- 2.51.2 -- Sincerely, Demi Marie Obenour (she/her/hers)
Demi Marie Obenour <demiobenour@gmail.com> writes:
On 11/13/25 06:57, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 46 ++++++++++++++++++++++++++++++++++++++++++++++ pkgs/default.nix | 1 + release/live/Makefile | 15 ++------------- release/live/default.nix | 19 +++++-------------- 4 files changed, 54 insertions(+), 27 deletions(-)
diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..a2b47fd050fbf00050473a0d5a1373eb96c341b5 --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,46 @@ +# SPDX-License-Identifier: EUPL-1.2+
MIT for Nix files please. (Fine to take my stuff from the EUPL-1.2+ Makefile and use it in a MIT-licensed Nix file.)
I think it would be best to relicense the Makefiles under MIT if we can, so that we can move code back and forth even after neither of us knows every single copyright holder. Feel free to relicense my contributions to them.
Yes, perhaps worth considering. I'll think about it.
+ __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit systemd; }; + env = { + DTBS = "${rootfs.kernel}/dtbs"; + KERNEL = kernel; + INITRAMFS = initramfs; + ROOTFS = rootfs; + };
Usually we'd just inline these via string interpolation, rather than passing them through as environment variables.
Done, except for DTBS which is used more than once.
Even so it's very short.
diff --git a/pkgs/default.nix b/pkgs/default.nix index cc60228a10cddcb70e5ab9faa1bab7d74f3ebb35..c9f6dcfad9369567468b30d1c5697e3551a7b236 100644 --- a/pkgs/default.nix +++ b/pkgs/default.nix @@ -36,6 +36,7 @@ let path: (import path { inherit (self) callPackage; }).override;
rootfs = self.callSpectrumPackage ../host/rootfs {}; + efi = self.callSpectrumPackage ../host/efi.nix {}; spectrum-build-tools = self.callSpectrumPackage ../tools { appSupport = false; buildSupport = true;
Generally images don't need entries here, and can just be loaded by callSpectrumPackage. There was a specific reason to make an exception for rootfs (which I've now forgotten).
What is the general rule for what should go in pkgs/default.nix? If you could add it to the docs that would be great.
Uh, "packages" should go in pkgs/default.nix. I'd need to remember the rationale for rootfs being in there to say more, and I don't right now.
diff --git a/release/live/Makefile b/release/live/Makefile index 191b44944af0adf965e1d5f2785719b236bfd99c..4de8743f42dec65aa863c3020cd70124316a6118 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,19 +19,8 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@
-build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat "$$ROOT_FS_VERITY_ROOTHASH")" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty + ln -sf -- "$$EFI_IMAGE" build/spectrum.efi $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux
Why a symlink? Why not just replace the path we copy from?
The basename of the path is actually important. I tried using $(EFI_IMAGE) and the system didn't boot.
So this doesn't work? $(MCOPY) -i $@ $(EFI_IMAGE) ::/EFI/Linux/spectrum.efi I'd be very curious to see the diff between that and a working image.
- SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + SYSTEMD_BOOT_EFI = "${efi.systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi";
We can just get this from the default systemd package. Doesn't need to be efi's special overridden one.
Would it be better to have the override in a Spectrum-wide overlay?
You'd end up doing a lot of rebuilding for everything that depends on systemd. We could also have it so that Spectrum's "systemd" in pkgs/default.nix differs from the systemd used inside Nixpkgs and available as pkgs.systemd, but that would get /extremely/ confusing.
This doesn't have any functional change, other than to use the read builtin instead of a cat command in a shell script. However, it does make the code much cleaner and more reusable. For instance, one can easily build just the verity image or just the UKI. This will be used by the Nix code that generates an update package. The update package needs the root filesystem, the verity superblock, and the UKI. It doesn't need the installer or the live image. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes in v4: - Many cleanups. - Respond to suggestions from code review. - Link to v3: https://spectrum-os.org/lists/archives/spectrum-devel/20251111-refactor-veri... Changes in v3: - Rebase on main - Link to v2: https://spectrum-os.org/lists/archives/spectrum-devel/20251107-refactor-veri... Changes in v2: - Do not break interactive rootfs development. - Link to v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251105-refactor-veri... --- Demi Marie Obenour (2): Build verity images in rootfs Nix derivation Move UKI creation to a separate derivation host/efi.nix | 40 +++++++++++++++++++++++++++++++++++++++ host/initramfs/Makefile | 26 +++++-------------------- host/initramfs/default.nix | 1 + host/initramfs/shell.nix | 2 +- host/rootfs/Makefile | 47 ++++++++++++++++++++++------------------------ host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 38 +++++-------------------------------- release/live/default.nix | 27 +++++++++++--------------- release/live/shell.nix | 9 ++++++++- 11 files changed, 102 insertions(+), 100 deletions(-) --- base-commit: 99f09ab0a69f41eb14795c1cd047d5cd6ee5896e change-id: 20251105-refactor-verity-9c8ca37e021a -- Sincerely, Demi Marie Obenour (she/her/hers)
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++-------------------- host/initramfs/default.nix | 1 + host/initramfs/shell.nix | 2 +- host/rootfs/Makefile | 47 ++++++++++++++++++++++------------------------ host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 26 +++++-------------------- release/live/default.nix | 2 +- release/live/shell.nix | 3 ++- 10 files changed, 46 insertions(+), 73 deletions(-) diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..13bb548d6146684a25dab1e31228c0b9a4ca8db7 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/loop.tar: build/live.img @@ -69,12 +53,12 @@ clean: rm -rf build .PHONY: clean -run: $(dest) build/rootfs.verity.roothash $(RUN_IMAGE) +run: $(dest) $(RUN_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) @../../scripts/run-qemu.sh -m 4G \ -machine virtualization=on \ -kernel $(KERNEL) \ -initrd $(dest) \ - -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< build/rootfs.verity.roothash) nokaslr" \ + -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") nokaslr" \ -cpu max \ -gdb unix:build/gdb.sock,server,nowait \ -parallel none \ diff --git a/host/initramfs/default.nix b/host/initramfs/default.nix index d35e1b514ec48015f5110e65e5ae944b28244c4f..88f9379444148a071ef0de45132415fba0f6c12e 100644 --- a/host/initramfs/default.nix +++ b/host/initramfs/default.nix @@ -105,6 +105,7 @@ stdenvNoCC.mkDerivation { env = { PACKAGES_CPIO = packagesCpio; + ROOT_FS_DIR = rootfs; } // lib.optionalAttrs stdenvNoCC.hostPlatform.isx86_64 { MICROCODE = microcode; }; diff --git a/host/initramfs/shell.nix b/host/initramfs/shell.nix index 8b47aa53bc19a818ebf563e281f22e82202a8ea5..ff067354881b480656fae9b339a0a9068475d85f 100644 --- a/host/initramfs/shell.nix +++ b/host/initramfs/shell.nix @@ -17,6 +17,6 @@ initramfs.overrideAttrs ({ nativeBuildInputs ? [], env ? {}, ... }: { env = env // { KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS_DIR = rootfs; }; })) (_: {}) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 27a7c689c39bf9bc93b5ba33ce661be7e47b67f1..055185064d84d9450c2076fdeb410b21d00f1d40 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> .POSIX: include ../../lib/common.mk include file-list.mk - -dest = build/rootfs.erofs +ROOT_FS_DIR = build DIRS = \ dev \ @@ -46,15 +46,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc -$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +build/verity-timestamp: $(ROOT_FS) + $(VERITYSETUP) format \ + --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ + -- $(ROOT_FS) $(ROOT_FS_VERITY) + # Add trailing newline + echo >> $(ROOT_FS_VERITY_ROOTHASH) + touch -- $(ROOT_FS_DIR)/verity-timestamp + +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +$(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk + mkdir -p $(ROOT_FS_DIR) && \ { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(ROOT_FS) build/fifo: mkdir -p build @@ -83,25 +95,10 @@ clean: rm -rf build .PHONY: clean -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_DIR)/verity-timestamp $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH)") mv $@.tmp $@ debug: @@ -111,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug -run: build/live.img build/rootfs.verity.roothash +run: build/live.img @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -132,7 +129,7 @@ run: build/live.img build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 0ac70c7c077c0656c5820a5d8b3c7ce0e7c78e54..1578155fa0fb9a4df3fb4884e21ed7d8d8f821dc 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -138,7 +138,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs"; - nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ]; env = { PACKAGES = runCommand "packages" {} '' @@ -147,7 +147,9 @@ stdenvNoCC.mkDerivation { ''; }; - makeFlags = [ "dest=$(out)" ]; + # The Makefile uses $(ROOT_FS_DIR), not $(dest), so it can share code + # with other Makefiles that also use this variable. + makeFlags = [ "ROOT_FS_DIR=$(out)" ]; dontInstall = true; diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs ( { nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ]; env = env // { diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..d1cc4d0514070cc3f418c4d1b7e929abd40d985c 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -11,6 +11,10 @@ GDB = gdb MCOPY = mcopy MKFS_FAT = mkfs.fat MMD = mmd +ROOT_FS = $(ROOT_FS_DIR)/rootfs +ROOT_FS_IMAGES = $(ROOT_FS) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS_VERITY) +ROOT_FS_VERITY = $(ROOT_FS_DIR)/rootfs.verity.superblock +ROOT_FS_VERITY_ROOTHASH = $(ROOT_FS_DIR)/rootfs.verity.roothash S6_IPCSERVER_SOCKETBINDER = s6-ipcserver-socketbinder TAR = tar TRUNCATE = truncate diff --git a/release/live/Makefile b/release/live/Makefile index 6dcbdeedda5d6ccf293f60dc62043f46c81ecf83..7372b41d94bfb10f7761955d9d1a246e9785b7f8 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -9,17 +9,17 @@ DTBS ?= build/empty dest = build/live.img -$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/empty: mkdir -p $@ -build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) +build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) { \ printf "[UKI]\nDeviceTreeAuto=" && \ find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ @@ -29,7 +29,7 @@ build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) --linux $(KERNEL) \ --initrd $(INITRAMFS) \ --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat build/rootfs.verity.roothash)" + --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(TRUNCATE) -s 440401920 $@ @@ -38,22 +38,6 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - clean: rm -rf build .PHONY: clean diff --git a/release/live/default.nix b/release/live/default.nix index 2a1dc3e1dd939f21edac582bf39737eb4d46eb0c..7adaefef330daf11372cff0d2d04cca400efba1f 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -46,7 +46,7 @@ stdenv.mkDerivation { env = { INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS_DIR = rootfs; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; EFINAME = "BOOT${toUpper efiArch}.EFI"; } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { diff --git a/release/live/shell.nix b/release/live/shell.nix index 5acaa8c5b113fd2789aaea9268487b193bab37af..c5db7b732ef048b4c0cb87a4c5ea614e993db516 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: +import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,6 +10,7 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; + ROOT_FS_DIR = rootfs; }; } )) (_: {}) -- 2.52.0
Demi Marie Obenour <demiobenour@gmail.com> writes:
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 27a7c689c39bf9bc93b5ba33ce661be7e47b67f1..055185064d84d9450c2076fdeb410b21d00f1d40 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com>
.POSIX:
include ../../lib/common.mk include file-list.mk - -dest = build/rootfs.erofs +ROOT_FS_DIR = build
DIRS = \ dev \ @@ -46,15 +46,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo
BUILD_FILES = build/etc/s6-rc
-$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +build/verity-timestamp: $(ROOT_FS) + $(VERITYSETUP) format \ + --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ + -- $(ROOT_FS) $(ROOT_FS_VERITY) + # Add trailing newline + echo >> $(ROOT_FS_VERITY_ROOTHASH)
Why do we need to do this? (Emacs would also rather your comments were not indented, so they're interpreted by Make as comments rather than being passed on to the shell.)
+ touch -- $(ROOT_FS_DIR)/verity-timestamp
This should be build/verity-timestamp (like the rule), or even better $@.
+ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects.
Is this comment supposed to be on the previous rule?
+$(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk + mkdir -p $(ROOT_FS_DIR) && \ { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(ROOT_FS)
Why change this?
build/fifo: mkdir -p build @@ -83,25 +95,10 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_DIR)/verity-timestamp $(ROOT_FS)
Here you're also still referring to $(ROOT_FS_DIR)/verity-timestamp rather than build/verity-timestamp.
../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH)")
This can't be right, can it? $(ROOT_FS) is a file.
mv $@.tmp $@
debug: @@ -111,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img build/rootfs.verity.roothash +run: build/live.img
I'd still prefer we kept the explicit dependency, even though we will get it via build/live.img as well.
@set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -132,7 +129,7 @@ run: build/live.img build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 0ac70c7c077c0656c5820a5d8b3c7ce0e7c78e54..1578155fa0fb9a4df3fb4884e21ed7d8d8f821dc 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -138,7 +138,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs";
- nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ];
env = { PACKAGES = runCommand "packages" {} '' @@ -147,7 +147,9 @@ stdenvNoCC.mkDerivation { ''; };
- makeFlags = [ "dest=$(out)" ]; + # The Makefile uses $(ROOT_FS_DIR), not $(dest), so it can share code + # with other Makefiles that also use this variable. + makeFlags = [ "ROOT_FS_DIR=$(out)" ];
dontInstall = true;
diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs (
{ nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ];
env = env // { diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..d1cc4d0514070cc3f418c4d1b7e929abd40d985c 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -11,6 +11,10 @@ GDB = gdb MCOPY = mcopy MKFS_FAT = mkfs.fat MMD = mmd +ROOT_FS = $(ROOT_FS_DIR)/rootfs
Would be nice for this to keep its file extension.
+ROOT_FS_IMAGES = $(ROOT_FS) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS_VERITY)
I'm not sure "IMAGES" makes sense as a name for this. A verity roothash is not an image. ROOT_FS_FILES? Alternative naming scheme idea, that avoids mistaking ROOT_FS for the directory like has happened above: ROOT_FS (for the directory), ROOT_FS_IMAGE, ROOT_FS_VERITY, ROOT_FS_VERITY_ROOTHASH.
Whoops, just realised I replied to v4 and not v5. You can ignore this, and I'll resend any comments that are still relevant to v5. Alyssa Ross <hi@alyssa.is> writes:
Demi Marie Obenour <demiobenour@gmail.com> writes:
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 27a7c689c39bf9bc93b5ba33ce661be7e47b67f1..055185064d84d9450c2076fdeb410b21d00f1d40 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com>
.POSIX:
include ../../lib/common.mk include file-list.mk - -dest = build/rootfs.erofs +ROOT_FS_DIR = build
DIRS = \ dev \ @@ -46,15 +46,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo
BUILD_FILES = build/etc/s6-rc
-$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +build/verity-timestamp: $(ROOT_FS) + $(VERITYSETUP) format \ + --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ + -- $(ROOT_FS) $(ROOT_FS_VERITY) + # Add trailing newline + echo >> $(ROOT_FS_VERITY_ROOTHASH)
Why do we need to do this?
(Emacs would also rather your comments were not indented, so they're interpreted by Make as comments rather than being passed on to the shell.)
+ touch -- $(ROOT_FS_DIR)/verity-timestamp
This should be build/verity-timestamp (like the rule), or even better $@.
+ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects.
Is this comment supposed to be on the previous rule?
+$(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk + mkdir -p $(ROOT_FS_DIR) && \ { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(ROOT_FS)
Why change this?
build/fifo: mkdir -p build @@ -83,25 +95,10 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_DIR)/verity-timestamp $(ROOT_FS)
Here you're also still referring to $(ROOT_FS_DIR)/verity-timestamp rather than build/verity-timestamp.
../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH)")
This can't be right, can it? $(ROOT_FS) is a file.
mv $@.tmp $@
debug: @@ -111,7 +108,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img build/rootfs.verity.roothash +run: build/live.img
I'd still prefer we kept the explicit dependency, even though we will get it via build/live.img as well.
@set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -132,7 +129,7 @@ run: build/live.img build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 0ac70c7c077c0656c5820a5d8b3c7ce0e7c78e54..1578155fa0fb9a4df3fb4884e21ed7d8d8f821dc 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -138,7 +138,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs";
- nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ];
env = { PACKAGES = runCommand "packages" {} '' @@ -147,7 +147,9 @@ stdenvNoCC.mkDerivation { ''; };
- makeFlags = [ "dest=$(out)" ]; + # The Makefile uses $(ROOT_FS_DIR), not $(dest), so it can share code + # with other Makefiles that also use this variable. + makeFlags = [ "ROOT_FS_DIR=$(out)" ];
dontInstall = true;
diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs (
{ nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ];
env = env // { diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..d1cc4d0514070cc3f418c4d1b7e929abd40d985c 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -11,6 +11,10 @@ GDB = gdb MCOPY = mcopy MKFS_FAT = mkfs.fat MMD = mmd +ROOT_FS = $(ROOT_FS_DIR)/rootfs
Would be nice for this to keep its file extension.
+ROOT_FS_IMAGES = $(ROOT_FS) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS_VERITY)
I'm not sure "IMAGES" makes sense as a name for this. A verity roothash is not an image. ROOT_FS_FILES?
Alternative naming scheme idea, that avoids mistaking ROOT_FS for the directory like has happened above:
ROOT_FS (for the directory), ROOT_FS_IMAGE, ROOT_FS_VERITY, ROOT_FS_VERITY_ROOTHASH.
It will be used by the update code later. No functional change intended, other than a trivial shell script refactoring. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit. --- host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ host/rootfs/Makefile | 8 ++++---- release/live/Makefile | 16 ++-------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 10 ++++++++-- 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..d0ce260bd908c186059b75a1b4f42258b0e62bff --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ callSpectrumPackage, config, cryptsetup, rootfs +, runCommand, stdenv, systemdUkify +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit initramfs rootfs systemd; }; +} '' + read -r roothash < ${rootfs}/rootfs.verity.roothash + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d ${rootfs.kernel}/dtbs ]; then + find ${rootfs.kernel}/dtbs -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux ${kernel} \ + --initrd ${initramfs} \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 055185064d84d9450c2076fdeb410b21d00f1d40..4c14d3acfa8f7ffd276fdfb684d08bf58fd80a15 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -46,6 +46,10 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. build/verity-timestamp: $(ROOT_FS) $(VERITYSETUP) format \ --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ @@ -54,10 +58,6 @@ build/verity-timestamp: $(ROOT_FS) echo >> $(ROOT_FS_VERITY_ROOTHASH) touch -- $(ROOT_FS_DIR)/verity-timestamp -# This rule produces three files but Make only (portably) -# supports one output per rule. Instead of resorting to temporary -# files, a timestamp file is created as the last step. The actual -# outputs are produced as side-effects. $(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk mkdir -p $(ROOT_FS_DIR) && \ { \ diff --git a/release/live/Makefile b/release/live/Makefile index 7372b41d94bfb10f7761955d9d1a246e9785b7f8..d61248e94599adc5229d0ad38d54b9f649d66ca1 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,23 +19,11 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@ -build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux - $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux + $(MCOPY) -i $@ $(EFI_IMAGE) ::/EFI/Linux/spectrum.efi $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) clean: diff --git a/release/live/default.nix b/release/live/default.nix index 7adaefef330daf11372cff0d2d04cca400efba1f..ac2d7a55fd4fe0c02108309ecea20e368000af0d 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -3,10 +3,9 @@ # SPDX-FileCopyrightText: 2022 Unikie import ../../lib/call-package.nix ( -{ callSpectrumPackage, spectrum-build-tools, rootfs, src +{ callSpectrumPackage, spectrum-build-tools, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify }: let @@ -14,14 +13,12 @@ let stdenv = stdenvNoCC; - systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; + + efi = callSpectrumPackage ../../host/efi.nix {}; + + # The initramfs and rootfs must match those used to build the UKI. + inherit (efi) initramfs rootfs systemd; in stdenv.mkDerivation { @@ -40,17 +37,15 @@ stdenv.mkDerivation { sourceRoot = "source/release/live"; nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ]; env = { - INITRAMFS = initramfs; - KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS_DIR = rootfs; + KERNEL = "${efi.rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + ROOT_FS_DIR = "${efi.rootfs}"; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; }; buildFlags = [ "dest=$(out)" ]; @@ -63,6 +58,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true; - passthru = { inherit initramfs rootfs; }; + passthru = { inherit efi initramfs rootfs; }; } ) (_: {}) diff --git a/release/live/shell.nix b/release/live/shell.nix index c5db7b732ef048b4c0cb87a4c5ea614e993db516..ffaa9a571c662810348822a5952d479d251a25e5 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,12 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: +import ../../lib/call-package.nix ( +{ callSpectrumPackage, stdenv, qemu_kvm }: + +let + efi = callSpectrumPackage ../../host/efi.nix {}; +in (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,7 +15,8 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, root env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; - ROOT_FS_DIR = rootfs; + ROOT_FS_DIR = efi.rootfs; + EFI_IMAGE = efi; }; } )) (_: {}) -- 2.52.0
This doesn't have any functional change, other than to use the read builtin instead of a cat command in a shell script. However, it does make the code much cleaner and more reusable. For instance, one can easily build just the verity image or just the UKI. This will be used by the Nix code that generates an update package. The update package needs the root filesystem, the verity superblock, and the UKI. It doesn't need the installer or the live image. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes in v5: - Rebase - Link to v4: https://spectrum-os.org/lists/archives/spectrum-devel/20251119-refactor-veri... Changes in v4: - Many cleanups. - Respond to suggestions from code review. - Link to v3: https://spectrum-os.org/lists/archives/spectrum-devel/20251111-refactor-veri... Changes in v3: - Rebase on main - Link to v2: https://spectrum-os.org/lists/archives/spectrum-devel/20251107-refactor-veri... Changes in v2: - Do not break interactive rootfs development. - Link to v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251105-refactor-veri... --- Demi Marie Obenour (2): Build verity images in rootfs Nix derivation Move UKI creation to a separate derivation host/efi.nix | 40 +++++++++++++++++++++++++++++++++++++++ host/initramfs/Makefile | 26 +++++-------------------- host/initramfs/default.nix | 1 + host/initramfs/shell.nix | 2 +- host/rootfs/Makefile | 47 ++++++++++++++++++++++------------------------ host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 38 +++++-------------------------------- release/live/default.nix | 27 +++++++++++--------------- release/live/shell.nix | 9 ++++++++- 11 files changed, 102 insertions(+), 100 deletions(-) --- base-commit: f41b4ab1e6dace7ee3c184f3154cda76f34be7db change-id: 20251105-refactor-verity-9c8ca37e021a -- Sincerely, Demi Marie Obenour (she/her/hers)
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++-------------------- host/initramfs/default.nix | 1 + host/initramfs/shell.nix | 2 +- host/rootfs/Makefile | 47 ++++++++++++++++++++++------------------------ host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 26 +++++-------------------- release/live/default.nix | 2 +- release/live/shell.nix | 3 ++- 10 files changed, 46 insertions(+), 73 deletions(-) diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..13bb548d6146684a25dab1e31228c0b9a4ca8db7 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/loop.tar: build/live.img @@ -69,12 +53,12 @@ clean: rm -rf build .PHONY: clean -run: $(dest) build/rootfs.verity.roothash $(RUN_IMAGE) +run: $(dest) $(RUN_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) @../../scripts/run-qemu.sh -m 4G \ -machine virtualization=on \ -kernel $(KERNEL) \ -initrd $(dest) \ - -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< build/rootfs.verity.roothash) nokaslr" \ + -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< "$$ROOT_FS_VERITY_ROOTHASH") nokaslr" \ -cpu max \ -gdb unix:build/gdb.sock,server,nowait \ -parallel none \ diff --git a/host/initramfs/default.nix b/host/initramfs/default.nix index d35e1b514ec48015f5110e65e5ae944b28244c4f..88f9379444148a071ef0de45132415fba0f6c12e 100644 --- a/host/initramfs/default.nix +++ b/host/initramfs/default.nix @@ -105,6 +105,7 @@ stdenvNoCC.mkDerivation { env = { PACKAGES_CPIO = packagesCpio; + ROOT_FS_DIR = rootfs; } // lib.optionalAttrs stdenvNoCC.hostPlatform.isx86_64 { MICROCODE = microcode; }; diff --git a/host/initramfs/shell.nix b/host/initramfs/shell.nix index 8b47aa53bc19a818ebf563e281f22e82202a8ea5..ff067354881b480656fae9b339a0a9068475d85f 100644 --- a/host/initramfs/shell.nix +++ b/host/initramfs/shell.nix @@ -17,6 +17,6 @@ initramfs.overrideAttrs ({ nativeBuildInputs ? [], env ? {}, ... }: { env = env // { KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS_DIR = rootfs; }; })) (_: {}) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 4067be0c45cc83ce4670ed76e956db58f8e93e02..5e3c9238f0e00f86aa5943212b8fc8fd896ce54a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> .POSIX: include ../../lib/common.mk include file-list.mk - -dest = build/rootfs.erofs +ROOT_FS_DIR = build DIRS = \ dev \ @@ -40,15 +40,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc -$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +build/verity-timestamp: $(ROOT_FS) + $(VERITYSETUP) format \ + --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ + -- $(ROOT_FS) $(ROOT_FS_VERITY) + # Add trailing newline + echo >> $(ROOT_FS_VERITY_ROOTHASH) + touch -- $(ROOT_FS_DIR)/verity-timestamp + +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +$(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk + mkdir -p $(ROOT_FS_DIR) && \ { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(ROOT_FS) build/fifo: mkdir -p build @@ -77,25 +89,10 @@ clean: rm -rf build .PHONY: clean -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_DIR)/verity-timestamp $(ROOT_FS) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH)") mv $@.tmp $@ debug: @@ -105,7 +102,7 @@ debug: $(VMLINUX) .PHONY: debug -run: build/live.img build/rootfs.verity.roothash +run: build/live.img @set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -126,7 +123,7 @@ run: build/live.img build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 0ac70c7c077c0656c5820a5d8b3c7ce0e7c78e54..1578155fa0fb9a4df3fb4884e21ed7d8d8f821dc 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -138,7 +138,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs"; - nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ]; env = { PACKAGES = runCommand "packages" {} '' @@ -147,7 +147,9 @@ stdenvNoCC.mkDerivation { ''; }; - makeFlags = [ "dest=$(out)" ]; + # The Makefile uses $(ROOT_FS_DIR), not $(dest), so it can share code + # with other Makefiles that also use this variable. + makeFlags = [ "ROOT_FS_DIR=$(out)" ]; dontInstall = true; diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs ( { nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ]; env = env // { diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..d1cc4d0514070cc3f418c4d1b7e929abd40d985c 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -11,6 +11,10 @@ GDB = gdb MCOPY = mcopy MKFS_FAT = mkfs.fat MMD = mmd +ROOT_FS = $(ROOT_FS_DIR)/rootfs +ROOT_FS_IMAGES = $(ROOT_FS) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS_VERITY) +ROOT_FS_VERITY = $(ROOT_FS_DIR)/rootfs.verity.superblock +ROOT_FS_VERITY_ROOTHASH = $(ROOT_FS_DIR)/rootfs.verity.roothash S6_IPCSERVER_SOCKETBINDER = s6-ipcserver-socketbinder TAR = tar TRUNCATE = truncate diff --git a/release/live/Makefile b/release/live/Makefile index 6dcbdeedda5d6ccf293f60dc62043f46c81ecf83..7372b41d94bfb10f7761955d9d1a246e9785b7f8 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -9,17 +9,17 @@ DTBS ?= build/empty dest = build/live.img -$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/empty: mkdir -p $@ -build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) +build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) { \ printf "[UKI]\nDeviceTreeAuto=" && \ find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ @@ -29,7 +29,7 @@ build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) --linux $(KERNEL) \ --initrd $(INITRAMFS) \ --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat build/rootfs.verity.roothash)" + --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(TRUNCATE) -s 440401920 $@ @@ -38,22 +38,6 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - clean: rm -rf build .PHONY: clean diff --git a/release/live/default.nix b/release/live/default.nix index 2a1dc3e1dd939f21edac582bf39737eb4d46eb0c..7adaefef330daf11372cff0d2d04cca400efba1f 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -46,7 +46,7 @@ stdenv.mkDerivation { env = { INITRAMFS = initramfs; KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + ROOT_FS_DIR = rootfs; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; EFINAME = "BOOT${toUpper efiArch}.EFI"; } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { diff --git a/release/live/shell.nix b/release/live/shell.nix index 5acaa8c5b113fd2789aaea9268487b193bab37af..c5db7b732ef048b4c0cb87a4c5ea614e993db516 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: +import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,6 +10,7 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; + ROOT_FS_DIR = rootfs; }; } )) (_: {}) -- 2.52.0
Okay, resending relevant comments from my accidental review of v4: Demi Marie Obenour <demiobenour@gmail.com> writes:
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 4067be0c45cc83ce4670ed76e956db58f8e93e02..5e3c9238f0e00f86aa5943212b8fc8fd896ce54a 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -1,12 +1,12 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com>
.POSIX:
include ../../lib/common.mk include file-list.mk - -dest = build/rootfs.erofs +ROOT_FS_DIR = build
DIRS = \ dev \ @@ -40,15 +40,27 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo
BUILD_FILES = build/etc/s6-rc
-$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +build/verity-timestamp: $(ROOT_FS) + $(VERITYSETUP) format \ + --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ + -- $(ROOT_FS) $(ROOT_FS_VERITY) + # Add trailing newline + echo >> $(ROOT_FS_VERITY_ROOTHASH)
Why do we need to do this? (Emacs would also rather your comments were not indented, so they're interpreted by Make as comments rather than being passed on to the shell.)
+ touch -- $(ROOT_FS_DIR)/verity-timestamp
This should be build/verity-timestamp (like the rule), or even better $@.
+ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects.
Is this comment supposed to be on the previous rule?
+$(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk + mkdir -p $(ROOT_FS_DIR) && \ { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ for file in $(BUILD_FILES); do printf '%s\n%s\n' $$file $${file#build/}; done ;\ printf 'build/empty\n%s\n' $(DIRS) ;\ printf 'build/fifo\n%s\n' $(FIFOS) ;\ - } | ../../scripts/make-erofs.sh $@ + } | ../../scripts/make-erofs.sh $(ROOT_FS)
Why change this to something more likely to get out of sync?
build/fifo: mkdir -p build @@ -77,25 +89,10 @@ clean: rm -rf build .PHONY: clean
-# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_DIR)/verity-timestamp $(ROOT_FS)
Here you're also still referring to $(ROOT_FS_DIR)/verity-timestamp rather than build/verity-timestamp.
../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS)/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS)/rootfs:root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH)")
This can't be right, can it? $(ROOT_FS) is a file.
mv $@.tmp $@
debug: @@ -105,7 +102,7 @@ debug: $(VMLINUX) .PHONY: debug
-run: build/live.img build/rootfs.verity.roothash +run: build/live.img
I'd still prefer we kept the explicit dependency, even though we will get it via build/live.img as well.
@set -x && \ ext="$$(mktemp build/spectrum-rootfs-extfs.XXXXXXXXXX.img)" && \ truncate -s 10G "$$ext" && \ @@ -126,7 +123,7 @@ run: build/live.img build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index 0ac70c7c077c0656c5820a5d8b3c7ce0e7c78e54..1578155fa0fb9a4df3fb4884e21ed7d8d8f821dc 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -138,7 +138,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs";
- nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ];
env = { PACKAGES = runCommand "packages" {} '' @@ -147,7 +147,9 @@ stdenvNoCC.mkDerivation { ''; };
- makeFlags = [ "dest=$(out)" ]; + # The Makefile uses $(ROOT_FS_DIR), not $(dest), so it can share code + # with other Makefiles that also use this variable. + makeFlags = [ "ROOT_FS_DIR=$(out)" ];
dontInstall = true;
diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs (
{ nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ];
env = env // { diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..d1cc4d0514070cc3f418c4d1b7e929abd40d985c 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -11,6 +11,10 @@ GDB = gdb MCOPY = mcopy MKFS_FAT = mkfs.fat MMD = mmd +ROOT_FS = $(ROOT_FS_DIR)/rootfs
Would be nice for this to keep its file extension.
+ROOT_FS_IMAGES = $(ROOT_FS) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS_VERITY)
I'm not sure "IMAGES" makes sense as a name for this. A verity roothash is not an image. ROOT_FS_FILES? Alternative naming scheme idea, that avoids mistaking ROOT_FS for the directory like has happened above: ROOT_FS (for the directory), ROOT_FS_IMAGE, ROOT_FS_VERITY, ROOT_FS_VERITY_ROOTHASH.
It will be used by the update code later. No functional change intended, other than a trivial shell script refactoring. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit. --- host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ host/rootfs/Makefile | 8 ++++---- release/live/Makefile | 16 ++-------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 10 ++++++++-- 5 files changed, 65 insertions(+), 36 deletions(-) diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..d0ce260bd908c186059b75a1b4f42258b0e62bff --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ callSpectrumPackage, config, cryptsetup, rootfs +, runCommand, stdenv, systemdUkify +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit initramfs rootfs systemd; }; +} '' + read -r roothash < ${rootfs}/rootfs.verity.roothash + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d ${rootfs.kernel}/dtbs ]; then + find ${rootfs.kernel}/dtbs -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux ${kernel} \ + --initrd ${initramfs} \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 5e3c9238f0e00f86aa5943212b8fc8fd896ce54a..aac915ffb2781aee0997c169e86e3fd1983aa3b3 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -40,6 +40,10 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. build/verity-timestamp: $(ROOT_FS) $(VERITYSETUP) format \ --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ @@ -48,10 +52,6 @@ build/verity-timestamp: $(ROOT_FS) echo >> $(ROOT_FS_VERITY_ROOTHASH) touch -- $(ROOT_FS_DIR)/verity-timestamp -# This rule produces three files but Make only (portably) -# supports one output per rule. Instead of resorting to temporary -# files, a timestamp file is created as the last step. The actual -# outputs are produced as side-effects. $(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk mkdir -p $(ROOT_FS_DIR) && \ { \ diff --git a/release/live/Makefile b/release/live/Makefile index 7372b41d94bfb10f7761955d9d1a246e9785b7f8..d61248e94599adc5229d0ad38d54b9f649d66ca1 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,23 +19,11 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@ -build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux - $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux + $(MCOPY) -i $@ $(EFI_IMAGE) ::/EFI/Linux/spectrum.efi $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) clean: diff --git a/release/live/default.nix b/release/live/default.nix index 7adaefef330daf11372cff0d2d04cca400efba1f..ac2d7a55fd4fe0c02108309ecea20e368000af0d 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -3,10 +3,9 @@ # SPDX-FileCopyrightText: 2022 Unikie import ../../lib/call-package.nix ( -{ callSpectrumPackage, spectrum-build-tools, rootfs, src +{ callSpectrumPackage, spectrum-build-tools, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify }: let @@ -14,14 +13,12 @@ let stdenv = stdenvNoCC; - systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; + + efi = callSpectrumPackage ../../host/efi.nix {}; + + # The initramfs and rootfs must match those used to build the UKI. + inherit (efi) initramfs rootfs systemd; in stdenv.mkDerivation { @@ -40,17 +37,15 @@ stdenv.mkDerivation { sourceRoot = "source/release/live"; nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ]; env = { - INITRAMFS = initramfs; - KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS_DIR = rootfs; + KERNEL = "${efi.rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + ROOT_FS_DIR = "${efi.rootfs}"; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; }; buildFlags = [ "dest=$(out)" ]; @@ -63,6 +58,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true; - passthru = { inherit initramfs rootfs; }; + passthru = { inherit efi initramfs rootfs; }; } ) (_: {}) diff --git a/release/live/shell.nix b/release/live/shell.nix index c5db7b732ef048b4c0cb87a4c5ea614e993db516..ffaa9a571c662810348822a5952d479d251a25e5 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,12 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: +import ../../lib/call-package.nix ( +{ callSpectrumPackage, stdenv, qemu_kvm }: + +let + efi = callSpectrumPackage ../../host/efi.nix {}; +in (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,7 +15,8 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, root env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; - ROOT_FS_DIR = rootfs; + ROOT_FS_DIR = efi.rootfs; + EFI_IMAGE = efi; }; } )) (_: {}) -- 2.52.0
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit. --- host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ host/rootfs/Makefile | 8 ++++---- release/live/Makefile | 16 ++-------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 10 ++++++++-- 5 files changed, 65 insertions(+), 36 deletions(-)
Looking good. Just some style notes.
diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 5e3c9238f0e00f86aa5943212b8fc8fd896ce54a..aac915ffb2781aee0997c169e86e3fd1983aa3b3 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -40,6 +40,10 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo
BUILD_FILES = build/etc/s6-rc
+# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. build/verity-timestamp: $(ROOT_FS) $(VERITYSETUP) format \ --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ @@ -48,10 +52,6 @@ build/verity-timestamp: $(ROOT_FS) echo >> $(ROOT_FS_VERITY_ROOTHASH) touch -- $(ROOT_FS_DIR)/verity-timestamp
-# This rule produces three files but Make only (portably) -# supports one output per rule. Instead of resorting to temporary -# files, a timestamp file is created as the last step. The actual -# outputs are produced as side-effects. $(ROOT_FS): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk mkdir -p $(ROOT_FS_DIR) && \ { \ diff --git a/release/live/Makefile b/release/live/Makefile index 7372b41d94bfb10f7761955d9d1a246e9785b7f8..d61248e94599adc5229d0ad38d54b9f649d66ca1 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,23 +19,11 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@
-build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty
I'd call "EFI_IMAGE" "SPECTRUM_EFI", so we aren't using two different naming schemes for the two different EFI executables.
$(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux - $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux + $(MCOPY) -i $@ $(EFI_IMAGE) ::/EFI/Linux/spectrum.efi $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME)
clean: diff --git a/release/live/default.nix b/release/live/default.nix index 7adaefef330daf11372cff0d2d04cca400efba1f..ac2d7a55fd4fe0c02108309ecea20e368000af0d 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -3,10 +3,9 @@ # SPDX-FileCopyrightText: 2022 Unikie
import ../../lib/call-package.nix ( -{ callSpectrumPackage, spectrum-build-tools, rootfs, src +{ callSpectrumPackage, spectrum-build-tools, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify }:
let @@ -14,14 +13,12 @@ let
stdenv = stdenvNoCC;
- systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; + + efi = callSpectrumPackage ../../host/efi.nix {}; + + # The initramfs and rootfs must match those used to build the UKI. + inherit (efi) initramfs rootfs systemd; in
stdenv.mkDerivation { @@ -40,17 +37,15 @@ stdenv.mkDerivation { sourceRoot = "source/release/live";
nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ];
env = { - INITRAMFS = initramfs; - KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS_DIR = rootfs; + KERNEL = "${efi.rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + ROOT_FS_DIR = "${efi.rootfs}";
Why inherit these from efi above if you're going to refer to them through efi here anyway?
SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; };
buildFlags = [ "dest=$(out)" ]; @@ -63,6 +58,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true;
- passthru = { inherit initramfs rootfs; }; + passthru = { inherit efi initramfs rootfs; }; } ) (_: {}) diff --git a/release/live/shell.nix b/release/live/shell.nix index c5db7b732ef048b4c0cb87a4c5ea614e993db516..ffaa9a571c662810348822a5952d479d251a25e5 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,12 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is>
-import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: +import ../../lib/call-package.nix ( +{ callSpectrumPackage, stdenv, qemu_kvm }:
This has reduced in length, so it doesn't need to be broken on to a separate line.
+ +let + efi = callSpectrumPackage ../../host/efi.nix {}; +in
(callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,7 +15,8 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, root
env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; - ROOT_FS_DIR = rootfs; + ROOT_FS_DIR = efi.rootfs; + EFI_IMAGE = efi; }; } )) (_: {})
-- 2.52.0
This doesn't have any functional change, other than to use the read builtin instead of a cat command in a shell script. However, it does make the code much cleaner and more reusable. For instance, one can easily build just the verity image or just the UKI. This will be used by the Nix code that generates an update package. The update package needs the root filesystem, the verity superblock, and the UKI. It doesn't need the installer or the live image. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes in v6: - Rebase - Fix shell.nix files - Link to v5: https://spectrum-os.org/lists/archives/spectrum-devel/20251121-refactor-veri... Changes in v5: - Rebase - Fix shell.nix files - Link to v4: https://spectrum-os.org/lists/archives/spectrum-devel/20251119-refactor-veri... Changes in v4: - Many cleanups. - Respond to suggestions from code review. - Link to v3: https://spectrum-os.org/lists/archives/spectrum-devel/20251111-refactor-veri... Changes in v3: - Rebase on main - Link to v2: https://spectrum-os.org/lists/archives/spectrum-devel/20251107-refactor-veri... Changes in v2: - Do not break interactive rootfs development. - Link to v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251105-refactor-veri... --- Demi Marie Obenour (2): Build verity images in rootfs Nix derivation Move UKI creation to a separate derivation host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/default.nix | 1 + host/rootfs/Makefile | 44 ++++++++++++++++++++++---------------------- host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 39 +++++++-------------------------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 9 ++++++++- 10 files changed, 103 insertions(+), 95 deletions(-) --- base-commit: c3d53b92c32636736c6585cd934210e29613e38e change-id: 20251105-refactor-verity-9c8ca37e021a -- Sincerely, Demi Marie Obenour (she/her/hers)
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes since v5: - Use consistent naming scheme for Make variables: ROOT_FS is the directory containing the artifacts. ROOT_FS_IMAGE is the root filesystem image, ROOT_FS_VERITY is the verity image, and ROOT_FS_VERITY_ROOTHASH is its root filesystem hash. - Do not try to use a file as a directory. - Use $@ where possible. - Use consistent indentation. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/default.nix | 1 + host/rootfs/Makefile | 44 ++++++++++++++++++++++---------------------- host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 26 +++++--------------------- release/live/shell.nix | 3 ++- 8 files changed, 44 insertions(+), 68 deletions(-) diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..f27f5e07c4707914962197b4fea8f385729370aa 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/loop.tar: build/live.img @@ -69,12 +53,12 @@ clean: rm -rf build .PHONY: clean -run: $(dest) build/rootfs.verity.roothash $(RUN_IMAGE) +run: $(dest) $(RUN_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) @../../scripts/run-qemu.sh -m 4G \ -machine virtualization=on \ -kernel $(KERNEL) \ -initrd $(dest) \ - -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< build/rootfs.verity.roothash) nokaslr" \ + -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) nokaslr" \ -cpu max \ -gdb unix:build/gdb.sock,server,nowait \ -parallel none \ diff --git a/host/initramfs/default.nix b/host/initramfs/default.nix index d35e1b514ec48015f5110e65e5ae944b28244c4f..16c932600c0ab54cf439dc7931fc12e863677e0e 100644 --- a/host/initramfs/default.nix +++ b/host/initramfs/default.nix @@ -105,6 +105,7 @@ stdenvNoCC.mkDerivation { env = { PACKAGES_CPIO = packagesCpio; + ROOT_FS = rootfs; } // lib.optionalAttrs stdenvNoCC.hostPlatform.isx86_64 { MICROCODE = microcode; }; diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 4067be0c45cc83ce4670ed76e956db58f8e93e02..4cb048ac08b3265b0435d6ff6fc612a58c169ce9 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -1,12 +1,13 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> .POSIX: include ../../lib/common.mk include file-list.mk -dest = build/rootfs.erofs +ROOT_FS = build DIRS = \ dev \ @@ -40,8 +41,22 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc -$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +build/verity-timestamp: $(ROOT_FS_IMAGE) + $(VERITYSETUP) format \ + --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ + -- $(ROOT_FS_IMAGE) $(ROOT_FS_VERITY) +# Add trailing newline so that the read < $(ROOT_FS_VERITY_ROOTHASH) succeeds. +# Without the trailing newline it assumes a premature EOF happened and returns +# a nonzero status. + echo >> $(ROOT_FS_VERITY_ROOTHASH) + touch -- $@ + +$(ROOT_FS_IMAGE): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk + mkdir -p $(ROOT_FS) && \ { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ @@ -77,25 +92,10 @@ clean: rm -rf build .PHONY: clean -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/verity-timestamp $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ debug: @@ -126,7 +126,7 @@ run: build/live.img build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index f7974a41052468f9782214f32355dda97af3cd60..941c04e619baa7652d1812f4eb50445c607d5884 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -118,7 +118,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs"; - nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ]; env = { PACKAGES = runCommand "packages" {} '' @@ -127,7 +127,9 @@ stdenvNoCC.mkDerivation { ''; }; - makeFlags = [ "dest=$(out)" ]; + # The Makefile uses $(ROOT_FS), not $(dest), so it can share code + # with other Makefiles that also use this variable. + makeFlags = [ "ROOT_FS=$(out)" ]; dontInstall = true; diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs ( { nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ]; env = env // { diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..84091a8dfd615b2aaa021c7477f34c4dff88ccde 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -11,6 +11,10 @@ GDB = gdb MCOPY = mcopy MKFS_FAT = mkfs.fat MMD = mmd +ROOT_FS_IMAGE = $(ROOT_FS)/rootfs +ROOT_FS_IMAGES = $(ROOT_FS_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS_VERITY) +ROOT_FS_VERITY = $(ROOT_FS)/rootfs.verity.superblock +ROOT_FS_VERITY_ROOTHASH = $(ROOT_FS)/rootfs.verity.roothash S6_IPCSERVER_SOCKETBINDER = s6-ipcserver-socketbinder TAR = tar TRUNCATE = truncate diff --git a/release/live/Makefile b/release/live/Makefile index 6dcbdeedda5d6ccf293f60dc62043f46c81ecf83..ba81c7e679429e045b24c1591a9f0b72f016cfab 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -9,17 +9,17 @@ DTBS ?= build/empty dest = build/live.img -$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/empty: mkdir -p $@ -build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) +build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) { \ printf "[UKI]\nDeviceTreeAuto=" && \ find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ @@ -29,7 +29,7 @@ build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) --linux $(KERNEL) \ --initrd $(INITRAMFS) \ --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat build/rootfs.verity.roothash)" + --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(TRUNCATE) -s 440401920 $@ @@ -38,22 +38,6 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - clean: rm -rf build .PHONY: clean diff --git a/release/live/shell.nix b/release/live/shell.nix index 5acaa8c5b113fd2789aaea9268487b193bab37af..799d575b4f6e6f3dad8ac1a0a8bc2e3fc46aab44 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: +import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,6 +10,7 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; + ROOT_FS = rootfs; }; } )) (_: {}) -- 2.52.0
This patch has been committed as 96f4b9798d5069f6b502915270293dcaf0c6ad8c, which can be viewed online at https://spectrum-os.org/git/spectrum/commit/?id=96f4b9798d5069f6b50291527029.... This is an automated message. Send comments/questions/requests to: Alyssa Ross <hi@alyssa.is>
It will be used by the update code later. No functional change intended, other than a trivial shell script refactoring. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit. Changes since v5: - Create a temporary symlink named build/spectrum.efi and then run $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux, rather than copying the file with its original name. The latter results in an unbootable image. I do not know the reason. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ release/live/Makefile | 17 ++++------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 10 ++++++++-- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..ecedb6bea6bf29c7a7303dc9062fe12b5c7a9fbd --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ callSpectrumPackage, cryptsetup, rootfs +, runCommand, stdenv, systemdUkify +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit initramfs rootfs systemd; }; +} '' + read -r roothash < ${rootfs}/rootfs.verity.roothash + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d ${rootfs.kernel}/dtbs ]; then + find ${rootfs.kernel}/dtbs -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux ${kernel} \ + --initrd ${initramfs} \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/release/live/Makefile b/release/live/Makefile index ba81c7e679429e045b24c1591a9f0b72f016cfab..b37ccce42feb3ac7e8ce4faf96a67902b55be808 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,22 +19,13 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@ -build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux +# This symlink is necessary. Copying $(EFI_IMAGE) directly +# results in an unbootable image. TODO: figure out why. + ln -s $(EFI_IMAGE) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) diff --git a/release/live/default.nix b/release/live/default.nix index 2a1dc3e1dd939f21edac582bf39737eb4d46eb0c..ba9bb17e697a6ecfe81e52a4ffbc375ef443b6f3 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -3,10 +3,9 @@ # SPDX-FileCopyrightText: 2022 Unikie import ../../lib/call-package.nix ( -{ callSpectrumPackage, spectrum-build-tools, rootfs, src +{ callSpectrumPackage, spectrum-build-tools, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify }: let @@ -14,14 +13,12 @@ let stdenv = stdenvNoCC; - systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; + + efi = callSpectrumPackage ../../host/efi.nix {}; + + # The initramfs and rootfs must match those used to build the UKI. + inherit (efi) initramfs rootfs systemd; in stdenv.mkDerivation { @@ -40,17 +37,15 @@ stdenv.mkDerivation { sourceRoot = "source/release/live"; nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ]; env = { - INITRAMFS = initramfs; - KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + KERNEL = "${efi.rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + ROOT_FS = "${efi.rootfs}"; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; }; buildFlags = [ "dest=$(out)" ]; @@ -63,6 +58,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true; - passthru = { inherit initramfs rootfs; }; + passthru = { inherit efi initramfs rootfs; }; } ) (_: {}) diff --git a/release/live/shell.nix b/release/live/shell.nix index 799d575b4f6e6f3dad8ac1a0a8bc2e3fc46aab44..b0bf957c085d1581a24d8916925611da0a60ec8b 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,12 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: +import ../../lib/call-package.nix ( +{ callSpectrumPackage, stdenv, qemu_kvm }: + +let + efi = callSpectrumPackage ../../host/efi.nix {}; +in (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,7 +15,8 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, root env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; - ROOT_FS = rootfs; + ROOT_FS = efi.rootfs; + EFI_IMAGE = efi; }; } )) (_: {}) -- 2.52.0
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit.
Yep, makes sense.
Changes since v5:
- Create a temporary symlink named build/spectrum.efi and then run $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux, rather than copying the file with its original name. The latter results in an unbootable image. I do not know the reason.
If I just mcopy -i $@ $(EFI_IMAGE) ::/EFI/Linux/spectrum.efi (explicitly specifying the destination file name), then it works. It doesn't is something like "/nix/store/3yqb8mfv6skp43yp2r7sn098zrj0hrjf-spectrum-efi". This could be avoided by installing EFI_IMAGE to a subdirectory, so the file name didn't get a hash prepended to it by Nix. Happy to just go ahead with changing this and applying my style comments from last time[1] if you agree. [1]: https://spectrum-os.org/lists/archives/spectrum-devel/877bve2skh.fsf@alyssa....
On 11/28/25 05:47, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit.
Yep, makes sense.
Changes since v5:
- Create a temporary symlink named build/spectrum.efi and then run $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux, rather than copying the file with its original name. The latter results in an unbootable image. I do not know the reason.
If I just mcopy -i $@ $(EFI_IMAGE) ::/EFI/Linux/spectrum.efi (explicitly specifying the destination file name), then it works. It doesn't is something like "/nix/store/3yqb8mfv6skp43yp2r7sn098zrj0hrjf-spectrum-efi".
I distinctly remember it *not* working for me, but I might have used the wrong destination name. Perhaps I used Spectrum.efi (wrong case)?
This could be avoided by installing EFI_IMAGE to a subdirectory, so the file name didn't get a hash prepended to it by Nix. Happy to just go ahead with changing this and applying my style comments from last time[1] if you agree.
[1]: https://spectrum-os.org/lists/archives/spectrum-devel/877bve2skh.fsf@alyssa....
That would be great and an even better solution. -- Sincerely, Demi Marie Obenour (she/her/hers)
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit.
Changes since v5:
- Create a temporary symlink named build/spectrum.efi and then run $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux, rather than copying the file with its original name. The latter results in an unbootable image. I do not know the reason.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ release/live/Makefile | 17 ++++------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 10 ++++++++-- 4 files changed, 63 insertions(+), 31 deletions(-)
diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..ecedb6bea6bf29c7a7303dc9062fe12b5c7a9fbd --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ callSpectrumPackage, cryptsetup, rootfs +, runCommand, stdenv, systemdUkify +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit initramfs rootfs systemd; }; +} '' + read -r roothash < ${rootfs}/rootfs.verity.roothash + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d ${rootfs.kernel}/dtbs ]; then + find ${rootfs.kernel}/dtbs -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux ${kernel} \ + --initrd ${initramfs} \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/release/live/Makefile b/release/live/Makefile index ba81c7e679429e045b24c1591a9f0b72f016cfab..b37ccce42feb3ac7e8ce4faf96a67902b55be808 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,22 +19,13 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@
-build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty
Why add a build/empty dependency? It doesn't seem to be used for anything any more? (Neither does the DTBS variable, actually.)
$(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux +# This symlink is necessary. Copying $(EFI_IMAGE) directly +# results in an unbootable image. TODO: figure out why. + ln -s $(EFI_IMAGE) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME)
On 11/28/25 06:02, Alyssa Ross wrote:
Demi Marie Obenour <demiobenour@gmail.com> writes:
It will be used by the update code later.
No functional change intended, other than a trivial shell script refactoring.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit.
Changes since v5:
- Create a temporary symlink named build/spectrum.efi and then run $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux, rather than copying the file with its original name. The latter results in an unbootable image. I do not know the reason.
Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ release/live/Makefile | 17 ++++------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 10 ++++++++-- 4 files changed, 63 insertions(+), 31 deletions(-)
diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..ecedb6bea6bf29c7a7303dc9062fe12b5c7a9fbd --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ callSpectrumPackage, cryptsetup, rootfs +, runCommand, stdenv, systemdUkify +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit initramfs rootfs systemd; }; +} '' + read -r roothash < ${rootfs}/rootfs.verity.roothash + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d ${rootfs.kernel}/dtbs ]; then + find ${rootfs.kernel}/dtbs -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux ${kernel} \ + --initrd ${initramfs} \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/release/live/Makefile b/release/live/Makefile index ba81c7e679429e045b24c1591a9f0b72f016cfab..b37ccce42feb3ac7e8ce4faf96a67902b55be808 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,22 +19,13 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@
-build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty
Why add a build/empty dependency? It doesn't seem to be used for anything any more? (Neither does the DTBS variable, actually.)
The temporary symlink bodge below. build/empty isn't needed, but build is. DTBS can just be deleted.
$(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux +# This symlink is necessary. Copying $(EFI_IMAGE) directly +# results in an unbootable image. TODO: figure out why. + ln -s $(EFI_IMAGE) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME)
-- Sincerely, Demi Marie Obenour (she/her/hers)
This patch has been committed as a11ec96aba792c573f670de6ec207a5eea4b0bbd, which can be viewed online at https://spectrum-os.org/git/spectrum/commit/?id=a11ec96aba792c573f670de6ec20.... This is an automated message. Send comments/questions/requests to: Alyssa Ross <hi@alyssa.is>
This doesn't have any functional change, other than to use the read builtin instead of a cat command in a shell script. However, it does make the code much cleaner and more reusable. For instance, one can easily build just the verity image or just the UKI. This will be used by the Nix code that generates an update package. The update package needs the root filesystem, the verity superblock, and the UKI. It doesn't need the installer or the live image. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes in v5: - Rebase - Fix shell.nix files - Link to v4: https://spectrum-os.org/lists/archives/spectrum-devel/20251119-refactor-veri... Changes in v4: - Many cleanups. - Respond to suggestions from code review. - Link to v3: https://spectrum-os.org/lists/archives/spectrum-devel/20251111-refactor-veri... Changes in v3: - Rebase on main - Link to v2: https://spectrum-os.org/lists/archives/spectrum-devel/20251107-refactor-veri... Changes in v2: - Do not break interactive rootfs development. - Link to v1: https://spectrum-os.org/lists/archives/spectrum-devel/20251105-refactor-veri... --- Demi Marie Obenour (2): Build verity images in rootfs Nix derivation Move UKI creation to a separate derivation host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/default.nix | 1 + host/rootfs/Makefile | 44 ++++++++++++++++++++++---------------------- host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 39 +++++++-------------------------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 9 ++++++++- 10 files changed, 103 insertions(+), 95 deletions(-) --- base-commit: c3d53b92c32636736c6585cd934210e29613e38e change-id: 20251105-refactor-verity-9c8ca37e021a -- Sincerely, Demi Marie Obenour (she/her/hers)
Avoid redundant rebuilds of the rootfs verity superblock and roothash. Remove duplicate code. Clean up Makefile to avoid temporary files. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- Changes since v5: - Use consistent naming scheme for Make variables: ROOT_FS is the directory containing the artifacts. ROOT_FS_IMAGE is the root filesystem image, ROOT_FS_VERITY is the verity image, and ROOT_FS_VERITY_ROOTHASH is its root filesystem hash. - Do not try to use a file as a directory. - Use $@ where possible. - Use consistent indentation. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/initramfs/Makefile | 26 +++++--------------------- host/initramfs/default.nix | 1 + host/rootfs/Makefile | 44 ++++++++++++++++++++++---------------------- host/rootfs/default.nix | 6 ++++-- host/rootfs/shell.nix | 2 +- lib/common.mk | 4 ++++ release/live/Makefile | 26 +++++--------------------- release/live/shell.nix | 3 ++- 8 files changed, 44 insertions(+), 68 deletions(-) diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index cb13fbb35f065b67d291d4a35591d6f12720060c..f27f5e07c4707914962197b4fea8f385729370aa 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -35,26 +35,10 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/loop.tar: build/live.img @@ -69,12 +53,12 @@ clean: rm -rf build .PHONY: clean -run: $(dest) build/rootfs.verity.roothash $(RUN_IMAGE) +run: $(dest) $(RUN_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) @../../scripts/run-qemu.sh -m 4G \ -machine virtualization=on \ -kernel $(KERNEL) \ -initrd $(dest) \ - -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< build/rootfs.verity.roothash) nokaslr" \ + -append "ro earlycon console=hvc0 intel_iommu=on roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) nokaslr" \ -cpu max \ -gdb unix:build/gdb.sock,server,nowait \ -parallel none \ diff --git a/host/initramfs/default.nix b/host/initramfs/default.nix index d35e1b514ec48015f5110e65e5ae944b28244c4f..16c932600c0ab54cf439dc7931fc12e863677e0e 100644 --- a/host/initramfs/default.nix +++ b/host/initramfs/default.nix @@ -105,6 +105,7 @@ stdenvNoCC.mkDerivation { env = { PACKAGES_CPIO = packagesCpio; + ROOT_FS = rootfs; } // lib.optionalAttrs stdenvNoCC.hostPlatform.isx86_64 { MICROCODE = microcode; }; diff --git a/host/rootfs/Makefile b/host/rootfs/Makefile index 4067be0c45cc83ce4670ed76e956db58f8e93e02..4cb048ac08b3265b0435d6ff6fc612a58c169ce9 100644 --- a/host/rootfs/Makefile +++ b/host/rootfs/Makefile @@ -1,12 +1,13 @@ # SPDX-License-Identifier: EUPL-1.2+ # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> .POSIX: include ../../lib/common.mk include file-list.mk -dest = build/rootfs.erofs +ROOT_FS = build DIRS = \ dev \ @@ -40,8 +41,22 @@ FIFOS = etc/s6-linux-init/run-image/service/s6-svscan-log/fifo BUILD_FILES = build/etc/s6-rc -$(dest): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk - set -euo pipefail; \ +# This rule produces three files but Make only (portably) +# supports one output per rule. Instead of resorting to temporary +# files, a timestamp file is created as the last step. The actual +# outputs are produced as side-effects. +build/verity-timestamp: $(ROOT_FS_IMAGE) + $(VERITYSETUP) format \ + --root-hash-file $(ROOT_FS_VERITY_ROOTHASH) \ + -- $(ROOT_FS_IMAGE) $(ROOT_FS_VERITY) +# Add trailing newline so that the read < $(ROOT_FS_VERITY_ROOTHASH) succeeds. +# Without the trailing newline it assumes a premature EOF happened and returns +# a nonzero status. + echo >> $(ROOT_FS_VERITY_ROOTHASH) + touch -- $@ + +$(ROOT_FS_IMAGE): ../../scripts/make-erofs.sh $(PACKAGES_FILE) $(FILES) $(BUILD_FILES) build/empty build/fifo file-list.mk + mkdir -p $(ROOT_FS) && \ { \ cat $(PACKAGES_FILE) ;\ for file in $(FILES) $(LINKS); do printf '%s\n%s\n' $$file "$${file#image/}"; done ;\ @@ -77,25 +92,10 @@ clean: rm -rf build .PHONY: clean -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(dest) - $(VERITYSETUP) format $(dest) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - -build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/rootfs.verity.superblock build/rootfs.verity.roothash $(dest) +build/live.img: ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/verity-timestamp $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(dest):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ debug: @@ -126,7 +126,7 @@ run: build/live.img build/rootfs.verity.roothash -device virtconsole,chardev=virtiocon0 \ -drive file=build/live.img,if=virtio,format=raw,readonly=on \ -drive file=/proc/self/fd/3,if=virtio,format=raw \ - -append "earlycon console=hvc0 roothash=$$(< build/rootfs.verity.roothash) intel_iommu=on nokaslr" \ + -append "earlycon console=hvc0 roothash=$$(< $(ROOT_FS_VERITY_ROOTHASH)) intel_iommu=on nokaslr" \ -device virtio-keyboard \ -device virtio-mouse \ -device virtio-gpu \ diff --git a/host/rootfs/default.nix b/host/rootfs/default.nix index f7974a41052468f9782214f32355dda97af3cd60..941c04e619baa7652d1812f4eb50445c607d5884 100644 --- a/host/rootfs/default.nix +++ b/host/rootfs/default.nix @@ -118,7 +118,7 @@ stdenvNoCC.mkDerivation { }; sourceRoot = "source/host/rootfs"; - nativeBuildInputs = [ erofs-utils spectrum-build-tools s6-rc ]; + nativeBuildInputs = [ cryptsetup erofs-utils spectrum-build-tools s6-rc ]; env = { PACKAGES = runCommand "packages" {} '' @@ -127,7 +127,9 @@ stdenvNoCC.mkDerivation { ''; }; - makeFlags = [ "dest=$(out)" ]; + # The Makefile uses $(ROOT_FS), not $(dest), so it can share code + # with other Makefiles that also use this variable. + makeFlags = [ "ROOT_FS=$(out)" ]; dontInstall = true; diff --git a/host/rootfs/shell.nix b/host/rootfs/shell.nix index 1bf61bebf418333624e799cc8ca231f5783206f4..6df2f575fdfc7cdf8067ccfdb5fecaad9f6ea5e6 100644 --- a/host/rootfs/shell.nix +++ b/host/rootfs/shell.nix @@ -12,7 +12,7 @@ rootfs.overrideAttrs ( { nativeBuildInputs = nativeBuildInputs ++ [ - btrfs-progs cryptsetup jq netcat qemu_kvm reuse util-linux + btrfs-progs jq netcat qemu_kvm reuse util-linux ]; env = env // { diff --git a/lib/common.mk b/lib/common.mk index 277c3544036d9a9057f8ba4ad37fe2207548cc59..84091a8dfd615b2aaa021c7477f34c4dff88ccde 100644 --- a/lib/common.mk +++ b/lib/common.mk @@ -11,6 +11,10 @@ GDB = gdb MCOPY = mcopy MKFS_FAT = mkfs.fat MMD = mmd +ROOT_FS_IMAGE = $(ROOT_FS)/rootfs +ROOT_FS_IMAGES = $(ROOT_FS_IMAGE) $(ROOT_FS_VERITY_ROOTHASH) $(ROOT_FS_VERITY) +ROOT_FS_VERITY = $(ROOT_FS)/rootfs.verity.superblock +ROOT_FS_VERITY_ROOTHASH = $(ROOT_FS)/rootfs.verity.roothash S6_IPCSERVER_SOCKETBINDER = s6-ipcserver-socketbinder TAR = tar TRUNCATE = truncate diff --git a/release/live/Makefile b/release/live/Makefile index 6dcbdeedda5d6ccf293f60dc62043f46c81ecf83..ba81c7e679429e045b24c1591a9f0b72f016cfab 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -9,17 +9,17 @@ DTBS ?= build/empty dest = build/live.img -$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) +$(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sfdisk-field.awk build/boot.fat $(ROOT_FS_IMAGES) ../../scripts/make-gpt.sh $@.tmp \ build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ - build/rootfs.verity.superblock:verity:$$(../../scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ - $(ROOT_FS):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") + $(ROOT_FS_VERITY):verity:$$(../../scripts/format-uuid.sh "$$(dd if=$(ROOT_FS_VERITY_ROOTHASH) bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS_IMAGE):root:$$(../../scripts/format-uuid.sh "$$(head -c 32 $(ROOT_FS_VERITY_ROOTHASH))") mv $@.tmp $@ build/empty: mkdir -p $@ -build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) +build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) { \ printf "[UKI]\nDeviceTreeAuto=" && \ find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ @@ -29,7 +29,7 @@ build/spectrum.efi: build/rootfs.verity.roothash $(DTBS) $(KERNEL) $(INITRAMFS) --linux $(KERNEL) \ --initrd $(INITRAMFS) \ --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat build/rootfs.verity.roothash)" + --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(TRUNCATE) -s 440401920 $@ @@ -38,22 +38,6 @@ build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) -# veritysetup format produces two files, but Make only (portably) -# supports one output per rule, so we combine the two outputs then -# define two more rules to separate them again. -build/rootfs.verity: $(ROOT_FS) - mkdir -p build - $(VERITYSETUP) format $(ROOT_FS) build/rootfs.verity.superblock.tmp \ - | awk -F ':[[:blank:]]*' '$$1 == "Root hash" {print $$2; exit}' \ - > build/rootfs.verity.roothash.tmp - cat build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp \ - > $@ - rm build/rootfs.verity.roothash.tmp build/rootfs.verity.superblock.tmp -build/rootfs.verity.roothash: build/rootfs.verity - head -n 1 build/rootfs.verity > $@ -build/rootfs.verity.superblock: build/rootfs.verity - tail -n +2 build/rootfs.verity > $@ - clean: rm -rf build .PHONY: clean diff --git a/release/live/shell.nix b/release/live/shell.nix index 5acaa8c5b113fd2789aaea9268487b193bab37af..799d575b4f6e6f3dad8ac1a0a8bc2e3fc46aab44 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,7 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: +import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,6 +10,7 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm }: env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; + ROOT_FS = rootfs; }; } )) (_: {}) -- 2.52.0
It will be used by the update code later. No functional change intended, other than a trivial shell script refactoring. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- I kept release/live/default.nix using the UKI's systemd because the old code did it that way. Changing this would be better in a separate commit. Changes since v5: - Create a temporary symlink named build/spectrum.efi and then run $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux, rather than copying the file with its original name. The latter results in an unbootable image. I do not know the reason. Signed-off-by: Demi Marie Obenour <demiobenour@gmail.com> --- host/efi.nix | 40 ++++++++++++++++++++++++++++++++++++++++ release/live/Makefile | 17 ++++------------- release/live/default.nix | 27 +++++++++++---------------- release/live/shell.nix | 10 ++++++++-- 4 files changed, 63 insertions(+), 31 deletions(-) diff --git a/host/efi.nix b/host/efi.nix new file mode 100644 index 0000000000000000000000000000000000000000..ecedb6bea6bf29c7a7303dc9062fe12b5c7a9fbd --- /dev/null +++ b/host/efi.nix @@ -0,0 +1,40 @@ +# SPDX-License-Identifier: MIT +# SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2025 Demi Marie Obenour <demiobenour@gmail.com> + +import ../lib/call-package.nix ( +{ callSpectrumPackage, cryptsetup, rootfs +, runCommand, stdenv, systemdUkify +}: +let + initramfs = callSpectrumPackage ./initramfs {}; + kernel = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { + # The default limit is too low to build a generic aarch64 distro image: + # https://github.com/systemd/systemd/pull/37417 + mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; + }); +in + +runCommand "spectrum-efi" { + nativeBuildInputs = [ cryptsetup systemd ]; + __structuredAttrs = true; + unsafeDiscardReferences = { out = true; }; + dontFixup = true; + passthru = { inherit initramfs rootfs systemd; }; +} '' + read -r roothash < ${rootfs}/rootfs.verity.roothash + { \ + printf "[UKI]\nDeviceTreeAuto=" + if [ -d ${rootfs.kernel}/dtbs ]; then + find ${rootfs.kernel}/dtbs -name '*.dtb' -print0 | tr '\0' ' ' + fi + } | ukify build \ + --output "$out" \ + --config /dev/stdin \ + --linux ${kernel} \ + --initrd ${initramfs} \ + --os-release $'NAME="Spectrum"\n' \ + --cmdline "ro intel_iommu=on roothash=$roothash" + '' +) (_: {}) diff --git a/release/live/Makefile b/release/live/Makefile index ba81c7e679429e045b24c1591a9f0b72f016cfab..b37ccce42feb3ac7e8ce4faf96a67902b55be808 100644 --- a/release/live/Makefile +++ b/release/live/Makefile @@ -19,22 +19,13 @@ $(dest): ../../scripts/format-uuid.sh ../../scripts/make-gpt.sh ../../scripts/sf build/empty: mkdir -p $@ -build/spectrum.efi: $(DTBS) $(KERNEL) $(INITRAMFS) $(ROOT_FS_VERITY_ROOTHASH) - { \ - printf "[UKI]\nDeviceTreeAuto=" && \ - find $(DTBS) -name '*.dtb' -print0 | tr '\0' ' ' ;\ - } | $(UKIFY) build \ - --output $@ \ - --config /dev/stdin \ - --linux $(KERNEL) \ - --initrd $(INITRAMFS) \ - --os-release $$'NAME="Spectrum"\n' \ - --cmdline "ro intel_iommu=on roothash=$$(cat $(ROOT_FS_VERITY_ROOTHASH))" - -build/boot.fat: $(SYSTEMD_BOOT_EFI) build/spectrum.efi +build/boot.fat: $(SYSTEMD_BOOT_EFI) $(EFI_IMAGE) build/empty $(TRUNCATE) -s 440401920 $@ $(MKFS_FAT) $@ $(MMD) -i $@ ::/EFI ::/EFI/BOOT ::/EFI/Linux +# This symlink is necessary. Copying $(EFI_IMAGE) directly +# results in an unbootable image. TODO: figure out why. + ln -s $(EFI_IMAGE) build/spectrum.efi $(MCOPY) -i $@ build/spectrum.efi ::/EFI/Linux $(MCOPY) -i $@ $(SYSTEMD_BOOT_EFI) ::/EFI/BOOT/$(EFINAME) diff --git a/release/live/default.nix b/release/live/default.nix index 2a1dc3e1dd939f21edac582bf39737eb4d46eb0c..ba9bb17e697a6ecfe81e52a4ffbc375ef443b6f3 100644 --- a/release/live/default.nix +++ b/release/live/default.nix @@ -3,10 +3,9 @@ # SPDX-FileCopyrightText: 2022 Unikie import ../../lib/call-package.nix ( -{ callSpectrumPackage, spectrum-build-tools, rootfs, src +{ callSpectrumPackage, spectrum-build-tools, src , lib, pkgsStatic, stdenvNoCC , cryptsetup, dosfstools, jq, mtools, util-linux -, systemdUkify }: let @@ -14,14 +13,12 @@ let stdenv = stdenvNoCC; - systemd = systemdUkify.overrideAttrs ({ mesonFlags ? [], ... }: { - # The default limit is too low to build a generic aarch64 distro image: - # https://github.com/systemd/systemd/pull/37417 - mesonFlags = mesonFlags ++ [ "-Defi-stub-extra-sections=3000" ]; - }); - - initramfs = callSpectrumPackage ../../host/initramfs {}; efiArch = stdenv.hostPlatform.efiArch; + + efi = callSpectrumPackage ../../host/efi.nix {}; + + # The initramfs and rootfs must match those used to build the UKI. + inherit (efi) initramfs rootfs systemd; in stdenv.mkDerivation { @@ -40,17 +37,15 @@ stdenv.mkDerivation { sourceRoot = "source/release/live"; nativeBuildInputs = [ - cryptsetup dosfstools jq spectrum-build-tools mtools systemd util-linux + cryptsetup dosfstools jq spectrum-build-tools mtools util-linux ]; env = { - INITRAMFS = initramfs; - KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; - ROOT_FS = rootfs; + KERNEL = "${efi.rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + ROOT_FS = "${efi.rootfs}"; SYSTEMD_BOOT_EFI = "${systemd}/lib/systemd/boot/efi/systemd-boot${efiArch}.efi"; + EFI_IMAGE = efi; EFINAME = "BOOT${toUpper efiArch}.EFI"; - } // lib.optionalAttrs stdenv.hostPlatform.linux-kernel.DTB or false { - DTBS = "${rootfs.kernel}/dtbs"; }; buildFlags = [ "dest=$(out)" ]; @@ -63,6 +58,6 @@ stdenv.mkDerivation { unsafeDiscardReferences = { out = true; }; dontFixup = true; - passthru = { inherit initramfs rootfs; }; + passthru = { inherit efi initramfs rootfs; }; } ) (_: {}) diff --git a/release/live/shell.nix b/release/live/shell.nix index 799d575b4f6e6f3dad8ac1a0a8bc2e3fc46aab44..b0bf957c085d1581a24d8916925611da0a60ec8b 100644 --- a/release/live/shell.nix +++ b/release/live/shell.nix @@ -1,7 +1,12 @@ # SPDX-License-Identifier: MIT # SPDX-FileCopyrightText: 2021-2024 Alyssa Ross <hi@alyssa.is> -import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, rootfs }: +import ../../lib/call-package.nix ( +{ callSpectrumPackage, stdenv, qemu_kvm }: + +let + efi = callSpectrumPackage ../../host/efi.nix {}; +in (callSpectrumPackage ./. {}).overrideAttrs ( { nativeBuildInputs ? [], env ? {}, ... }: @@ -10,7 +15,8 @@ import ../../lib/call-package.nix ({ callSpectrumPackage, stdenv, qemu_kvm, root env = env // { OVMF_CODE = "${qemu_kvm}/share/qemu/edk2-${stdenv.hostPlatform.qemuArch}-code.fd"; - ROOT_FS = rootfs; + ROOT_FS = efi.rootfs; + EFI_IMAGE = efi; }; } )) (_: {}) -- 2.52.0
participants (3)
-
Alyssa Ross -
Alyssa Ross -
Demi Marie Obenour