initramfs_test_extract() and friends call unpack_to_rootfs() from a
kunit kthread while do_populate_rootfs() may still be running
asynchronously from rootfs_initcall. unpack_to_rootfs() keeps its
parser state in module-static variables (victim, byte_count, state,
this_header, header_buf, name_buf, ...), so the two writers corrupt
each other.

On arm64 v7.0-rc5+ this oopses early in boot:

  Unable to handle kernel paging request at virtual address ffff80018f9f0ffc
  pc : do_reset+0x3c/0x98
  Call trace:
   do_reset
   initramfs_test_extract
   kunit_try_run_case
  Initramfs unpacking failed: junk within compressed archive

do_reset() faults because 'victim' was overwritten by the boot-time
unpacker; the boot unpacker meanwhile logs the bogus "junk within
compressed archive" on the real initrd because the test wrecked its
state machine.

Add a suite .init that calls wait_for_initramfs() so the async unpack
is quiescent before the first case runs.

To: Alexander Viro <[email protected]>
To: Christian Brauner <[email protected]>
To: Jan Kara <[email protected]>
To: David Disseldorp <[email protected]>
Cc: [email protected]

Fixes: 83c0b27266ec ("initramfs_test: kunit tests for initramfs unpacking")
Signed-off-by: Jia He <[email protected]>
---
 init/initramfs_test.c | 17 ++++++++++++++++-
 1 file changed, 16 insertions(+), 1 deletion(-)

diff --git a/init/initramfs_test.c b/init/initramfs_test.c
index 2ce38d9a8fd0..eb76f63f302e 100644
--- a/init/initramfs_test.c
+++ b/init/initramfs_test.c
@@ -3,7 +3,9 @@
 #include <linux/fcntl.h>
 #include <linux/file.h>
 #include <linux/fs.h>
+#include <linux/init.h>
 #include <linux/init_syscalls.h>
+#include <linux/initrd.h>
 #include <linux/stringify.h>
 #include <linux/timekeeping.h>
 #include "initramfs_internal.h"
@@ -510,8 +512,21 @@ static struct kunit_case __refdata initramfs_test_cases[] 
= {
        {},
 };
 
-static struct kunit_suite initramfs_test_suite = {
+static int __init initramfs_test_init(struct kunit *test)
+{
+       /*
+        * unpack_to_rootfs() uses module-static state (victim, byte_count,
+        * state, ...). The boot-time async do_populate_rootfs() may still be
+        * running, so wait for it to finish before we call unpack_to_rootfs()
+        * from the test thread, otherwise the two writers race and crash.
+        */
+       wait_for_initramfs();
+       return 0;
+}
+
+static struct kunit_suite __refdata initramfs_test_suite = {
        .name = "initramfs",
+       .init = initramfs_test_init,
        .test_cases = initramfs_test_cases,
 };
 kunit_test_init_section_suites(&initramfs_test_suite);
-- 
2.34.1


Reply via email to