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
fill_cpio(struct initramfs_test_cpio * cs,size_t csz,char * out)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
initramfs_test_extract(struct kunit * test)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/[email protected]
144*83c0b272SDavid Disseldorp */
initramfs_test_fname_overrun(struct kunit * test)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
initramfs_test_data(struct kunit * test)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
initramfs_test_csum(struct kunit * test)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/[email protected]/
301*83c0b272SDavid Disseldorp */
initramfs_test_hardlink(struct kunit * test)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)))
initramfs_test_many(struct kunit * test)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