Hi, some time ago I added zfs verification to cgdconfig which I'd like to share in case others find it useful. This lets you use zpools/vdevs on cgd encrypted disks without an intermediate gpt label. The verification method is the same as used in usr.sbin/fstyp. The downside is that this modification requires linking cgdconfig against libnvpair when compiling with MKZFS, which adds about 100kb. I've attached 3 patches: 0001-cgdconfig-Add-zfs-verification-method.patch Everything necessary to add ZFS verification for cgdconfig, including changes to the man page, Makefile, and linking libnvpair for rescue and cgdroot when building with MKZFS. 0002-Add-cgd-zfs-ramdisk.patch Adds a cgdzfsroot ramdisk, a simple combination of the existing cgdroot and zfsroot ramdisks which lets you boot a system from a cgd-encrypted zfs root pool. 0003-fstyp-Don-t-link-libzfs.patch Don't link usr.sbin/fstyp against libzfs. It really just needs libnvpair. You can also pull the changes from here: https://github.com/mdehling/netbsd-src/tree/mdehling_cgd-zfs Cheers, -- Malte Dehling
From 3b9daeb69e8db94cbd5321e903d0a0cdce504b0f Mon Sep 17 00:00:00 2001 From: Malte Dehling <mdehling%gmail.com@localhost> Date: Sun, 14 Apr 2024 10:04:27 -0700 Subject: [PATCH 1/3] cgdconfig: Add zfs verification method This allows us to create a zpool directly on a cgd device without having to place a gpt label in between. --- .../amd64/ramdisks/ramdisk-cgdroot/Makefile | 3 ++ .../amd64/ramdisks/ramdisk-cgdroot/list.zfs | 3 ++ rescue/Makefile | 4 ++ rescue/list.zfs | 3 ++ sbin/cgdconfig/Makefile | 18 +++++++ sbin/cgdconfig/cgdconfig.8 | 2 + sbin/cgdconfig/cgdconfig.c | 53 +++++++++++++++++++ sbin/cgdconfig/params.c | 9 ++++ sbin/cgdconfig/params.h | 1 + 9 files changed, 96 insertions(+) create mode 100644 distrib/amd64/ramdisks/ramdisk-cgdroot/list.zfs create mode 100644 rescue/list.zfs diff --git a/distrib/amd64/ramdisks/ramdisk-cgdroot/Makefile b/distrib/amd64/ramdisks/ramdisk-cgdroot/Makefile index 7be7a009f28..75b07c6ebf0 100644 --- a/distrib/amd64/ramdisks/ramdisk-cgdroot/Makefile +++ b/distrib/amd64/ramdisks/ramdisk-cgdroot/Makefile @@ -9,6 +9,9 @@ SMALLPROG_INET6=1 .include "${.CURDIR}/../common/Makefile.ramdisk" LISTS+= ${DISTRIBDIR}/common/list.cgdroot +.if ${MKZFS} != "no" +LISTS+= ${.CURDIR}/list.zfs +.endif MTREECONF+= ${DISTRIBDIR}/common/mtree.cgdroot .if ${USE_INET6} != "no" diff --git a/distrib/amd64/ramdisks/ramdisk-cgdroot/list.zfs b/distrib/amd64/ramdisks/ramdisk-cgdroot/list.zfs new file mode 100644 index 00000000000..8247065d020 --- /dev/null +++ b/distrib/amd64/ramdisks/ramdisk-cgdroot/list.zfs @@ -0,0 +1,3 @@ +# $NetBSD$ + +LIBS -lnvpair diff --git a/rescue/Makefile b/rescue/Makefile index 459e8a7135a..6ed6c178f3f 100644 --- a/rescue/Makefile +++ b/rescue/Makefile @@ -42,6 +42,10 @@ LISTS+= ${.CURDIR}/list.${f} LISTS+= ${.CURDIR}/list.inet6 .endif +.if ${MKZFS} != "no" +LISTS+= ${.CURDIR}/list.zfs +.endif + LISTS+= ${.CURDIR}/list.crypto CRUNCHENV+= MKKERBEROS=no # for ssh diff --git a/rescue/list.zfs b/rescue/list.zfs new file mode 100644 index 00000000000..02bf8bc362c --- /dev/null +++ b/rescue/list.zfs @@ -0,0 +1,3 @@ +# $NetBSD$ + +LIBS -lnvpair diff --git a/sbin/cgdconfig/Makefile b/sbin/cgdconfig/Makefile index fec75b4e375..bf1be8109e3 100644 --- a/sbin/cgdconfig/Makefile +++ b/sbin/cgdconfig/Makefile @@ -29,4 +29,22 @@ ARGON2_NO_THREADS=1 .include "${NETBSDSRCDIR}/external/apache2/argon2/lib/libargon2/Makefile.inc" .endif +.if ${MKZFS} != "no" +DPADD+= ${LIBNVPAIR} +LDADD+= -lnvpair +CPPFLAGS+= -DHAVE_ZFS + +OSNET=${NETBSDSRCDIR}/external/cddl/osnet +CPPFLAGS.cgdconfig.c+= -I${OSNET}/include +CPPFLAGS.cgdconfig.c+= -I${OSNET}/sys +CPPFLAGS.cgdconfig.c+= -I${OSNET}/dist/head +CPPFLAGS.cgdconfig.c+= -I${OSNET}/dist/lib/libzpool/common +CPPFLAGS.cgdconfig.c+= -I${OSNET}/dist/uts/common +CPPFLAGS.cgdconfig.c+= -I${OSNET}/dist/uts/common/fs/zfs +CPPFLAGS.cgdconfig.c+= -I${OSNET}/dist/lib/libnvpair + +COPTS.cgdconfig.c+= -Wno-unknown-pragmas +COPTS.cgdconfig.c+= -Wno-strict-prototypes +.endif + .include <bsd.prog.mk> diff --git a/sbin/cgdconfig/cgdconfig.8 b/sbin/cgdconfig/cgdconfig.8 index 2b0da2cb732..e48ccde02c5 100644 --- a/sbin/cgdconfig/cgdconfig.8 +++ b/sbin/cgdconfig/cgdconfig.8 @@ -270,6 +270,8 @@ scan for a valid Master Boot Record. scan for a valid GUID partition table. .It ffs scan for a valid FFS file system. +.It zfs +scan for a valid ZFS vdev label (if compiled with MKZFS). .It re-enter prompt for passphrase twice, and ensure entered passphrases are identical. diff --git a/sbin/cgdconfig/cgdconfig.c b/sbin/cgdconfig/cgdconfig.c index 9a634ef37e2..4baccb1d68f 100644 --- a/sbin/cgdconfig/cgdconfig.c +++ b/sbin/cgdconfig/cgdconfig.c @@ -73,6 +73,11 @@ __RCSID("$NetBSD: cgdconfig.c,v 1.61 2022/11/17 06:40:38 chs Exp $"); #include <ufs/ffs/fs.h> +#ifdef HAVE_ZFS +#include <libnvpair.h> +#include <sys/vdev_impl.h> +#endif + #include "params.h" #include "pkcs5_pbkdf2.h" #include "utils.h" @@ -170,6 +175,9 @@ static int verify_ffs(int); static int verify_reenter(struct params *); static int verify_mbr(int); static int verify_gpt(int); +#ifdef HAVE_ZFS +static int verify_zfs(int); +#endif __dead static void usage(void); @@ -1024,6 +1032,10 @@ verify(struct params *p, int fd) return verify_mbr(fd); case VERIFY_GPT: return verify_gpt(fd); +#ifdef HAVE_ZFS + case VERIFY_ZFS: + return verify_zfs(fd); +#endif default: warnx("unimplemented verification method"); return -1; @@ -1182,6 +1194,47 @@ verify_gpt(int fd) return ret; } +#ifdef HAVE_ZFS +static int +verify_zfs(int fd) +{ + vdev_label_t *vdev_label; + vdev_phys_t *vdev_phys; + nvlist_t *config = NULL; + ssize_t ret; + + /* + * Read the first ZFS vdev label located at offset 0. + */ + vdev_label = emalloc(sizeof *vdev_label); + ret = prog_pread(fd, vdev_label, sizeof(*vdev_label), 0); + if (ret < 0) { + warn("pread"); + ret = 1; + goto bail; + } else if ((size_t)ret < sizeof(*vdev_label)) { + warnx("pread: incomplete block"); + ret = 1; + goto bail; + }; + + ret = 0; + + vdev_phys = &(vdev_label->vl_vdev_phys); + if ((nvlist_unpack(vdev_phys->vp_nvlist, + sizeof(vdev_phys->vp_nvlist), &config, 0)) != 0 || + !nvlist_exists(config, "name")) + { + ret = 1; + }; + + nvlist_free(config); + bail: + free(vdev_label); + return ret; +} +#endif + static off_t sblock_try[] = SBLOCKSEARCH; static int diff --git a/sbin/cgdconfig/params.c b/sbin/cgdconfig/params.c index 91af02c21cc..5da25ec0595 100644 --- a/sbin/cgdconfig/params.c +++ b/sbin/cgdconfig/params.c @@ -287,6 +287,10 @@ params_verify_method(string_t *in) p->verify_method = VERIFY_MBR; if (!strcmp("gpt", vm)) p->verify_method = VERIFY_GPT; +#ifdef HAVE_ZFS + if (!strcmp("zfs", vm)) + p->verify_method = VERIFY_ZFS; +#endif string_free(in); @@ -1065,6 +1069,11 @@ params_fput(struct params *p, FILE *f) case VERIFY_GPT: print_kvpair_cstr(f, ts, "verify_method", "gpt"); break; +#ifdef HAVE_ZFS + case VERIFY_ZFS: + print_kvpair_cstr(f, ts, "verify_method", "zfs"); + break; +#endif default: warnx("unsupported verify_method (%d)", p->verify_method); return -1; diff --git a/sbin/cgdconfig/params.h b/sbin/cgdconfig/params.h index fb79a0deb80..ef49dde6aba 100644 --- a/sbin/cgdconfig/params.h +++ b/sbin/cgdconfig/params.h @@ -81,6 +81,7 @@ struct params { #define VERIFY_REENTER 0x4 #define VERIFY_MBR 0x5 #define VERIFY_GPT 0x6 +#define VERIFY_ZFS 0x7 /* shared key derivation methods */ -- 2.44.0
From 31fdb4c03d3dd0ee8236b3e7a37653522a47c75d Mon Sep 17 00:00:00 2001 From: Malte Dehling <mdehling%gmail.com@localhost> Date: Mon, 15 Apr 2024 11:34:30 -0700 Subject: [PATCH 2/3] Add cgd/zfs ramdisk Allows booting into a zfs root pool on a cgd encrypted device. --- distrib/amd64/ramdisks/Makefile | 7 +++- .../ramdisks/ramdisk-cgdzfsroot/Makefile | 23 ++++++++++++ .../amd64/ramdisks/ramdisk-cgdzfsroot/list | 12 +++++++ distrib/common/cgdzfsroot.rc | 36 +++++++++++++++++++ distrib/common/list.cgdzfsroot | 35 ++++++++++++++++++ distrib/common/mtree.cgdzfsroot | 6 ++++ 6 files changed, 118 insertions(+), 1 deletion(-) create mode 100644 distrib/amd64/ramdisks/ramdisk-cgdzfsroot/Makefile create mode 100644 distrib/amd64/ramdisks/ramdisk-cgdzfsroot/list create mode 100644 distrib/common/cgdzfsroot.rc create mode 100644 distrib/common/list.cgdzfsroot create mode 100644 distrib/common/mtree.cgdzfsroot diff --git a/distrib/amd64/ramdisks/Makefile b/distrib/amd64/ramdisks/Makefile index d99db1158da..2addb5e9870 100644 --- a/distrib/amd64/ramdisks/Makefile +++ b/distrib/amd64/ramdisks/Makefile @@ -1,8 +1,13 @@ -# $NetBSD: Makefile,v 1.4.20.1 2024/02/23 18:07:24 martin Exp $ +# $NetBSD$ + +.include <bsd.own.mk> SUBDIR= SUBDIR+= ramdisk SUBDIR+= ramdisk-cgdroot +.if ${MKZFS} != "no" +SUBDIR+= ramdisk-cgdzfsroot +.endif SUBDIR+= ramdisk-zfsroot TARGETS+= release diff --git a/distrib/amd64/ramdisks/ramdisk-cgdzfsroot/Makefile b/distrib/amd64/ramdisks/ramdisk-cgdzfsroot/Makefile new file mode 100644 index 00000000000..4983bc04790 --- /dev/null +++ b/distrib/amd64/ramdisks/ramdisk-cgdzfsroot/Makefile @@ -0,0 +1,23 @@ +# $NetBSD$ + +IMAGE= ramdisk-cgdzfsroot.fs +IMAGESIZE= 5000k +IMAGEDEPENDS= +MAKEDEVTARGETS= all +CRUNCHENV= INIT_CHROOT=1 +SMALLPROG_INET6= 1 + +# Build as re-entrant because zpool requires libhack built this way. +CPPFLAGS+= -D_REENTRANT + +LISTS+= ${.CURDIR}/list +LISTS+= ${DISTRIBDIR}/common/list.cgdzfsroot + +.include "${.CURDIR}/../common/Makefile.ramdisk" +.include "${DISTRIBDIR}/common/Makefile.makedev" + +MTREECONF+= ${DISTRIBDIR}/common/mtree.cgdzfsroot + +.if ${USE_INET6} != "no" +LISTS+= ${DISTRIBDIR}/common/list.inet6 +.endif diff --git a/distrib/amd64/ramdisks/ramdisk-cgdzfsroot/list b/distrib/amd64/ramdisks/ramdisk-cgdzfsroot/list new file mode 100644 index 00000000000..bbcaa577901 --- /dev/null +++ b/distrib/amd64/ramdisks/ramdisk-cgdzfsroot/list @@ -0,0 +1,12 @@ +# $NetBSD$ + +PROG bin/sync + +PROG sbin/fdisk +PROG sbin/gpt +PROG sbin/mbrlabel +PROG sbin/shutdown + +PROG usr/bin/less usr/bin/more + +PROG usr/sbin/installboot diff --git a/distrib/common/cgdzfsroot.rc b/distrib/common/cgdzfsroot.rc new file mode 100644 index 00000000000..cf08a123f5e --- /dev/null +++ b/distrib/common/cgdzfsroot.rc @@ -0,0 +1,36 @@ +# $NetBSD$ + +# Assumption - boot.cfg loads this ramdisk. +# Assumption - The needed kernel modules (solaris, and zfs) are either on this +# ramdisk or loaded by boot.cfg. +# Assumption - The root pool has mountpoint=legacy set. + +# +# XXX: Can these be set in boot.cfg? Or should we read them from /efi? +# +rpool="rpool" +rdataset="ROOT/default" + +export PATH=/sbin:/bin:/usr/sbin:/usr/bin +export HOME=/ +export TERM=wsvt25 +export BLOCKSIZE=1k +export EDITOR=ed + +umask 022 + +echo "Mounting /boot read-only." +mount -o ro NAME=boot /boot || exit 1 + +echo "Running cgdconfig..." +cgdconfig -C || exit 1 +umount /boot + +echo "Importing ${rpool}." +zpool import -f -N "${rpool}" || exit 1 + +echo "Mounting ${rpool}/${rdataset} to /altroot." +mount_zfs "${rpool}/${rdataset}" /altroot || exit 1 + +echo "Booting into /altroot..." +sysctl -w init.root=/altroot diff --git a/distrib/common/list.cgdzfsroot b/distrib/common/list.cgdzfsroot new file mode 100644 index 00000000000..29db5b77b1f --- /dev/null +++ b/distrib/common/list.cgdzfsroot @@ -0,0 +1,35 @@ +# $NetBSD$ +# +# list file (c.f. parselist.awk) for root on CGD encrypted ZFS. +# + +PROG sbin/cgdconfig + +SYMLINK /boot/cgd etc/cgd + +PROG sbin/modload +PROG sbin/modunload +PROG sbin/modstat + +SRCDIRS external/cddl/osnet/sbin +PROG sbin/zpool +PROG sbin/zfs sbin/mount_zfs + +PROG sbin/sysctl + +LIBS -lcrypto +LIBS -lnvpair +LIBS -luutil +LIBS -lzfs +LIBS -lavl +LIBS -lm +LIBS -lpthread +LIBS -lumem +#LIBS -lutil # replaced by libhack +LIBS -lz +LIBS -lzfs_core + +COPY ${NETBSDSRCDIR}/distrib/common/cgdzfsroot.rc etc/rc + +SYMLINK altroot/stand stand +SYMLINK altroot/libdata libdata diff --git a/distrib/common/mtree.cgdzfsroot b/distrib/common/mtree.cgdzfsroot new file mode 100644 index 00000000000..882cda1fdf8 --- /dev/null +++ b/distrib/common/mtree.cgdzfsroot @@ -0,0 +1,6 @@ +# $NetBSD$ + +. +./altroot +./boot +./etc -- 2.44.0
From d50b05a300851be4e83702ac42658999592b4e1c Mon Sep 17 00:00:00 2001 From: Malte Dehling <mdehling%gmail.com@localhost> Date: Tue, 16 Apr 2024 18:02:54 -0700 Subject: [PATCH 3/3] fstyp: Don't link libzfs --- usr.sbin/fstyp/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usr.sbin/fstyp/Makefile b/usr.sbin/fstyp/Makefile index 27482d2ee47..03d4ed9c199 100644 --- a/usr.sbin/fstyp/Makefile +++ b/usr.sbin/fstyp/Makefile @@ -17,7 +17,7 @@ WARNS?= 6 COPTS.zfs.c+= -Wno-unknown-pragmas COPTS.zfs.c+= -Wno-sign-conversion COPTS.zfs.c+= -Wno-strict-prototypes -LDADD+= -lnvpair -lzfs +LDADD+= -lnvpair OSNET=${NETBSDSRCDIR}/external/cddl/osnet CPPFLAGS+= -DHAVE_ZFS -- 2.44.0
Attachment:
signature.asc
Description: PGP signature