]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
initramfs_test: add filename padding test case
authorDavid Disseldorp <ddiss@suse.de>
Tue, 19 Aug 2025 03:05:51 +0000 (13:05 +1000)
committerNathan Chancellor <nathan@kernel.org>
Thu, 21 Aug 2025 19:00:10 +0000 (12:00 -0700)
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>
init/initramfs_test.c

index 517e5e04e5ccf690a91f05b52c19e4be75ff0a1b..5d2db455e60c55941ad6b70c745bdae0b544f5d0 100644 (file)
@@ -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';
 
@@ -383,6 +386,67 @@ static void __init initramfs_test_many(struct kunit *test)
        kfree(cpio_srcbuf);
 }
 
+/*
+ * 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),
        {},
 };