Skip to content

Commit 6da752f

Browse files
ddissnathanchance
authored andcommitted
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>
1 parent 5467e85 commit 6da752f

File tree

1 file changed

+66
-1
lines changed

1 file changed

+66
-1
lines changed

init/initramfs_test.c

Lines changed: 66 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,8 +45,11 @@ static size_t fill_cpio(struct initramfs_test_cpio *cs, size_t csz, char *out)
4545
c->mtime, c->filesize, c->devmajor, c->devminor,
4646
c->rdevmajor, c->rdevminor, c->namesize, c->csum,
4747
c->fname) + 1;
48+
4849
pr_debug("packing (%zu): %.*s\n", thislen, (int)thislen, pos);
49-
off += thislen;
50+
if (thislen != CPIO_HDRLEN + c->namesize)
51+
pr_debug("padded to: %u\n", CPIO_HDRLEN + c->namesize);
52+
off += CPIO_HDRLEN + c->namesize;
5053
while (off & 3)
5154
out[off++] = '\0';
5255

@@ -383,6 +386,67 @@ static void __init initramfs_test_many(struct kunit *test)
383386
kfree(cpio_srcbuf);
384387
}
385388

389+
/*
390+
* An initramfs filename is namesize in length, including the zero-terminator.
391+
* A filename can be zero-terminated prior to namesize, with the remainder used
392+
* as padding. This can be useful for e.g. alignment of file data segments with
393+
* a 4KB filesystem block, allowing for extent sharing (reflinks) between cpio
394+
* source and destination. This hack works with both GNU cpio and initramfs, as
395+
* long as PATH_MAX isn't exceeded.
396+
*/
397+
static void __init initramfs_test_fname_pad(struct kunit *test)
398+
{
399+
char *err;
400+
size_t len;
401+
struct file *file;
402+
char fdata[] = "this file data is aligned at 4K in the archive";
403+
struct test_fname_pad {
404+
char padded_fname[4096 - CPIO_HDRLEN];
405+
char cpio_srcbuf[CPIO_HDRLEN + PATH_MAX + 3 + sizeof(fdata)];
406+
} *tbufs = kzalloc(sizeof(struct test_fname_pad), GFP_KERNEL);
407+
struct initramfs_test_cpio c[] = { {
408+
.magic = "070701",
409+
.ino = 1,
410+
.mode = S_IFREG | 0777,
411+
.uid = 0,
412+
.gid = 0,
413+
.nlink = 1,
414+
.mtime = 1,
415+
.filesize = sizeof(fdata),
416+
.devmajor = 0,
417+
.devminor = 1,
418+
.rdevmajor = 0,
419+
.rdevminor = 0,
420+
/* align file data at 4K archive offset via padded fname */
421+
.namesize = 4096 - CPIO_HDRLEN,
422+
.csum = 0,
423+
.fname = tbufs->padded_fname,
424+
.data = fdata,
425+
} };
426+
427+
memcpy(tbufs->padded_fname, "padded_fname", sizeof("padded_fname"));
428+
len = fill_cpio(c, ARRAY_SIZE(c), tbufs->cpio_srcbuf);
429+
430+
err = unpack_to_rootfs(tbufs->cpio_srcbuf, len);
431+
KUNIT_EXPECT_NULL(test, err);
432+
433+
file = filp_open(c[0].fname, O_RDONLY, 0);
434+
if (IS_ERR(file)) {
435+
KUNIT_FAIL(test, "open failed");
436+
goto out;
437+
}
438+
439+
/* read back file contents into @cpio_srcbuf and confirm match */
440+
len = kernel_read(file, tbufs->cpio_srcbuf, c[0].filesize, NULL);
441+
KUNIT_EXPECT_EQ(test, len, c[0].filesize);
442+
KUNIT_EXPECT_MEMEQ(test, tbufs->cpio_srcbuf, c[0].data, len);
443+
444+
fput(file);
445+
KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0);
446+
out:
447+
kfree(tbufs);
448+
}
449+
386450
/*
387451
* The kunit_case/_suite struct cannot be marked as __initdata as this will be
388452
* used in debugfs to retrieve results after test has run.
@@ -394,6 +458,7 @@ static struct kunit_case __refdata initramfs_test_cases[] = {
394458
KUNIT_CASE(initramfs_test_csum),
395459
KUNIT_CASE(initramfs_test_hardlink),
396460
KUNIT_CASE(initramfs_test_many),
461+
KUNIT_CASE(initramfs_test_fname_pad),
397462
{},
398463
};
399464

0 commit comments

Comments
 (0)