1*83c0b272SDavid Disseldorp // SPDX-License-Identifier: GPL-2.0 2*83c0b272SDavid Disseldorp #include <kunit/test.h> 3*83c0b272SDavid Disseldorp #include <linux/fcntl.h> 4*83c0b272SDavid Disseldorp #include <linux/file.h> 5*83c0b272SDavid Disseldorp #include <linux/fs.h> 6*83c0b272SDavid Disseldorp #include <linux/init_syscalls.h> 7*83c0b272SDavid Disseldorp #include <linux/stringify.h> 8*83c0b272SDavid Disseldorp #include <linux/timekeeping.h> 9*83c0b272SDavid Disseldorp #include "initramfs_internal.h" 10*83c0b272SDavid Disseldorp 11*83c0b272SDavid Disseldorp struct initramfs_test_cpio { 12*83c0b272SDavid Disseldorp char *magic; 13*83c0b272SDavid Disseldorp unsigned int ino; 14*83c0b272SDavid Disseldorp unsigned int mode; 15*83c0b272SDavid Disseldorp unsigned int uid; 16*83c0b272SDavid Disseldorp unsigned int gid; 17*83c0b272SDavid Disseldorp unsigned int nlink; 18*83c0b272SDavid Disseldorp unsigned int mtime; 19*83c0b272SDavid Disseldorp unsigned int filesize; 20*83c0b272SDavid Disseldorp unsigned int devmajor; 21*83c0b272SDavid Disseldorp unsigned int devminor; 22*83c0b272SDavid Disseldorp unsigned int rdevmajor; 23*83c0b272SDavid Disseldorp unsigned int rdevminor; 24*83c0b272SDavid Disseldorp unsigned int namesize; 25*83c0b272SDavid Disseldorp unsigned int csum; 26*83c0b272SDavid Disseldorp char *fname; 27*83c0b272SDavid Disseldorp char *data; 28*83c0b272SDavid Disseldorp }; 29*83c0b272SDavid Disseldorp 30*83c0b272SDavid Disseldorp static size_t fill_cpio(struct initramfs_test_cpio *cs, size_t csz, char *out) 31*83c0b272SDavid Disseldorp { 32*83c0b272SDavid Disseldorp int i; 33*83c0b272SDavid Disseldorp size_t off = 0; 34*83c0b272SDavid Disseldorp 35*83c0b272SDavid Disseldorp for (i = 0; i < csz; i++) { 36*83c0b272SDavid Disseldorp char *pos = &out[off]; 37*83c0b272SDavid Disseldorp struct initramfs_test_cpio *c = &cs[i]; 38*83c0b272SDavid Disseldorp size_t thislen; 39*83c0b272SDavid Disseldorp 40*83c0b272SDavid Disseldorp /* +1 to account for nulterm */ 41*83c0b272SDavid Disseldorp thislen = sprintf(pos, "%s" 42*83c0b272SDavid Disseldorp "%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x" 43*83c0b272SDavid Disseldorp "%s", 44*83c0b272SDavid Disseldorp c->magic, c->ino, c->mode, c->uid, c->gid, c->nlink, 45*83c0b272SDavid Disseldorp c->mtime, c->filesize, c->devmajor, c->devminor, 46*83c0b272SDavid Disseldorp c->rdevmajor, c->rdevminor, c->namesize, c->csum, 47*83c0b272SDavid Disseldorp c->fname) + 1; 48*83c0b272SDavid Disseldorp pr_debug("packing (%zu): %.*s\n", thislen, (int)thislen, pos); 49*83c0b272SDavid Disseldorp off += thislen; 50*83c0b272SDavid Disseldorp while (off & 3) 51*83c0b272SDavid Disseldorp out[off++] = '\0'; 52*83c0b272SDavid Disseldorp 53*83c0b272SDavid Disseldorp memcpy(&out[off], c->data, c->filesize); 54*83c0b272SDavid Disseldorp off += c->filesize; 55*83c0b272SDavid Disseldorp while (off & 3) 56*83c0b272SDavid Disseldorp out[off++] = '\0'; 57*83c0b272SDavid Disseldorp } 58*83c0b272SDavid Disseldorp 59*83c0b272SDavid Disseldorp return off; 60*83c0b272SDavid Disseldorp } 61*83c0b272SDavid Disseldorp 62*83c0b272SDavid Disseldorp static void __init initramfs_test_extract(struct kunit *test) 63*83c0b272SDavid Disseldorp { 64*83c0b272SDavid Disseldorp char *err, *cpio_srcbuf; 65*83c0b272SDavid Disseldorp size_t len; 66*83c0b272SDavid Disseldorp struct timespec64 ts_before, ts_after; 67*83c0b272SDavid Disseldorp struct kstat st = {}; 68*83c0b272SDavid Disseldorp struct initramfs_test_cpio c[] = { { 69*83c0b272SDavid Disseldorp .magic = "070701", 70*83c0b272SDavid Disseldorp .ino = 1, 71*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 72*83c0b272SDavid Disseldorp .uid = 12, 73*83c0b272SDavid Disseldorp .gid = 34, 74*83c0b272SDavid Disseldorp .nlink = 1, 75*83c0b272SDavid Disseldorp .mtime = 56, 76*83c0b272SDavid Disseldorp .filesize = 0, 77*83c0b272SDavid Disseldorp .devmajor = 0, 78*83c0b272SDavid Disseldorp .devminor = 1, 79*83c0b272SDavid Disseldorp .rdevmajor = 0, 80*83c0b272SDavid Disseldorp .rdevminor = 0, 81*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_extract"), 82*83c0b272SDavid Disseldorp .csum = 0, 83*83c0b272SDavid Disseldorp .fname = "initramfs_test_extract", 84*83c0b272SDavid Disseldorp }, { 85*83c0b272SDavid Disseldorp .magic = "070701", 86*83c0b272SDavid Disseldorp .ino = 2, 87*83c0b272SDavid Disseldorp .mode = S_IFDIR | 0777, 88*83c0b272SDavid Disseldorp .nlink = 1, 89*83c0b272SDavid Disseldorp .mtime = 57, 90*83c0b272SDavid Disseldorp .devminor = 1, 91*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_extract_dir"), 92*83c0b272SDavid Disseldorp .fname = "initramfs_test_extract_dir", 93*83c0b272SDavid Disseldorp }, { 94*83c0b272SDavid Disseldorp .magic = "070701", 95*83c0b272SDavid Disseldorp .namesize = sizeof("TRAILER!!!"), 96*83c0b272SDavid Disseldorp .fname = "TRAILER!!!", 97*83c0b272SDavid Disseldorp } }; 98*83c0b272SDavid Disseldorp 99*83c0b272SDavid Disseldorp /* +3 to cater for any 4-byte end-alignment */ 100*83c0b272SDavid Disseldorp cpio_srcbuf = kzalloc(ARRAY_SIZE(c) * (CPIO_HDRLEN + PATH_MAX + 3), 101*83c0b272SDavid Disseldorp GFP_KERNEL); 102*83c0b272SDavid Disseldorp len = fill_cpio(c, ARRAY_SIZE(c), cpio_srcbuf); 103*83c0b272SDavid Disseldorp 104*83c0b272SDavid Disseldorp ktime_get_real_ts64(&ts_before); 105*83c0b272SDavid Disseldorp err = unpack_to_rootfs(cpio_srcbuf, len); 106*83c0b272SDavid Disseldorp ktime_get_real_ts64(&ts_after); 107*83c0b272SDavid Disseldorp if (err) { 108*83c0b272SDavid Disseldorp KUNIT_FAIL(test, "unpack failed %s", err); 109*83c0b272SDavid Disseldorp goto out; 110*83c0b272SDavid Disseldorp } 111*83c0b272SDavid Disseldorp 112*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_stat(c[0].fname, &st, 0), 0); 113*83c0b272SDavid Disseldorp KUNIT_EXPECT_TRUE(test, S_ISREG(st.mode)); 114*83c0b272SDavid Disseldorp KUNIT_EXPECT_TRUE(test, uid_eq(st.uid, KUIDT_INIT(c[0].uid))); 115*83c0b272SDavid Disseldorp KUNIT_EXPECT_TRUE(test, gid_eq(st.gid, KGIDT_INIT(c[0].gid))); 116*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, st.nlink, 1); 117*83c0b272SDavid Disseldorp if (IS_ENABLED(CONFIG_INITRAMFS_PRESERVE_MTIME)) { 118*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, st.mtime.tv_sec, c[0].mtime); 119*83c0b272SDavid Disseldorp } else { 120*83c0b272SDavid Disseldorp KUNIT_EXPECT_GE(test, st.mtime.tv_sec, ts_before.tv_sec); 121*83c0b272SDavid Disseldorp KUNIT_EXPECT_LE(test, st.mtime.tv_sec, ts_after.tv_sec); 122*83c0b272SDavid Disseldorp } 123*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, st.blocks, c[0].filesize); 124*83c0b272SDavid Disseldorp 125*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_stat(c[1].fname, &st, 0), 0); 126*83c0b272SDavid Disseldorp KUNIT_EXPECT_TRUE(test, S_ISDIR(st.mode)); 127*83c0b272SDavid Disseldorp if (IS_ENABLED(CONFIG_INITRAMFS_PRESERVE_MTIME)) { 128*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, st.mtime.tv_sec, c[1].mtime); 129*83c0b272SDavid Disseldorp } else { 130*83c0b272SDavid Disseldorp KUNIT_EXPECT_GE(test, st.mtime.tv_sec, ts_before.tv_sec); 131*83c0b272SDavid Disseldorp KUNIT_EXPECT_LE(test, st.mtime.tv_sec, ts_after.tv_sec); 132*83c0b272SDavid Disseldorp } 133*83c0b272SDavid Disseldorp 134*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0); 135*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_rmdir(c[1].fname), 0); 136*83c0b272SDavid Disseldorp out: 137*83c0b272SDavid Disseldorp kfree(cpio_srcbuf); 138*83c0b272SDavid Disseldorp } 139*83c0b272SDavid Disseldorp 140*83c0b272SDavid Disseldorp /* 141*83c0b272SDavid Disseldorp * Don't terminate filename. Previously, the cpio filename field was passed 142*83c0b272SDavid Disseldorp * directly to filp_open(collected, O_CREAT|..) without nulterm checks. See 143*83c0b272SDavid Disseldorp * https://lore.kernel.org/linux-fsdevel/20241030035509.20194-2-ddiss@suse.de 144*83c0b272SDavid Disseldorp */ 145*83c0b272SDavid Disseldorp static void __init initramfs_test_fname_overrun(struct kunit *test) 146*83c0b272SDavid Disseldorp { 147*83c0b272SDavid Disseldorp char *err, *cpio_srcbuf; 148*83c0b272SDavid Disseldorp size_t len, suffix_off; 149*83c0b272SDavid Disseldorp struct initramfs_test_cpio c[] = { { 150*83c0b272SDavid Disseldorp .magic = "070701", 151*83c0b272SDavid Disseldorp .ino = 1, 152*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 153*83c0b272SDavid Disseldorp .uid = 0, 154*83c0b272SDavid Disseldorp .gid = 0, 155*83c0b272SDavid Disseldorp .nlink = 1, 156*83c0b272SDavid Disseldorp .mtime = 1, 157*83c0b272SDavid Disseldorp .filesize = 0, 158*83c0b272SDavid Disseldorp .devmajor = 0, 159*83c0b272SDavid Disseldorp .devminor = 1, 160*83c0b272SDavid Disseldorp .rdevmajor = 0, 161*83c0b272SDavid Disseldorp .rdevminor = 0, 162*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_fname_overrun"), 163*83c0b272SDavid Disseldorp .csum = 0, 164*83c0b272SDavid Disseldorp .fname = "initramfs_test_fname_overrun", 165*83c0b272SDavid Disseldorp } }; 166*83c0b272SDavid Disseldorp 167*83c0b272SDavid Disseldorp /* 168*83c0b272SDavid Disseldorp * poison cpio source buffer, so we can detect overrun. source 169*83c0b272SDavid Disseldorp * buffer is used by read_into() when hdr or fname 170*83c0b272SDavid Disseldorp * are already available (e.g. no compression). 171*83c0b272SDavid Disseldorp */ 172*83c0b272SDavid Disseldorp cpio_srcbuf = kmalloc(CPIO_HDRLEN + PATH_MAX + 3, GFP_KERNEL); 173*83c0b272SDavid Disseldorp memset(cpio_srcbuf, 'B', CPIO_HDRLEN + PATH_MAX + 3); 174*83c0b272SDavid Disseldorp /* limit overrun to avoid crashes / filp_open() ENAMETOOLONG */ 175*83c0b272SDavid Disseldorp cpio_srcbuf[CPIO_HDRLEN + strlen(c[0].fname) + 20] = '\0'; 176*83c0b272SDavid Disseldorp 177*83c0b272SDavid Disseldorp len = fill_cpio(c, ARRAY_SIZE(c), cpio_srcbuf); 178*83c0b272SDavid Disseldorp /* overwrite trailing fname terminator and padding */ 179*83c0b272SDavid Disseldorp suffix_off = len - 1; 180*83c0b272SDavid Disseldorp while (cpio_srcbuf[suffix_off] == '\0') { 181*83c0b272SDavid Disseldorp cpio_srcbuf[suffix_off] = 'P'; 182*83c0b272SDavid Disseldorp suffix_off--; 183*83c0b272SDavid Disseldorp } 184*83c0b272SDavid Disseldorp 185*83c0b272SDavid Disseldorp err = unpack_to_rootfs(cpio_srcbuf, len); 186*83c0b272SDavid Disseldorp KUNIT_EXPECT_NOT_NULL(test, err); 187*83c0b272SDavid Disseldorp 188*83c0b272SDavid Disseldorp kfree(cpio_srcbuf); 189*83c0b272SDavid Disseldorp } 190*83c0b272SDavid Disseldorp 191*83c0b272SDavid Disseldorp static void __init initramfs_test_data(struct kunit *test) 192*83c0b272SDavid Disseldorp { 193*83c0b272SDavid Disseldorp char *err, *cpio_srcbuf; 194*83c0b272SDavid Disseldorp size_t len; 195*83c0b272SDavid Disseldorp struct file *file; 196*83c0b272SDavid Disseldorp struct initramfs_test_cpio c[] = { { 197*83c0b272SDavid Disseldorp .magic = "070701", 198*83c0b272SDavid Disseldorp .ino = 1, 199*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 200*83c0b272SDavid Disseldorp .uid = 0, 201*83c0b272SDavid Disseldorp .gid = 0, 202*83c0b272SDavid Disseldorp .nlink = 1, 203*83c0b272SDavid Disseldorp .mtime = 1, 204*83c0b272SDavid Disseldorp .filesize = sizeof("ASDF") - 1, 205*83c0b272SDavid Disseldorp .devmajor = 0, 206*83c0b272SDavid Disseldorp .devminor = 1, 207*83c0b272SDavid Disseldorp .rdevmajor = 0, 208*83c0b272SDavid Disseldorp .rdevminor = 0, 209*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_data"), 210*83c0b272SDavid Disseldorp .csum = 0, 211*83c0b272SDavid Disseldorp .fname = "initramfs_test_data", 212*83c0b272SDavid Disseldorp .data = "ASDF", 213*83c0b272SDavid Disseldorp } }; 214*83c0b272SDavid Disseldorp 215*83c0b272SDavid Disseldorp /* +6 for max name and data 4-byte padding */ 216*83c0b272SDavid Disseldorp cpio_srcbuf = kmalloc(CPIO_HDRLEN + c[0].namesize + c[0].filesize + 6, 217*83c0b272SDavid Disseldorp GFP_KERNEL); 218*83c0b272SDavid Disseldorp 219*83c0b272SDavid Disseldorp len = fill_cpio(c, ARRAY_SIZE(c), cpio_srcbuf); 220*83c0b272SDavid Disseldorp 221*83c0b272SDavid Disseldorp err = unpack_to_rootfs(cpio_srcbuf, len); 222*83c0b272SDavid Disseldorp KUNIT_EXPECT_NULL(test, err); 223*83c0b272SDavid Disseldorp 224*83c0b272SDavid Disseldorp file = filp_open(c[0].fname, O_RDONLY, 0); 225*83c0b272SDavid Disseldorp if (IS_ERR(file)) { 226*83c0b272SDavid Disseldorp KUNIT_FAIL(test, "open failed"); 227*83c0b272SDavid Disseldorp goto out; 228*83c0b272SDavid Disseldorp } 229*83c0b272SDavid Disseldorp 230*83c0b272SDavid Disseldorp /* read back file contents into @cpio_srcbuf and confirm match */ 231*83c0b272SDavid Disseldorp len = kernel_read(file, cpio_srcbuf, c[0].filesize, NULL); 232*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, len, c[0].filesize); 233*83c0b272SDavid Disseldorp KUNIT_EXPECT_MEMEQ(test, cpio_srcbuf, c[0].data, len); 234*83c0b272SDavid Disseldorp 235*83c0b272SDavid Disseldorp fput(file); 236*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0); 237*83c0b272SDavid Disseldorp out: 238*83c0b272SDavid Disseldorp kfree(cpio_srcbuf); 239*83c0b272SDavid Disseldorp } 240*83c0b272SDavid Disseldorp 241*83c0b272SDavid Disseldorp static void __init initramfs_test_csum(struct kunit *test) 242*83c0b272SDavid Disseldorp { 243*83c0b272SDavid Disseldorp char *err, *cpio_srcbuf; 244*83c0b272SDavid Disseldorp size_t len; 245*83c0b272SDavid Disseldorp struct initramfs_test_cpio c[] = { { 246*83c0b272SDavid Disseldorp /* 070702 magic indicates a valid csum is present */ 247*83c0b272SDavid Disseldorp .magic = "070702", 248*83c0b272SDavid Disseldorp .ino = 1, 249*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 250*83c0b272SDavid Disseldorp .nlink = 1, 251*83c0b272SDavid Disseldorp .filesize = sizeof("ASDF") - 1, 252*83c0b272SDavid Disseldorp .devminor = 1, 253*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_csum"), 254*83c0b272SDavid Disseldorp .csum = 'A' + 'S' + 'D' + 'F', 255*83c0b272SDavid Disseldorp .fname = "initramfs_test_csum", 256*83c0b272SDavid Disseldorp .data = "ASDF", 257*83c0b272SDavid Disseldorp }, { 258*83c0b272SDavid Disseldorp /* mix csum entry above with no-csum entry below */ 259*83c0b272SDavid Disseldorp .magic = "070701", 260*83c0b272SDavid Disseldorp .ino = 2, 261*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 262*83c0b272SDavid Disseldorp .nlink = 1, 263*83c0b272SDavid Disseldorp .filesize = sizeof("ASDF") - 1, 264*83c0b272SDavid Disseldorp .devminor = 1, 265*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_csum_not_here"), 266*83c0b272SDavid Disseldorp /* csum ignored */ 267*83c0b272SDavid Disseldorp .csum = 5555, 268*83c0b272SDavid Disseldorp .fname = "initramfs_test_csum_not_here", 269*83c0b272SDavid Disseldorp .data = "ASDF", 270*83c0b272SDavid Disseldorp } }; 271*83c0b272SDavid Disseldorp 272*83c0b272SDavid Disseldorp cpio_srcbuf = kmalloc(8192, GFP_KERNEL); 273*83c0b272SDavid Disseldorp 274*83c0b272SDavid Disseldorp len = fill_cpio(c, ARRAY_SIZE(c), cpio_srcbuf); 275*83c0b272SDavid Disseldorp 276*83c0b272SDavid Disseldorp err = unpack_to_rootfs(cpio_srcbuf, len); 277*83c0b272SDavid Disseldorp KUNIT_EXPECT_NULL(test, err); 278*83c0b272SDavid Disseldorp 279*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0); 280*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[1].fname), 0); 281*83c0b272SDavid Disseldorp 282*83c0b272SDavid Disseldorp /* mess up the csum and confirm that unpack fails */ 283*83c0b272SDavid Disseldorp c[0].csum--; 284*83c0b272SDavid Disseldorp len = fill_cpio(c, ARRAY_SIZE(c), cpio_srcbuf); 285*83c0b272SDavid Disseldorp 286*83c0b272SDavid Disseldorp err = unpack_to_rootfs(cpio_srcbuf, len); 287*83c0b272SDavid Disseldorp KUNIT_EXPECT_NOT_NULL(test, err); 288*83c0b272SDavid Disseldorp 289*83c0b272SDavid Disseldorp /* 290*83c0b272SDavid Disseldorp * file (with content) is still retained in case of bad-csum abort. 291*83c0b272SDavid Disseldorp * Perhaps we should change this. 292*83c0b272SDavid Disseldorp */ 293*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0); 294*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[1].fname), -ENOENT); 295*83c0b272SDavid Disseldorp kfree(cpio_srcbuf); 296*83c0b272SDavid Disseldorp } 297*83c0b272SDavid Disseldorp 298*83c0b272SDavid Disseldorp /* 299*83c0b272SDavid Disseldorp * hardlink hashtable may leak when the archive omits a trailer: 300*83c0b272SDavid Disseldorp * https://lore.kernel.org/r/20241107002044.16477-10-ddiss@suse.de/ 301*83c0b272SDavid Disseldorp */ 302*83c0b272SDavid Disseldorp static void __init initramfs_test_hardlink(struct kunit *test) 303*83c0b272SDavid Disseldorp { 304*83c0b272SDavid Disseldorp char *err, *cpio_srcbuf; 305*83c0b272SDavid Disseldorp size_t len; 306*83c0b272SDavid Disseldorp struct kstat st0, st1; 307*83c0b272SDavid Disseldorp struct initramfs_test_cpio c[] = { { 308*83c0b272SDavid Disseldorp .magic = "070701", 309*83c0b272SDavid Disseldorp .ino = 1, 310*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 311*83c0b272SDavid Disseldorp .nlink = 2, 312*83c0b272SDavid Disseldorp .devminor = 1, 313*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_hardlink"), 314*83c0b272SDavid Disseldorp .fname = "initramfs_test_hardlink", 315*83c0b272SDavid Disseldorp }, { 316*83c0b272SDavid Disseldorp /* hardlink data is present in last archive entry */ 317*83c0b272SDavid Disseldorp .magic = "070701", 318*83c0b272SDavid Disseldorp .ino = 1, 319*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 320*83c0b272SDavid Disseldorp .nlink = 2, 321*83c0b272SDavid Disseldorp .filesize = sizeof("ASDF") - 1, 322*83c0b272SDavid Disseldorp .devminor = 1, 323*83c0b272SDavid Disseldorp .namesize = sizeof("initramfs_test_hardlink_link"), 324*83c0b272SDavid Disseldorp .fname = "initramfs_test_hardlink_link", 325*83c0b272SDavid Disseldorp .data = "ASDF", 326*83c0b272SDavid Disseldorp } }; 327*83c0b272SDavid Disseldorp 328*83c0b272SDavid Disseldorp cpio_srcbuf = kmalloc(8192, GFP_KERNEL); 329*83c0b272SDavid Disseldorp 330*83c0b272SDavid Disseldorp len = fill_cpio(c, ARRAY_SIZE(c), cpio_srcbuf); 331*83c0b272SDavid Disseldorp 332*83c0b272SDavid Disseldorp err = unpack_to_rootfs(cpio_srcbuf, len); 333*83c0b272SDavid Disseldorp KUNIT_EXPECT_NULL(test, err); 334*83c0b272SDavid Disseldorp 335*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_stat(c[0].fname, &st0, 0), 0); 336*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_stat(c[1].fname, &st1, 0), 0); 337*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, st0.ino, st1.ino); 338*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, st0.nlink, 2); 339*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, st1.nlink, 2); 340*83c0b272SDavid Disseldorp 341*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0); 342*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(c[1].fname), 0); 343*83c0b272SDavid Disseldorp 344*83c0b272SDavid Disseldorp kfree(cpio_srcbuf); 345*83c0b272SDavid Disseldorp } 346*83c0b272SDavid Disseldorp 347*83c0b272SDavid Disseldorp #define INITRAMFS_TEST_MANY_LIMIT 1000 348*83c0b272SDavid Disseldorp #define INITRAMFS_TEST_MANY_PATH_MAX (sizeof("initramfs_test_many-") \ 349*83c0b272SDavid Disseldorp + sizeof(__stringify(INITRAMFS_TEST_MANY_LIMIT))) 350*83c0b272SDavid Disseldorp static void __init initramfs_test_many(struct kunit *test) 351*83c0b272SDavid Disseldorp { 352*83c0b272SDavid Disseldorp char *err, *cpio_srcbuf, *p; 353*83c0b272SDavid Disseldorp size_t len = INITRAMFS_TEST_MANY_LIMIT * 354*83c0b272SDavid Disseldorp (CPIO_HDRLEN + INITRAMFS_TEST_MANY_PATH_MAX + 3); 355*83c0b272SDavid Disseldorp char thispath[INITRAMFS_TEST_MANY_PATH_MAX]; 356*83c0b272SDavid Disseldorp int i; 357*83c0b272SDavid Disseldorp 358*83c0b272SDavid Disseldorp p = cpio_srcbuf = kmalloc(len, GFP_KERNEL); 359*83c0b272SDavid Disseldorp 360*83c0b272SDavid Disseldorp for (i = 0; i < INITRAMFS_TEST_MANY_LIMIT; i++) { 361*83c0b272SDavid Disseldorp struct initramfs_test_cpio c = { 362*83c0b272SDavid Disseldorp .magic = "070701", 363*83c0b272SDavid Disseldorp .ino = i, 364*83c0b272SDavid Disseldorp .mode = S_IFREG | 0777, 365*83c0b272SDavid Disseldorp .nlink = 1, 366*83c0b272SDavid Disseldorp .devminor = 1, 367*83c0b272SDavid Disseldorp .fname = thispath, 368*83c0b272SDavid Disseldorp }; 369*83c0b272SDavid Disseldorp 370*83c0b272SDavid Disseldorp c.namesize = 1 + sprintf(thispath, "initramfs_test_many-%d", i); 371*83c0b272SDavid Disseldorp p += fill_cpio(&c, 1, p); 372*83c0b272SDavid Disseldorp } 373*83c0b272SDavid Disseldorp 374*83c0b272SDavid Disseldorp len = p - cpio_srcbuf; 375*83c0b272SDavid Disseldorp err = unpack_to_rootfs(cpio_srcbuf, len); 376*83c0b272SDavid Disseldorp KUNIT_EXPECT_NULL(test, err); 377*83c0b272SDavid Disseldorp 378*83c0b272SDavid Disseldorp for (i = 0; i < INITRAMFS_TEST_MANY_LIMIT; i++) { 379*83c0b272SDavid Disseldorp sprintf(thispath, "initramfs_test_many-%d", i); 380*83c0b272SDavid Disseldorp KUNIT_EXPECT_EQ(test, init_unlink(thispath), 0); 381*83c0b272SDavid Disseldorp } 382*83c0b272SDavid Disseldorp 383*83c0b272SDavid Disseldorp kfree(cpio_srcbuf); 384*83c0b272SDavid Disseldorp } 385*83c0b272SDavid Disseldorp 386*83c0b272SDavid Disseldorp /* 387*83c0b272SDavid Disseldorp * The kunit_case/_suite struct cannot be marked as __initdata as this will be 388*83c0b272SDavid Disseldorp * used in debugfs to retrieve results after test has run. 389*83c0b272SDavid Disseldorp */ 390*83c0b272SDavid Disseldorp static struct kunit_case __refdata initramfs_test_cases[] = { 391*83c0b272SDavid Disseldorp KUNIT_CASE(initramfs_test_extract), 392*83c0b272SDavid Disseldorp KUNIT_CASE(initramfs_test_fname_overrun), 393*83c0b272SDavid Disseldorp KUNIT_CASE(initramfs_test_data), 394*83c0b272SDavid Disseldorp KUNIT_CASE(initramfs_test_csum), 395*83c0b272SDavid Disseldorp KUNIT_CASE(initramfs_test_hardlink), 396*83c0b272SDavid Disseldorp KUNIT_CASE(initramfs_test_many), 397*83c0b272SDavid Disseldorp {}, 398*83c0b272SDavid Disseldorp }; 399*83c0b272SDavid Disseldorp 400*83c0b272SDavid Disseldorp static struct kunit_suite initramfs_test_suite = { 401*83c0b272SDavid Disseldorp .name = "initramfs", 402*83c0b272SDavid Disseldorp .test_cases = initramfs_test_cases, 403*83c0b272SDavid Disseldorp }; 404*83c0b272SDavid Disseldorp kunit_test_init_section_suites(&initramfs_test_suite); 405*83c0b272SDavid Disseldorp 406*83c0b272SDavid Disseldorp MODULE_DESCRIPTION("Initramfs KUnit test suite"); 407*83c0b272SDavid Disseldorp MODULE_LICENSE("GPL v2"); 408