mail archive of the barebox mailing list
 help / color / mirror / Atom feed
* [PATCH 00/11] dm: verity: Add transparent integrity checking target
@ 2025-09-18  7:43 Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 01/11] dm: Add helper to manage a lower device Tobias Waldekranz
                   ` (13 more replies)
  0 siblings, 14 replies; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

This series adds initial support for dm-verity. Notably, it does not
include any support for validation of any root hash signature. As
such, practical use in a production setting is still limited, unless
you have some other way of securely determining that the root hash is
valid.

3/11 is where the action is.

TL;DR: What follows is just a discussion about the future - it has
       nothing to do with the contents of this series.


Once this is in place, signature validation is next on my TODO. The
kernel accepts a PKCS7 signature for this purpose. This is therefore
also what Discoverable Partitions Specification (DPS) provides in its
<arch>-<part>-verity-sig partitions, which contain a NUL-padded JSON
document like this:

{
	"roothash": "0123456789abcdef...",
	"certificateFingerprint": "0123456789abcdef..",
	"signature": "MIIINQYJKo..."
}

To avoid having to integrate full ASN.1 + X509 parsing in Barebox, my
plan is:

1. Add support for (optionally) storing a certificate fingerprint
   along with a `struct public_key`. So at build time, we can note the
   fingerprint of keys that we include in the builtin keystore.

   We could also support parsing fingerprints from a DT. Not sure if
   this is needed.

2. Add a simplified PKCS7 validation function that relies on:
   a. Knowing which public key to use in advance, rather than
      determining it by walking the ASN.1 data.
   b. The last $KEY_LEN_BYTES of the PKCS7 blob holds the raw
      RFC4880§5.2.2 signature bytes that Barebox already knows how to
      verify.

3. Add a "dps-open" subcommand to veritysetup that only requires the
   partition to open and a name for the dm-verity device:

   veritysetup dps-open /dev/disk0.root os

   Based on the partition type UUID, we would then locate the
   corresponding -verity and -verity-sig partitions, parse the verity
   superblock, validate the signature and then create the dm-verity
   device.

Some other thoughts for the future (I have done no research here, so
some of this might already exist in Barebox and I just haven't
stumbled across it):

- Similar to the automounter, it would be good to have an
  "auto-dps-verityer" that will do the equivalent of `veritysetup
  dps-open` on the DPS partitions matching the current architecture.

- Having the ability to tag a partition as trusted, which could then
  be used to tag filesystems as such.

- Having a build-time option that limits booting to only be allowed
  from trusted filesystems.

Tobias Waldekranz (11):
  dm: Add helper to manage a lower device
  dm: linear: Refactor to make use of the generalized cdev management
  dm: verity: Add transparent integrity checking target
  dm: verity: Add helper to parse superblock information
  commands: veritysetup: Create dm-verity devices
  ci: pytest: Open up testfs to more consumers than the FIT test
  ci: pytest: Enable testfs feature on malta boards
  ci: pytest: Generate test data for dm-verity
  test: pytest: add basic dm-verity test
  ci: pytest: Centralize feature discovery to a separate step
  ci: pytest: Enable device-mapper labgrid tests

 .github/workflows/test-labgrid-pytest.yml     |  26 +-
 arch/mips/configs/qemu-malta_defconfig        |   4 +
 commands/Kconfig                              |  10 +
 commands/Makefile                             |   1 +
 commands/veritysetup.c                        | 123 +++++
 .../boards/configs/enable_dm_testing.config   |   9 +
 drivers/block/dm/Kconfig                      |   7 +
 drivers/block/dm/Makefile                     |   1 +
 drivers/block/dm/dm-core.c                    | 118 ++++
 drivers/block/dm/dm-linear.c                  |  64 +--
 drivers/block/dm/dm-target.h                  |  34 ++
 drivers/block/dm/dm-verity.c                  | 517 ++++++++++++++++++
 include/device-mapper.h                       |   5 +
 scripts/generate_testfs.sh                    |  64 ++-
 test/mips/be@qemu-malta_defconfig.yaml        |   1 +
 test/mips/qemu-malta64el_defconfig.yaml       |   1 +
 test/py/test_dm.py                            |  38 ++
 test/py/test_fit.py                           |   4 +-
 test/riscv/qemu-virt64@rv64i_defconfig.yaml   |   1 +
 test/riscv/qemu@virt32_defconfig.yaml         |   1 +
 20 files changed, 968 insertions(+), 61 deletions(-)
 create mode 100644 commands/veritysetup.c
 create mode 100644 common/boards/configs/enable_dm_testing.config
 create mode 100644 drivers/block/dm/dm-verity.c
 create mode 100644 test/py/test_dm.py

-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 01/11] dm: Add helper to manage a lower device
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 02/11] dm: linear: Refactor to make use of the generalized cdev management Tobias Waldekranz
                   ` (12 subsequent siblings)
  13 siblings, 0 replies; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

With the upcoming support for dm-verity, some patterns started to emerge
about commonalities between target types when it comes to dealing with
lower devices:

- Transparently creating/removing loop devices when a regular file is
  passed in place of a device special
- Validation of offsets and sizes
- Reading in chunks of block sizes (possibly different from 512B)

Therefore, add a generic way of dealing with this that all targets can
hook into.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 drivers/block/dm/dm-core.c   | 118 +++++++++++++++++++++++++++++++++++
 drivers/block/dm/dm-target.h |  20 ++++++
 2 files changed, 138 insertions(+)

diff --git a/drivers/block/dm/dm-core.c b/drivers/block/dm/dm-core.c
index 953673073b..1bc3446cb0 100644
--- a/drivers/block/dm/dm-core.c
+++ b/drivers/block/dm/dm-core.c
@@ -7,11 +7,129 @@
 #include <stdio.h>
 #include <string.h>
 #include <xfuncs.h>
+#include <unistd.h>
 
 #include <linux/kstrtox.h>
+#include <linux/stat.h>
 
 #include "dm-target.h"
 
+int dm_cdev_read(struct dm_cdev *dmcdev, void *buf, sector_t block,
+		 blkcnt_t num_blocks)
+{
+	ssize_t n;
+
+	n = cdev_read(dmcdev->cdev, buf, num_blocks << dmcdev->blk.bits,
+		      (dmcdev->blk.start + block) << dmcdev->blk.bits, 0);
+	if (n < 0)
+		return n;
+
+	if (n < (num_blocks << dmcdev->blk.bits))
+		return -EIO;
+
+	return 0;
+}
+
+int dm_cdev_write(struct dm_cdev *dmcdev, const void *buf, sector_t block,
+		  blkcnt_t num_blocks)
+{
+	ssize_t n;
+
+	n = cdev_write(dmcdev->cdev, buf, num_blocks << dmcdev->blk.bits,
+		       (dmcdev->blk.start + block) << dmcdev->blk.bits, 0);
+	if (n < 0)
+		return n;
+
+	if (n < (num_blocks << dmcdev->blk.bits))
+		return -EIO;
+
+	return 0;
+}
+
+int dm_cdev_open(struct dm_cdev *dmcdev, const char *path, ulong flags,
+		 sector_t start, blkcnt_t num_blocks, size_t blocksize, char **errmsg)
+{
+	struct stat st;
+	int err;
+
+	memset(dmcdev, 0, sizeof(*dmcdev));
+
+	err = stat(path, &st);
+	if (err) {
+		*errmsg = xasprintf("Cannot determine type: %m");
+		return err;
+	}
+
+	switch (st.st_mode & S_IFMT) {
+	case S_IFREG:
+		dmcdev->cdev = cdev_create_loop(path, flags, 0);
+		if (!dmcdev->cdev) {
+			*errmsg = xstrdup("Cannot create loop device");
+			return -ENODEV;
+		}
+		dmcdev->loop = true;
+		break;
+	case S_IFBLK:
+	case S_IFCHR:
+		dmcdev->cdev = cdev_open_by_path_name(path, flags);
+		if (!dmcdev->cdev) {
+			*errmsg = xstrdup("Cannot open device");
+			return -ENODEV;
+		}
+
+		dmcdev->cdev = cdev_readlink(dmcdev->cdev);
+		break;
+	default:
+		*errmsg = xstrdup("Only regular files and device specials are supported");
+		return -EINVAL;
+	}
+
+	if (blocksize == 0 || (blocksize & (blocksize - 1))) {
+		*errmsg = xasprintf("Invalid block size: %zu is not a power of 2",
+				    blocksize);
+		goto err;
+	}
+
+	dmcdev->blk.bits = ffs(blocksize) - 1;
+	if (dmcdev->blk.bits < SECTOR_SHIFT) {
+		*errmsg = xasprintf("Invalid block size: %zu, must be at least %u",
+				    blocksize, SECTOR_SIZE);
+		goto err;
+	}
+
+	dmcdev->blk.mask = (1 << (dmcdev->blk.bits - SECTOR_SHIFT)) - 1;
+
+	if (((start + num_blocks) << dmcdev->blk.bits) > dmcdev->cdev->size) {
+		*errmsg = xstrdup("# of blocks is larger than device");
+		err = -E2BIG;
+		goto err;
+	}
+
+	dmcdev->blk.start = start;
+	dmcdev->blk.num = num_blocks;
+	return 0;
+err:
+	if (dmcdev->cdev) {
+		if (dmcdev->loop)
+			cdev_remove_loop(dmcdev->cdev);
+		else
+			cdev_close(dmcdev->cdev);
+
+		memset(dmcdev, 0, sizeof(*dmcdev));
+	}
+	return err;
+}
+
+void dm_cdev_close(struct dm_cdev *dmcdev)
+{
+	if (dmcdev->loop)
+		cdev_remove_loop(dmcdev->cdev);
+	else
+		cdev_close(dmcdev->cdev);
+
+	memset(dmcdev, 0, sizeof(*dmcdev));
+}
+
 static LIST_HEAD(dm_target_ops_list);
 
 static struct dm_target_ops *dm_target_ops_find(const char *name)
diff --git a/drivers/block/dm/dm-target.h b/drivers/block/dm/dm-target.h
index 506e808b79..bd25208889 100644
--- a/drivers/block/dm/dm-target.h
+++ b/drivers/block/dm/dm-target.h
@@ -4,6 +4,26 @@
 #ifndef __DM_TARGET_H
 #define __DM_TARGET_H
 
+struct dm_cdev {
+	struct cdev *cdev;
+	bool loop;
+
+	struct {
+		sector_t start;
+		blkcnt_t num;
+		u32 mask;
+		u8 bits;
+	} blk;
+};
+
+int dm_cdev_read(struct dm_cdev *dmc, void *buf, sector_t block,
+		 blkcnt_t num_blocks);
+int dm_cdev_write(struct dm_cdev *dmc, const void *buf, sector_t block,
+		  blkcnt_t num_blocks);
+int dm_cdev_open(struct dm_cdev *dmcdev, const char *path, ulong flags,
+		 sector_t start, blkcnt_t num_blocks, size_t blocksize, char **errmsg);
+void dm_cdev_close(struct dm_cdev *dmcdev);
+
 struct dm_device;
 struct dm_target_ops;
 
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 02/11] dm: linear: Refactor to make use of the generalized cdev management
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 01/11] dm: Add helper to manage a lower device Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 03/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (11 subsequent siblings)
  13 siblings, 0 replies; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

Rely on the dm_cdev operations to do most of the heavy lifting of
managing the lower device. In addition this also adds support for
creating a linear target from a regular file (via a loop device).

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 drivers/block/dm/dm-linear.c | 64 +++++++++++-------------------------
 1 file changed, 19 insertions(+), 45 deletions(-)

diff --git a/drivers/block/dm/dm-linear.c b/drivers/block/dm/dm-linear.c
index 797d761f63..38e340af3a 100644
--- a/drivers/block/dm/dm-linear.c
+++ b/drivers/block/dm/dm-linear.c
@@ -11,45 +11,30 @@
 #include "dm-target.h"
 
 struct dm_linear {
-	struct cdev *cdev;
-	loff_t offset;
+	struct dm_cdev dmcdev;
 };
 
 static int dm_linear_read(struct dm_target *ti, void *buf,
 			  sector_t block, blkcnt_t num_blocks)
 {
 	struct dm_linear *l = ti->private;
-	ssize_t ret;
-
-	block <<= SECTOR_SHIFT;
-	num_blocks <<= SECTOR_SHIFT;
 
-	ret = cdev_read(l->cdev, buf, num_blocks, l->offset + block, 0);
-	if (ret < num_blocks)
-		return (ret < 0) ? ret : -EIO;
-
-	return 0;
+	return dm_cdev_read(&l->dmcdev, buf, block, num_blocks);
 }
 
 static int dm_linear_write(struct dm_target *ti, const void *buf,
 			   sector_t block, blkcnt_t num_blocks)
 {
 	struct dm_linear *l = ti->private;
-	ssize_t ret;
 
-	block <<= SECTOR_SHIFT;
-	num_blocks <<= SECTOR_SHIFT;
-
-	ret = cdev_write(l->cdev, buf, num_blocks, l->offset + block, 0);
-	if (ret < num_blocks)
-		return (ret < 0) ? ret : -EIO;
-
-	return 0;
+	return dm_cdev_write(&l->dmcdev, buf, block, num_blocks);
 }
 
 static int dm_linear_create(struct dm_target *ti, unsigned int argc, char **argv)
 {
-	struct dm_linear *l;
+	struct dm_linear *l = NULL;
+	loff_t offset;
+	char *errmsg;
 	int err;
 
 	if (argc != 2) {
@@ -62,37 +47,26 @@ static int dm_linear_create(struct dm_target *ti, unsigned int argc, char **argv
 	l = xzalloc(sizeof(*l));
 	ti->private = l;
 
-	if (kstrtoull(argv[1], 0, &l->offset)) {
+	if (kstrtoull(argv[1], 0, &offset)) {
 		dm_target_err(ti, "Invalid offset: \"%s\"\n", argv[1]);
 		err = -EINVAL;
-		goto err_free;
-	}
-	l->offset <<= SECTOR_SHIFT;
-
-	l->cdev = cdev_open_by_path_name(argv[0], O_RDWR);
-	if (!l->cdev) {
-		dm_target_err(ti, "Cannot open device %s: %m\n", argv[0]);
-		err = -ENODEV;
-		goto err_free;
+		goto err;
 	}
 
-	l->cdev = cdev_readlink(l->cdev);
-
-	if ((ti->size << SECTOR_SHIFT) > (l->cdev->size - l->offset)) {
-		dm_target_err(ti, "%s is too small to map %llu blocks at %llu, %llu available\n",
-			      argv[0], ti->size, l->offset >> SECTOR_SHIFT,
-			      (l->cdev->size - l->offset) >> SECTOR_SHIFT);
-		err = -ENOSPC;
-		goto err_close;
+	err = dm_cdev_open(&l->dmcdev, argv[0], O_RDWR, offset,
+			   ti->size, SECTOR_SIZE, &errmsg);
+	if (err) {
+		dm_target_err(ti, "Cannot open device %s: %s\n", argv[0], errmsg);
+		free(errmsg);
+		goto err;
 	}
 
 	return 0;
 
-err_close:
-	cdev_close(l->cdev);
-err_free:
-	free(l);
 err:
+	if (l)
+		free(l);
+
 	return err;
 }
 
@@ -100,7 +74,7 @@ static int dm_linear_destroy(struct dm_target *ti)
 {
 	struct dm_linear *l = ti->private;
 
-	cdev_close(l->cdev);
+	dm_cdev_close(&l->dmcdev);
 	free(l);
 	return 0;
 }
@@ -110,7 +84,7 @@ static char *dm_linear_asprint(struct dm_target *ti)
 	struct dm_linear *l = ti->private;
 
 	return xasprintf("dev:%s offset:%llu",
-			 cdev_name(l->cdev), l->offset >> SECTOR_SHIFT);
+			 cdev_name(l->dmcdev.cdev), l->dmcdev.blk.start);
 }
 
 static struct dm_target_ops dm_linear_ops = {
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 03/11] dm: verity: Add transparent integrity checking target
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 01/11] dm: Add helper to manage a lower device Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 02/11] dm: linear: Refactor to make use of the generalized cdev management Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-18 13:06   ` Sascha Hauer
  2025-09-18  7:43 ` [PATCH 04/11] dm: verity: Add helper to parse superblock information Tobias Waldekranz
                   ` (10 subsequent siblings)
  13 siblings, 1 reply; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

Add the dm-verity target, which is compatible with the Linux
implementation. This means that we can now create dm-verity devices on
top of partitions containing read-only filesystems and transparently
verify the integrity of all data is associated the verity root hash.

CRUCIALLY: The root hash still has be validated by some other means,
which is outside of the scope of this implementation. Future changes
will add support for validation of the root hash using a PKCS#7
signature, again compatible with the Linux kernel implementation.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 drivers/block/dm/Kconfig     |   7 +
 drivers/block/dm/Makefile    |   1 +
 drivers/block/dm/dm-target.h |  14 ++
 drivers/block/dm/dm-verity.c | 463 +++++++++++++++++++++++++++++++++++
 4 files changed, 485 insertions(+)
 create mode 100644 drivers/block/dm/dm-verity.c

diff --git a/drivers/block/dm/Kconfig b/drivers/block/dm/Kconfig
index 03a0876eda..93f29c84a1 100644
--- a/drivers/block/dm/Kconfig
+++ b/drivers/block/dm/Kconfig
@@ -11,3 +11,10 @@ config DM_BLK_LINEAR
 	help
 	  Maps a contiguous region of an existing device into a dm
 	  device.
+
+config DM_BLK_VERITY
+	bool "Verity target"
+	depends on DM_BLK
+	help
+	  Transparent integrity checking of underlying device using a
+	  pre-computed Merkle tree.
diff --git a/drivers/block/dm/Makefile b/drivers/block/dm/Makefile
index f52d19f9c4..3650f4c856 100644
--- a/drivers/block/dm/Makefile
+++ b/drivers/block/dm/Makefile
@@ -1,3 +1,4 @@
 # SPDX-License-Identifier: GPL-2.0-only
 obj-$(CONFIG_DM_BLK) += dm-core.o
 obj-$(CONFIG_DM_BLK_LINEAR) += dm-linear.o
+obj-$(CONFIG_DM_BLK_VERITY) += dm-verity.o
diff --git a/drivers/block/dm/dm-target.h b/drivers/block/dm/dm-target.h
index bd25208889..5c7c6f612f 100644
--- a/drivers/block/dm/dm-target.h
+++ b/drivers/block/dm/dm-target.h
@@ -38,8 +38,22 @@ struct dm_target {
 	void *private;
 };
 
+static inline size_t dm_target_size(struct dm_target *ti)
+{
+	return ti->size << SECTOR_SHIFT;
+}
+
 void dm_target_err(struct dm_target *ti, const char *fmt, ...);
 
+#define dm_target_err_once(_ti, _format, _args...) do {	\
+	static bool __print_once;				\
+								\
+	if (!__print_once && LOGLEVEL >= MSG_ERR) {		\
+		__print_once = true;				\
+		dm_target_err((_ti), (_format), ##_args);	\
+	}							\
+} while (0)
+
 struct dm_target_ops {
 	struct list_head list;
 	const char *name;
diff --git a/drivers/block/dm/dm-verity.c b/drivers/block/dm/dm-verity.c
new file mode 100644
index 0000000000..b7ed3dcc93
--- /dev/null
+++ b/drivers/block/dm/dm-verity.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: © 2025 Tobias Waldekranz <tobias@waldekranz.com>, Wires
+/*
+ * Based on dm-verity from Linux:
+ *
+ * Copyright (C) 2012 Red Hat, Inc.
+ *
+ * Author: Mikulas Patocka <mpatocka@redhat.com>
+ *
+ * Based on Chromium dm-verity driver (C) 2011 The Chromium OS Authors
+ */
+
+#include <block.h>
+#include <device-mapper.h>
+#include <digest.h>
+#include <disks.h>
+#include <fcntl.h>
+#include <xfuncs.h>
+
+#include <linux/bitmap.h>
+#include <linux/bitops.h>
+#include <linux/hex.h>
+#include <linux/kstrtox.h>
+
+#include "dm-target.h"
+
+#define DM_VERITY_MAX_LEVELS 63
+
+struct dm_verity {
+	struct dm_cdev ddev;
+	struct dm_cdev hdev;
+
+	struct digest *digest_algo;
+	size_t digest_len;
+
+	u8 *root_digest;
+	u8 *salt;
+	size_t salt_size;
+
+	u8 levels;
+	u8 hash_per_block_bits;
+	sector_t hash_level_block[DM_VERITY_MAX_LEVELS];
+
+	struct {
+		unsigned long *trusted;
+		u8 *digest;
+
+		struct {
+			u8 *data;
+			sector_t block;
+		} hblock;
+	} verify;
+};
+
+static sector_t dm_verity_position_at_level(struct dm_verity *v, sector_t dblock,
+					    int level)
+{
+	return dblock >> (level * v->hash_per_block_bits);
+}
+
+static void dm_verity_hash_at_level(struct dm_verity *v, sector_t dblock, int level,
+				    sector_t *hblock, unsigned int *offset)
+{
+	sector_t position = dm_verity_position_at_level(v, dblock, level);
+	unsigned int idx;
+
+	*hblock = v->hash_level_block[level] + (position >> v->hash_per_block_bits);
+
+	if (!offset)
+		return;
+
+	idx = position & ((1 << v->hash_per_block_bits) - 1);
+	*offset = idx << (v->hdev.blk.bits - v->hash_per_block_bits);
+}
+
+static int dm_verity_set_digest(struct dm_verity *v, const void *buf, size_t buflen)
+{
+	int err;
+
+	err = digest_init(v->digest_algo);
+	err = err ? : digest_update(v->digest_algo, v->salt, v->salt_size);
+	err = err ? : digest_update(v->digest_algo, buf, buflen);
+	err = err ? : digest_final(v->digest_algo, v->verify.digest);
+	return err;
+}
+
+static int dm_verity_set_hblock(struct dm_verity *v, sector_t hblock)
+{
+	int err;
+
+	if (v->verify.hblock.block == hblock)
+		/* Requested block is already loaded. This is the
+		 * common scenario for sequential block checking once
+		 * the upper levels of hash blocks have been marked as
+		 * trusted.
+		 */
+		return 0;
+
+	err = dm_cdev_read(&v->hdev, v->verify.hblock.data, hblock, 1);
+	if (err)
+		return err;
+
+	v->verify.hblock.block = hblock;
+	return 0;
+}
+
+static int dm_verity_verify(struct dm_target *ti, const void *buf, sector_t dblock)
+{
+	struct dm_verity *v = ti->private;
+	const u8 *expected;
+	unsigned int hoffs;
+	sector_t hblock;
+	int err, level;
+
+	err = dm_verity_set_digest(v, buf, 1 << v->ddev.blk.bits);
+	if (err)
+		return err;
+
+	for (level = 0; level < v->levels; level++) {
+		dm_verity_hash_at_level(v, dblock, level, &hblock, &hoffs);
+
+		err = dm_verity_set_hblock(v, hblock);
+		if (err)
+			return err;
+
+		expected = v->verify.hblock.data + hoffs;
+
+		if (memcmp(v->verify.digest, expected, v->digest_len)) {
+			dm_target_err_once(
+				ti, "Verity error for data block %llu at level %d\n",
+				dblock, level);
+			return -EINVAL;
+		}
+
+		if (test_bit(hblock, v->verify.trusted)) {
+			/* This hash block has already been validated
+			 * all the way up to the root digest by an
+			 * earlier operation, we do not need to ascend
+			 * any further.
+			 *
+			 * Make sure to mark any subset of branches
+			 * that this operation might have verified.
+			 */
+			goto mark_as_trusted;
+		}
+
+		/* Current level OK. Now calculate the digest for the
+		 * entire hblock, which then becomes the input when
+		 * checking the next level up.
+		 */
+		err = dm_verity_set_digest(v, v->verify.hblock.data,
+					   1 << v->hdev.blk.bits);
+		if (err)
+			return err;
+	}
+
+	/* Data is consistent with hash tree. Now make sure that the top
+	 * level matches the externally provided root digest.
+	 */
+	if (memcmp(v->verify.digest, v->root_digest, v->digest_len)) {
+		dm_target_err_once(ti, "Verity error for data block %llu at root\n",
+				   dblock);
+		return -EINVAL;
+
+	}
+
+mark_as_trusted:
+	/* All hash blocks in the chain from dblock to the root digest
+	 * are valid. Cache this knowledge for subsequent operations
+	 * that map to the same subtree.
+	 */
+	for (level--; level >= 0; level--) {
+		dm_verity_hash_at_level(v, dblock, level, &hblock, NULL);
+		set_bit(hblock, v->verify.trusted);
+	}
+
+	return 0;
+}
+
+static int dm_verity_verify_range(struct dm_target *ti, const void *buf,
+				  sector_t block, blkcnt_t num_blocks)
+{
+	struct dm_verity *v = ti->private;
+	int err;
+
+	for (; num_blocks; block++, num_blocks--, buf += 1 << v->ddev.blk.bits) {
+		err = dm_verity_verify(ti, buf, block);
+		if (err)
+			return err;
+	}
+
+	return 0;
+}
+
+static int dm_verity_read(struct dm_target *ti, void *in_buf,
+			  sector_t block, blkcnt_t num_blocks)
+{
+	struct dm_verity *v = ti->private;
+	blkcnt_t pre_blocks, post_blocks, dblocks;
+	void *buf = in_buf;
+	sector_t dblock;
+	int err;
+
+	/* The dm-verity data block size is guaranteed to be at least
+	 * 512B, but typically larger. Make sure we align the request
+	 * to even data block size boundaries, since those are the
+	 * chunks we need to hash.
+	 */
+	pre_blocks = block & v->ddev.blk.mask;
+	post_blocks = (pre_blocks + num_blocks) & v->ddev.blk.mask;
+	if (post_blocks)
+		post_blocks = v->ddev.blk.mask + 1 - post_blocks;
+
+	if (pre_blocks || post_blocks) {
+		/* Need to read more data than in_buf will hold. */
+		buf = malloc((pre_blocks + num_blocks + post_blocks) << SECTOR_SHIFT);
+		if (!buf)
+			return -ENOMEM;
+	}
+
+	dblock = block - pre_blocks;
+	dblock >>= (v->ddev.blk.bits - SECTOR_SHIFT);
+
+	dblocks = pre_blocks + num_blocks + post_blocks;
+	dblocks >>= (v->ddev.blk.bits - SECTOR_SHIFT);
+
+	err = dm_cdev_read(&v->ddev, buf, dblock, dblocks);
+	if (err)
+		goto err;
+
+	err = dm_verity_verify_range(ti, buf, dblock, dblocks);
+	if (err)
+		goto err;
+
+	if (buf != in_buf) {
+		memcpy(in_buf, buf + (pre_blocks << SECTOR_SHIFT),
+		       num_blocks << SECTOR_SHIFT);
+		free(buf);
+	}
+
+	return 0;
+
+err:
+	if (buf != in_buf)
+		free(buf);
+
+	return err;
+}
+
+static int dm_verity_measure(struct dm_target *ti)
+{
+	struct dm_verity *v = ti->private;
+	sector_t lstart, lsize;
+	unsigned int lshift;
+	size_t minsize;
+	int i;
+
+	v->hash_per_block_bits =
+		fls((1 << v->hdev.blk.bits) / v->digest_len) - 1;
+
+	v->levels = 0;
+	if (v->ddev.blk.num)
+		while (v->hash_per_block_bits * v->levels < 64 &&
+		       (unsigned long long)(v->ddev.blk.num - 1) >>
+		       (v->hash_per_block_bits * v->levels))
+			v->levels++;
+
+	if (v->levels > DM_VERITY_MAX_LEVELS) {
+		dm_target_err(ti, "Too many tree levels\n");
+		return -E2BIG;
+	}
+
+	for (lstart = 0, i = v->levels - 1; i >= 0; i--) {
+		v->hash_level_block[i] = lstart;
+
+		lshift = (i + 1) * v->hash_per_block_bits;
+		lsize = (v->ddev.blk.num + ((sector_t)1 << lshift) - 1) >> lshift;
+		if (lstart + lsize < lstart) {
+			dm_target_err(ti, "Hash device offset overflow\n");
+			return -E2BIG;
+		}
+		lstart += lsize;
+	}
+	v->hdev.blk.num = lstart;
+
+	minsize = (v->hdev.blk.start + v->hdev.blk.num) << v->hdev.blk.bits;
+	if (minsize > v->hdev.cdev->size) {
+		dm_target_err(ti, "Hash device is too small to fit tree\n");
+		return -E2BIG;
+	}
+
+	return 0;
+}
+
+static int dm_verity_cdev_init(struct dm_target *ti, struct dm_cdev *dmcdev,
+			       const char *devstr, const char *blkszstr,
+			       const char *num_blkstr, const char *start_blkstr)
+{
+	struct dm_verity *v = ti->private;
+	const char *kind = (dmcdev == &v->ddev) ? "data" : "hash";
+	unsigned long blocksize;
+	blkcnt_t num_blocks = 0;
+	sector_t start = 0;
+	char *errmsg;
+	int err;
+
+	if (kstrtoul(blkszstr, 0, &blocksize)) {
+		dm_target_err(ti, "Invalid %s block size: \"%s\"\n", kind, blkszstr);
+		return -EINVAL;
+	}
+
+	if (num_blkstr && kstrtoull(num_blkstr, 0, &num_blocks)) {
+		dm_target_err(ti, "Invalid # of %s blocks: \"%s\"\n", kind, num_blkstr);
+		return -EINVAL;
+	}
+
+	if (start_blkstr && kstrtoull(start_blkstr, 0, &start)) {
+		dm_target_err(ti, "Invalid start %s block: \"%s\"\n", kind, start_blkstr);
+		return -EINVAL;
+	}
+
+	err = dm_cdev_open(dmcdev, devstr, O_RDONLY,
+			   start, num_blocks, blocksize, &errmsg);
+	if (err) {
+		dm_target_err(ti, "Error opening %d device: %s\n", kind, errmsg);
+		free(errmsg);
+	}
+
+	return err;
+}
+
+static int dm_verity_create(struct dm_target *ti, unsigned int argc, char **argv)
+{
+	struct dm_verity *v;
+	unsigned int ver;
+	int err;
+
+	if (argc != 10) {
+		dm_target_err(ti, "Expected 10 arguments, got %u\n", argc);
+		return -EINVAL;
+	}
+
+	if (kstrtouint(argv[0], 0, &ver) || ver != 1) {
+		dm_target_err(ti, "Only version 1 is supported, not \"%s\"\n", argv[0]);
+		return -EINVAL;
+	}
+
+	v = xzalloc(sizeof(*v));
+	ti->private = v;
+
+	err = dm_verity_cdev_init(ti, &v->ddev, argv[1], argv[3], argv[5], NULL);
+	if (err)
+		goto err;
+
+	err = dm_verity_cdev_init(ti, &v->hdev, argv[2], argv[4], NULL, argv[6]);
+	if (err)
+		goto err;
+
+	v->digest_algo = digest_alloc(argv[7]);
+	if (!v->digest_algo) {
+		dm_target_err(ti, "Unknown digest \"%s\"\n", argv[7]);
+		err = -EINVAL;
+		goto err;
+	}
+
+	v->digest_len = digest_length(v->digest_algo);
+	if ((1 << v->hdev.blk.bits) < v->digest_len * 2) {
+		dm_target_err(ti, "Digest size too big\n");
+		err = -EINVAL;
+		goto err;
+	}
+
+	v->root_digest = xmalloc(v->digest_len);
+	if (strlen(argv[8]) != v->digest_len * 2 ||
+	    hex2bin(v->root_digest, argv[8], v->digest_len)) {
+		dm_target_err(ti, "Invalid root digest \"%s\"\n", argv[8]);
+		err = -EINVAL;
+		goto err;
+	}
+
+	if (strcmp(argv[9], "-")) {
+		v->salt_size = strlen(argv[9]) / 2;
+		v->salt = xmalloc(v->salt_size);
+
+		if (strlen(argv[9]) != v->salt_size * 2 ||
+		    hex2bin(v->salt, argv[9], v->salt_size)) {
+			dm_target_err(ti, "Invalid salt \"%s\"\n", argv[9]);
+			err = -EINVAL;
+			goto err;
+		}
+	}
+
+	err = dm_verity_measure(ti);
+	if (err)
+		goto err;
+
+	/* Initialize this to a value larger than the largest possible
+	 * hash block lba to make sure that the first hash block read
+	 * in dm_verity_verify() always misses the cache.
+	 */
+	v->verify.hblock.block = v->hdev.blk.num;
+	v->verify.hblock.data = xmalloc(1 << v->hdev.blk.bits);
+
+	v->verify.digest = xmalloc(v->digest_len);
+	v->verify.trusted = bitmap_xzalloc(v->hdev.blk.num);
+	return 0;
+
+err:
+	if (v->salt)
+		free(v->salt);
+	if (v->root_digest)
+		free(v->root_digest);
+	if (v->digest_algo)
+		digest_free(v->digest_algo);
+	if (v->hdev.cdev)
+		cdev_close(v->hdev.cdev);
+	if (v->ddev.cdev)
+		cdev_close(v->ddev.cdev);
+
+	free(v);
+	return err;
+}
+
+static int dm_verity_destroy(struct dm_target *ti)
+{
+	struct dm_verity *v = ti->private;
+
+	free(v->verify.digest);
+	free(v->verify.hblock.data);
+	free(v->verify.trusted);
+	free(v->salt);
+	free(v->root_digest);
+	digest_free(v->digest_algo);
+	dm_cdev_close(&v->hdev);
+	dm_cdev_close(&v->ddev);
+
+	free(v);
+	return 0;
+}
+
+static char *dm_verity_asprint(struct dm_target *ti)
+{
+	struct dm_verity *v = ti->private;
+
+	return xasprintf("data:%s hash:%s@%llu root:%*phN",
+			 cdev_name(v->ddev.cdev),
+			 cdev_name(v->hdev.cdev), v->hdev.blk.start,
+			 (int)v->digest_len, v->root_digest);
+}
+
+static struct dm_target_ops dm_verity_ops = {
+	.name = "verity",
+	.asprint = dm_verity_asprint,
+	.create = dm_verity_create,
+	.destroy = dm_verity_destroy,
+	.read = dm_verity_read,
+};
+
+static int __init dm_verity_init(void)
+{
+	return dm_target_register(&dm_verity_ops);
+}
+device_initcall(dm_verity_init);
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 04/11] dm: verity: Add helper to parse superblock information
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (2 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 03/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 05/11] commands: veritysetup: Create dm-verity devices Tobias Waldekranz
                   ` (9 subsequent siblings)
  13 siblings, 0 replies; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

For hash devices that have been created with metadata information in
the first block (superblock), parse this information into a dm-verity
table entry.

Primary user of this will be the upcoming veritysetup command.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 drivers/block/dm/dm-verity.c | 54 ++++++++++++++++++++++++++++++++++++
 include/device-mapper.h      |  5 ++++
 2 files changed, 59 insertions(+)

diff --git a/drivers/block/dm/dm-verity.c b/drivers/block/dm/dm-verity.c
index b7ed3dcc93..d7b212fba6 100644
--- a/drivers/block/dm/dm-verity.c
+++ b/drivers/block/dm/dm-verity.c
@@ -16,6 +16,7 @@
 #include <disks.h>
 #include <fcntl.h>
 #include <xfuncs.h>
+#include <unistd.h>
 
 #include <linux/bitmap.h>
 #include <linux/bitops.h>
@@ -461,3 +462,56 @@ static int __init dm_verity_init(void)
 	return dm_target_register(&dm_verity_ops);
 }
 device_initcall(dm_verity_init);
+
+struct dm_verity_sb {
+	    u8 signature[8];    /* "verity\0\0" */
+	__le32 version;         /* superblock version, 1 */
+	__le32 hash_type;       /* 0 - Chrome OS, 1 - normal */
+	    u8 uuid[16];        /* UUID of hash device */
+	    u8 algorithm[32];   /* hash algorithm name */
+	__le32 data_block_size; /* data block in bytes */
+	__le32 hash_block_size; /* hash block in bytes */
+	__le64 data_blocks;     /* number of data blocks */
+	__le16 salt_size;       /* salt size */
+	    u8 _pad1[6];
+	    u8 salt[256];       /* salt */
+	    u8 _pad2[168];
+} __packed;
+
+char *dm_verity_config_from_sb(const char *data_dev, const char *hash_dev,
+			       const char *root_hash)
+{
+	struct dm_verity_sb sb;
+	blkcnt_t sects;
+	ssize_t n;
+	int fd;
+
+	fd = open(hash_dev, O_RDONLY);
+	if (fd < 0)
+		return ERR_PTR(-ENOENT);
+
+	n = read(fd, &sb, sizeof(sb));
+	close(fd);
+	if (n != sizeof(sb))
+		return ERR_PTR((n < 0) ? n : -EIO);
+
+	if (memcmp(sb.signature, "verity\0\0", sizeof(sb.signature)))
+		return ERR_PTR(-EINVAL);
+
+	if (le32_to_cpu(sb.version) != 1)
+		return ERR_PTR(-ENOTSUPP);
+
+	sects = le32_to_cpu(sb.data_block_size) >> SECTOR_SHIFT;
+	if (!sects)
+		return ERR_PTR(-ERANGE);
+
+	sects *= le64_to_cpu(sb.data_blocks);
+
+	return xasprintf("0 %llu verity %u %s %s %u %u %llu 1 %s %s %*phN",
+			 sects, le32_to_cpu(sb.hash_type), data_dev, hash_dev,
+			 le32_to_cpu(sb.data_block_size),
+			 le32_to_cpu(sb.hash_block_size),
+			 le64_to_cpu(sb.data_blocks), sb.algorithm, root_hash,
+			 le16_to_cpu(sb.salt_size), sb.salt);
+}
+EXPORT_SYMBOL(dm_verity_config_from_sb);
diff --git a/include/device-mapper.h b/include/device-mapper.h
index 255796ca2f..d7080101b0 100644
--- a/include/device-mapper.h
+++ b/include/device-mapper.h
@@ -13,4 +13,9 @@ char *dm_asprint(struct dm_device *dm);
 void dm_destroy(struct dm_device *dm);
 struct dm_device *dm_create(const char *name, const char *ctable);
 
+#if defined(CONFIG_DM_BLK_VERITY)
+char *dm_verity_config_from_sb(const char *data_dev, const char *hash_dev,
+			       const char *root_hash);
+#endif
+
 #endif /* __DM_H */
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 05/11] commands: veritysetup: Create dm-verity devices
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (3 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 04/11] dm: verity: Add helper to parse superblock information Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-18  7:43 ` [PATCH 06/11] ci: pytest: Open up testfs to more consumers than the FIT test Tobias Waldekranz
                   ` (8 subsequent siblings)
  13 siblings, 0 replies; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

For hash devices that contain a superblock, parse it and setup a
dm-verity device based on that information.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 commands/Kconfig       |  10 ++++
 commands/Makefile      |   1 +
 commands/veritysetup.c | 123 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 134 insertions(+)
 create mode 100644 commands/veritysetup.c

diff --git a/commands/Kconfig b/commands/Kconfig
index 219f626c3e..1924016756 100644
--- a/commands/Kconfig
+++ b/commands/Kconfig
@@ -789,6 +789,16 @@ config CMD_UMOUNT
 
 	  Unmount a filesystem mounted on a specific MOINTPOINT
 
+config CMD_VERITYSETUP
+	tristate
+	depends on DM_BLK_VERITY
+	prompt "veritysetup"
+	help
+	  veritysetup - manage dm-verity volumes
+
+	  commands:
+	        open <data-dev> <name> <hash-dev> <root-hash>
+
 # end Partition commands
 endmenu
 
diff --git a/commands/Makefile b/commands/Makefile
index 6b010fe30c..62dd8284cd 100644
--- a/commands/Makefile
+++ b/commands/Makefile
@@ -167,4 +167,5 @@ obj-$(CONFIG_CMD_PARTED)	+= parted.o
 obj-$(CONFIG_CMD_EFI_HANDLE_DUMP)	+= efi_handle_dump.o
 obj-$(CONFIG_CMD_HOST)		+= host.o
 obj-$(CONFIG_CMD_DMSETUP)	+= dmsetup.o
+obj-$(CONFIG_CMD_VERITYSETUP)	+= veritysetup.o
 UBSAN_SANITIZE_ubsan.o := y
diff --git a/commands/veritysetup.c b/commands/veritysetup.c
new file mode 100644
index 0000000000..99f27278f8
--- /dev/null
+++ b/commands/veritysetup.c
@@ -0,0 +1,123 @@
+// SPDX-License-Identifier: GPL-2.0-only
+// SPDX-FileCopyrightText: © 2025 Tobias Waldekranz <tobias@waldekranz.com>, Wires
+
+#include <command.h>
+#include <device-mapper.h>
+#include <libfile.h>
+#include <stdio.h>
+
+static int veritysetup_dump(int argc, char *argv[])
+{
+	char *config;
+
+	if (argc != 1)
+		return COMMAND_ERROR_USAGE;
+
+	config = dm_verity_config_from_sb("<data-dev>", argv[0], "<root-hash>");
+	if (IS_ERR(config)) {
+		printf("Invalid or missing superblock: %pe\n", config);
+		return COMMAND_ERROR;
+	}
+
+	puts(config);
+	free(config);
+	return COMMAND_SUCCESS;
+}
+
+static struct dm_device *veritysetup_find(const char *name)
+{
+	struct dm_device *dm;
+
+	dm = dm_find_by_name(name);
+	if (IS_ERR_OR_NULL(dm)) {
+		printf("Found no device named \"%s\"\n", name);
+		return NULL;
+	}
+
+	return dm;
+}
+
+static int veritysetup_close(int argc, char *argv[])
+{
+	struct dm_device *dm;
+
+	if (argc != 1)
+		return COMMAND_ERROR_USAGE;
+
+	dm = veritysetup_find(argv[0]);
+	if (!dm)
+		return COMMAND_ERROR;
+
+	dm_destroy(dm);
+
+	printf("Removed %s\n", argv[0]);
+	return COMMAND_SUCCESS;
+}
+
+static int veritysetup_open(int argc, char *argv[])
+{
+	struct dm_device *dm;
+	char *config;
+
+	if (argc != 4)
+		return COMMAND_ERROR_USAGE;
+
+	config = dm_verity_config_from_sb(argv[0], argv[2], argv[3]);
+	if (IS_ERR(config)) {
+		printf("Invalid or missing superblock: %pe\n", config);
+		return COMMAND_ERROR;
+	}
+
+	dm = dm_create(argv[1], config);
+	free(config);
+	if (IS_ERR_OR_NULL(dm)) {
+		printf("Failed to create %s: %pe\n", argv[1], dm);
+		return COMMAND_ERROR;
+	}
+
+	printf("Created %s\n", argv[1]);
+	return COMMAND_SUCCESS;
+}
+
+static int do_veritysetup(int argc, char *argv[])
+{
+	const char *cmd;
+
+	if (argc < 2)
+		return COMMAND_ERROR_USAGE;
+
+	cmd = argv[1];
+	argc -= 2;
+	argv += 2;
+
+	if (!strcmp(cmd, "open"))
+		return veritysetup_open(argc, argv);
+	else if (!strcmp(cmd, "close"))
+		return veritysetup_close(argc, argv);
+	else if (!strcmp(cmd, "dump"))
+		return veritysetup_dump(argc, argv);
+
+	printf("Unknown command: %s\n", cmd);
+	return -EINVAL;
+}
+
+BAREBOX_CMD_HELP_START(veritysetup)
+BAREBOX_CMD_HELP_TEXT("veritysetup - manage dm-verity volumes")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("Layers a transparent integrity layer on top of an existing")
+BAREBOX_CMD_HELP_TEXT("device, backed by a Merkle tree whose root hash must be")
+BAREBOX_CMD_HELP_TEXT("verified by an externally provided signature")
+BAREBOX_CMD_HELP_TEXT("")
+BAREBOX_CMD_HELP_TEXT("commands:")
+BAREBOX_CMD_HELP_OPT("open <data-dev> <name> <hash-dev> <root-hash>", "Create new device")
+BAREBOX_CMD_HELP_OPT("close <name>", "Remove device")
+BAREBOX_CMD_HELP_OPT("dump <hash-dev>", "Dump superblock information")
+BAREBOX_CMD_HELP_END
+
+BAREBOX_CMD_START(veritysetup)
+	.cmd = do_veritysetup,
+	BAREBOX_CMD_DESC("manage dm-verity volumes")
+	BAREBOX_CMD_OPTS("<command> [args...]")
+	BAREBOX_CMD_GROUP(CMD_GRP_PART)
+	BAREBOX_CMD_HELP(cmd_veritysetup_help)
+BAREBOX_CMD_END
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 06/11] ci: pytest: Open up testfs to more consumers than the FIT test
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (4 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 05/11] commands: veritysetup: Create dm-verity devices Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-22 15:38   ` Ahmad Fatoum
  2025-09-18  7:43 ` [PATCH 07/11] ci: pytest: Enable testfs feature on malta boards Tobias Waldekranz
                   ` (7 subsequent siblings)
  13 siblings, 1 reply; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

With upcoming dm-verity tests, we want to store more test artifacts
than the FIT image in the testfs.

Since the dm tests might run on systems for which no ITS is available
to build an FIT from, make FIT generation conditional on the ITS being
available. This allows us to enable the testfs feature on all matrix
cells that support 9p over virtio.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 scripts/generate_testfs.sh                  | 20 ++++++++++++--------
 test/py/test_fit.py                         |  4 +++-
 test/riscv/qemu-virt64@rv64i_defconfig.yaml |  1 +
 test/riscv/qemu@virt32_defconfig.yaml       |  1 +
 4 files changed, 17 insertions(+), 9 deletions(-)

diff --git a/scripts/generate_testfs.sh b/scripts/generate_testfs.sh
index c5d24f7e1a..3c200bd401 100755
--- a/scripts/generate_testfs.sh
+++ b/scripts/generate_testfs.sh
@@ -13,14 +13,18 @@ fi
 rm -rf "${KBUILD_OUTPUT}/testfs/"
 mkdir -p ${KBUILD_OUTPUT}/testfs
 
-cat ${KBUILD_OUTPUT}/images/barebox-dt-2nd.img | \
-  ${KGZIP} -n -f -9 >${KBUILD_OUTPUT}/barebox-dt-2nd.img.gz
+generate_fit()
+{
+    cat ${KBUILD_OUTPUT}/images/barebox-dt-2nd.img | \
+	${KGZIP} -n -f -9 >${KBUILD_OUTPUT}/barebox-dt-2nd.img.gz
 
-cp .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ${KBUILD_OUTPUT}/
+    cp .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ${KBUILD_OUTPUT}/
 
-find COPYING LICENSES/ | cpio -o -H newc | ${KGZIP} \
-  > ${KBUILD_OUTPUT}/ramdisk.cpio.gz
+    find COPYING LICENSES/ | cpio -o -H newc | ${KGZIP} \
+						   > ${KBUILD_OUTPUT}/ramdisk.cpio.gz
 
-${MKIMAGE} -G $PWD/test/self/development_rsa2048.pem -r \
-      -f ${KBUILD_OUTPUT}/${KBUILD_DEFCONFIG}-gzipped.its \
-	 ${KBUILD_OUTPUT}/testfs/barebox-gzipped.fit
+    ${MKIMAGE} -G $PWD/test/self/development_rsa2048.pem -r \
+	       -f ${KBUILD_OUTPUT}/${KBUILD_DEFCONFIG}-gzipped.its \
+	       ${KBUILD_OUTPUT}/testfs/barebox-gzipped.fit
+}
+[ -f .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ] && generate_fit
diff --git a/test/py/test_fit.py b/test/py/test_fit.py
index c53a1ece14..1a23a53a32 100644
--- a/test/py/test_fit.py
+++ b/test/py/test_fit.py
@@ -23,7 +23,9 @@ def test_fit(barebox, env, target, barebox_config):
     if returncode != 0:
         pytest.xfail("skipping test due to missing --fs testfs=")
 
-    barebox.run_check(f"ls {fit_name('gzipped')}")
+    _, _, returncode = barebox.run(f"ls {fit_name('gzipped')}")
+    if returncode != 0:
+        pytest.xfail("skipping test due to missing FIT image")
 
     # Sanity check, this is only fixed up on first boot
     assert of_get_property(barebox, "/chosen/barebox-version") is False
diff --git a/test/riscv/qemu-virt64@rv64i_defconfig.yaml b/test/riscv/qemu-virt64@rv64i_defconfig.yaml
index 7f86d9ac7d..5f1310617a 100644
--- a/test/riscv/qemu-virt64@rv64i_defconfig.yaml
+++ b/test/riscv/qemu-virt64@rv64i_defconfig.yaml
@@ -15,6 +15,7 @@ targets:
     features:
       - virtio-mmio
       - barebox-state
+      - testfs
 images:
   barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
 imports:
diff --git a/test/riscv/qemu@virt32_defconfig.yaml b/test/riscv/qemu@virt32_defconfig.yaml
index 7860e97c52..d0b640aa18 100644
--- a/test/riscv/qemu@virt32_defconfig.yaml
+++ b/test/riscv/qemu@virt32_defconfig.yaml
@@ -16,6 +16,7 @@ targets:
     features:
       - virtio-mmio
       - barebox-state
+      - testfs
     runner:
       download:
         opensbi-riscv32-generic-fw_dynamic.bin: https://github.com/qemu/qemu/blob/v5.2.0/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin?raw=true
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 07/11] ci: pytest: Enable testfs feature on malta boards
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (5 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 06/11] ci: pytest: Open up testfs to more consumers than the FIT test Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-22 15:40   ` Ahmad Fatoum
  2025-09-18  7:43 ` [PATCH 08/11] ci: pytest: Generate test data for dm-verity Tobias Waldekranz
                   ` (6 subsequent siblings)
  13 siblings, 1 reply; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

By enabling 9p in the defconfig, we get access to the testfs feature,
which will enable the upcoming dm-verity labgrid tests to be run on
this platform.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 arch/mips/configs/qemu-malta_defconfig  | 4 ++++
 test/mips/be@qemu-malta_defconfig.yaml  | 1 +
 test/mips/qemu-malta64el_defconfig.yaml | 1 +
 3 files changed, 6 insertions(+)

diff --git a/arch/mips/configs/qemu-malta_defconfig b/arch/mips/configs/qemu-malta_defconfig
index e5bc8ff8cb..64279f7ff4 100644
--- a/arch/mips/configs/qemu-malta_defconfig
+++ b/arch/mips/configs/qemu-malta_defconfig
@@ -58,6 +58,8 @@ CONFIG_CMD_OFTREE=y
 CONFIG_CMD_TIME=y
 CONFIG_NET=y
 CONFIG_NET_NETCONSOLE=y
+CONFIG_NET_9P=y
+CONFIG_NET_9P_VIRTIO=y
 CONFIG_OFDEVICE=y
 CONFIG_OF_BAREBOX_DRIVERS=y
 CONFIG_VIRTIO_CONSOLE=y
@@ -91,6 +93,8 @@ CONFIG_FS_CRAMFS=y
 CONFIG_FS_EXT4=y
 CONFIG_FS_TFTP=y
 CONFIG_FS_NFS=y
+CONFIG_9P_FS=y
+CONFIG_9P_FS_WRITE=y
 CONFIG_FS_FAT=y
 CONFIG_FS_FAT_WRITE=y
 CONFIG_FS_FAT_LFN=y
diff --git a/test/mips/be@qemu-malta_defconfig.yaml b/test/mips/be@qemu-malta_defconfig.yaml
index a3d34a660d..2f3b7e674b 100644
--- a/test/mips/be@qemu-malta_defconfig.yaml
+++ b/test/mips/be@qemu-malta_defconfig.yaml
@@ -14,6 +14,7 @@ targets:
       BareboxTestStrategy: {}
     features:
       - virtio-pci
+      - testfs
 images:
   barebox-qemu-malta.img: !template "$LG_BUILDDIR/images/barebox-qemu-malta.img"
 imports:
diff --git a/test/mips/qemu-malta64el_defconfig.yaml b/test/mips/qemu-malta64el_defconfig.yaml
index 5562f59dc7..dfbdb21ee8 100644
--- a/test/mips/qemu-malta64el_defconfig.yaml
+++ b/test/mips/qemu-malta64el_defconfig.yaml
@@ -14,6 +14,7 @@ targets:
       BareboxTestStrategy: {}
     features:
       - virtio-pci
+      - testfs
 images:
   barebox-qemu-malta.img.swapped: !template "$LG_BUILDDIR/images/barebox-qemu-malta.img.swapped"
 imports:
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 08/11] ci: pytest: Generate test data for dm-verity
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (6 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 07/11] ci: pytest: Enable testfs feature on malta boards Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-22 15:41   ` Ahmad Fatoum
  2025-09-18  7:43 ` [PATCH 09/11] test: pytest: add basic dm-verity test Tobias Waldekranz
                   ` (5 subsequent siblings)
  13 siblings, 1 reply; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

Create a small FAT fs with a couple of files, and the corresponding
hash tree. Then create a modified copy that we can use to make sure
that errors are detected.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 scripts/generate_testfs.sh | 44 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/scripts/generate_testfs.sh b/scripts/generate_testfs.sh
index 3c200bd401..1c358ff846 100755
--- a/scripts/generate_testfs.sh
+++ b/scripts/generate_testfs.sh
@@ -28,3 +28,47 @@ generate_fit()
 	       ${KBUILD_OUTPUT}/testfs/barebox-gzipped.fit
 }
 [ -f .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ] && generate_fit
+
+alias pad128k="dd if=/dev/zero bs=128k count=1 status=none"
+
+generate_dm_verity()
+{
+    work=$(mktemp -d)
+    cd ${work}
+
+    # Create two dummy files; use lots of padding to make sure that
+    # when we alter the contents of 'english' in root-bad, 'latin' is
+    # still be readable, as their contents wont (a) share the same
+    # hash block and (b) the block cache layer won't accedentally read
+    # the invalid block.
+
+    pad128k  >latin
+    echo -n "veritas vos liberabit" >>latin
+    pad128k >>latin
+
+    pad128k  >english
+    echo -n "truth will set you free" >>english
+    pad128k >>english
+
+    truncate -s 1M good.fat
+    mkfs.vfat good.fat
+    mcopy -i good.fat latin english ::
+
+    veritysetup format \
+		--root-hash-file=good.hash \
+		good.fat good.verity
+
+    sed 's/truth will set you free/LIAR LIAR PANTS ON FIRE/' \
+	<good.fat >bad.fat
+
+    cd -
+    cp \
+	${work}/good.fat \
+	${work}/good.verity \
+	${work}/good.hash \
+	${work}/bad.fat \
+	${KBUILD_OUTPUT}/testfs
+
+    rm -rf ${work}
+}
+generate_dm_verity
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 09/11] test: pytest: add basic dm-verity test
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (7 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 08/11] ci: pytest: Generate test data for dm-verity Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-22 15:44   ` Ahmad Fatoum
  2025-09-18  7:43 ` [PATCH 10/11] ci: pytest: Centralize feature discovery to a separate step Tobias Waldekranz
                   ` (4 subsequent siblings)
  13 siblings, 1 reply; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

>From a consistent dm-verity device (good):

- Ensure that we can read from the underlying filesystem.

>From a dm-verity device where the data device does not match the hash
tree (bad):

- Ensure that unmodified parts are readable
- Ensure that reading from a modified block results in an I/O error

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 test/py/test_dm.py | 38 ++++++++++++++++++++++++++++++++++++++
 1 file changed, 38 insertions(+)
 create mode 100644 test/py/test_dm.py

diff --git a/test/py/test_dm.py b/test/py/test_dm.py
new file mode 100644
index 0000000000..a9debd85b5
--- /dev/null
+++ b/test/py/test_dm.py
@@ -0,0 +1,38 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+
+import re
+import pytest
+from .helper import of_get_property
+
+
+
+def test_dm_verity(barebox):
+    _, _, returncode = barebox.run("ls /mnt/9p/testfs")
+    if returncode != 0:
+        pytest.xfail("skipping test due to missing --fs testfs=")
+
+    barebox.run_check("cd /mnt/9p/testfs")
+
+    # Since commands run in a subshell, export the root hash in a
+    # global, so that we can access it from subsequent commands
+    barebox.run_check("readf good.hash roothash && global roothash=$roothash")
+
+    barebox.run_check("veritysetup open good.fat good good.verity $global.roothash")
+    barebox.run_check("veritysetup open bad.fat  bad  good.verity $global.roothash")
+
+    barebox.run_check("md5sum /mnt/good/latin /mnt/good/english")
+
+    # 'latin' has not been modified, so it should read fine even from
+    # 'bad'
+    barebox.run_check("md5sum /mnt/bad/latin")
+
+    # 'english' however, does not match the data in the hash tree and
+    # MUST thus fail
+    _, _, returncode = barebox.run("md5sum /mnt/bad/english")
+    assert returncode != 0, "'english' should not be readable from 'bad'"
+
+    barebox.run_check("umount /dev/good")
+    barebox.run_check("veritysetup close good")
+
+    barebox.run_check("umount /dev/bad")
+    barebox.run_check("veritysetup close bad")
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 10/11] ci: pytest: Centralize feature discovery to a separate step
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (8 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 09/11] test: pytest: add basic dm-verity test Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-22 15:45   ` Ahmad Fatoum
  2025-09-18  7:43 ` [PATCH 11/11] ci: pytest: Enable device-mapper labgrid tests Tobias Waldekranz
                   ` (3 subsequent siblings)
  13 siblings, 1 reply; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

This avoids the need for each step to (re)discover features. Start off
by only checking for 'testfs', but this can easily be expanded in the
future.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 .github/workflows/test-labgrid-pytest.yml | 22 +++++++++++++++-------
 1 file changed, 15 insertions(+), 7 deletions(-)

diff --git a/.github/workflows/test-labgrid-pytest.yml b/.github/workflows/test-labgrid-pytest.yml
index adec3defc1..6918ea1b98 100644
--- a/.github/workflows/test-labgrid-pytest.yml
+++ b/.github/workflows/test-labgrid-pytest.yml
@@ -64,6 +64,17 @@ jobs:
     - name: Checkout code
       uses: actions/checkout@v4
 
+    - name: Determine used features
+      id: used-features
+      run: |
+        for i in ${{matrix.lgenv}}; do
+          if grep -wq 'testfs' "$i"; then
+            echo "testfs=true" >>$GITHUB_OUTPUT
+            exit
+          fi
+        done
+        echo "testfs=false" >> $GITHUB_OUTPUT
+
     - name: Build
       id: build
       run: |
@@ -83,17 +94,14 @@ jobs:
         fi
 
     - name: Populate testfs
+      if: steps.used-features.outputs.testfs == 'true'
       run: |
         export KBUILD_OUTPUT=build-${{matrix.arch}}-${{matrix.defconfig}}
         export KBUILD_DEFCONFIG=${{matrix.defconfig}}
 
-        for i in ${{matrix.lgenv}}; do
-          grep -wq 'testfs' "$i" || continue
-
-          # Just use already built dtc
-          export PATH="$PATH:${KBUILD_OUTPUT}/scripts/dtc/"
-          exec scripts/generate_testfs.sh
-        done
+        # Just use already built dtc
+        export PATH="$PATH:${KBUILD_OUTPUT}/scripts/dtc/"
+        exec scripts/generate_testfs.sh
 
     - name: labgrid-pytest
       if: steps.build.outcome == 'success'
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* [PATCH 11/11] ci: pytest: Enable device-mapper labgrid tests
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (9 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 10/11] ci: pytest: Centralize feature discovery to a separate step Tobias Waldekranz
@ 2025-09-18  7:43 ` Tobias Waldekranz
  2025-09-22 15:46   ` Ahmad Fatoum
  2025-09-18 14:08 ` [PATCH 00/11] dm: verity: Add transparent integrity checking target Sascha Hauer
                   ` (2 subsequent siblings)
  13 siblings, 1 reply; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18  7:43 UTC (permalink / raw)
  To: barebox

For targets that support inclusion of the testfs, make sure to inject
all config options needed to run the device mapper pytests.

Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
---
 .github/workflows/test-labgrid-pytest.yml      | 4 ++++
 common/boards/configs/enable_dm_testing.config | 9 +++++++++
 2 files changed, 13 insertions(+)
 create mode 100644 common/boards/configs/enable_dm_testing.config

diff --git a/.github/workflows/test-labgrid-pytest.yml b/.github/workflows/test-labgrid-pytest.yml
index 6918ea1b98..ccf8ae172c 100644
--- a/.github/workflows/test-labgrid-pytest.yml
+++ b/.github/workflows/test-labgrid-pytest.yml
@@ -87,6 +87,10 @@ jobs:
           KCONFIG_ADD="${KCONFIG_ADD} CONFIG_CONSOLE_DISABLE_INPUT=n CONFIG_MALLOC_LIBC=y"
         fi
 
+        if [ "${{ steps.used-features.outputs.testfs }}" = "true" ]; then
+          KCONFIG_ADD="${KCONFIG_ADD} common/boards/configs/enable_dm_testing.config"
+        fi
+
         ./MAKEALL -O ${KBUILD_OUTPUT} -l "" -v 0 ${{matrix.defconfig}}
 
         if [ ${{matrix.arch}} = "riscv" ]; then
diff --git a/common/boards/configs/enable_dm_testing.config b/common/boards/configs/enable_dm_testing.config
new file mode 100644
index 0000000000..16c3f702c1
--- /dev/null
+++ b/common/boards/configs/enable_dm_testing.config
@@ -0,0 +1,9 @@
+CONFIG_FS_FAT=y
+CONFIG_DISK=y
+CONFIG_DM_BLK=y
+CONFIG_DM_BLK_LINEAR=y
+CONFIG_DM_BLK_VERITY=y
+CONFIG_CMD_DMSETUP=y
+CONFIG_CMD_VERITYSETUP=y
+CONFIG_CMD_MD5SUM=y
+CONFIG_CMD_READF=y
-- 
2.43.0




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 03/11] dm: verity: Add transparent integrity checking target
  2025-09-18  7:43 ` [PATCH 03/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
@ 2025-09-18 13:06   ` Sascha Hauer
  0 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2025-09-18 13:06 UTC (permalink / raw)
  To: Tobias Waldekranz; +Cc: barebox

On Thu, Sep 18, 2025 at 09:43:13AM +0200, Tobias Waldekranz wrote:
> Add the dm-verity target, which is compatible with the Linux
> implementation. This means that we can now create dm-verity devices on
> top of partitions containing read-only filesystems and transparently
> verify the integrity of all data is associated the verity root hash.
> 
> CRUCIALLY: The root hash still has be validated by some other means,
> which is outside of the scope of this implementation. Future changes
> will add support for validation of the root hash using a PKCS#7
> signature, again compatible with the Linux kernel implementation.
> 
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>
> ---
>  drivers/block/dm/Kconfig     |   7 +
>  drivers/block/dm/Makefile    |   1 +
>  drivers/block/dm/dm-target.h |  14 ++
>  drivers/block/dm/dm-verity.c | 463 +++++++++++++++++++++++++++++++++++
>  4 files changed, 485 insertions(+)
>  create mode 100644 drivers/block/dm/dm-verity.c
> 
> +static int dm_verity_create(struct dm_target *ti, unsigned int argc, char **argv)
> +{
> +	struct dm_verity *v;
> +	unsigned int ver;
> +	int err;
> +
> +	if (argc != 10) {
> +		dm_target_err(ti, "Expected 10 arguments, got %u\n", argc);
> +		return -EINVAL;
> +	}

For the sake of readablity, can you do a

	const char *verity_version = argv[0];
	const char *verity_device = argv[1];
	...

and use these instead of argv[x] directly?


> +
> +	if (kstrtouint(argv[0], 0, &ver) || ver != 1) {
> +		dm_target_err(ti, "Only version 1 is supported, not \"%s\"\n", argv[0]);
> +		return -EINVAL;
> +	}
> +
> +	v = xzalloc(sizeof(*v));
> +	ti->private = v;
> +
> +	err = dm_verity_cdev_init(ti, &v->ddev, argv[1], argv[3], argv[5], NULL);
> +	if (err)
> +		goto err;
> +
> +	err = dm_verity_cdev_init(ti, &v->hdev, argv[2], argv[4], NULL, argv[6]);
> +	if (err)
> +		goto err;
> +
> +	v->digest_algo = digest_alloc(argv[7]);
> +	if (!v->digest_algo) {
> +		dm_target_err(ti, "Unknown digest \"%s\"\n", argv[7]);
> +		err = -EINVAL;
> +		goto err;
> +	}
> +
> +	v->digest_len = digest_length(v->digest_algo);
> +	if ((1 << v->hdev.blk.bits) < v->digest_len * 2) {
> +		dm_target_err(ti, "Digest size too big\n");
> +		err = -EINVAL;
> +		goto err;
> +	}
> +
> +	v->root_digest = xmalloc(v->digest_len);
> +	if (strlen(argv[8]) != v->digest_len * 2 ||
> +	    hex2bin(v->root_digest, argv[8], v->digest_len)) {
> +		dm_target_err(ti, "Invalid root digest \"%s\"\n", argv[8]);
> +		err = -EINVAL;
> +		goto err;
> +	}
> +
> +	if (strcmp(argv[9], "-")) {
> +		v->salt_size = strlen(argv[9]) / 2;
> +		v->salt = xmalloc(v->salt_size);
> +
> +		if (strlen(argv[9]) != v->salt_size * 2 ||
> +		    hex2bin(v->salt, argv[9], v->salt_size)) {
> +			dm_target_err(ti, "Invalid salt \"%s\"\n", argv[9]);
> +			err = -EINVAL;
> +			goto err;
> +		}
> +	}
> +
> +	err = dm_verity_measure(ti);
> +	if (err)
> +		goto err;
> +
> +	/* Initialize this to a value larger than the largest possible
> +	 * hash block lba to make sure that the first hash block read
> +	 * in dm_verity_verify() always misses the cache.
> +	 */
> +	v->verify.hblock.block = v->hdev.blk.num;
> +	v->verify.hblock.data = xmalloc(1 << v->hdev.blk.bits);
> +
> +	v->verify.digest = xmalloc(v->digest_len);
> +	v->verify.trusted = bitmap_xzalloc(v->hdev.blk.num);
> +	return 0;
> +
> +err:
> +	if (v->salt)
> +		free(v->salt);
> +	if (v->root_digest)
> +		free(v->root_digest);

No need to check. free() handles NULL pointers.

Sascha

> +	if (v->digest_algo)
> +		digest_free(v->digest_algo);
> +	if (v->hdev.cdev)
> +		cdev_close(v->hdev.cdev);
> +	if (v->ddev.cdev)
> +		cdev_close(v->ddev.cdev);
> +
> +	free(v);
> +	return err;
> +}
> +

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/11] dm: verity: Add transparent integrity checking target
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (10 preceding siblings ...)
  2025-09-18  7:43 ` [PATCH 11/11] ci: pytest: Enable device-mapper labgrid tests Tobias Waldekranz
@ 2025-09-18 14:08 ` Sascha Hauer
  2025-09-18 15:38   ` Tobias Waldekranz
  2025-09-23  6:30 ` Sascha Hauer
  2025-10-07  9:05 ` Ahmad Fatoum
  13 siblings, 1 reply; 24+ messages in thread
From: Sascha Hauer @ 2025-09-18 14:08 UTC (permalink / raw)
  To: Tobias Waldekranz; +Cc: barebox

Hi Tobias,

On Thu, Sep 18, 2025 at 09:43:10AM +0200, Tobias Waldekranz wrote:
> This series adds initial support for dm-verity. Notably, it does not
> include any support for validation of any root hash signature. As
> such, practical use in a production setting is still limited, unless
> you have some other way of securely determining that the root hash is
> valid.
> 
> 3/11 is where the action is.

I gave this series a try and it indeed works like a charm. Great :)

I used a verity rootfs I had lying around which has data and hash tree
on the same partition, but even that worked out of the box.

I did some performance measurements just to get an idea how much penalty
we have to pay for dm-verity. Here are the times to read a 1 MiB file
from ext4, from ext4 on dm-verity and from a raw device:

raw device read:         24.28 ms
dm-verity raw read:	 33.90 ms
ext4 on raw device:      24.55 ms
ext4 on dm-verity:       34.93 ms
sha256 of 1 MiB:          3.30 ms

(done on eMMC on a TI-AM62L EVM board)

Ideally the difference between raw read and dm-verity read should be
roughly the time we need for hashing, so it seems there's still some
performance to squeeze out. Nothing to worry about now, I was just
curious.

> 
> TL;DR: What follows is just a discussion about the future - it has
>        nothing to do with the contents of this series.
> 
> 
> Once this is in place, signature validation is next on my TODO. The
> kernel accepts a PKCS7 signature for this purpose. This is therefore
> also what Discoverable Partitions Specification (DPS) provides in its
> <arch>-<part>-verity-sig partitions, which contain a NUL-padded JSON
> document like this:
> 
> {
> 	"roothash": "0123456789abcdef...",
> 	"certificateFingerprint": "0123456789abcdef..",
> 	"signature": "MIIINQYJKo..."
> }
> 
> To avoid having to integrate full ASN.1 + X509 parsing in Barebox, my
> plan is:
> 
> 1. Add support for (optionally) storing a certificate fingerprint
>    along with a `struct public_key`. So at build time, we can note the
>    fingerprint of keys that we include in the builtin keystore.

Something like
https://lore.barebox.org/barebox/20250821-keynames-v1-3-8144af76d0ab@pengutronix.de/
?

I don't know if that fingerprint is in the format you need it though.

> 
>    We could also support parsing fingerprints from a DT. Not sure if
>    this is needed.
> 
> 2. Add a simplified PKCS7 validation function that relies on:
>    a. Knowing which public key to use in advance, rather than
>       determining it by walking the ASN.1 data.
>    b. The last $KEY_LEN_BYTES of the PKCS7 blob holds the raw
>       RFC4880§5.2.2 signature bytes that Barebox already knows how to
>       verify.
> 
> 3. Add a "dps-open" subcommand to veritysetup that only requires the
>    partition to open and a name for the dm-verity device:
> 
>    veritysetup dps-open /dev/disk0.root os
> 
>    Based on the partition type UUID, we would then locate the
>    corresponding -verity and -verity-sig partitions, parse the verity
>    superblock, validate the signature and then create the dm-verity
>    device.
> 
> Some other thoughts for the future (I have done no research here, so
> some of this might already exist in Barebox and I just haven't
> stumbled across it):
> 
> - Similar to the automounter, it would be good to have an
>   "auto-dps-verityer" that will do the equivalent of `veritysetup
>   dps-open` on the DPS partitions matching the current architecture.

Once you have the dps-open subcommand you might be able to use the
autmount mechanism as-is. Something like:

autmount -d /mnt/mmc0.os "veritysetup dps-open /dev/disk0.root os && mount /dev/os /mnt/mmc0.os"

Maybe we can automatically create these automountpoints once we find
suitable GUIDs on a device.

> 
> - Having the ability to tag a partition as trusted, which could then
>   be used to tag filesystems as such.
> 
> - Having a build-time option that limits booting to only be allowed
>   from trusted filesystems.

Yes, there's still some work to do in this area. Right now our secure
boot approach only allows signed FIT images. Now with dm-verity not the
Kernel image itself becomes trusted, but the underlying filesystem. We
are not really prepared for that.

Sascha

-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/11] dm: verity: Add transparent integrity checking target
  2025-09-18 14:08 ` [PATCH 00/11] dm: verity: Add transparent integrity checking target Sascha Hauer
@ 2025-09-18 15:38   ` Tobias Waldekranz
  0 siblings, 0 replies; 24+ messages in thread
From: Tobias Waldekranz @ 2025-09-18 15:38 UTC (permalink / raw)
  To: Sascha Hauer; +Cc: barebox

On tor, sep 18, 2025 at 16:08, Sascha Hauer <s.hauer@pengutronix.de> wrote:
> Hi Tobias,
>
> On Thu, Sep 18, 2025 at 09:43:10AM +0200, Tobias Waldekranz wrote:
>> This series adds initial support for dm-verity. Notably, it does not
>> include any support for validation of any root hash signature. As
>> such, practical use in a production setting is still limited, unless
>> you have some other way of securely determining that the root hash is
>> valid.
>> 
>> 3/11 is where the action is.
>
> I gave this series a try and it indeed works like a charm. Great :)
>
> I used a verity rootfs I had lying around which has data and hash tree
> on the same partition, but even that worked out of the box.

Glad to hear it! :)

> I did some performance measurements just to get an idea how much penalty
> we have to pay for dm-verity. Here are the times to read a 1 MiB file
> from ext4, from ext4 on dm-verity and from a raw device:

Awesome, thanks for looking into this.

> raw device read:         24.28 ms
> dm-verity raw read:	 33.90 ms
> ext4 on raw device:      24.55 ms
> ext4 on dm-verity:       34.93 ms
> sha256 of 1 MiB:          3.30 ms
>
> (done on eMMC on a TI-AM62L EVM board)
>
> Ideally the difference between raw read and dm-verity read should be
> roughly the time we need for hashing, so it seems there's still some
> performance to squeeze out. Nothing to worry about now, I was just
> curious.

Do you have any sense of the time difference between a single digest of
1M compared to 256 4k (the default data block size) digests? I assume
you pay some penalty, but I have no idea if it could explain this
difference.

On that note, one thing that I think can be optimized, though I have no
profiling data to back this up yet, is how the digest object is
reused. Here is the relevant part:

static int dm_verity_set_digest(struct dm_verity *v, const void *buf, size_t buflen)
{
	int err;

	err = digest_init(v->digest_algo);
	err = err ? : digest_update(v->digest_algo, v->salt, v->salt_size);
	err = err ? : digest_update(v->digest_algo, buf, buflen);
	err = err ? : digest_final(v->digest_algo, v->verify.digest);
	return err;
}

Since the salt is fixed, the state of digest_algo after
init()+update(salt) is also fixed. So if there was a way to capture and
restore the digest to this known state, we could replace
init()+update(salt) with a memcpy(). There was no such API that I could
find (which makes sense, this is not the normal use-case), so I took the
naive approach. But maybe the performance gains would warrant something
a bit more quirky.

What was that saying about premature optimization again? :)

>> 
>> TL;DR: What follows is just a discussion about the future - it has
>>        nothing to do with the contents of this series.
>> 
>> 
>> Once this is in place, signature validation is next on my TODO. The
>> kernel accepts a PKCS7 signature for this purpose. This is therefore
>> also what Discoverable Partitions Specification (DPS) provides in its
>> <arch>-<part>-verity-sig partitions, which contain a NUL-padded JSON
>> document like this:
>> 
>> {
>> 	"roothash": "0123456789abcdef...",
>> 	"certificateFingerprint": "0123456789abcdef..",
>> 	"signature": "MIIINQYJKo..."
>> }
>> 
>> To avoid having to integrate full ASN.1 + X509 parsing in Barebox, my
>> plan is:
>> 
>> 1. Add support for (optionally) storing a certificate fingerprint
>>    along with a `struct public_key`. So at build time, we can note the
>>    fingerprint of keys that we include in the builtin keystore.
>
> Something like
> https://lore.barebox.org/barebox/20250821-keynames-v1-3-8144af76d0ab@pengutronix.de/
> ?
>
> I don't know if that fingerprint is in the format you need it though.

Unfortunatly not. The fingerprint produced by systemd-repart (which is
the reference implementation for creating DPS images, AFAIK) is of the
entire X509 cert, e.g.:

  barebox$ openssl x509 -fingerprint -sha256 -in crypto/fit-ecdsa-development.crt -noout
  sha256 Fingerprint=BA:50:D7:38:EA:68:AE:78:07:DD:C4:2E:5D:D6:26:69:B3:3E:0A:85:7D:BE:B0:98:9B:A5:F5:69:7D:A2:F6:A0

I have started to sketch this out:

https://github.com/wkz/barebox/tree/dm-verity-sig

>> 
>>    We could also support parsing fingerprints from a DT. Not sure if
>>    this is needed.
>> 
>> 2. Add a simplified PKCS7 validation function that relies on:
>>    a. Knowing which public key to use in advance, rather than
>>       determining it by walking the ASN.1 data.
>>    b. The last $KEY_LEN_BYTES of the PKCS7 blob holds the raw
>>       RFC4880§5.2.2 signature bytes that Barebox already knows how to
>>       verify.
>> 
>> 3. Add a "dps-open" subcommand to veritysetup that only requires the
>>    partition to open and a name for the dm-verity device:
>> 
>>    veritysetup dps-open /dev/disk0.root os
>> 
>>    Based on the partition type UUID, we would then locate the
>>    corresponding -verity and -verity-sig partitions, parse the verity
>>    superblock, validate the signature and then create the dm-verity
>>    device.
>> 
>> Some other thoughts for the future (I have done no research here, so
>> some of this might already exist in Barebox and I just haven't
>> stumbled across it):
>> 
>> - Similar to the automounter, it would be good to have an
>>   "auto-dps-verityer" that will do the equivalent of `veritysetup
>>   dps-open` on the DPS partitions matching the current architecture.
>
> Once you have the dps-open subcommand you might be able to use the
> autmount mechanism as-is. Something like:
>
> autmount -d /mnt/mmc0.os "veritysetup dps-open /dev/disk0.root os && mount /dev/os /mnt/mmc0.os"

Interesting, I have to read up on this.

> Maybe we can automatically create these automountpoints once we find
> suitable GUIDs on a device.

I think something like that would be ideal. Then Barebox should more or
less be able to automatically produce a list of all trusted boot sources
(using the existing blspec logic (which I also know too little about :))

>> 
>> - Having the ability to tag a partition as trusted, which could then
>>   be used to tag filesystems as such.
>> 
>> - Having a build-time option that limits booting to only be allowed
>>   from trusted filesystems.
>
> Yes, there's still some work to do in this area. Right now our secure
> boot approach only allows signed FIT images. Now with dm-verity not the
> Kernel image itself becomes trusted, but the underlying filesystem. We
> are not really prepared for that.

Right, that is fully understandable.

> Sascha
>
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 06/11] ci: pytest: Open up testfs to more consumers than the FIT test
  2025-09-18  7:43 ` [PATCH 06/11] ci: pytest: Open up testfs to more consumers than the FIT test Tobias Waldekranz
@ 2025-09-22 15:38   ` Ahmad Fatoum
  0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 15:38 UTC (permalink / raw)
  To: Tobias Waldekranz, barebox

On 18.09.25 09:43, Tobias Waldekranz wrote:
> With upcoming dm-verity tests, we want to store more test artifacts
> than the FIT image in the testfs.
> 
> Since the dm tests might run on systems for which no ITS is available
> to build an FIT from, make FIT generation conditional on the ITS being
> available. This allows us to enable the testfs feature on all matrix
> cells that support 9p over virtio.
> 
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

FWIW, testfs was supposed to be just a stop-gap.

My current plan is to have a "meta-bootstack" Yocto BSP that generates
actual artifacts that will be used for testing which affords us much
more flexibility.

I see the utility now though in having some tests that can be run locally
without building the BSP, so I would just add a second mount point for
it, so everything good here.

Cheers,
Ahmad

> ---
>  scripts/generate_testfs.sh                  | 20 ++++++++++++--------
>  test/py/test_fit.py                         |  4 +++-
>  test/riscv/qemu-virt64@rv64i_defconfig.yaml |  1 +
>  test/riscv/qemu@virt32_defconfig.yaml       |  1 +
>  4 files changed, 17 insertions(+), 9 deletions(-)
> 
> diff --git a/scripts/generate_testfs.sh b/scripts/generate_testfs.sh
> index c5d24f7e1a..3c200bd401 100755
> --- a/scripts/generate_testfs.sh
> +++ b/scripts/generate_testfs.sh
> @@ -13,14 +13,18 @@ fi
>  rm -rf "${KBUILD_OUTPUT}/testfs/"
>  mkdir -p ${KBUILD_OUTPUT}/testfs
>  
> -cat ${KBUILD_OUTPUT}/images/barebox-dt-2nd.img | \
> -  ${KGZIP} -n -f -9 >${KBUILD_OUTPUT}/barebox-dt-2nd.img.gz
> +generate_fit()
> +{
> +    cat ${KBUILD_OUTPUT}/images/barebox-dt-2nd.img | \
> +	${KGZIP} -n -f -9 >${KBUILD_OUTPUT}/barebox-dt-2nd.img.gz
>  
> -cp .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ${KBUILD_OUTPUT}/
> +    cp .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ${KBUILD_OUTPUT}/
>  
> -find COPYING LICENSES/ | cpio -o -H newc | ${KGZIP} \
> -  > ${KBUILD_OUTPUT}/ramdisk.cpio.gz
> +    find COPYING LICENSES/ | cpio -o -H newc | ${KGZIP} \
> +						   > ${KBUILD_OUTPUT}/ramdisk.cpio.gz
>  
> -${MKIMAGE} -G $PWD/test/self/development_rsa2048.pem -r \
> -      -f ${KBUILD_OUTPUT}/${KBUILD_DEFCONFIG}-gzipped.its \
> -	 ${KBUILD_OUTPUT}/testfs/barebox-gzipped.fit
> +    ${MKIMAGE} -G $PWD/test/self/development_rsa2048.pem -r \
> +	       -f ${KBUILD_OUTPUT}/${KBUILD_DEFCONFIG}-gzipped.its \
> +	       ${KBUILD_OUTPUT}/testfs/barebox-gzipped.fit
> +}
> +[ -f .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ] && generate_fit
> diff --git a/test/py/test_fit.py b/test/py/test_fit.py
> index c53a1ece14..1a23a53a32 100644
> --- a/test/py/test_fit.py
> +++ b/test/py/test_fit.py
> @@ -23,7 +23,9 @@ def test_fit(barebox, env, target, barebox_config):
>      if returncode != 0:
>          pytest.xfail("skipping test due to missing --fs testfs=")
>  
> -    barebox.run_check(f"ls {fit_name('gzipped')}")
> +    _, _, returncode = barebox.run(f"ls {fit_name('gzipped')}")
> +    if returncode != 0:
> +        pytest.xfail("skipping test due to missing FIT image")
>  
>      # Sanity check, this is only fixed up on first boot
>      assert of_get_property(barebox, "/chosen/barebox-version") is False
> diff --git a/test/riscv/qemu-virt64@rv64i_defconfig.yaml b/test/riscv/qemu-virt64@rv64i_defconfig.yaml
> index 7f86d9ac7d..5f1310617a 100644
> --- a/test/riscv/qemu-virt64@rv64i_defconfig.yaml
> +++ b/test/riscv/qemu-virt64@rv64i_defconfig.yaml
> @@ -15,6 +15,7 @@ targets:
>      features:
>        - virtio-mmio
>        - barebox-state
> +      - testfs
>  images:
>    barebox-dt-2nd.img: !template "$LG_BUILDDIR/images/barebox-dt-2nd.img"
>  imports:
> diff --git a/test/riscv/qemu@virt32_defconfig.yaml b/test/riscv/qemu@virt32_defconfig.yaml
> index 7860e97c52..d0b640aa18 100644
> --- a/test/riscv/qemu@virt32_defconfig.yaml
> +++ b/test/riscv/qemu@virt32_defconfig.yaml
> @@ -16,6 +16,7 @@ targets:
>      features:
>        - virtio-mmio
>        - barebox-state
> +      - testfs
>      runner:
>        download:
>          opensbi-riscv32-generic-fw_dynamic.bin: https://github.com/qemu/qemu/blob/v5.2.0/pc-bios/opensbi-riscv32-generic-fw_dynamic.bin?raw=true


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 07/11] ci: pytest: Enable testfs feature on malta boards
  2025-09-18  7:43 ` [PATCH 07/11] ci: pytest: Enable testfs feature on malta boards Tobias Waldekranz
@ 2025-09-22 15:40   ` Ahmad Fatoum
  0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 15:40 UTC (permalink / raw)
  To: Tobias Waldekranz, barebox

On 18.09.25 09:43, Tobias Waldekranz wrote:
> By enabling 9p in the defconfig, we get access to the testfs feature,
> which will enable the upcoming dm-verity labgrid tests to be run on
> this platform.
> 
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>

Nice. I meant to enable it in the past, but didn't debug into why the
build failed, but you fixed that already in the last series.

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

> ---
>  arch/mips/configs/qemu-malta_defconfig  | 4 ++++
>  test/mips/be@qemu-malta_defconfig.yaml  | 1 +
>  test/mips/qemu-malta64el_defconfig.yaml | 1 +
>  3 files changed, 6 insertions(+)
> 
> diff --git a/arch/mips/configs/qemu-malta_defconfig b/arch/mips/configs/qemu-malta_defconfig
> index e5bc8ff8cb..64279f7ff4 100644
> --- a/arch/mips/configs/qemu-malta_defconfig
> +++ b/arch/mips/configs/qemu-malta_defconfig
> @@ -58,6 +58,8 @@ CONFIG_CMD_OFTREE=y
>  CONFIG_CMD_TIME=y
>  CONFIG_NET=y
>  CONFIG_NET_NETCONSOLE=y
> +CONFIG_NET_9P=y
> +CONFIG_NET_9P_VIRTIO=y
>  CONFIG_OFDEVICE=y
>  CONFIG_OF_BAREBOX_DRIVERS=y
>  CONFIG_VIRTIO_CONSOLE=y
> @@ -91,6 +93,8 @@ CONFIG_FS_CRAMFS=y
>  CONFIG_FS_EXT4=y
>  CONFIG_FS_TFTP=y
>  CONFIG_FS_NFS=y
> +CONFIG_9P_FS=y
> +CONFIG_9P_FS_WRITE=y
>  CONFIG_FS_FAT=y
>  CONFIG_FS_FAT_WRITE=y
>  CONFIG_FS_FAT_LFN=y
> diff --git a/test/mips/be@qemu-malta_defconfig.yaml b/test/mips/be@qemu-malta_defconfig.yaml
> index a3d34a660d..2f3b7e674b 100644
> --- a/test/mips/be@qemu-malta_defconfig.yaml
> +++ b/test/mips/be@qemu-malta_defconfig.yaml
> @@ -14,6 +14,7 @@ targets:
>        BareboxTestStrategy: {}
>      features:
>        - virtio-pci
> +      - testfs
>  images:
>    barebox-qemu-malta.img: !template "$LG_BUILDDIR/images/barebox-qemu-malta.img"
>  imports:
> diff --git a/test/mips/qemu-malta64el_defconfig.yaml b/test/mips/qemu-malta64el_defconfig.yaml
> index 5562f59dc7..dfbdb21ee8 100644
> --- a/test/mips/qemu-malta64el_defconfig.yaml
> +++ b/test/mips/qemu-malta64el_defconfig.yaml
> @@ -14,6 +14,7 @@ targets:
>        BareboxTestStrategy: {}
>      features:
>        - virtio-pci
> +      - testfs
>  images:
>    barebox-qemu-malta.img.swapped: !template "$LG_BUILDDIR/images/barebox-qemu-malta.img.swapped"
>  imports:


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 08/11] ci: pytest: Generate test data for dm-verity
  2025-09-18  7:43 ` [PATCH 08/11] ci: pytest: Generate test data for dm-verity Tobias Waldekranz
@ 2025-09-22 15:41   ` Ahmad Fatoum
  0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 15:41 UTC (permalink / raw)
  To: Tobias Waldekranz, barebox

On 18.09.25 09:43, Tobias Waldekranz wrote:
> Create a small FAT fs with a couple of files, and the corresponding
> hash tree. Then create a modified copy that we can use to make sure
> that errors are detected.
> 
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

> ---
>  scripts/generate_testfs.sh | 44 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 44 insertions(+)
> 
> diff --git a/scripts/generate_testfs.sh b/scripts/generate_testfs.sh
> index 3c200bd401..1c358ff846 100755
> --- a/scripts/generate_testfs.sh
> +++ b/scripts/generate_testfs.sh
> @@ -28,3 +28,47 @@ generate_fit()
>  	       ${KBUILD_OUTPUT}/testfs/barebox-gzipped.fit
>  }
>  [ -f .github/testfs/${KBUILD_DEFCONFIG}-gzipped.its ] && generate_fit
> +
> +alias pad128k="dd if=/dev/zero bs=128k count=1 status=none"
> +
> +generate_dm_verity()
> +{
> +    work=$(mktemp -d)
> +    cd ${work}
> +
> +    # Create two dummy files; use lots of padding to make sure that
> +    # when we alter the contents of 'english' in root-bad, 'latin' is
> +    # still be readable, as their contents wont (a) share the same
> +    # hash block and (b) the block cache layer won't accedentally read
> +    # the invalid block.
> +
> +    pad128k  >latin
> +    echo -n "veritas vos liberabit" >>latin
> +    pad128k >>latin
> +
> +    pad128k  >english
> +    echo -n "truth will set you free" >>english
> +    pad128k >>english
> +
> +    truncate -s 1M good.fat
> +    mkfs.vfat good.fat
> +    mcopy -i good.fat latin english ::
> +
> +    veritysetup format \
> +		--root-hash-file=good.hash \
> +		good.fat good.verity
> +
> +    sed 's/truth will set you free/LIAR LIAR PANTS ON FIRE/' \
> +	<good.fat >bad.fat
> +
> +    cd -
> +    cp \
> +	${work}/good.fat \
> +	${work}/good.verity \
> +	${work}/good.hash \
> +	${work}/bad.fat \
> +	${KBUILD_OUTPUT}/testfs
> +
> +    rm -rf ${work}
> +}
> +generate_dm_verity


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 09/11] test: pytest: add basic dm-verity test
  2025-09-18  7:43 ` [PATCH 09/11] test: pytest: add basic dm-verity test Tobias Waldekranz
@ 2025-09-22 15:44   ` Ahmad Fatoum
  0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 15:44 UTC (permalink / raw)
  To: Tobias Waldekranz, barebox

On 18.09.25 09:43, Tobias Waldekranz wrote:
> From a consistent dm-verity device (good):
> 
> - Ensure that we can read from the underlying filesystem.
> 
> From a dm-verity device where the data device does not match the hash
> tree (bad):
> 
> - Ensure that unmodified parts are readable
> - Ensure that reading from a modified block results in an I/O error
> 
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

Thanks for including a test!
Ahmad

> ---
>  test/py/test_dm.py | 38 ++++++++++++++++++++++++++++++++++++++
>  1 file changed, 38 insertions(+)
>  create mode 100644 test/py/test_dm.py
> 
> diff --git a/test/py/test_dm.py b/test/py/test_dm.py
> new file mode 100644
> index 0000000000..a9debd85b5
> --- /dev/null
> +++ b/test/py/test_dm.py
> @@ -0,0 +1,38 @@
> +# SPDX-License-Identifier: GPL-2.0-or-later
> +
> +import re
> +import pytest
> +from .helper import of_get_property
> +
> +
> +
> +def test_dm_verity(barebox):
> +    _, _, returncode = barebox.run("ls /mnt/9p/testfs")
> +    if returncode != 0:
> +        pytest.xfail("skipping test due to missing --fs testfs=")
> +
> +    barebox.run_check("cd /mnt/9p/testfs")
> +
> +    # Since commands run in a subshell, export the root hash in a
> +    # global, so that we can access it from subsequent commands
> +    barebox.run_check("readf good.hash roothash && global roothash=$roothash")
> +
> +    barebox.run_check("veritysetup open good.fat good good.verity $global.roothash")
> +    barebox.run_check("veritysetup open bad.fat  bad  good.verity $global.roothash")
> +
> +    barebox.run_check("md5sum /mnt/good/latin /mnt/good/english")
> +
> +    # 'latin' has not been modified, so it should read fine even from
> +    # 'bad'
> +    barebox.run_check("md5sum /mnt/bad/latin")
> +
> +    # 'english' however, does not match the data in the hash tree and
> +    # MUST thus fail
> +    _, _, returncode = barebox.run("md5sum /mnt/bad/english")
> +    assert returncode != 0, "'english' should not be readable from 'bad'"
> +
> +    barebox.run_check("umount /dev/good")
> +    barebox.run_check("veritysetup close good")
> +
> +    barebox.run_check("umount /dev/bad")
> +    barebox.run_check("veritysetup close bad")


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 10/11] ci: pytest: Centralize feature discovery to a separate step
  2025-09-18  7:43 ` [PATCH 10/11] ci: pytest: Centralize feature discovery to a separate step Tobias Waldekranz
@ 2025-09-22 15:45   ` Ahmad Fatoum
  0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 15:45 UTC (permalink / raw)
  To: Tobias Waldekranz, barebox

On 18.09.25 09:43, Tobias Waldekranz wrote:
> This avoids the need for each step to (re)discover features. Start off
> by only checking for 'testfs', but this can easily be expanded in the
> future.
> 
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

> ---
>  .github/workflows/test-labgrid-pytest.yml | 22 +++++++++++++++-------
>  1 file changed, 15 insertions(+), 7 deletions(-)
> 
> diff --git a/.github/workflows/test-labgrid-pytest.yml b/.github/workflows/test-labgrid-pytest.yml
> index adec3defc1..6918ea1b98 100644
> --- a/.github/workflows/test-labgrid-pytest.yml
> +++ b/.github/workflows/test-labgrid-pytest.yml
> @@ -64,6 +64,17 @@ jobs:
>      - name: Checkout code
>        uses: actions/checkout@v4
>  
> +    - name: Determine used features
> +      id: used-features
> +      run: |
> +        for i in ${{matrix.lgenv}}; do
> +          if grep -wq 'testfs' "$i"; then
> +            echo "testfs=true" >>$GITHUB_OUTPUT
> +            exit
> +          fi
> +        done
> +        echo "testfs=false" >> $GITHUB_OUTPUT
> +
>      - name: Build
>        id: build
>        run: |
> @@ -83,17 +94,14 @@ jobs:
>          fi
>  
>      - name: Populate testfs
> +      if: steps.used-features.outputs.testfs == 'true'
>        run: |
>          export KBUILD_OUTPUT=build-${{matrix.arch}}-${{matrix.defconfig}}
>          export KBUILD_DEFCONFIG=${{matrix.defconfig}}
>  
> -        for i in ${{matrix.lgenv}}; do
> -          grep -wq 'testfs' "$i" || continue
> -
> -          # Just use already built dtc
> -          export PATH="$PATH:${KBUILD_OUTPUT}/scripts/dtc/"
> -          exec scripts/generate_testfs.sh
> -        done
> +        # Just use already built dtc
> +        export PATH="$PATH:${KBUILD_OUTPUT}/scripts/dtc/"
> +        exec scripts/generate_testfs.sh
>  
>      - name: labgrid-pytest
>        if: steps.build.outcome == 'success'


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 11/11] ci: pytest: Enable device-mapper labgrid tests
  2025-09-18  7:43 ` [PATCH 11/11] ci: pytest: Enable device-mapper labgrid tests Tobias Waldekranz
@ 2025-09-22 15:46   ` Ahmad Fatoum
  0 siblings, 0 replies; 24+ messages in thread
From: Ahmad Fatoum @ 2025-09-22 15:46 UTC (permalink / raw)
  To: Tobias Waldekranz, barebox

On 18.09.25 09:43, Tobias Waldekranz wrote:
> For targets that support inclusion of the testfs, make sure to inject
> all config options needed to run the device mapper pytests.
> 
> Signed-off-by: Tobias Waldekranz <tobias@waldekranz.com>

Reviewed-by: Ahmad Fatoum <a.fatoum@pengutronix.de>

> ---
>  .github/workflows/test-labgrid-pytest.yml      | 4 ++++
>  common/boards/configs/enable_dm_testing.config | 9 +++++++++
>  2 files changed, 13 insertions(+)
>  create mode 100644 common/boards/configs/enable_dm_testing.config
> 
> diff --git a/.github/workflows/test-labgrid-pytest.yml b/.github/workflows/test-labgrid-pytest.yml
> index 6918ea1b98..ccf8ae172c 100644
> --- a/.github/workflows/test-labgrid-pytest.yml
> +++ b/.github/workflows/test-labgrid-pytest.yml
> @@ -87,6 +87,10 @@ jobs:
>            KCONFIG_ADD="${KCONFIG_ADD} CONFIG_CONSOLE_DISABLE_INPUT=n CONFIG_MALLOC_LIBC=y"
>          fi
>  
> +        if [ "${{ steps.used-features.outputs.testfs }}" = "true" ]; then
> +          KCONFIG_ADD="${KCONFIG_ADD} common/boards/configs/enable_dm_testing.config"
> +        fi
> +
>          ./MAKEALL -O ${KBUILD_OUTPUT} -l "" -v 0 ${{matrix.defconfig}}
>  
>          if [ ${{matrix.arch}} = "riscv" ]; then
> diff --git a/common/boards/configs/enable_dm_testing.config b/common/boards/configs/enable_dm_testing.config
> new file mode 100644
> index 0000000000..16c3f702c1
> --- /dev/null
> +++ b/common/boards/configs/enable_dm_testing.config
> @@ -0,0 +1,9 @@
> +CONFIG_FS_FAT=y
> +CONFIG_DISK=y
> +CONFIG_DM_BLK=y
> +CONFIG_DM_BLK_LINEAR=y
> +CONFIG_DM_BLK_VERITY=y
> +CONFIG_CMD_DMSETUP=y
> +CONFIG_CMD_VERITYSETUP=y
> +CONFIG_CMD_MD5SUM=y
> +CONFIG_CMD_READF=y


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/11] dm: verity: Add transparent integrity checking target
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (11 preceding siblings ...)
  2025-09-18 14:08 ` [PATCH 00/11] dm: verity: Add transparent integrity checking target Sascha Hauer
@ 2025-09-23  6:30 ` Sascha Hauer
  2025-10-07  9:05 ` Ahmad Fatoum
  13 siblings, 0 replies; 24+ messages in thread
From: Sascha Hauer @ 2025-09-23  6:30 UTC (permalink / raw)
  To: barebox, Tobias Waldekranz


On Thu, 18 Sep 2025 09:43:10 +0200, Tobias Waldekranz wrote:
> This series adds initial support for dm-verity. Notably, it does not
> include any support for validation of any root hash signature. As
> such, practical use in a production setting is still limited, unless
> you have some other way of securely determining that the root hash is
> valid.
> 
> 3/11 is where the action is.
> 
> [...]

Applied, thanks!

[01/11] dm: Add helper to manage a lower device
        https://git.pengutronix.de/cgit/barebox/commit/?id=80da07bfd0e0 (link may not be stable)
[02/11] dm: linear: Refactor to make use of the generalized cdev management
        https://git.pengutronix.de/cgit/barebox/commit/?id=bc2d05fa2df9 (link may not be stable)
[03/11] dm: verity: Add transparent integrity checking target
        https://git.pengutronix.de/cgit/barebox/commit/?id=3afa68742281 (link may not be stable)
[04/11] dm: verity: Add helper to parse superblock information
        https://git.pengutronix.de/cgit/barebox/commit/?id=f2cc4a0a5f3c (link may not be stable)
[05/11] commands: veritysetup: Create dm-verity devices
        https://git.pengutronix.de/cgit/barebox/commit/?id=086f03c157b9 (link may not be stable)
[06/11] ci: pytest: Open up testfs to more consumers than the FIT test
        https://git.pengutronix.de/cgit/barebox/commit/?id=739a1a7855f5 (link may not be stable)
[07/11] ci: pytest: Enable testfs feature on malta boards
        https://git.pengutronix.de/cgit/barebox/commit/?id=e58164d5436c (link may not be stable)
[08/11] ci: pytest: Generate test data for dm-verity
        https://git.pengutronix.de/cgit/barebox/commit/?id=812e36a3ffb2 (link may not be stable)
[09/11] test: pytest: add basic dm-verity test
        https://git.pengutronix.de/cgit/barebox/commit/?id=59eb868b8c63 (link may not be stable)
[10/11] ci: pytest: Centralize feature discovery to a separate step
        https://git.pengutronix.de/cgit/barebox/commit/?id=37caa86ca175 (link may not be stable)
[11/11] ci: pytest: Enable device-mapper labgrid tests
        https://git.pengutronix.de/cgit/barebox/commit/?id=0407b4e8400a (link may not be stable)

Best regards,
-- 
Sascha Hauer <s.hauer@pengutronix.de>




^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/11] dm: verity: Add transparent integrity checking target
  2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
                   ` (12 preceding siblings ...)
  2025-09-23  6:30 ` Sascha Hauer
@ 2025-10-07  9:05 ` Ahmad Fatoum
  2025-10-07 20:15   ` Tobias Waldekranz
  13 siblings, 1 reply; 24+ messages in thread
From: Ahmad Fatoum @ 2025-10-07  9:05 UTC (permalink / raw)
  To: Tobias Waldekranz, barebox; +Cc: Jonas Rebmann

Hi,

On 18.09.25 09:43, Tobias Waldekranz wrote:
> This series adds initial support for dm-verity. Notably, it does not
> include any support for validation of any root hash signature. As
> such, practical use in a production setting is still limited, unless
> you have some other way of securely determining that the root hash is
> valid.
> 
> 3/11 is where the action is.
> 
> TL;DR: What follows is just a discussion about the future - it has
>        nothing to do with the contents of this series.

Thanks for pointing out the shed for I come with color.

> Once this is in place, signature validation is next on my TODO. The
> kernel accepts a PKCS7 signature for this purpose. This is therefore
> also what Discoverable Partitions Specification (DPS) provides in its
> <arch>-<part>-verity-sig partitions, which contain a NUL-padded JSON
> document like this:
> 
> {
> 	"roothash": "0123456789abcdef...",
> 	"certificateFingerprint": "0123456789abcdef..",
> 	"signature": "MIIINQYJKo..."
> }
> 
> To avoid having to integrate full ASN.1 + X509 parsing in Barebox, my
> plan is:

We've been piecewise importing crypto primitives from the Linux kernel
so far, but I've been thinking if we shouldn't take the leap and import
mbedtls, but we haven't had the need so far. Sascha is not opposed, if
there's a good use case for it.

> 1. Add support for (optionally) storing a certificate fingerprint
>    along with a `struct public_key`. So at build time, we can note the
>    fingerprint of keys that we include in the builtin keystore.
> 
>    We could also support parsing fingerprints from a DT. Not sure if
>    this is needed.

ECDSA support in barebox afaik doesn't have a DT representation and
going forward CONFIG_CRYPTO_PUBLIC_KEYS is the standard way to pass keys
into barebox.

Jonas (Cc'd) is working right now in a backwards-compatible manner of
attaching meta-data to keys, e.g.:

export myfitkey="keyring=fit,hint=myhint:pkcs11:token=foo,bar;object=bl"
export myjwtkey="keyring=jwt-myboard:jwt_pub.pem"


scripts/config --set-str CONFIG_CRYPTO_PUBLIC_KEYS \
		"__ENV_myfitkey __ENV_myjwtkey"

> 2. Add a simplified PKCS7 validation function that relies on:
>    a. Knowing which public key to use in advance, rather than
>       determining it by walking the ASN.1 data.
>    b. The last $KEY_LEN_BYTES of the PKCS7 blob holds the raw
>       RFC4880§5.2.2 signature bytes that Barebox already knows how to
>       verify.
> 
> 3. Add a "dps-open" subcommand to veritysetup that only requires the
>    partition to open and a name for the dm-verity device:
> 
>    veritysetup dps-open /dev/disk0.root os
> 
>    Based on the partition type UUID, we would then locate the
>    corresponding -verity and -verity-sig partitions, parse the verity
>    superblock, validate the signature and then create the dm-verity
>    device.

This makes sense, even if there is no decision yet for
https://github.com/uapi-group/specifications/issues/167

I would suggest we hardcode (and document) that in case there are
multiple candidates, the ones closest after the root partition are taken?

> Some other thoughts for the future (I have done no research here, so
> some of this might already exist in Barebox and I just haven't
> stumbled across it):
> 
> - Similar to the automounter, it would be good to have an
>   "auto-dps-verityer" that will do the equivalent of `veritysetup
>   dps-open` on the DPS partitions matching the current architecture.
> 
> - Having the ability to tag a partition as trusted, which could then
>   be used to tag filesystems as such.

This would mesh nicely with security policies. We can allow board code
to tag device files and then mounting them would be allowed even if
SCONFIG_FS_UNTRUSTED is disabled per currently active security policy.

> - Having a build-time option that limits booting to only be allowed
>   from trusted filesystems.

Ye, for users without security policies, a build-time option would be apt.

Cheers,
Ahmad

> 
> Tobias Waldekranz (11):
>   dm: Add helper to manage a lower device
>   dm: linear: Refactor to make use of the generalized cdev management
>   dm: verity: Add transparent integrity checking target
>   dm: verity: Add helper to parse superblock information
>   commands: veritysetup: Create dm-verity devices
>   ci: pytest: Open up testfs to more consumers than the FIT test
>   ci: pytest: Enable testfs feature on malta boards
>   ci: pytest: Generate test data for dm-verity
>   test: pytest: add basic dm-verity test
>   ci: pytest: Centralize feature discovery to a separate step
>   ci: pytest: Enable device-mapper labgrid tests
> 
>  .github/workflows/test-labgrid-pytest.yml     |  26 +-
>  arch/mips/configs/qemu-malta_defconfig        |   4 +
>  commands/Kconfig                              |  10 +
>  commands/Makefile                             |   1 +
>  commands/veritysetup.c                        | 123 +++++
>  .../boards/configs/enable_dm_testing.config   |   9 +
>  drivers/block/dm/Kconfig                      |   7 +
>  drivers/block/dm/Makefile                     |   1 +
>  drivers/block/dm/dm-core.c                    | 118 ++++
>  drivers/block/dm/dm-linear.c                  |  64 +--
>  drivers/block/dm/dm-target.h                  |  34 ++
>  drivers/block/dm/dm-verity.c                  | 517 ++++++++++++++++++
>  include/device-mapper.h                       |   5 +
>  scripts/generate_testfs.sh                    |  64 ++-
>  test/mips/be@qemu-malta_defconfig.yaml        |   1 +
>  test/mips/qemu-malta64el_defconfig.yaml       |   1 +
>  test/py/test_dm.py                            |  38 ++
>  test/py/test_fit.py                           |   4 +-
>  test/riscv/qemu-virt64@rv64i_defconfig.yaml   |   1 +
>  test/riscv/qemu@virt32_defconfig.yaml         |   1 +
>  20 files changed, 968 insertions(+), 61 deletions(-)
>  create mode 100644 commands/veritysetup.c
>  create mode 100644 common/boards/configs/enable_dm_testing.config
>  create mode 100644 drivers/block/dm/dm-verity.c
>  create mode 100644 test/py/test_dm.py
> 


-- 
Pengutronix e.K.                           |                             |
Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

* Re: [PATCH 00/11] dm: verity: Add transparent integrity checking target
  2025-10-07  9:05 ` Ahmad Fatoum
@ 2025-10-07 20:15   ` Tobias Waldekranz
  0 siblings, 0 replies; 24+ messages in thread
From: Tobias Waldekranz @ 2025-10-07 20:15 UTC (permalink / raw)
  To: Ahmad Fatoum, barebox; +Cc: Jonas Rebmann

On tis, okt 07, 2025 at 11:05, Ahmad Fatoum <a.fatoum@pengutronix.de> wrote:
> Hi,
>
> On 18.09.25 09:43, Tobias Waldekranz wrote:
>> This series adds initial support for dm-verity. Notably, it does not
>> include any support for validation of any root hash signature. As
>> such, practical use in a production setting is still limited, unless
>> you have some other way of securely determining that the root hash is
>> valid.
>> 
>> 3/11 is where the action is.
>> 
>> TL;DR: What follows is just a discussion about the future - it has
>>        nothing to do with the contents of this series.
>
> Thanks for pointing out the shed for I come with color.
>
>> Once this is in place, signature validation is next on my TODO. The
>> kernel accepts a PKCS7 signature for this purpose. This is therefore
>> also what Discoverable Partitions Specification (DPS) provides in its
>> <arch>-<part>-verity-sig partitions, which contain a NUL-padded JSON
>> document like this:
>> 
>> {
>> 	"roothash": "0123456789abcdef...",
>> 	"certificateFingerprint": "0123456789abcdef..",
>> 	"signature": "MIIINQYJKo..."
>> }
>> 
>> To avoid having to integrate full ASN.1 + X509 parsing in Barebox, my
>> plan is:
>
> We've been piecewise importing crypto primitives from the Linux kernel
> so far, but I've been thinking if we shouldn't take the leap and import
> mbedtls, but we haven't had the need so far. Sascha is not opposed, if
> there's a good use case for it.

IMO, for this particular feature, it is certainly possible to get by
without something like that. I have implemented signature validation by
pretty much following the road-map detailed in my original message:

https://github.com/wkz/barebox/commit/4779bd7c766bab704aed982d8fa79d99078633b7#diff-4a7f94e9bbcea0d43614b6f3e7edeedfc0a597a1d284c9ffe4f002ad621f580fR127-R128

The work is now stalled on getting
https://github.com/pengutronix/genimage/pull/312 merged (yes, I am
shamelessly trying to get some attention on this PR :)),

- ...so that can be included in a new release of genimage,

- ...so that I can eventually include that in
  ghcr.io/barebox/barebox/barebox-ci,

- ...so that I can then use it to generate test images,

- ...so that I can write tests,

- ...so that I can publish v1

...its...a whole thing :)

Anyway, this only works with existing crypto primitives because (a) we
can use the certificateFingerprint property to locate the key, without
having to parse the PKCS#7 data and (b) because the hash algorithm is
specified by DPS to SHA256, again letting us skip over parsing the ASN.1
data to determine that.

If we want to support more general operations, e.g. have some
lightweight openssl(1)-like command that can validate detached
signatures, then I think something like mbedtls is definitely needed.

>> 1. Add support for (optionally) storing a certificate fingerprint
>>    along with a `struct public_key`. So at build time, we can note the
>>    fingerprint of keys that we include in the builtin keystore.
>> 
>>    We could also support parsing fingerprints from a DT. Not sure if
>>    this is needed.
>
> ECDSA support in barebox afaik doesn't have a DT representation and
> going forward CONFIG_CRYPTO_PUBLIC_KEYS is the standard way to pass keys
> into barebox.
>
> Jonas (Cc'd) is working right now in a backwards-compatible manner of
> attaching meta-data to keys, e.g.:
>
> export myfitkey="keyring=fit,hint=myhint:pkcs11:token=foo,bar;object=bl"
> export myjwtkey="keyring=jwt-myboard:jwt_pub.pem"

Shiny! Being able to have multiple keyrings is a great feature.

>
> scripts/config --set-str CONFIG_CRYPTO_PUBLIC_KEYS \
> 		"__ENV_myfitkey __ENV_myjwtkey"
>
>> 2. Add a simplified PKCS7 validation function that relies on:
>>    a. Knowing which public key to use in advance, rather than
>>       determining it by walking the ASN.1 data.
>>    b. The last $KEY_LEN_BYTES of the PKCS7 blob holds the raw
>>       RFC4880§5.2.2 signature bytes that Barebox already knows how to
>>       verify.
>> 
>> 3. Add a "dps-open" subcommand to veritysetup that only requires the
>>    partition to open and a name for the dm-verity device:
>> 
>>    veritysetup dps-open /dev/disk0.root os
>> 
>>    Based on the partition type UUID, we would then locate the
>>    corresponding -verity and -verity-sig partitions, parse the verity
>>    superblock, validate the signature and then create the dm-verity
>>    device.
>
> This makes sense, even if there is no decision yet for
> https://github.com/uapi-group/specifications/issues/167

Ehm, yeah. I have lots of thoughts about the response to this
issue. Maybe over a beer sometime :)

> I would suggest we hardcode (and document) that in case there are
> multiple candidates, the ones closest after the root partition are taken?

I think this is a great approach. Simple, yet seems like it solves all
the common setups.

>> Some other thoughts for the future (I have done no research here, so
>> some of this might already exist in Barebox and I just haven't
>> stumbled across it):
>> 
>> - Similar to the automounter, it would be good to have an
>>   "auto-dps-verityer" that will do the equivalent of `veritysetup
>>   dps-open` on the DPS partitions matching the current architecture.
>> 
>> - Having the ability to tag a partition as trusted, which could then
>>   be used to tag filesystems as such.
>
> This would mesh nicely with security policies. We can allow board code
> to tag device files and then mounting them would be allowed even if
> SCONFIG_FS_UNTRUSTED is disabled per currently active security policy.
>
>> - Having a build-time option that limits booting to only be allowed
>>   from trusted filesystems.
>
> Ye, for users without security policies, a build-time option would be apt.

No no, forget that - just I suggested that someone who already owns a
2kW electric nailgun should buy a hammer :)

I just watched your talk and Security policies sound really great!

Is there any information/examples on how to use JWTs to dynamically
switch into a developer/rma mode?

> Cheers,
> Ahmad
>
>> 
>> Tobias Waldekranz (11):
>>   dm: Add helper to manage a lower device
>>   dm: linear: Refactor to make use of the generalized cdev management
>>   dm: verity: Add transparent integrity checking target
>>   dm: verity: Add helper to parse superblock information
>>   commands: veritysetup: Create dm-verity devices
>>   ci: pytest: Open up testfs to more consumers than the FIT test
>>   ci: pytest: Enable testfs feature on malta boards
>>   ci: pytest: Generate test data for dm-verity
>>   test: pytest: add basic dm-verity test
>>   ci: pytest: Centralize feature discovery to a separate step
>>   ci: pytest: Enable device-mapper labgrid tests
>> 
>>  .github/workflows/test-labgrid-pytest.yml     |  26 +-
>>  arch/mips/configs/qemu-malta_defconfig        |   4 +
>>  commands/Kconfig                              |  10 +
>>  commands/Makefile                             |   1 +
>>  commands/veritysetup.c                        | 123 +++++
>>  .../boards/configs/enable_dm_testing.config   |   9 +
>>  drivers/block/dm/Kconfig                      |   7 +
>>  drivers/block/dm/Makefile                     |   1 +
>>  drivers/block/dm/dm-core.c                    | 118 ++++
>>  drivers/block/dm/dm-linear.c                  |  64 +--
>>  drivers/block/dm/dm-target.h                  |  34 ++
>>  drivers/block/dm/dm-verity.c                  | 517 ++++++++++++++++++
>>  include/device-mapper.h                       |   5 +
>>  scripts/generate_testfs.sh                    |  64 ++-
>>  test/mips/be@qemu-malta_defconfig.yaml        |   1 +
>>  test/mips/qemu-malta64el_defconfig.yaml       |   1 +
>>  test/py/test_dm.py                            |  38 ++
>>  test/py/test_fit.py                           |   4 +-
>>  test/riscv/qemu-virt64@rv64i_defconfig.yaml   |   1 +
>>  test/riscv/qemu@virt32_defconfig.yaml         |   1 +
>>  20 files changed, 968 insertions(+), 61 deletions(-)
>>  create mode 100644 commands/veritysetup.c
>>  create mode 100644 common/boards/configs/enable_dm_testing.config
>>  create mode 100644 drivers/block/dm/dm-verity.c
>>  create mode 100644 test/py/test_dm.py
>> 
>
>
> -- 
> Pengutronix e.K.                           |                             |
> Steuerwalder Str. 21                       | http://www.pengutronix.de/  |
> 31137 Hildesheim, Germany                  | Phone: +49-5121-206917-0    |
> Amtsgericht Hildesheim, HRA 2686           | Fax:   +49-5121-206917-5555 |



^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2025-10-07 20:16 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2025-09-18  7:43 [PATCH 00/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
2025-09-18  7:43 ` [PATCH 01/11] dm: Add helper to manage a lower device Tobias Waldekranz
2025-09-18  7:43 ` [PATCH 02/11] dm: linear: Refactor to make use of the generalized cdev management Tobias Waldekranz
2025-09-18  7:43 ` [PATCH 03/11] dm: verity: Add transparent integrity checking target Tobias Waldekranz
2025-09-18 13:06   ` Sascha Hauer
2025-09-18  7:43 ` [PATCH 04/11] dm: verity: Add helper to parse superblock information Tobias Waldekranz
2025-09-18  7:43 ` [PATCH 05/11] commands: veritysetup: Create dm-verity devices Tobias Waldekranz
2025-09-18  7:43 ` [PATCH 06/11] ci: pytest: Open up testfs to more consumers than the FIT test Tobias Waldekranz
2025-09-22 15:38   ` Ahmad Fatoum
2025-09-18  7:43 ` [PATCH 07/11] ci: pytest: Enable testfs feature on malta boards Tobias Waldekranz
2025-09-22 15:40   ` Ahmad Fatoum
2025-09-18  7:43 ` [PATCH 08/11] ci: pytest: Generate test data for dm-verity Tobias Waldekranz
2025-09-22 15:41   ` Ahmad Fatoum
2025-09-18  7:43 ` [PATCH 09/11] test: pytest: add basic dm-verity test Tobias Waldekranz
2025-09-22 15:44   ` Ahmad Fatoum
2025-09-18  7:43 ` [PATCH 10/11] ci: pytest: Centralize feature discovery to a separate step Tobias Waldekranz
2025-09-22 15:45   ` Ahmad Fatoum
2025-09-18  7:43 ` [PATCH 11/11] ci: pytest: Enable device-mapper labgrid tests Tobias Waldekranz
2025-09-22 15:46   ` Ahmad Fatoum
2025-09-18 14:08 ` [PATCH 00/11] dm: verity: Add transparent integrity checking target Sascha Hauer
2025-09-18 15:38   ` Tobias Waldekranz
2025-09-23  6:30 ` Sascha Hauer
2025-10-07  9:05 ` Ahmad Fatoum
2025-10-07 20:15   ` Tobias Waldekranz

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox