Skip to content

MiscDevice missing module reference counting causes use-after-free crashes #1182

@ileixe

Description

@ileixe

TLDR: Hi, while migrating our C driver into Rust misc device, I found there's no API expected for module reference.

Can we add such API? I am not sure what's proper fix, so want to ask

Here's long story.

Summary

All rust-for-linux drivers using MiscDevice are vulnerable to use-after-free crashes during module removal while file operations are active. This is a critical safety issue that causes immediate system reboots.

Problem Description

The rust-for-linux MiscDevice implementation generates file_operations structures without setting the .owner field, which is essential for kernel module reference counting. This leads to use-after-free vulnerabilities when:

  1. A userspace process opens a misc device file (/dev/device)
  2. The kernel module is unloaded (rmmod) while the file is still open
  3. VFS continues to access the freed module memory → immediate system crash

In C kernel drivers, this is automatically prevented by setting .owner = THIS_MODULE in file_operations, which makes the VFS call try_module_get()/module_put() to prevent module unloading while files are open.

Reproduction Steps

Environment: Any system with a rust-for-linux misc device driver

# Terminal 1 - Open the device file
tail -f /dev/rust-misc-device

# Terminal 2 - Unload the module
sudo rmmod rust_misc_device_module
# Result: Immediate system reboot/crash (no error messages)

Expected vs Actual Behavior

Expected (like C drivers):

$ sudo rmmod rust_misc_device_module
rmmod: ERROR: Module 'rust_misc_device_module' is in use
# Module removal blocks safely until file is closed

Actual:

$ sudo rmmod rust_misc_device_module
# System immediately reboots - use-after-free crash

Root Cause Analysis

File: rust/kernel/miscdevice.rs, line 325

const VTABLE: bindings::file_operations = bindings::file_operations {
    // MISSING: owner field is not set!
    open: Some(Self::open),
    release: Some(Self::release),
    unlocked_ioctl: if T::HAS_IOCTL { Some(Self::ioctl) } else { None },
    // ...
    ..unsafe { MaybeUninit::zeroed().assume_init() }
};

The generated file_operations structure has owner: null instead of pointing to the module, so the VFS cannot perform automatic module reference counting.

Impact Assessment

  • Scope: Every Rust driver using MiscDevice trait
  • Severity: System crashes/reboots during normal module operations
  • Examples affected:
    • samples/rust/rust_misc_device.rs
    • All out-of-tree Rust misc device drivers
  • Security implications: Use-after-free vulnerabilities in kernel space

Technical Analysis

C driver equivalent (works correctly):

static const struct file_operations my_fops = {
    .owner = THIS_MODULE,  // ← This prevents the crash
    .open = my_open,
    .release = my_release,
    // ...
};

Rust driver (vulnerable):

// In MiscdeviceVTable<T>::VTABLE - owner field is missing
const VTABLE: bindings::file_operations = bindings::file_operations {
    // owner: ???,  // No access to THIS_MODULE in this context
    open: Some(Self::open),
    // ...
};

Proposed Solution Approaches

Option 1: Extend Registration API

// New method alongside existing register()
pub fn register_with_module(
    opts: MiscDeviceOptions, 
    module: &'static ThisModule
) -> impl PinInit<Self, Error>

Option 2: Automatic Injection

Modify the #[vtable] proc macro system to automatically inject module references during vtable generation.

Option 3: Context-based Solution

Make THIS_MODULE available in the vtable generation context through thread-local storage or similar mechanism.

Verification

This issue can be confirmed by:

  1. Building any Rust misc device driver
  2. Checking that cat /proc/modules shows the module as loaded
  3. Opening the device file: tail -f /dev/device
  4. Running rmmod module_name → immediate system crash

References

  • Linux VFS module reference counting: fs/file_table.c:__fget_files_rcu()
  • C driver example: Any driver in drivers/ with .owner = THIS_MODULE
  • rust-for-linux MiscDevice: rust/kernel/miscdevice.rs:325

Workaround (Temporary)

Until this is fixed upstream, drivers must implement manual module reference counting:

// In device open()
let success = unsafe { kernel::bindings::try_module_get(module_ptr) };
if !success { return Err(ENODEV); }

// In device drop()  
unsafe { kernel::bindings::module_put(module_ptr) };

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions