NetBSD-Bugs archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: Re: Re: bin/58212: cgdconfig(8): Add zfs verification method
The following reply was made to PR bin/58212; it has been noted by GNATS.
From: Malte Dehling <mdehling%gmail.com@localhost>
To: netbsd-bugs%netbsd.org@localhost
Cc: Taylor R Campbell <riastradh%netbsd.org@localhost>, gnats-bugs%netbsd.org@localhost
Subject: Re: Re: Re: bin/58212: cgdconfig(8): Add zfs verification method
Date: Mon, 29 Apr 2024 18:46:11 -0700
Hi,
On Sun, Apr 28, 2024 at 01:13:05PM -0700, Malte Dehling wrote:
> >Submitter-Id: net
> >Originator: Malte Dehling
> >Organization:
> >Confidential: no
> >Synopsis: cgdconfig(8): Add zfs verification method
> >Severity: non-critical
> >Priority: medium
> >Category: bin
> >Class: change-request
> >Release: NetBSD 10.0, -current
> >Environment:
> NetBSD 10.0 (GENERIC) #4: Wed Apr 24 12:21:26 PDT 2024
> mdehling@nb-base-dev:/scratch/obj/sys/arch/amd64/compile/GENERIC amd64
>
> >Description:
> I would like to propose the attached patch to add a zfs verification
> method to the cgdconfig(8) program. With such a method, it will be
> possible to use cgd devices as vdevs in a zpool without an intermediate
> gpt.
How about this version instead?
I _think_ I got the byte order logic right:
- deduce the byte order from the magic bytes and use it to initialize
the checksum computation with the same byte order
- on-disk sha256 is always stored in big-endian order, so convert
whatever we compute to BE before comparing
Tested only on LE since I don't have a BE netbsd system handy right now.
---
Implement vdev label checksum verification. Allows using raw cgd
devices as vdevs in a zpool.
---
sbin/cgdconfig/Makefile | 15 +++++
sbin/cgdconfig/cgdconfig.8 | 2 +
sbin/cgdconfig/cgdconfig.c | 111 +++++++++++++++++++++++++++++++++++++
sbin/cgdconfig/params.c | 9 +++
sbin/cgdconfig/params.h | 1 +
5 files changed, 138 insertions(+)
diff --git a/sbin/cgdconfig/Makefile b/sbin/cgdconfig/Makefile
index fec75b4e375..0ed669ab738 100644
--- a/sbin/cgdconfig/Makefile
+++ b/sbin/cgdconfig/Makefile
@@ -29,4 +29,19 @@ ARGON2_NO_THREADS=1
.include "${NETBSDSRCDIR}/external/apache2/argon2/lib/libargon2/Makefile.inc"
.endif
+.if ${MKZFS} != "no"
+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
+
+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..de4d09013bf 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 <sys/vdev_impl.h>
+#include <sha2.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,105 @@ verify_gpt(int fd)
return ret;
}
+#ifdef HAVE_ZFS
+
+#define ZIO_CHECKSUM_BE(zcp) \
+{ \
+ (zcp)->zc_word[0] = BE_64((zcp)->zc_word[0]); \
+ (zcp)->zc_word[1] = BE_64((zcp)->zc_word[1]); \
+ (zcp)->zc_word[2] = BE_64((zcp)->zc_word[2]); \
+ (zcp)->zc_word[3] = BE_64((zcp)->zc_word[3]); \
+}
+
+static int
+verify_zfs(int fd)
+{
+ struct stat sb;
+ vdev_phys_t *vdev_phys;
+ off_t vdev_phys_off;
+ ssize_t ret;
+ bool byteswap;
+ zio_cksum_t cksum_found, cksum_real;
+ SHA256_CTX ctx;
+
+ if (fstat(fd, &sb)) {
+ warn("fstat");
+ return 1;
+ } else if (sb.st_size == 0) {
+ warnx("fstat returned size zero");
+ return 1;
+ }
+
+ vdev_phys = emalloc(sizeof *vdev_phys);
+ for (int l = 0; l < VDEV_LABELS; l++) {
+ vdev_phys_off = ( l < VDEV_LABELS/2 ?
+ l * sizeof(vdev_label_t) :
+ sb.st_size - (VDEV_LABELS-l) * sizeof(vdev_label_t) ) \
+ + offsetof(vdev_label_t, vl_vdev_phys);
+
+ ret = prog_pread(fd, vdev_phys, sizeof *vdev_phys,
+ vdev_phys_off);
+ if (ret < 0) {
+ warn("pread");
+ ret = 1;
+ break;
+ } else if ((size_t)ret < sizeof *vdev_phys) {
+ warnx("pread: incomplete block");
+ ret = 1;
+ break;
+ }
+
+ ret = 0;
+
+ if (vdev_phys->vp_zbt.zec_magic == BSWAP_64(ZEC_MAGIC))
+ byteswap = true;
+ else if (vdev_phys->vp_zbt.zec_magic == ZEC_MAGIC)
+ byteswap = false;
+ else {
+ ret = 1;
+ break;
+ };
+
+ cksum_found = vdev_phys->vp_zbt.zec_cksum;
+
+ ZIO_SET_CHECKSUM(&vdev_phys->vp_zbt.zec_cksum,
+ vdev_phys_off, 0, 0, 0);
+ if (byteswap)
+ ZIO_CHECKSUM_BSWAP(&vdev_phys->vp_zbt.zec_cksum);
+
+ SHA256Init(&ctx);
+ SHA256Update(&ctx, (uint8_t *)vdev_phys, sizeof *vdev_phys);
+ SHA256Final(&cksum_real, &ctx);
+
+ /*
+ * For historical reasons the on-disk sha256 checksums are
+ * always in big endian format.
+ * (see cddl/osnet/dist/uts/common/fs/zfs/sha256.c)
+ */
+ ZIO_CHECKSUM_BE(&cksum_real);
+
+ if (!ZIO_CHECKSUM_EQUAL(cksum_found, cksum_real)) {
+ warnx("checksum mismatch on vdev label %d", l);
+ warnx("found %lx, %lx, %lx, %lx",
+ (unsigned long)cksum_found.zc_word[0],
+ (unsigned long)cksum_found.zc_word[1],
+ (unsigned long)cksum_found.zc_word[2],
+ (unsigned long)cksum_found.zc_word[3]);
+ warnx("expected %lx, %lx, %lx, %lx",
+ (unsigned long)cksum_real.zc_word[0],
+ (unsigned long)cksum_real.zc_word[1],
+ (unsigned long)cksum_real.zc_word[2],
+ (unsigned long)cksum_real.zc_word[3]);
+ ret = 1;
+ break;
+ }
+ }
+ free(vdev_phys);
+ 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
Cheers,
--
Malte Dehling
Home |
Main Index |
Thread Index |
Old Index