logoalt Hacker News

Linux Kernel Rust Code Sees Its First CVE Vulnerability

86 pointsby weinzierltoday at 5:30 PM84 commentsview on HN

Comments

tekacstoday at 6:04 PM

To pre-empt the folks who'll come in here and laugh about how Rust should be preventing memory corruption... I'll just directly quote from the mailing list:

  Rust Binder contains the following unsafe operation:
  
   // SAFETY: A `NodeDeath` is never inserted into the death list
   // of any node other than its owner, so it is either in this
   // death list or in no death list.
   unsafe { node_inner.death_list.remove(self) };
  
  This operation is unsafe because when touching the prev/next pointers of
  a list element, we have to ensure that no other thread is also touching
  them in parallel. If the node is present in the list that `remove` is
  called on, then that is fine because we have exclusive access to that
  list. If the node is not in any list, then it's also ok. But if it's
  present in a different list that may be accessed in parallel, then that
  may be a data race on the prev/next pointers.
  
  And unfortunately that is exactly what is happening here. In
  Node::release, we:
  
   1. Take the lock.
   2. Move all items to a local list on the stack.
   3. Drop the lock.
   4. Iterate the local list on the stack.
  
  Combined with threads using the unsafe remove method on the original
  list, this leads to memory corruption of the prev/next pointers. This
  leads to crashes like this one:
show 4 replies
n2d4today at 7:12 PM

I recommend you read Greg Koah-Hartman's thread instead of this article: https://social.kernel.org/notice/B1JLrtkxEBazCPQHDM

    > Rust is is not a "silver bullet" that can solve all security problems, but it sure helps out a lot and will cut out huge swatches of Linux kernel vulnerabilities as it gets used more widely in our codebase.
    
    > That being said, we just assigned our first CVE for some Rust code in the kernel: https://lore.kernel.org/all/2025121614-CVE-2025-68260-558d@gregkh/ where the offending issue just causes a crash, not the ability to take advantage of the memory corruption, a much better thing overall.

    > Note the other 159 kernel CVEs issued today for fixes in the C portion of the codebase, so as always, everyone should be upgrading to newer kernels to remain secure overall.
show 1 reply
drob518today at 6:09 PM

Anybody who thought the simple action of rewriting things in Rust would eliminate all bugs was hopelessly naive. Particularly since Rust allows unsafe operations. That doesn’t mean Rust provides no value over C, just that the value is short of total elimination of bugs. Which was never advertised as the value to begin with.

show 4 replies
phendrenad2today at 6:44 PM

I feel like everyone involved in the Linux Kernel Rust world is ironically woefully unaware of how Rust actually works, and what it's actually capable of. I suspect that Rust gurus agree with me, but don't want to say anything because it would hurt Rust adoption in places where it actually is helpful (encryption algorithms...)

Kernels - and especially the Linux kernel - are high-performance systems that require lots of shared mutable state. Every driver is a glorified while loop waiting for an IRQ so it can copy a chunk of data from one shared mutable buffer to another shared mutable buffer. So there will need to be some level of unsafe in the code.

There's a fallacy that if 95% of the code is safe, and 5% is unsafe, then that code is only 5% as likely to contain memory errors as a comparable C program. But, to reiterate what another commenter said, and something I've predicted for a long time, the tendency for the "unsafe block" to become instrumented by the "safe block" will always exist. People will loosen the API contract between the "safe" and "unsafe" sides until an error in the "safe" side kicks off an error in the "unsafe" side.

show 1 reply
bangaladoretoday at 6:15 PM

Correct me if I'm wrong, but this comment is atleast partially incorrect right?

> Since it was in an unsafe block, the error for sure was way easier to find within the codebase than in C. Everything that's not unsafe can be ruled out as a reason for race conditions and the usual memory handling mistakes - that's already a huge win.

The benefit of Rust is you can isolate the possible code that causes an XYZ to an unsafe block*. But that doesn't necessarily mean the error shown is directly related to the unsafe block. Like C++, triggering undefined behavior can in theory cause the program to do anything, including fail spectacularly within seemingly unrelated safe code.

* Excluding cases where safe things are actually possibly unsafe (like some incorrectly marked FFI)

show 5 replies
aw1621107today at 6:44 PM

Direct link to the mailing list entry at [0]. The fix for 6.19-rc1 is commit 3e0ae02ba831 [1]. The patch is pretty small (added some extra context since the function it's from is short):

        pub(crate) fn release(&self) {
            let mut guard = self.owner.inner.lock();
            while let Some(work) = self.inner.access_mut(&mut guard).oneway_todo.pop_front() {
                drop(guard);
                work.into_arc().cancel();
                guard = self.owner.inner.lock();
            }

    -       let death_list = core::mem::take(&mut self.inner.access_mut(&mut guard).death_list);
    -       drop(guard);
    -       for death in death_list {
    +       while let Some(death) = self.inner.access_mut(&mut guard).death_list.pop_front() {
    +           drop(guard);
                death.into_arc().set_dead();
    +           guard = self.owner.inner.lock();
            }
        }
And here is the unsafe block mentioned in the commit message with some more context [3]:

    fn set_cleared(self: &DArc<Self>, abort: bool) -> bool {
        // <snip>

        // Remove death notification from node.
        if needs_removal {
            let mut owner_inner = self.node.owner.inner.lock();
            let node_inner = self.node.inner.access_mut(&mut owner_inner);
            // SAFETY: A `NodeDeath` is never inserted into the death list of any node other than
            // its owner, so it is either in this death list or in no death list.
            unsafe { node_inner.death_list.remove(self) };
        }
        needs_queueing
    }
[0]: https://lore.kernel.org/linux-cve-announce/2025121614-CVE-20...

[1]: https://github.com/torvalds/linux/commit/3e0ae02ba831da2b707...

[2]: https://github.com/torvalds/linux/blob/3e0ae02ba831da2b70790...

[3]: https://github.com/torvalds/linux/blob/3e0ae02ba831da2b70790...

show 1 reply
HumanOstrichtoday at 6:02 PM

They're still 90% of the way to their goal. And there's only 90% left to go.

samdoesnothingtoday at 6:46 PM

I think it's pretty telling that there are people in this thread trying to pre-empt the expected criticism in this thread. Might be worth thinking why there might be criticism, and why it wouldn't be the case if it was a different language.

secondcomingtoday at 6:07 PM

[flagged]

kahloneltoday at 5:57 PM

Now we have vulnerabilities in two different flavors.

greatgibtoday at 5:58 PM

"That code can lead to memory corruption of the previous/next pointers and in turn cause a crash."

Oh no, what happened to Rust will save us from retarded legacy languages prone to memory corruption?

show 2 replies
pa7chtoday at 6:02 PM

Honestly seems like zig is shaping up to be a better fit for kernel. Regardless the language that attracts skilled kernel devs will matter more then lang.

show 1 reply
troglo-bytetoday at 6:40 PM

I'll confess I'm a bit less than well-read on this, but I can't help but wonder. How can increasing the number of languages in use within one enormous project possibly reduce critical vulnerabilities over the next decade?

If we're looking beyond one decade, then:

- As with all other utility, the future must be discounted compared to the present.

- A language that might look sterling today might fall behind tomorrow.

- Something something AI by 2035.