Skip to content

Fix module_control0 double-free via unsynchronized ctl_args lifecycle - #296

Open
Admirepowered with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-double-free-concurrent-ctl-supercalls
Open

Fix module_control0 double-free via unsynchronized ctl_args lifecycle#296
Admirepowered with Copilot wants to merge 7 commits into
mainfrom
copilot/fix-double-free-concurrent-ctl-supercalls

Conversation

Copilot AI commented Aug 10, 2026

Copy link
Copy Markdown

module_control0() freed and re-allocated the shared per-module mod->ctl_args buffer without any locking. Two threads issuing SUPERCALL_KPM_CONTROL against the same module could both pass the kvfree(mod->ctl_args) check before either reassigned the pointer, causing a double-free, vmalloc metadata corruption, and a kernel panic.

Changes

  • Add module_ctl_lock mutex (kernel module code, mod->ctl0 may sleep so a mutex is required, not a spinlock) to serialize the free → vmalloc → copy → ctl0() sequence in module_control0().
  • Serialize unload_module() with the same lock around find_module(), list_del(), mod->exit(), and freeing mod->args/mod->ctl_args/mod, so a module can't be unloaded and freed while a concurrent module_control0() is still using it.
  • Serialize load_module() with the same lock around the existence-check and list_add_tail() (plus cleanup paths), so all three module-list mutators (load/unload/control) are mutually exclusive on the shared list and per-module buffers.
  • Drop the previously-held rcu_read_lock()/rcu_read_unlock() in unload_module()/module_control0() — now redundant since the mutex fully serializes these paths, and the prior usage was itself unsound (structural list_del() under a read lock, and sleeping via ctl0()/mod->exit() inside an RCU read-side critical section).
  • Remove the unused module_lock spinlock — it was declared/initialized but never actually locked anywhere, and would have been confusing alongside the new mutex.
static DEFINE_MUTEX(module_ctl_lock);

long module_control0(...)
{
    ...
    mutex_lock(&module_ctl_lock);
    struct module *mod = find_module(name);
    ...
    if (mod->ctl_args) kvfree(mod->ctl_args);
    mod->ctl_args = vmalloc(args_len + 1);
    ...
    rc = (*mod->ctl0)(mod->ctl_args, out_msg, outlen);
    mutex_unlock(&module_ctl_lock);
    ...
}

Copilot AI and others added 6 commits August 10, 2026 03:21
Co-authored-by: Admirepowered <43035036+Admirepowered@users.noreply.github.com>
Co-authored-by: Admirepowered <43035036+Admirepowered@users.noreply.github.com>
Co-authored-by: Admirepowered <43035036+Admirepowered@users.noreply.github.com>
…utex

Co-authored-by: Admirepowered <43035036+Admirepowered@users.noreply.github.com>
Co-authored-by: Admirepowered <43035036+Admirepowered@users.noreply.github.com>
…_lock

Co-authored-by: Admirepowered <43035036+Admirepowered@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix double-free issue in module_control0 during concurrent supercalls Fix module_control0 double-free via unsynchronized ctl_args lifecycle Aug 10, 2026
Copilot AI requested a review from Admirepowered August 10, 2026 03:29
@Admirepowered
Admirepowered marked this pull request as ready for review August 10, 2026 07:43
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug] module_control0 double-free on concurrent ctl supercalls

2 participants