On Fri, Jun 05, 2026 at 01:49:35PM +0000, [email protected] wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) 
> to consider:
> - [Critical] RcuBox::into_foreign drops `self` instead of forgetting it, 
> causing a guaranteed Use-After-Free.
> - [High] RcuBox::drop bypasses the custom Allocator A and hardcodes 
> kvfree_call_rcu() for types that do not require dropping, causing undefined 
> behavior for non-kvfree compatible allocators.
> --
> 
> commit f69c06884595bb68a76f4f1dd4014ee9e2c9e31c
> Author: Alice Ryhl <[email protected]>
> 
> rust: rcu: add RcuBox type
>     
> This adds an RcuBox container, which is like Box except that the value
> is freed after waiting for one grace period (via {kvfree_,}call_rcu()).
> To allow containers to rely on the RCU properties of RcuBox, an
> extension of ForeignOwnable is added.
> 
> > diff --git a/rust/kernel/sync/rcu/rcu_box.rs 
> > b/rust/kernel/sync/rcu/rcu_box.rs
> > new file mode 100644
> > index 0000000000000..943fe3e8974e0
> > --- /dev/null
> > +++ b/rust/kernel/sync/rcu/rcu_box.rs
> 
> [ ... ]
> 
> > +// SAFETY:
> > +// * The `RcuBoxInner<T>` was allocated with `A`.
> > +// * `NonNull::as_ptr` returns a non-null pointer.
> > +unsafe impl<T: Send + 'static, A: Allocator> ForeignOwnable for RcuBox<T, 
> > A> {
> > +    const FOREIGN_ALIGN: usize = <Box<RcuBoxInner<T>, A> as 
> > ForeignOwnable>::FOREIGN_ALIGN;
> > +
> > +    type Borrowed<'a> = &'a T;
> > +    type BorrowedMut<'a> = &'a T;
> > +
> > +    fn into_foreign(self) -> *mut c_void {
> > +        self.0.as_ptr().cast()
> > +    }
> 
> [Severity: Critical]
> Since `self` is consumed by value here without being wrapped in `ManuallyDrop`
> or passed to `core::mem::forget()`, won't it be dropped at the end of this
> method?
> 
> This seems like it would immediately schedule the memory for RCU free, causing
> a use-after-free for the foreign code when it later accesses the pointer.
> 

[Cc Alice]

I fixed this locally by:

    fn into_foreign(self) -> *mut c_void {
        let ptr = self.0.as_ptr().cast();

        // FORGET: Leaking it as a pointer, the caller is responsible to free 
it or unleak it by
        // from_foreign().
        core::mem::forget(self);

        ptr
    }


Regards,
Boqun

> > +
> > +    unsafe fn from_foreign(ptr: *mut c_void) -> Self {
> 
[..]

Reply via email to