Skip to content

Soundness Issue: ProcessInner::death_delivered Does Not Enforce List Ownership Invariant #1238

@GeorgeAndrou

Description

@GeorgeAndrou

Hello,

Following the same pattern identified in #1237, ProcessInner::death_delivered is a safe function that does not enforce the invariant documented on delivered_links, relying entirely on callers to uphold a precondition that is neither checked nor expressed in the type system. Calling it with a mismatched NodeDeath can cause a null pointer dereference by invoking only safe Rust functions.

Confirmed on: Linux kernel 7.1.0-rc5 mainline (8fde5d1d47f6).

PoC

let name = CStr::from_bytes_with_nul(b"q\0").map_err(|_| EINVAL)?;
let ctx = crate::Context::new(name)?;
let local_file = kernel::fs::LocalFile::fget(3)?;
let cred = local_file.cred();
let proc_a = Process::new(ctx.clone().into(), ARef::from(cred))?;
let proc_b = Process::new(ctx.into(), ARef::from(cred))?;
let thread_a = proc_a.as_arc_borrow().get_current_thread()?;

let node_ref = Process::get_node(
    proc_a.as_arc_borrow(), 0x660, 4, 2, false, &thread_a,
)?;
let node = node_ref.node.clone();

let death: DArc<NodeDeath> = {
    let uninit = kernel::sync::UniqueArc::new_uninit(GFP_KERNEL)?;
    let init = NodeDeath::new(node, proc_a.clone(), 4);
    let death = uninit.pin_init_with(init).map_err(|_| ENOMEM)?;
    Arc::from(death)
};

{
    let mut inner = proc_b.inner.lock();
    inner.death_delivered(death.clone());
}

proc_a.remove_from_delivered_deaths(&death);
Process::deferred_release(proc_b);

Metadata

Metadata

Assignees

No one assigned

    Labels

    unsoundThe possibility of UB in safe code.• driversRelated to the example drivers in `drivers/`.

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions