xref: /linux/init/initramfs_test.c (revision 59e6295fac26b8e85c1ea859cdd89fa1e47519d7)
1 // SPDX-License-Identifier: GPL-2.0
2 #include <kunit/test.h>
3 #include <linux/fcntl.h>
4 #include <linux/file.h>
5 #include <linux/fs.h>
6 #include <linux/fs_struct.h>
7 #include <linux/init.h>
8 #include <linux/init_syscalls.h>
9 #include <linux/initrd.h>
10 #include <linux/stringify.h>
11 #include <linux/timekeeping.h>
12 #include "initramfs_internal.h"
13 
14 struct initramfs_test_cpio {
15 	char *magic;
16 	unsigned int ino;
17 	unsigned int mode;
18 	unsigned int uid;
19 	unsigned int gid;
20 	unsigned int nlink;
21 	unsigned int mtime;
22 	unsigned int filesize;
23 	unsigned int devmajor;
24 	unsigned int devminor;
25 	unsigned int rdevmajor;
26 	unsigned int rdevminor;
27 	unsigned int namesize;
28 	unsigned int csum;
29 	char *fname;
30 	char *data;
31 };
32 
33 /* regular newc header format */
34 #define CPIO_HDR_FMT "%s%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%08x%s"
35 /*
36  * Bogus newc header with "0x" prefixes on the uid, gid, and namesize values.
37  * parse_header()/simple_str[n]toul() accepted this, contrary to the initramfs
38  * specification. hex2bin() now fails.
39  */
40 #define CPIO_HDR_OX_INJECT \
41 	"%s%08x%08x0x%06x0X%06x%08x%08x%08x%08x%08x%08x%08x0x%06x%08x%s"
42 
43 static size_t fill_cpio(struct initramfs_test_cpio *cs, size_t csz,
44 			bool inject_ox, char *out)
45 {
46 	int i;
47 	size_t off = 0;
48 
49 	for (i = 0; i < csz; i++) {
50 		char *pos = &out[off];
51 		struct initramfs_test_cpio *c = &cs[i];
52 		size_t thislen;
53 
54 		/* +1 to account for nulterm */
55 		thislen = sprintf(pos,
56 			inject_ox ? CPIO_HDR_OX_INJECT : CPIO_HDR_FMT,
57 			c->magic, c->ino, c->mode, c->uid, c->gid, c->nlink,
58 			c->mtime, c->filesize, c->devmajor, c->devminor,
59 			c->rdevmajor, c->rdevminor, c->namesize, c->csum,
60 			c->fname) + 1;
61 
62 		pr_debug("packing (%zu): %.*s\n", thislen, (int)thislen, pos);
63 		if (thislen != CPIO_HDRLEN + c->namesize)
64 			pr_debug("padded to: %u\n", CPIO_HDRLEN + c->namesize);
65 		off += CPIO_HDRLEN + c->namesize;
66 		while (off & 3)
67 			out[off++] = '\0';
68 
69 		memcpy(&out[off], c->data, c->filesize);
70 		off += c->filesize;
71 		while (off & 3)
72 			out[off++] = '\0';
73 	}
74 
75 	return off;
76 }
77 
78 static void __init initramfs_test_extract(struct kunit *test)
79 {
80 	char *err, *cpio_srcbuf;
81 	size_t len;
82 	struct timespec64 ts_before, ts_after;
83 	struct kstat st = {};
84 	struct initramfs_test_cpio c[] = { {
85 		.magic = "070701",
86 		.ino = 1,
87 		.mode = S_IFREG | 0777,
88 		.uid = 12,
89 		.gid = 34,
90 		.nlink = 1,
91 		.mtime = 56,
92 		.filesize = 0,
93 		.devmajor = 0,
94 		.devminor = 1,
95 		.rdevmajor = 0,
96 		.rdevminor = 0,
97 		.namesize = sizeof("initramfs_test_extract"),
98 		.csum = 0,
99 		.fname = "initramfs_test_extract",
100 	}, {
101 		.magic = "070701",
102 		.ino = 2,
103 		.mode = S_IFDIR | 0777,
104 		.nlink = 1,
105 		.mtime = 57,
106 		.devminor = 1,
107 		.namesize = sizeof("initramfs_test_extract_dir"),
108 		.fname = "initramfs_test_extract_dir",
109 	}, {
110 		.magic = "070701",
111 		.namesize = sizeof("TRAILER!!!"),
112 		.fname = "TRAILER!!!",
113 	} };
114 
115 	/* +3 to cater for any 4-byte end-alignment */
116 	cpio_srcbuf = kzalloc(ARRAY_SIZE(c) * (CPIO_HDRLEN + PATH_MAX + 3),
117 			      GFP_KERNEL);
118 	len = fill_cpio(c, ARRAY_SIZE(c), false, cpio_srcbuf);
119 
120 	ktime_get_real_ts64(&ts_before);
121 	err = unpack_to_rootfs(cpio_srcbuf, len);
122 	ktime_get_real_ts64(&ts_after);
123 	if (err) {
124 		KUNIT_FAIL(test, "unpack failed %s", err);
125 		goto out;
126 	}
127 
128 	KUNIT_EXPECT_EQ(test, init_stat(c[0].fname, &st, 0), 0);
129 	KUNIT_EXPECT_TRUE(test, S_ISREG(st.mode));
130 	KUNIT_EXPECT_TRUE(test, uid_eq(st.uid, KUIDT_INIT(c[0].uid)));
131 	KUNIT_EXPECT_TRUE(test, gid_eq(st.gid, KGIDT_INIT(c[0].gid)));
132 	KUNIT_EXPECT_EQ(test, st.nlink, 1);
133 	if (IS_ENABLED(CONFIG_INITRAMFS_PRESERVE_MTIME)) {
134 		KUNIT_EXPECT_EQ(test, st.mtime.tv_sec, c[0].mtime);
135 	} else {
136 		KUNIT_EXPECT_GE(test, st.mtime.tv_sec, ts_before.tv_sec);
137 		KUNIT_EXPECT_LE(test, st.mtime.tv_sec, ts_after.tv_sec);
138 	}
139 	KUNIT_EXPECT_EQ(test, st.blocks, c[0].filesize);
140 
141 	KUNIT_EXPECT_EQ(test, init_stat(c[1].fname, &st, 0), 0);
142 	KUNIT_EXPECT_TRUE(test, S_ISDIR(st.mode));
143 	if (IS_ENABLED(CONFIG_INITRAMFS_PRESERVE_MTIME)) {
144 		KUNIT_EXPECT_EQ(test, st.mtime.tv_sec, c[1].mtime);
145 	} else {
146 		KUNIT_EXPECT_GE(test, st.mtime.tv_sec, ts_before.tv_sec);
147 		KUNIT_EXPECT_LE(test, st.mtime.tv_sec, ts_after.tv_sec);
148 	}
149 
150 	KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0);
151 	KUNIT_EXPECT_EQ(test, init_rmdir(c[1].fname), 0);
152 out:
153 	kfree(cpio_srcbuf);
154 }
155 
156 /*
157  * Don't terminate filename. Previously, the cpio filename field was passed
158  * directly to filp_open(collected, O_CREAT|..) without nulterm checks. See
159  * https://lore.kernel.org/linux-fsdevel/20241030035509.20194-2-ddiss@suse.de
160  */
161 static void __init initramfs_test_fname_overrun(struct kunit *test)
162 {
163 	char *err, *cpio_srcbuf;
164 	size_t len, suffix_off;
165 	struct initramfs_test_cpio c[] = { {
166 		.magic = "070701",
167 		.ino = 1,
168 		.mode = S_IFREG | 0777,
169 		.uid = 0,
170 		.gid = 0,
171 		.nlink = 1,
172 		.mtime = 1,
173 		.filesize = 0,
174 		.devmajor = 0,
175 		.devminor = 1,
176 		.rdevmajor = 0,
177 		.rdevminor = 0,
178 		.namesize = sizeof("initramfs_test_fname_overrun"),
179 		.csum = 0,
180 		.fname = "initramfs_test_fname_overrun",
181 	} };
182 
183 	/*
184 	 * poison cpio source buffer, so we can detect overrun. source
185 	 * buffer is used by read_into() when hdr or fname
186 	 * are already available (e.g. no compression).
187 	 */
188 	cpio_srcbuf = kmalloc(CPIO_HDRLEN + PATH_MAX + 3, GFP_KERNEL);
189 	memset(cpio_srcbuf, 'B', CPIO_HDRLEN + PATH_MAX + 3);
190 	/* limit overrun to avoid crashes / filp_open() ENAMETOOLONG */
191 	cpio_srcbuf[CPIO_HDRLEN + strlen(c[0].fname) + 20] = '\0';
192 
193 	len = fill_cpio(c, ARRAY_SIZE(c), false, cpio_srcbuf);
194 	/* overwrite trailing fname terminator and padding */
195 	suffix_off = len - 1;
196 	while (cpio_srcbuf[suffix_off] == '\0') {
197 		cpio_srcbuf[suffix_off] = 'P';
198 		suffix_off--;
199 	}
200 
201 	err = unpack_to_rootfs(cpio_srcbuf, len);
202 	KUNIT_EXPECT_NOT_NULL(test, err);
203 
204 	kfree(cpio_srcbuf);
205 }
206 
207 static void __init initramfs_test_data(struct kunit *test)
208 {
209 	char *err, *cpio_srcbuf;
210 	size_t len;
211 	struct file *file;
212 	struct initramfs_test_cpio c[] = { {
213 		.magic = "070701",
214 		.ino = 1,
215 		.mode = S_IFREG | 0777,
216 		.uid = 0,
217 		.gid = 0,
218 		.nlink = 1,
219 		.mtime = 1,
220 		.filesize = sizeof("ASDF") - 1,
221 		.devmajor = 0,
222 		.devminor = 1,
223 		.rdevmajor = 0,
224 		.rdevminor = 0,
225 		.namesize = sizeof("initramfs_test_data"),
226 		.csum = 0,
227 		.fname = "initramfs_test_data",
228 		.data = "ASDF",
229 	} };
230 
231 	/* +6 for max name and data 4-byte padding */
232 	cpio_srcbuf = kmalloc(CPIO_HDRLEN + c[0].namesize + c[0].filesize + 6,
233 			      GFP_KERNEL);
234 
235 	len = fill_cpio(c, ARRAY_SIZE(c), false, cpio_srcbuf);
236 
237 	err = unpack_to_rootfs(cpio_srcbuf, len);
238 	KUNIT_EXPECT_NULL(test, err);
239 
240 	file = filp_open(c[0].fname, O_RDONLY, 0);
241 	if (IS_ERR(file)) {
242 		KUNIT_FAIL(test, "open failed");
243 		goto out;
244 	}
245 
246 	/* read back file contents into @cpio_srcbuf and confirm match */
247 	len = kernel_read(file, cpio_srcbuf, c[0].filesize, NULL);
248 	KUNIT_EXPECT_EQ(test, len, c[0].filesize);
249 	KUNIT_EXPECT_MEMEQ(test, cpio_srcbuf, c[0].data, len);
250 
251 	fput(file);
252 	KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0);
253 out:
254 	kfree(cpio_srcbuf);
255 }
256 
257 static void __init initramfs_test_csum(struct kunit *test)
258 {
259 	char *err, *cpio_srcbuf;
260 	size_t len;
261 	struct initramfs_test_cpio c[] = { {
262 		/* 070702 magic indicates a valid csum is present */
263 		.magic = "070702",
264 		.ino = 1,
265 		.mode = S_IFREG | 0777,
266 		.nlink = 1,
267 		.filesize = sizeof("ASDF") - 1,
268 		.devminor = 1,
269 		.namesize = sizeof("initramfs_test_csum"),
270 		.csum = 'A' + 'S' + 'D' + 'F',
271 		.fname = "initramfs_test_csum",
272 		.data = "ASDF",
273 	}, {
274 		/* mix csum entry above with no-csum entry below */
275 		.magic = "070701",
276 		.ino = 2,
277 		.mode = S_IFREG | 0777,
278 		.nlink = 1,
279 		.filesize = sizeof("ASDF") - 1,
280 		.devminor = 1,
281 		.namesize = sizeof("initramfs_test_csum_not_here"),
282 		/* csum ignored */
283 		.csum = 5555,
284 		.fname = "initramfs_test_csum_not_here",
285 		.data = "ASDF",
286 	} };
287 
288 	cpio_srcbuf = kmalloc(8192, GFP_KERNEL);
289 
290 	len = fill_cpio(c, ARRAY_SIZE(c), false, cpio_srcbuf);
291 
292 	err = unpack_to_rootfs(cpio_srcbuf, len);
293 	KUNIT_EXPECT_NULL(test, err);
294 
295 	KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0);
296 	KUNIT_EXPECT_EQ(test, init_unlink(c[1].fname), 0);
297 
298 	/* mess up the csum and confirm that unpack fails */
299 	c[0].csum--;
300 	len = fill_cpio(c, ARRAY_SIZE(c), false, cpio_srcbuf);
301 
302 	err = unpack_to_rootfs(cpio_srcbuf, len);
303 	KUNIT_EXPECT_NOT_NULL(test, err);
304 
305 	/*
306 	 * file (with content) is still retained in case of bad-csum abort.
307 	 * Perhaps we should change this.
308 	 */
309 	KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0);
310 	KUNIT_EXPECT_EQ(test, init_unlink(c[1].fname), -ENOENT);
311 	kfree(cpio_srcbuf);
312 }
313 
314 /*
315  * hardlink hashtable may leak when the archive omits a trailer:
316  * https://lore.kernel.org/r/20241107002044.16477-10-ddiss@suse.de/
317  */
318 static void __init initramfs_test_hardlink(struct kunit *test)
319 {
320 	char *err, *cpio_srcbuf;
321 	size_t len;
322 	struct kstat st0 = {}, st1 = {};
323 	struct initramfs_test_cpio c[] = { {
324 		.magic = "070701",
325 		.ino = 1,
326 		.mode = S_IFREG | 0777,
327 		.nlink = 2,
328 		.devminor = 1,
329 		.namesize = sizeof("initramfs_test_hardlink"),
330 		.fname = "initramfs_test_hardlink",
331 	}, {
332 		/* hardlink data is present in last archive entry */
333 		.magic = "070701",
334 		.ino = 1,
335 		.mode = S_IFREG | 0777,
336 		.nlink = 2,
337 		.filesize = sizeof("ASDF") - 1,
338 		.devminor = 1,
339 		.namesize = sizeof("initramfs_test_hardlink_link"),
340 		.fname = "initramfs_test_hardlink_link",
341 		.data = "ASDF",
342 	} };
343 
344 	cpio_srcbuf = kmalloc(8192, GFP_KERNEL);
345 
346 	len = fill_cpio(c, ARRAY_SIZE(c), false, cpio_srcbuf);
347 
348 	err = unpack_to_rootfs(cpio_srcbuf, len);
349 	KUNIT_EXPECT_NULL(test, err);
350 
351 	KUNIT_EXPECT_EQ(test, init_stat(c[0].fname, &st0, 0), 0);
352 	KUNIT_EXPECT_EQ(test, init_stat(c[1].fname, &st1, 0), 0);
353 	KUNIT_EXPECT_EQ(test, st0.ino, st1.ino);
354 	KUNIT_EXPECT_EQ(test, st0.nlink, 2);
355 	KUNIT_EXPECT_EQ(test, st1.nlink, 2);
356 
357 	KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0);
358 	KUNIT_EXPECT_EQ(test, init_unlink(c[1].fname), 0);
359 
360 	kfree(cpio_srcbuf);
361 }
362 
363 #define INITRAMFS_TEST_MANY_LIMIT 1000
364 #define INITRAMFS_TEST_MANY_PATH_MAX (sizeof("initramfs_test_many-") \
365 			+ sizeof(__stringify(INITRAMFS_TEST_MANY_LIMIT)))
366 static void __init initramfs_test_many(struct kunit *test)
367 {
368 	char *err, *cpio_srcbuf, *p;
369 	size_t len = INITRAMFS_TEST_MANY_LIMIT *
370 		     (CPIO_HDRLEN + INITRAMFS_TEST_MANY_PATH_MAX + 3);
371 	char thispath[INITRAMFS_TEST_MANY_PATH_MAX];
372 	int i;
373 
374 	p = cpio_srcbuf = kmalloc(len, GFP_KERNEL);
375 
376 	for (i = 0; i < INITRAMFS_TEST_MANY_LIMIT; i++) {
377 		struct initramfs_test_cpio c = {
378 			.magic = "070701",
379 			.ino = i,
380 			.mode = S_IFREG | 0777,
381 			.nlink = 1,
382 			.devminor = 1,
383 			.fname = thispath,
384 		};
385 
386 		c.namesize = 1 + sprintf(thispath, "initramfs_test_many-%d", i);
387 		p += fill_cpio(&c, 1, false, p);
388 	}
389 
390 	len = p - cpio_srcbuf;
391 	err = unpack_to_rootfs(cpio_srcbuf, len);
392 	KUNIT_EXPECT_NULL(test, err);
393 
394 	for (i = 0; i < INITRAMFS_TEST_MANY_LIMIT; i++) {
395 		sprintf(thispath, "initramfs_test_many-%d", i);
396 		KUNIT_EXPECT_EQ(test, init_unlink(thispath), 0);
397 	}
398 
399 	kfree(cpio_srcbuf);
400 }
401 
402 /*
403  * An initramfs filename is namesize in length, including the zero-terminator.
404  * A filename can be zero-terminated prior to namesize, with the remainder used
405  * as padding. This can be useful for e.g. alignment of file data segments with
406  * a 4KB filesystem block, allowing for extent sharing (reflinks) between cpio
407  * source and destination. This hack works with both GNU cpio and initramfs, as
408  * long as PATH_MAX isn't exceeded.
409  */
410 static void __init initramfs_test_fname_pad(struct kunit *test)
411 {
412 	char *err;
413 	size_t len;
414 	struct file *file;
415 	char fdata[] = "this file data is aligned at 4K in the archive";
416 	struct test_fname_pad {
417 		char padded_fname[4096 - CPIO_HDRLEN];
418 		char cpio_srcbuf[CPIO_HDRLEN + PATH_MAX + 3 + sizeof(fdata)];
419 	} *tbufs = kzalloc_obj(struct test_fname_pad);
420 	struct initramfs_test_cpio c[] = { {
421 		.magic = "070701",
422 		.ino = 1,
423 		.mode = S_IFREG | 0777,
424 		.uid = 0,
425 		.gid = 0,
426 		.nlink = 1,
427 		.mtime = 1,
428 		.filesize = sizeof(fdata),
429 		.devmajor = 0,
430 		.devminor = 1,
431 		.rdevmajor = 0,
432 		.rdevminor = 0,
433 		/* align file data at 4K archive offset via padded fname */
434 		.namesize = 4096 - CPIO_HDRLEN,
435 		.csum = 0,
436 		.fname = tbufs->padded_fname,
437 		.data = fdata,
438 	} };
439 
440 	memcpy(tbufs->padded_fname, "padded_fname", sizeof("padded_fname"));
441 	len = fill_cpio(c, ARRAY_SIZE(c), false, tbufs->cpio_srcbuf);
442 
443 	err = unpack_to_rootfs(tbufs->cpio_srcbuf, len);
444 	KUNIT_EXPECT_NULL(test, err);
445 
446 	file = filp_open(c[0].fname, O_RDONLY, 0);
447 	if (IS_ERR(file)) {
448 		KUNIT_FAIL(test, "open failed");
449 		goto out;
450 	}
451 
452 	/* read back file contents into @cpio_srcbuf and confirm match */
453 	len = kernel_read(file, tbufs->cpio_srcbuf, c[0].filesize, NULL);
454 	KUNIT_EXPECT_EQ(test, len, c[0].filesize);
455 	KUNIT_EXPECT_MEMEQ(test, tbufs->cpio_srcbuf, c[0].data, len);
456 
457 	fput(file);
458 	KUNIT_EXPECT_EQ(test, init_unlink(c[0].fname), 0);
459 out:
460 	kfree(tbufs);
461 }
462 
463 static void __init initramfs_test_fname_path_max(struct kunit *test)
464 {
465 	char *err;
466 	size_t len;
467 	struct kstat st0 = {}, st1 = {};
468 	char fdata[] = "this file data will not be unpacked";
469 	struct test_fname_path_max {
470 		char fname_oversize[PATH_MAX + 1];
471 		char fname_ok[PATH_MAX];
472 		char cpio_src[(CPIO_HDRLEN + PATH_MAX + 3 + sizeof(fdata)) * 2];
473 	} *tbufs = kzalloc_obj(struct test_fname_path_max);
474 	struct initramfs_test_cpio c[] = { {
475 		.magic = "070701",
476 		.ino = 1,
477 		.mode = S_IFDIR | 0777,
478 		.nlink = 1,
479 		.namesize = sizeof(tbufs->fname_oversize),
480 		.fname = tbufs->fname_oversize,
481 		.filesize = sizeof(fdata),
482 		.data = fdata,
483 	}, {
484 		.magic = "070701",
485 		.ino = 2,
486 		.mode = S_IFDIR | 0777,
487 		.nlink = 1,
488 		.namesize = sizeof(tbufs->fname_ok),
489 		.fname = tbufs->fname_ok,
490 	} };
491 
492 	memset(tbufs->fname_oversize, '/', sizeof(tbufs->fname_oversize) - 1);
493 	memset(tbufs->fname_ok, '/', sizeof(tbufs->fname_ok) - 1);
494 	memcpy(tbufs->fname_oversize, "fname_oversize",
495 	       sizeof("fname_oversize") - 1);
496 	memcpy(tbufs->fname_ok, "fname_ok", sizeof("fname_ok") - 1);
497 	len = fill_cpio(c, ARRAY_SIZE(c), false, tbufs->cpio_src);
498 
499 	/* unpack skips over fname_oversize instead of returning an error */
500 	err = unpack_to_rootfs(tbufs->cpio_src, len);
501 	KUNIT_EXPECT_NULL(test, err);
502 
503 	KUNIT_EXPECT_EQ(test, init_stat("fname_oversize", &st0, 0), -ENOENT);
504 	KUNIT_EXPECT_EQ(test, init_stat("fname_ok", &st1, 0), 0);
505 	KUNIT_EXPECT_EQ(test, init_rmdir("fname_ok"), 0);
506 
507 	kfree(tbufs);
508 }
509 
510 static void __init initramfs_test_hdr_hex(struct kunit *test)
511 {
512 	char *err;
513 	size_t len;
514 	char fdata[] = "this file data will not be unpacked";
515 	struct initramfs_test_bufs {
516 		char cpio_src[(CPIO_HDRLEN + PATH_MAX + 3 + sizeof(fdata)) * 2];
517 	} *tbufs = kzalloc(sizeof(struct initramfs_test_bufs), GFP_KERNEL);
518 	struct initramfs_test_cpio c[] = { {
519 		.magic = "070701",
520 		.ino = 1,
521 		.mode = S_IFREG | 0777,
522 		.uid = 0x123456,
523 		.gid = 0x123457,
524 		.nlink = 1,
525 		.namesize = sizeof("initramfs_test_hdr_hex_0"),
526 		.fname = "initramfs_test_hdr_hex_0",
527 		.filesize = sizeof(fdata),
528 		.data = fdata,
529 	}, {
530 		.magic = "070701",
531 		.ino = 2,
532 		.mode = S_IFDIR | 0777,
533 		.uid = 0x000056,
534 		.gid = 0x000057,
535 		.nlink = 1,
536 		.namesize = sizeof("initramfs_test_hdr_hex_1"),
537 		.fname = "initramfs_test_hdr_hex_1",
538 	} };
539 
540 	/* inject_ox=true to add "0x" cpio field prefixes */
541 	len = fill_cpio(c, ARRAY_SIZE(c), true, tbufs->cpio_src);
542 
543 	err = unpack_to_rootfs(tbufs->cpio_src, len);
544 	KUNIT_EXPECT_NOT_NULL(test, err);
545 
546 	kfree(tbufs);
547 }
548 
549 /*
550  * The kunit_case/_suite struct cannot be marked as __initdata as this will be
551  * used in debugfs to retrieve results after test has run.
552  */
553 static struct kunit_case __refdata initramfs_test_cases[] = {
554 	KUNIT_CASE(initramfs_test_extract),
555 	KUNIT_CASE(initramfs_test_fname_overrun),
556 	KUNIT_CASE(initramfs_test_data),
557 	KUNIT_CASE(initramfs_test_csum),
558 	KUNIT_CASE(initramfs_test_hardlink),
559 	KUNIT_CASE(initramfs_test_many),
560 	KUNIT_CASE(initramfs_test_fname_pad),
561 	KUNIT_CASE(initramfs_test_fname_path_max),
562 	KUNIT_CASE(initramfs_test_hdr_hex),
563 	{},
564 };
565 
566 static int __init initramfs_suite_init(struct kunit_suite *suite)
567 {
568 	/*
569 	 * unpack_to_rootfs() uses module-static state (victim, byte_count,
570 	 * state, ...). The boot-time async do_populate_rootfs() may still be
571 	 * running, so wait for it to finish before we call unpack_to_rootfs()
572 	 * from the test thread, otherwise the two writers race and crash.
573 	 */
574 	wait_for_initramfs();
575 	return 0;
576 }
577 
578 /* Tests run in a nullfs kthread; always use the init fs for path resolution. */
579 static int __init initramfs_test_init(struct kunit *test)
580 {
581 	test->priv = __override_init_fs();
582 	return 0;
583 }
584 
585 static void __init initramfs_test_exit(struct kunit *test)
586 {
587 	__revert_init_fs(test->priv);
588 }
589 
590 static struct kunit_suite __refdata initramfs_test_suite = {
591 	.name = "initramfs",
592 	.suite_init = initramfs_suite_init,
593 	.init = initramfs_test_init,
594 	.exit = initramfs_test_exit,
595 	.test_cases = initramfs_test_cases,
596 };
597 kunit_test_init_section_suites(&initramfs_test_suite);
598 
599 MODULE_DESCRIPTION("Initramfs KUnit test suite");
600 MODULE_LICENSE("GPL v2");
601