mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] rust: net: netlink: validate attribute length before casting to `c_int`
@ 2026-09-13  2:17 Sagar Taunk
  2026-09-14  1:10 ` Alexandre Courbot
  0 siblings, 1 reply; 2+ messages in thread
From: Sagar Taunk @ 2026-09-13  2:17 UTC (permalink / raw)
  To: David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Miguel Ojeda, Boqun Feng, Gary Guo,
	Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
	Trevor Gross, Danilo Krummrich, Daniel Almeida, Tamir Duberstein,
	Alexandre Courbot, Onur Özkan, netdev, rust-for-linux,
	linux-kernel
  Cc: Sagar Taunk

As pointed out by Sashiko, `put()` trusted an unchecked `as` cast from
`usize` to `c_int`. When the length exceeds `i32::MAX`, that cast
wraps around to a negative value.

`nla_put()`'s `skb_tailroom()` check treats the length as signed, so
the wrapped negative value slips past it. Further down, `__nla_reserve()`
and `skb_put` reinterpret the same value as unsigned, turning it into an
enormous length and triggering a kernel panic via `skb_over_panic()`.

So, validate the cast with `c_int::try_from()` instead, and return
`EMSGSIZE` when the length doesn't fit.

Signed-off-by: Sagar Taunk <sagartaunk@proton.me>
---
 rust/kernel/net/netlink.rs | 18 +++++++++++++-----
 1 file changed, 13 insertions(+), 5 deletions(-)

diff --git a/rust/kernel/net/netlink.rs b/rust/kernel/net/netlink.rs
index 3c2b142a7402..f929f63b32c1 100644
--- a/rust/kernel/net/netlink.rs
+++ b/rust/kernel/net/netlink.rs
@@ -88,11 +88,19 @@ fn put<T>(&mut self, attrtype: c_int, value: &T) -> Result
         T: ?Sized + IntoBytes + Immutable,
     {
         let skb = self.skb.skb.as_ptr();
-        let len = size_of_val(value);
-        let ptr = core::ptr::from_ref(value).cast::<c_void>();
-        // SAFETY: `skb` is valid by `NetlinkSkBuff` type invariants, and the provided value is
-        // readable and initialized for its `size_of` bytes.
-        to_result(unsafe { bindings::nla_put(skb, attrtype, len as c_int, ptr) })
+        let bytes = value.as_bytes();
+        // `nla_put()` takes attrlen as a plain `c_int`. If `bytes.len()`
+        // doesn't fit, an `as` cast would wrap around a negative value.
+        // Which then, would feed a huge unsigned length to `__nla_reserve()`
+        // and `skb_put()` causing it to panic via `skb_over_panic()`. So,
+        // the following check will reject it instead.
+        let len = c_int::try_from(bytes.len()).map_err(|_| EMSGSIZE)?;
+        let ptr = bytes.as_ptr().cast::<c_void>();
+        // SAFETY: `skb` is valid as per `NetlinkSkBuff` type invariants.
+        // `bytes` is a valid Rust slice, so `ptr` is readable for `len`
+        // bytes, and `T: Immutable` guarantees nothing can mutate `*value`
+        // while `nla_put()` copies it.
+        to_result(unsafe { bindings::nla_put(skb, attrtype, len, ptr) })
     }
 
     /// Puts a `u32` attribute into the message.
-- 
2.55.0



^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-14  1:10 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-13  2:17 [PATCH] rust: net: netlink: validate attribute length before casting to `c_int` Sagar Taunk
2026-09-14  1:10 ` Alexandre Courbot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®