Hi Petr,
I'm confused by this description and I'm not sure what problem the patch
is trying to solve. A task is not normally terminated in the middle of
a syscall. This could happen only if it hits an oops. However, that
means there is an earlier bug and the module loader isn't expected to be
resilient to a post-oops state.
Could you clarify the scenario that you ran into?
Thank you for the review. You are entirely correct; the task did not
terminate during a normal syscall, but was indeed killed by a prior
oops.
Here is the exact scenario discovered during driver fuzzing by our
automated virtual device modeling tool, DevGen:
1. A `modprobe` task (PID 433) concurrently loaded a faulty driver
(the `atlantic` net driver in our trace).
2. It passed the idempotent() check and added its stack-allocated
`struct idempotent` node to the global `idem_hash` list.
3. During init_module_from_file(), the `atlantic` driver hit a fatal
oops in its hardware init path (aq_hw_write_reg+0x39/0x50).
4. The kernel initiated oops recovery, terminating the `modprobe` task
(exited with preempt_count 1) and freeing its kernel stack.
5. The oops recovery path does not clean up the `idem_hash` list,
leaving a dangling pointer to the freed stack in the global list.
6. A subsequent module loading attempt traversed `idem_hash`,
dereferenced the stale stack pointer, and triggered a secondary
KASAN use-after-free and GPF.
While the root cause of the initial crash lies within the specific
buggy driver, the current stack allocation allows an isolated driver
oops to corrupt a global synchronization primitive, preventing any
further module loading across the entire system.
By migrating this allocation to the heap via kmalloc_obj(), the patch
prevents the global memory corruption. We acknowledge this leaves a
leaked node in the hash list. Consequently, subsequent attempts to load
that *specific* oopsed module will hang, but the rest of the module
subsystem survives and functions normally.
Thanks,
Mingyu