lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [thread-next>] [day] [month] [year] [list]
Message-Id: <20250725-as_bytes-v1-1-6f06a3744f69@nvidia.com>
Date: Fri, 25 Jul 2025 11:11:18 +0900
From: Alexandre Courbot <acourbot@...dia.com>
To: Abdiel Janulgue <abdiel.janulgue@...il.com>, 
 Danilo Krummrich <dakr@...nel.org>, 
 Daniel Almeida <daniel.almeida@...labora.com>, 
 Robin Murphy <robin.murphy@....com>, 
 Andreas Hindborg <a.hindborg@...nel.org>, Miguel Ojeda <ojeda@...nel.org>, 
 Alex Gaynor <alex.gaynor@...il.com>, Boqun Feng <boqun.feng@...il.com>, 
 Gary Guo <gary@...yguo.net>, 
 Björn Roy Baron <bjorn3_gh@...tonmail.com>, 
 Benno Lossin <lossin@...nel.org>, Alice Ryhl <aliceryhl@...gle.com>, 
 Trevor Gross <tmgross@...ch.edu>
Cc: "Christian S. Lima" <christiansantoslima21@...il.com>, 
 rust-for-linux@...r.kernel.org, linux-kernel@...r.kernel.org, 
 Alexandre Courbot <acourbot@...dia.com>
Subject: [PATCH] rust: transmute: add `as_bytes` method for `AsBytes` trait

Every time that implements `AsBytes` should be able to provide its byte
representation. Introduce the `as_bytes` method that returns the
implementer as a stream of bytes.

Since types implementing `Sized` can trivially be represented as a
stream of bytes, introduce the `AsBytesSized` proxy trait that can be
implemented for any `Sized` type and provides an `AsBytes`
implementation suitable for such types. Types that are not `Sized` need
to implement `AsBytes` directly and provide a method implementation.

Signed-off-by: Alexandre Courbot <acourbot@...dia.com>
---
This is the sister patch of [1], requiring `AsBytes` implementors to
provide an `as_bytes` method, and adding the convenience trait
`AsBytesSized` that can be implemented on any sized type in order to
benefit from a suitable `AsBytes` implementation.

It is going to be used in Nova, but should also be universally useful -
if anything, it felt a bit strange that `AsBytes` did not require this
method so far as for unsized types the bytes representation cannot be
obviously inferred.

[1] https://lore.kernel.org/rust-for-linux/20250624042802.105623-1-christiansantoslima21@gmail.com/
---
 rust/kernel/dma.rs       |  4 ++--
 rust/kernel/transmute.rs | 48 ++++++++++++++++++++++++++++++++++++++++++------
 samples/rust/rust_dma.rs |  2 +-
 3 files changed, 45 insertions(+), 9 deletions(-)

diff --git a/rust/kernel/dma.rs b/rust/kernel/dma.rs
index 25dfa0e6cc3ce50aa85463dae00fbdebcf8975d2..2ada95fdb41186957ee8dd39d43e473286f01d2c 100644
--- a/rust/kernel/dma.rs
+++ b/rust/kernel/dma.rs
@@ -439,7 +439,7 @@ unsafe impl<T: AsBytes + FromBytes + Send> Send for CoherentAllocation<T> {}
 /// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
 /// unsafe impl kernel::transmute::FromBytes for MyStruct{};
 /// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
-/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
+/// unsafe impl kernel::transmute::AsBytesSized for MyStruct{};
 ///
 /// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
 /// let whole = kernel::dma_read!(alloc[2]);
@@ -483,7 +483,7 @@ macro_rules! dma_read {
 /// // SAFETY: All bit patterns are acceptable values for `MyStruct`.
 /// unsafe impl kernel::transmute::FromBytes for MyStruct{};
 /// // SAFETY: Instances of `MyStruct` have no uninitialized portions.
-/// unsafe impl kernel::transmute::AsBytes for MyStruct{};
+/// unsafe impl kernel::transmute::AsBytesSized for MyStruct{};
 ///
 /// # fn test(alloc: &kernel::dma::CoherentAllocation<MyStruct>) -> Result {
 /// kernel::dma_write!(alloc[2].member = 0xf);
diff --git a/rust/kernel/transmute.rs b/rust/kernel/transmute.rs
index 1c7d43771a37b90150de86699f114a2ffb84db91..91d977e035626bfb23910829653f1fc971e0e0f8 100644
--- a/rust/kernel/transmute.rs
+++ b/rust/kernel/transmute.rs
@@ -47,25 +47,61 @@ macro_rules! impl_frombytes {
 ///
 /// Values of this type may not contain any uninitialized bytes. This type must not have interior
 /// mutability.
-pub unsafe trait AsBytes {}
+pub unsafe trait AsBytes {
+    /// Returns `self` as a slice of bytes.
+    fn as_bytes(&self) -> &[u8];
+}
 
-macro_rules! impl_asbytes {
+/// Proxy trait for `AsBytes`, providing an implementation valid for all sized types.
+///
+/// If your type implements `Sized`, then you want to implement this instead of `AsBytes`.
+///
+/// # Safety
+///
+/// Values of this type may not contain any uninitialized bytes. This type must not have interior
+/// mutability.
+pub unsafe trait AsBytesSized: Sized {}
+
+unsafe impl<T: AsBytesSized> AsBytes for T {
+    fn as_bytes(&self) -> &[u8] {
+        unsafe {
+            core::slice::from_raw_parts((self as *const Self).cast::<u8>(), size_of::<Self>())
+        }
+    }
+}
+
+macro_rules! impl_asbytessized {
     ($($({$($generics:tt)*})? $t:ty, )*) => {
         // SAFETY: Safety comments written in the macro invocation.
-        $(unsafe impl$($($generics)*)? AsBytes for $t {})*
+        $(unsafe impl$($($generics)*)? AsBytesSized for $t {})*
     };
 }
 
-impl_asbytes! {
+impl_asbytessized! {
     // SAFETY: Instances of the following types have no uninitialized portions.
     u8, u16, u32, u64, usize,
     i8, i16, i32, i64, isize,
     bool,
     char,
-    str,
 
     // SAFETY: If individual values in an array have no uninitialized portions, then the array
     // itself does not have any uninitialized portions either.
-    {<T: AsBytes>} [T],
     {<T: AsBytes, const N: usize>} [T; N],
 }
+
+unsafe impl AsBytes for str {
+    fn as_bytes(&self) -> &[u8] {
+        self.as_bytes()
+    }
+}
+
+unsafe impl<T> AsBytes for [T]
+where
+    T: AsBytes,
+{
+    fn as_bytes(&self) -> &[u8] {
+        unsafe {
+            core::slice::from_raw_parts(self.as_ptr().cast::<u8>(), self.len() * size_of::<T>())
+        }
+    }
+}
diff --git a/samples/rust/rust_dma.rs b/samples/rust/rust_dma.rs
index 9e05d5c0cdaeb3b36fcf204a91b52e382e73fbe6..ab4814c848f928240fc49d57ac6a2efe636fb39f 100644
--- a/samples/rust/rust_dma.rs
+++ b/samples/rust/rust_dma.rs
@@ -30,7 +30,7 @@ fn new(h: u32, b: u32) -> Self {
     }
 }
 // SAFETY: All bit patterns are acceptable values for `MyStruct`.
-unsafe impl kernel::transmute::AsBytes for MyStruct {}
+unsafe impl kernel::transmute::AsBytesSized for MyStruct {}
 // SAFETY: Instances of `MyStruct` have no uninitialized portions.
 unsafe impl kernel::transmute::FromBytes for MyStruct {}
 

---
base-commit: 14ae91a81ec8fa0bc23170d4aa16dd2a20d54105
change-id: 20250725-as_bytes-6cbc11f2e8c3

Best regards,
-- 
Alexandre Courbot <acourbot@...dia.com>


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ