cpio header fields are 8-byte hex strings, but one "interesting" side-effect of our historic simple_str[n]toul() use means that a "0x" prefixed header field will be successfully processed when coupled alongside a 6-byte hex remainder string. Test for this corner case by injecting "0x" prefixes into the uid, gid and namesize cpio header fields. Confirm that init_stat() returns matching uid and gid values. Signed-off-by: David Disseldorp --- init/initramfs_test.c | 61 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/init/initramfs_test.c b/init/initramfs_test.c index 8dd752de16518..afbdbc0342bca 100644 --- a/init/initramfs_test.c +++ b/init/initramfs_test.c @@ -495,6 +495,66 @@ static void __init initramfs_test_fname_path_max(struct kunit *test) kfree(tbufs); } +static void __init initramfs_test_hdr_hex(struct kunit *test) +{ + char *err, *fmt; + size_t len; + struct kstat st0, st1; + char fdata[] = "this file data will be unpacked"; + struct test_fname_path_max { + char cpio_src[(CPIO_HDRLEN + PATH_MAX + 3 + sizeof(fdata)) * 2]; + } *tbufs = kzalloc(sizeof(struct test_fname_path_max), GFP_KERNEL); + struct initramfs_test_cpio c[] = { { + .magic = "070701", + .ino = 1, + .mode = S_IFREG | 0777, + .uid = 0x123456, + .gid = 0x123457, + .nlink = 1, + .namesize = sizeof("initramfs_test_hdr_hex_0"), + .fname = "initramfs_test_hdr_hex_0", + .filesize = sizeof(fdata), + .data = fdata, + }, { + .magic = "070701", + .ino = 2, + .mode = S_IFDIR | 0777, + .uid = 0x000056, + .gid = 0x000057, + .nlink = 1, + .namesize = sizeof("initramfs_test_hdr_hex_1"), + .fname = "initramfs_test_hdr_hex_1", + } }; + /* + * override CPIO_HDR_FMT and instead use a format string which places + * "0x" prefixes on the uid, gid and namesize values. + * parse_header()/simple_str[n]toul() accept this. + */ + fmt = "%s%08x%08x0x%06x0x%06x%08x%08x%08x%08x%08x%08x%08x0x%06x%08x%s"; + len = fill_cpio(c, ARRAY_SIZE(c), fmt, tbufs->cpio_src); + + /* unpack skips over fname_oversize instead of returning an error */ + err = unpack_to_rootfs(tbufs->cpio_src, len); + KUNIT_EXPECT_NULL(test, err); + + KUNIT_EXPECT_EQ(test, init_stat(c[0].fname, &st0, 0), 0); + KUNIT_EXPECT_EQ(test, init_stat(c[1].fname, &st1, 0), 0); + + KUNIT_EXPECT_TRUE(test, + uid_eq(st0.uid, make_kuid(current_user_ns(), (uid_t)0x123456))); + KUNIT_EXPECT_TRUE(test, + gid_eq(st0.gid, make_kgid(current_user_ns(), (gid_t)0x123457))); + KUNIT_EXPECT_TRUE(test, + uid_eq(st1.uid, make_kuid(current_user_ns(), (uid_t)0x56))); + KUNIT_EXPECT_TRUE(test, + gid_eq(st1.gid, make_kgid(current_user_ns(), (gid_t)0x57))); + + KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0); + KUNIT_EXPECT_EQ(test, init_rmdir(c[1].fname), 0); + + 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. @@ -508,6 +568,7 @@ static struct kunit_case __refdata initramfs_test_cases[] = { KUNIT_CASE(initramfs_test_many), KUNIT_CASE(initramfs_test_fname_pad), KUNIT_CASE(initramfs_test_fname_path_max), + KUNIT_CASE(initramfs_test_hdr_hex), {}, }; -- 2.51.0