diff options
| author | David Disseldorp <ddiss@suse.de> | 2025-08-19 13:05:51 +1000 | 
|---|---|---|
| committer | Nathan Chancellor <nathan@kernel.org> | 2025-08-21 12:00:10 -0700 | 
| commit | 6da752f55bc48fe2cf12ed208ab10295d796c2dd (patch) | |
| tree | c19e4741fa3b47c630ab5a94762626ea46e1cf7a | |
| parent | 5467e85508fd106443311eb7973ef588b4ef8bb6 (diff) | |
initramfs_test: add filename padding test case
Confirm that cpio filenames with multiple trailing zeros (accounted for
in namesize) extract successfully.
Signed-off-by: David Disseldorp <ddiss@suse.de>
Acked-by: Nicolas Schier <nsc@kernel.org>
Link: https://lore.kernel.org/r/20250819032607.28727-9-ddiss@suse.de
[nathan: Fix duplicate filesize initialization, reported at
         https://lore.kernel.org/202508200304.wF1u78il-lkp@intel.com/]
Signed-off-by: Nathan Chancellor <nathan@kernel.org>
| -rw-r--r-- | init/initramfs_test.c | 67 | 
1 files changed, 66 insertions, 1 deletions
| diff --git a/init/initramfs_test.c b/init/initramfs_test.c index 517e5e04e5cc..5d2db455e60c 100644 --- a/init/initramfs_test.c +++ b/init/initramfs_test.c @@ -45,8 +45,11 @@ static size_t fill_cpio(struct initramfs_test_cpio *cs, size_t csz, char *out)  			c->mtime, c->filesize, c->devmajor, c->devminor,  			c->rdevmajor, c->rdevminor, c->namesize, c->csum,  			c->fname) + 1; +  		pr_debug("packing (%zu): %.*s\n", thislen, (int)thislen, pos); -		off += thislen; +		if (thislen != CPIO_HDRLEN + c->namesize) +			pr_debug("padded to: %u\n", CPIO_HDRLEN + c->namesize); +		off += CPIO_HDRLEN + c->namesize;  		while (off & 3)  			out[off++] = '\0'; @@ -384,6 +387,67 @@ static void __init initramfs_test_many(struct kunit *test)  }  /* + * An initramfs filename is namesize in length, including the zero-terminator. + * A filename can be zero-terminated prior to namesize, with the remainder used + * as padding. This can be useful for e.g. alignment of file data segments with + * a 4KB filesystem block, allowing for extent sharing (reflinks) between cpio + * source and destination. This hack works with both GNU cpio and initramfs, as + * long as PATH_MAX isn't exceeded. + */ +static void __init initramfs_test_fname_pad(struct kunit *test) +{ +	char *err; +	size_t len; +	struct file *file; +	char fdata[] = "this file data is aligned at 4K in the archive"; +	struct test_fname_pad { +		char padded_fname[4096 - CPIO_HDRLEN]; +		char cpio_srcbuf[CPIO_HDRLEN + PATH_MAX + 3 + sizeof(fdata)]; +	} *tbufs = kzalloc(sizeof(struct test_fname_pad), GFP_KERNEL); +	struct initramfs_test_cpio c[] = { { +		.magic = "070701", +		.ino = 1, +		.mode = S_IFREG | 0777, +		.uid = 0, +		.gid = 0, +		.nlink = 1, +		.mtime = 1, +		.filesize = sizeof(fdata), +		.devmajor = 0, +		.devminor = 1, +		.rdevmajor = 0, +		.rdevminor = 0, +		/* align file data at 4K archive offset via padded fname */ +		.namesize = 4096 - CPIO_HDRLEN, +		.csum = 0, +		.fname = tbufs->padded_fname, +		.data = fdata, +	} }; + +	memcpy(tbufs->padded_fname, "padded_fname", sizeof("padded_fname")); +	len = fill_cpio(c, ARRAY_SIZE(c), tbufs->cpio_srcbuf); + +	err = unpack_to_rootfs(tbufs->cpio_srcbuf, len); +	KUNIT_EXPECT_NULL(test, err); + +	file = filp_open(c[0].fname, O_RDONLY, 0); +	if (IS_ERR(file)) { +		KUNIT_FAIL(test, "open failed"); +		goto out; +	} + +	/* read back file contents into @cpio_srcbuf and confirm match */ +	len = kernel_read(file, tbufs->cpio_srcbuf, c[0].filesize, NULL); +	KUNIT_EXPECT_EQ(test, len, c[0].filesize); +	KUNIT_EXPECT_MEMEQ(test, tbufs->cpio_srcbuf, c[0].data, len); + +	fput(file); +	KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0); +out: +	kfree(tbufs); +} + +/*   * The kunit_case/_suite struct cannot be marked as __initdata as this will be   * used in debugfs to retrieve results after test has run.   */ @@ -394,6 +458,7 @@ static struct kunit_case __refdata initramfs_test_cases[] = {  	KUNIT_CASE(initramfs_test_csum),  	KUNIT_CASE(initramfs_test_hardlink),  	KUNIT_CASE(initramfs_test_many), +	KUNIT_CASE(initramfs_test_fname_pad),  	{},  }; | 
