Add test/py/tests/test_fit_verity.py with two tests. Both tests are skipped if veritysetup is not installed on the host.
Signed-off-by: Daniel Golle <[email protected]> --- v3: drop unused 'struct' import and the home-rolled have_veritysetup() helper; use @pytest.mark.requiredtool('veritysetup') instead v2: new patch test/py/tests/test_fit_verity.py | 145 +++++++++++++++++++++++++++++++ 1 file changed, 145 insertions(+) create mode 100644 test/py/tests/test_fit_verity.py diff --git a/test/py/tests/test_fit_verity.py b/test/py/tests/test_fit_verity.py new file mode 100644 index 00000000000..b18c569d318 --- /dev/null +++ b/test/py/tests/test_fit_verity.py @@ -0,0 +1,145 @@ +# SPDX-License-Identifier: GPL-2.0+ +# +# Copyright 2026 Daniel Golle <[email protected]> + +""" +Test mkimage dm-verity Merkle-tree generation + +Build a minimal .its with a dm-verity subnode (user-provided properties only), +run mkimage -E, and verify that the computed properties (digest, salt, +num-data-blocks, hash-start-block) are written into the resulting FIT. + +This test does not run the sandbox. It only exercises the host tool 'mkimage'. +Requires 'veritysetup' from the cryptsetup package on the build host. +""" + +import os +import pytest +import utils + +ITS_TEMPLATE = """\ +/dts-v1/; + +/ { + description = "dm-verity test"; + #address-cells = <1>; + + images { + rootfs { + description = "test filesystem"; + data = /incbin/("./rootfs.bin"); + type = "filesystem"; + arch = "sandbox"; + compression = "none"; + + dm-verity { + algo = "sha256"; + data-block-size = <4096>; + hash-block-size = <4096>; + }; + }; + }; + + configurations { + default = "conf-1"; + conf-1 { + description = "test config"; + loadables = "rootfs"; + }; + }; +}; +""" + [email protected]('dtc') [email protected]('fdtget') [email protected]('veritysetup') +def test_mkimage_verity(ubman): + """Test that mkimage computes dm-verity properties correctly.""" + + mkimage = ubman.config.build_dir + '/tools/mkimage' + tempdir = os.path.join(ubman.config.result_dir, 'verity') + os.makedirs(tempdir, exist_ok=True) + + rootfs_file = os.path.join(tempdir, 'rootfs.bin') + its_file = os.path.join(tempdir, 'image.its') + fit_file = os.path.join(tempdir, 'image.itb') + + # Create a dummy filesystem image: 64 x 4096-byte blocks of 0xa5 + block_size = 4096 + num_blocks = 64 + with open(rootfs_file, 'wb') as f: + f.write(bytes([0xa5]) * block_size * num_blocks) + + with open(its_file, 'w') as f: + f.write(ITS_TEMPLATE) + + # Build the FIT with external data (required for dm-verity) + dtc_args = f'-I dts -O dtb -i {tempdir}' + utils.run_and_log(ubman, + [mkimage, '-E', '-D', dtc_args, '-f', its_file, fit_file]) + + # Helper to read FIT properties via fdtget + def fdt_get(node, prop): + val = utils.run_and_log( + ubman, f'fdtget {fit_file} {node} {prop}') + return val.strip() + + def fdt_get_hex(node, prop): + """Read a byte-array property as hex string.""" + val = utils.run_and_log( + ubman, f'fdtget -tbx {fit_file} {node} {prop}') + return ''.join(b.zfill(2) for b in val.strip().split()) + + verity_path = '/images/rootfs/dm-verity' + + # Verify mkimage filled in the computed properties + algo = fdt_get(verity_path, 'algo') + assert algo == 'sha256', f'algo mismatch: {algo}' + + dbs = int(fdt_get(verity_path, 'data-block-size')) + assert dbs == block_size, f'data-block-size mismatch: {dbs}' + + hbs = int(fdt_get(verity_path, 'hash-block-size')) + assert hbs == block_size, f'hash-block-size mismatch: {hbs}' + + nblk = int(fdt_get(verity_path, 'num-data-blocks')) + assert nblk == num_blocks, f'num-data-blocks mismatch: {nblk} != {num_blocks}' + + hblk = int(fdt_get(verity_path, 'hash-start-block')) + # With --no-superblock, hash-start-block == num-data-blocks + assert hblk == num_blocks, f'hash-start-block mismatch: {hblk} != {num_blocks}' + + # digest and salt should be non-empty hex strings (sha256 = 32 bytes = 64 hex chars) + digest = fdt_get_hex(verity_path, 'digest') + assert len(digest) == 64, f'digest length mismatch: {len(digest)} (expected 64)' + # Should not be all zeros + assert digest != '0' * 64, 'digest is all zeros' + + salt = fdt_get_hex(verity_path, 'salt') + assert len(salt) == 64, f'salt length mismatch: {len(salt)} (expected 64)' + + [email protected]('dtc') [email protected]('veritysetup') +def test_mkimage_verity_requires_external(ubman): + """Test that mkimage rejects dm-verity without -E flag.""" + + mkimage = ubman.config.build_dir + '/tools/mkimage' + tempdir = os.path.join(ubman.config.result_dir, 'verity_no_ext') + os.makedirs(tempdir, exist_ok=True) + + rootfs_file = os.path.join(tempdir, 'rootfs.bin') + its_file = os.path.join(tempdir, 'image.its') + fit_file = os.path.join(tempdir, 'image.itb') + + with open(rootfs_file, 'wb') as f: + f.write(bytes([0xa5]) * 4096 * 8) + + with open(its_file, 'w') as f: + f.write(ITS_TEMPLATE) + + # Without -E, mkimage should fail for dm-verity images + dtc_args = f'-I dts -O dtb -i {tempdir}' + with pytest.raises(Exception): + utils.run_and_log(ubman, + [mkimage, '-D', dtc_args, '-f', its_file, fit_file]) -- 2.54.0

