diff --git a/.build.yml b/.build.yml index b6cd65f..202dc94 100644 --- a/.build.yml +++ b/.build.yml @@ -7,6 +7,7 @@ packages: - libtss2-dev - libtspi-dev - ronn + - shellcheck tasks: - get-zfs: | sudo sed -i 's/main/main contrib non-free/' /etc/apt/sources.list diff --git a/.gitignore b/.gitignore index dc1fd43..f72360a 100644 --- a/.gitignore +++ b/.gitignore @@ -15,7 +15,5 @@ !man/** !ext !ext/** -!test -!test/** -!test-data -!test-data/** +!initrd +!initrd/** diff --git a/Makefile b/Makefile index 8debce3..31d8979 100644 --- a/Makefile +++ b/Makefile @@ -30,36 +30,41 @@ INCAR := $(foreach l,$(foreach l,,$(l)/include),-isystemext/$(l)) $(foreach l,,- VERAR := $(foreach l,TZPFMS,-D$(l)_VERSION='$($(l)_VERSION)') BINARY_SOURCES := $(sort $(wildcard $(SRCDIR)bin/*.cpp $(SRCDIR)bin/**/*.cpp)) COMMON_SOURCES := $(filter-out $(BINARY_SOURCES),$(sort $(wildcard $(SRCDIR)*.cpp $(SRCDIR)**/*.cpp $(SRCDIR)**/**/*.cpp $(SRCDIR)**/**/**/*.cpp))) -# TEST_SOURCES := $(sort $(wildcard $(TSTDIR)*.cpp $(TSTDIR)**/*.cpp $(TSTDIR)**/**/*.cpp $(TSTDIR)**/**/**/*.cpp)) +SHELLCHECK_SOURCES := $(sort $(shell grep -lR '#!/bin/.*sh' $(INITRDDIR))) MANPAGE_SOURCES := $(sort $(wildcard $(MANDIR)*.md.pp)) -.PHONY : all clean build build-test man +.PHONY : all clean build shellcheck i-t man .SECONDARY: -all : build man # build-test test - -#test: build-test -# $(OUTDIR)tzpfms-test$(EXE) +all : build man shellcheck i-t clean : rm -rf $(OUTDIR) build : $(subst $(SRCDIR)bin/,$(OUTDIR),$(subst .cpp,$(EXE),$(BINARY_SOURCES))) -#build-test : $(OUTDIR)tzpfms-test$(EXE) man : $(OUTDIR)man/index.txt +shellcheck : $(BLDDIR)shellcheck-stamp +i-t : $(OUTDIR)initramfs-tools -#$(OUTDIR)tzpfms-test$(EXE) : $(subst $(TSTDIR),$(BLDDIR)test/,$(subst .cpp,$(OBJ),$(TEST_SOURCES))) $(subst $(SRCDIR),$(OBJDIR),$(subst .cpp,$(OBJ),$(filter-out $(SRCDIR)main.cpp,$(SOURCES)))) $(patsubst ext/fmt/src/%.cc,$(BLDDIR)fmt/obj/%$(OBJ),$(wildcard ext/fmt/src/*.cc)) -# $(CXX) $(CXXAR) -o$@ $^ $(PIC) $(LDAR) - $(OUTDIR)man/index.txt : $(MANDIR)index.txt $(patsubst $(MANDIR)%.pp,$(OUTDIR)man/%,$(MANPAGE_SOURCES)) @mkdir -p $(dir $@) cp $< $(dir $@) $(RONN) --organization="tzpfms developers" $(filter-out $<,$^) $(RONN) --organization="tzpfms developers" -f $(filter-out $<,$^) +$(BLDDIR)shellcheck-stamp : $(SHELLCHECK_SOURCES) + @mkdir -p $(dir $@) + $(SHELLCHECK) --exclude SC1091 $^ + @date > $@ + +$(OUTDIR)initramfs-tools : $(sort $(wildcard $(INITRDDIR)initramfs-tools)) + @mkdir -p $@/usr/share/initramfs-tools/hooks $@/usr/share/tzpfms + ln $(INITRDDIR)initramfs-tools/hook $@/usr/share/initramfs-tools/hooks/tzpfms + ln $(INITRDDIR)initramfs-tools/zfs-patch.sh $@/usr/share/tzpfms/initramfs-tools-zfs-patch.sh + $(OUTDIR)%$(EXE) : $(subst $(SRCDIR),$(OBJDIR),$(subst .cpp,$(OBJ),$(SRCDIR)bin/%.cpp $(COMMON_SOURCES))) @mkdir -p $(dir $@) diff --git a/README.md b/README.md index 2b43d37..40e1d32 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ Plus it's a pretty good annoyed sigh onomatopoeia. ### Building -You'll need `pkg-config`, `ronn`, `libzfslinux-dev`, `libtss2-dev`, `libtspi-dev`, and `make` should hopefully Just Work™ if you have a C++17-capable compiler. +You'll need `pkg-config`, `ronn`, `shellcheck`, `libzfslinux-dev`, `libtss2-dev`, `libtspi-dev`, and `make` should hopefully Just Work™ if you have a C++17-capable compiler. The output binaries are trimmed of extraneous dependencies, so they're all just libc + libzfs and friends + the chosen TPM back-end, if any. ### Installation diff --git a/configMakefile b/configMakefile index 831ded7..82f5325 100644 --- a/configMakefile +++ b/configMakefile @@ -54,6 +54,7 @@ LNCMAKEAR := LDFLAGS="$(LNCXXAR)" AWK ?= awk RONN ?= ronn +SHELLCHECK ?= shellcheck OBJ := .o CXXAR := -O3 -std=c++17 -fno-exceptions -Wall -Wextra $(CXXSPECIFIC) -pipe $(INCCXXAR) $(PIC) STRIP ?= strip @@ -65,3 +66,4 @@ OBJDIR := $(BLDDIR)obj/ SRCDIR := src/ TSTDIR := test/ MANDIR := man/ +INITRDDIR := initrd/ diff --git a/initrd/initramfs-tools/hook b/initrd/initramfs-tools/hook new file mode 100755 index 0000000..c09f7d0 --- /dev/null +++ b/initrd/initramfs-tools/hook @@ -0,0 +1,20 @@ +#!/bin/sh +# SPDX-License-Identifier: MIT + +PREREQ="zfs" +[ "$1" = "prereqs" ] && exec echo "$PREREQ" +. /usr/share/initramfs-tools/hook-functions + + +# Bit of a hack: replace zfs-intramfs' decrypt_fs() in /scripts/zfs with our version that understands tzpfms datasets +sed -Ei 's/decrypt_fs\(\)/__tzpfms__&/' "$DESTDIR/scripts/zfs" +cat /usr/share/tzpfms/initramfs-tools-zfs-patch.sh >> "$DESTDIR/scripts/zfs" + + +for x in zfs-tpm-list zfs-tpm2-load-key zfs-tpm1x-load-key; do + xloc="$(command -v "$x")" + [ "$xloc" = "" ] || copy_exec "$xloc" +done + + +add_loaded_modules '*tpm*' # TODO: is this the best way of going about this? diff --git a/initrd/initramfs-tools/zfs-patch.sh b/initrd/initramfs-tools/zfs-patch.sh new file mode 100644 index 0000000..0252456 --- /dev/null +++ b/initrd/initramfs-tools/zfs-patch.sh @@ -0,0 +1,52 @@ +#!/bin/sh +# SPDX-License-Identifier: MIT + +# Included into /scripts/zfs in the initrd, replacing the original decrypt_fs(), now available as __tzpfms__decrypt_fs() +decrypt_fs() { + fs="$1" + + # Bail early if we don't have even the common binaries + if ! command -v zfs-tpm-list > /dev/null; then + __tzpfms__decrypt_fs "${fs}" + return + fi + + # First three lines borrowed from /scripts/zfs#decrypt_fs() + # If pool encryption is active and the zfs command understands '-o encryption' + if [ "$(zpool list -H -o feature@encryption "$(echo "${fs}" | awk -F/ '{print $1}')")" = 'active' ]; then + ENCRYPTIONROOT="$(get_fs_value "${fs}" encryptionroot)" + + if ! [ "$ENCRYPTIONROOT" = "-" ]; then + if command -v zfs-tpm2-load-key > /dev/null && ! [ "$(zfs-tpm-list -Hub TPM2 "$ENCRYPTIONROOT")" = "" ]; then + with_promptable_tty zfs-tpm2-load-key "$ENCRYPTIONROOT" + return + fi + + if command -v zfs-tpm1x-load-key > /dev/null && ! [ "$(zfs-tpm-list -Hub TPM1.X "$ENCRYPTIONROOT")" = "" ]; then + with_promptable_tty zfs-tpm1x-load-key "$ENCRYPTIONROOT" + return + fi + + __tzpfms__decrypt_fs "${fs}" + return + fi + fi + + return 0 +} + +# Mimic /scripts/zfs#decrypt_fs(): setting "printk" temporarily to "7" will allow prompt even if kernel option "quiet" +# TODO?: /scripts/zfs#decrypt_fs() checks for plymouth and systemd, +# but we don't know how many passphrases we're gonna read (anywhere between 0 and 2 best-base or 0 and 6 worst-case); +# can we "disable" plymouth somehow? +with_promptable_tty() { + printk="$(awk '{print $1}' /proc/sys/kernel/printk)" + echo 7 > /proc/sys/kernel/printk + + "$@" + ret="$?" + + echo "$printk" > /proc/sys/kernel/printk + + return "$ret" +} diff --git a/tzpfms.sublime-project b/tzpfms.sublime-project index accad71..a274aaa 100644 --- a/tzpfms.sublime-project +++ b/tzpfms.sublime-project @@ -27,18 +27,8 @@ }, { "follow_symlinks": true, - "name": "Test", - "path": "test" - }, - { - "follow_symlinks": true, - "name": "Test data", - "path": "test-data" - }, - { - "follow_symlinks": true, - "name": "External code", - "path": "ext" + "name": "Initrd plug-ins", + "path": "initrd" }, { "follow_symlinks": true,