diff options
Diffstat (limited to 'host/initramfs')
-rw-r--r-- | host/initramfs/Makefile | 65 | ||||
-rw-r--r-- | host/initramfs/default.nix | 12 | ||||
-rw-r--r-- | host/initramfs/live.nix | 102 | ||||
-rwxr-xr-x | host/initramfs/run | 9 | ||||
-rwxr-xr-x | host/initramfs/scripts/format-uuid.sh | 6 | ||||
-rwxr-xr-x | host/initramfs/scripts/make-gpt.sh | 59 | ||||
-rw-r--r-- | host/initramfs/scripts/sfdisk-field.awk | 20 | ||||
-rw-r--r-- | host/initramfs/shell.nix | 10 |
8 files changed, 191 insertions, 92 deletions
diff --git a/host/initramfs/Makefile b/host/initramfs/Makefile index a001c36..77919c9 100644 --- a/host/initramfs/Makefile +++ b/host/initramfs/Makefile @@ -1,8 +1,19 @@ # SPDX-License-Identifier: EUPL-1.2 -# SPDX-FileCopyrightText: 2021 Alyssa Ross <hi@alyssa.is> +# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is> + +# qemu-kvm is non-standard, but is present in at least Fedora and +# Nixpkgs. If you don't have qemu-kvm, you'll need to set e.g. +# QEMU_KVM = qemu-system-x86_64 -enable-kvm. +QEMU_KVM = qemu-kvm CPIO = cpio CPIOFLAGS = --reproducible -R +0:+0 -H newc +MCOPY = mcopy +MKFS_FAT = mkfs.fat +MMD = mmd +OBJCOPY = objcopy +TRUNCATE = truncate +VERITYSETUP = veritysetup build/initramfs: build/local.cpio $(PACKAGES_CPIO) cat build/local.cpio $(PACKAGES_CPIO) | gzip -9n > $@ @@ -29,6 +40,58 @@ build/mountpoints: cd build/mountpoints && mkdir -p $(MOUNTPOINTS) find build/mountpoints -mindepth 1 -exec touch -d @0 {} ';' +build/cmdline: build/rootfs.verity.roothash + printf "ro console=ttyS0 roothash=" > $@ + cat build/rootfs.verity.roothash >> $@ + +build/bootx64.efi: etc/os-release build/cmdline build/initramfs + $(OBJCOPY) --add-section .osrel=etc/os-release --change-section-vma .osrel=0x20000 \ + --add-section .cmdline=build/cmdline --change-section-vma .cmdline=0x30000 \ + --add-section .linux=$(KERNEL) --change-section-vma .linux=0x40000 \ + --add-section .initrd=build/initramfs --change-section-vma .initrd=0x3000000 \ + $(EFI_STUB) $@ + +build/boot.fat: build/bootx64.efi + $(TRUNCATE) -s 157286400 $@ + $(MKFS_FAT) $@ + $(MMD) -i $@ ::/EFI ::/EFI/BOOT + $(MCOPY) -i $@ build/bootx64.efi ::/EFI/BOOT + +# 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 build/boot.fat build/rootfs.verity.superblock build/rootfs.verity.roothash $(ROOT_FS) $(EXT_FS) + scripts/make-gpt.sh $@.tmp \ + build/boot.fat:c12a7328-f81f-11d2-ba4b-00a0c93ec93b \ + build/rootfs.verity.superblock:2c7357ed-ebd2-46d9-aec1-23d437ec2bf5:$$(scripts/format-uuid.sh "$$(dd if=build/rootfs.verity.roothash bs=32 skip=1 count=1 status=none)") \ + $(ROOT_FS):4f68bce3-e8cd-4db1-96e7-fbcaf984b709:$$(scripts/format-uuid.sh "$$(head -c 32 build/rootfs.verity.roothash)") \ + $(EXT_FS):9293e1ff-cee4-4658-88be-898ec863944f + mv $@.tmp $@ + clean: rm -rf build .PHONY: clean + +run: build/live.img + $(QEMU_KVM) -m 4G \ + -bios $(OVMF_FD) \ + -cpu host \ + -display gtk,gl=on \ + -device virtio-vga-gl \ + -device qemu-xhci \ + -device usb-storage,drive=drive1,removable=true \ + -drive file=build/live.img,id=drive1,format=raw,if=none,readonly=true +.PHONY: run diff --git a/host/initramfs/default.nix b/host/initramfs/default.nix index ba6ede2..833da69 100644 --- a/host/initramfs/default.nix +++ b/host/initramfs/default.nix @@ -1,7 +1,10 @@ -{ pkgs ? import <nixpkgs> {} }: pkgs.callPackage ( +{ pkgs ? import <nixpkgs> {} +, rootfs ? import ../rootfs { inherit pkgs; } +}: +pkgs.callPackage ( { lib, stdenv, runCommand, writeReferencesToFile, pkgsStatic -, busybox, cpio, cryptsetup, linux, lvm2 +, busybox, cpio, cryptsetup, lvm2 }: let @@ -11,6 +14,7 @@ let inherit (lib) cleanSource cleanSourceWith concatMapStringsSep; cryptsetup = cryptsetup'.override { lvm2 = lvm2.override { udev = null; }; }; + linux = rootfs.kernel; packages = [ cryptsetup pkgsStatic.mdevd pkgsStatic.execline @@ -49,7 +53,7 @@ stdenv.mkDerivation { name = "initramfs"; src = cleanSourceWith { - filter = name: _type: name != "${toString ./.}/build" && name != "${toString ./.}/spectrum-live"; + filter = name: _type: name != "${toString ./.}/build"; src = cleanSource ./.; }; @@ -58,7 +62,9 @@ stdenv.mkDerivation { nativeBuildInputs = [ cpio ]; installPhase = '' + runHook preInstall cp build/initramfs $out + runHook postInstall ''; enableParallelBuilding = true; diff --git a/host/initramfs/live.nix b/host/initramfs/live.nix index 80463d7..2c520d8 100644 --- a/host/initramfs/live.nix +++ b/host/initramfs/live.nix @@ -1,89 +1,33 @@ -{ pkgs ? import <nixpkgs> {} }: pkgs.callPackage ( +# SPDX-License-Identifier: EUPL-1.2 +# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is> -{ stdenv, runCommand, runCommandCC, callPackage, pkgsStatic -, cryptsetup, dosfstools, jq, mtools, systemd, util-linux -}: +{ pkgs ? import <nixpkgs> {} }: let - initramfs = (import ./. { inherit pkgs; }).override { linux = kernel; }; - host-rootfs = import ../rootfs { inherit pkgs; }; - extfs = pkgsStatic.callPackage ./extfs.nix { inherit pkgs; }; - - inherit (host-rootfs) kernel; - kernelTarget = stdenv.hostPlatform.linux-kernel.target; - - uki = runCommandCC "spectrum-uki" { - passAsFile = [ "cmdline" ]; - cmdline = "ro console=ttyS0"; - inherit initramfs; - } '' - roothash="$(awk -F ':[[:blank:]]*' '$1 == "Root hash" {print $2; exit}' ${verity.table})" - echo "ro console=ttyS0 roothash=$roothash" > cmdline - objcopy --add-section .osrel=${etc/os-release} --change-section-vma .osrel=0x20000 \ - --add-section .cmdline=cmdline --change-section-vma .cmdline=0x30000 \ - --add-section .linux=${kernel}/${kernelTarget} --change-section-vma .linux=0x40000 \ - --add-section .initrd=$initramfs --change-section-vma .initrd=0x3000000 \ - ${systemd}/lib/systemd/boot/efi/linuxx64.efi.stub $out - ''; - - efi = runCommand "spectrum-efi" { - nativeBuildInputs = [ dosfstools mtools ]; - passthru = { inherit uki; }; - } '' - truncate -s ${toString (150 * 1024 * 1024)} $out - mkfs.vfat $out - mmd -i $out ::/EFI ::/EFI/BOOT - mcopy -i $out ${uki} ::/EFI/BOOT/BOOTX64.EFI - ''; - - verity = runCommand "spectrum-verity" { - nativeBuildInputs = [ cryptsetup ]; - outputs = [ "out" "table" ]; - } '' - veritysetup format ${host-rootfs} $out > $table - ''; + extfs = pkgs.pkgsStatic.callPackage ./extfs.nix { inherit pkgs; }; + rootfs = import ../rootfs { inherit pkgs; }; + initramfs = import ./. { inherit pkgs rootfs; }; in -runCommand "spectrum-live" { - nativeBuildInputs = [ jq util-linux ]; - passthru = { - inherit efi verity; - rootfs = host-rootfs; - }; -} '' - blockSize() { - wc -c "$1" | awk '{printf "%d\n", ($1 + 511) / 512}' - } +with pkgs; - fillPartition() { - read start size < <(sfdisk -J "$1" | jq -r --argjson index "$2" \ - '.partitiontable.partitions[$index] | "\(.start) \(.size)"') - dd if="$3" of="$1" seek="$start" count="$size" conv=notrunc - } +initramfs.overrideAttrs ({ buildFlags ? "", nativeBuildInputs ? [], ... }: { + name = "spectrum-live.img"; - formatUuid() { - printf "%s\n" "''${1:0:8}-''${1:8:4}-''${1:12:4}-''${1:16:4}-''${1:20}" - } + nativeBuildInputs = nativeBuildInputs ++ [ + cryptsetup dosfstools jq mtools util-linux + ]; - roothash="$(awk -F ':[[:blank:]]*' '$1 == "Root hash" {print $2; exit}' ${verity.table})" + EFI_STUB = "${systemd}/lib/systemd/boot/efi/linuxx64.efi.stub"; + EXT_FS = extfs; + KERNEL = "${rootfs.kernel}/${stdenv.hostPlatform.linux-kernel.target}"; + ROOT_FS = rootfs; - efiSize="$(blockSize ${efi})" - veritySize="$(blockSize ${verity})" - rootfsSize="$(blockSize ${host-rootfs})" - extSize="$(blockSize ${extfs})" + buildFlags = "${toString buildFlags} build/live.img"; - truncate -s $(((4 * 2048 + $efiSize + $veritySize + $rootfsSize + $extSize) * 512)) $out - sfdisk $out <<EOF - label: gpt - size=$efiSize, type=c12a7328-f81f-11d2-ba4b-00a0c93ec93b - size=$veritySize, type=2c7357ed-ebd2-46d9-aec1-23d437ec2bf5, uuid=$(formatUuid "$(printf "%s" "$roothash" | tail -c 32)") - size=$rootfsSize, type=4f68bce3-e8cd-4db1-96e7-fbcaf984b709, uuid=$(formatUuid "$(printf "%s" "$roothash" | head -c 32)") - size=$extSize, type=9293e1ff-cee4-4658-88be-898ec863944f - EOF - - fillPartition $out 0 ${efi} - fillPartition $out 1 ${verity} - fillPartition $out 2 ${host-rootfs} - fillPartition $out 3 ${extfs} -'' -) {} + installPhase = '' + runHook preInstall + mv build/live.img $out + runHook postInstall + ''; +}) diff --git a/host/initramfs/run b/host/initramfs/run deleted file mode 100755 index 300ae63..0000000 --- a/host/initramfs/run +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/sh -eux -qemu-kvm -m 4G \ - -bios $(nix-build --no-out-link -A OVMF.fd '<nixpkgs>')/FV/OVMF.fd \ - -cpu host \ - -display gtk,gl=on \ - -device virtio-vga-gl \ - -device qemu-xhci \ - -device usb-storage,drive=drive1,removable=true \ - -drive file=$(nix-build --no-out-link live.nix),id=drive1,format=raw,if=none,readonly=true diff --git a/host/initramfs/scripts/format-uuid.sh b/host/initramfs/scripts/format-uuid.sh new file mode 100755 index 0000000..bada8ce --- /dev/null +++ b/host/initramfs/scripts/format-uuid.sh @@ -0,0 +1,6 @@ +#!/bin/sh -eu +# +# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is> +# SPDX-License-Identifier: EUPL-1.2 + +printf "%s\n" "${1:0:8}-${1:8:4}-${1:12:4}-${1:16:4}-${1:20}" diff --git a/host/initramfs/scripts/make-gpt.sh b/host/initramfs/scripts/make-gpt.sh new file mode 100755 index 0000000..6097d04 --- /dev/null +++ b/host/initramfs/scripts/make-gpt.sh @@ -0,0 +1,59 @@ +#!/bin/sh -eu +# +# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is> +# SPDX-License-Identifier: EUPL-1.2 +# +# usage: make-gpt.sh GPT_PATH PATH:PARTTYPE[:PARTUUID]... + +ONE_MiB=1048576 +TWO_MiB=2097152 + +# Prints the number of 1MiB blocks required to store the file named +# $1. We use 1MiB blocks because that's what sfdisk uses for +# alignment. It would be possible to get a slightly smaller image +# using actual normal-sized 512-byte blocks, but it's probably not +# worth it to configure sfdisk to do that. +sizeMiB() { + wc -c "$1" | awk -v ONE_MiB=$ONE_MiB \ + '{printf "%d\n", ($1 + ONE_MiB - 1) / ONE_MiB}' +} + +# Copies from path $3 into partition number $2 in partition table $1. +fillPartition() { + sfdisk -J "$1" | jq -r --argjson index "$2" \ + '.partitiontable.partitions[$index] | "\(.start) \(.size)"' | + (read start size; + dd if="$3" of="$1" seek="$start" count="$size" conv=notrunc) +} + +# Prints the partition path from a PATH:PARTTYPE[:PARTUUID] string. +partitionPath() { + awk -F: '{print $1}' <<EOF +$1 +EOF +} + +out="$1" +shift + +nl=$'\n' +table="label: gpt" + +# Keep 1MiB free at the start, and 1MiB free at the end. +gptBytes=$TWO_MiB +for partition; do + sizeMiB="$(sizeMiB "$(partitionPath "$partition")")" + table="$table${nl}size=${sizeMiB}MiB,$(awk -f scripts/sfdisk-field.awk -v partition="$partition")" + gptBytes="$(expr "$gptBytes" + "$sizeMiB" \* $ONE_MiB)" +done + +truncate -s "$gptBytes" "$out" +sfdisk "$out" <<EOF +$table +EOF + +n=0 +for partition; do + fillPartition "$out" "$n" "$(partitionPath "$partition")" + n="$(expr "$n" + 1)" +done diff --git a/host/initramfs/scripts/sfdisk-field.awk b/host/initramfs/scripts/sfdisk-field.awk new file mode 100644 index 0000000..c2d9e5d --- /dev/null +++ b/host/initramfs/scripts/sfdisk-field.awk @@ -0,0 +1,20 @@ +#!/usr/bin/awk -f +# +# SPDX-License-Identifier: EUPL-1.2 +# SPDX-FileCopyrightText: 2022 Alyssa Ross <hi@alyssa.is> + +BEGIN { + # Field #1 is the partition path, which make-gpt.sh will turn into + # the size field. Since it's handled elsewhere, we skip that + # first field. + skip=1 + + split("type uuid", keys) + split(partition, fields, ":") + + for (n in fields) { + if (n <= skip) + continue + printf "%s=%s,", keys[n - skip], fields[n] + } +} diff --git a/host/initramfs/shell.nix b/host/initramfs/shell.nix new file mode 100644 index 0000000..02aa685 --- /dev/null +++ b/host/initramfs/shell.nix @@ -0,0 +1,10 @@ +# SPDX-License-Identifier: EUPL-1.2 +# SPDX-FileCopyrightText: 2021-2022 Alyssa Ross <hi@alyssa.is> + +{ pkgs ? import <nixpkgs> {} }: + +with pkgs; + +(import ./live.nix { inherit pkgs; }).overrideAttrs ({ ... }: { + OVMF_FD = "${OVMF.fd}/FV/OVMF.fd"; +}) |