* Re: [PATCH 2/2] rust: add hw_random module
From: Miguel Ojeda @ 2026-05-29 20:01 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu, rust-for-linux, linux-kernel,
linux-crypto, manos.pitsidianakis
In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-2-b3153dd90311@pitsidianak.is>
Hi Manos,
Some quick doc nits I noticed while managing our list...
On Fri, May 29, 2026 at 5:50 PM Manos Pitsidianakis
<manos@pitsidianak.is> wrote:
>
> +//! # Example
"Examples" is the section name we use.
> +//!# fn no_run() {
> +//!# use kernel::hw_random::*;
> +//!# use kernel::str::CString;
> +//!# use kernel::prelude::*;
Missing indentation.
> +//! fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()> {
-> Result
> +//! // write zeroes - in your driver, this should write actual data from your hardware.
"Write"
> +//! let name = CString::try_from(c"example_hwrng").unwrap();
Could you avoid `unwrap()`s, perhaps using `?` etc.? It is not
critical, but good practice to try to show how "real code" would be
written.
> + from_result, //
> + to_result, //
> + VTABLE_DEFAULT_ERROR, //
Please only use the slashes in the last one:
> + },
...but add one here, since this level doesn't have it.
> + /// Returns `true` if the buffer has been filled.
[`true`]
> + // SAFETY: u8 and MaybeUninit<u8> have the same layout
Please use Markdown (but no intra-doc links needed) in comments too, e.g.
`u8` ... `MaybeUninit<u8>`
There are other instances below.
> +/// [`struct hwrng`]: srctree/include/linux/hw_random.h
Is this reference used?
> +#[vtable]
> +/// Trait for the implementation of hardware RNGs.
Attributes after documentation.
Other instances below too.
> + /// [`hwrng_unregister`]: srctree/include/linux/hw_random.h
> + #[inline]
> + #[doc(alias = "hwrng_unregister")]
Is this one for the alias? How does it behave when rendered?
> + pub fn unregister(&self) {
> + if self
> + .registered
> + .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acquire)
> + .is_ok()
We are starting to add `// ORDERING: ...` comments for things like
this, so it would be nice to have them here already.
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
Please start comments capitalized. Other instances elsewhere too.
Cheers,
Miguel
^ permalink raw reply
* Re: [PATCH 2/2] rust: add hw_random module
From: Onur Özkan @ 2026-05-29 19:56 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu, rust-for-linux, linux-kernel,
linux-crypto, manos.pitsidianakis
In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-2-b3153dd90311@pitsidianak.is>
On Fri, 29 May 2026 18:50:27 +0300
Manos Pitsidianakis <manos@pitsidianak.is> wrote:
> Add abstraction for the hardware random number generator core subsystem.
>
> The registration is guarded by an atomic boolean, because we cannot yet
> use IRQ disabling spinlocks in Rust. Once they are supported, we should
> switch to that, because it's theoretically possible to construct a data
> race. In practice I do not think it's possible, since registration
> happens once in driver probe and unregistration happens on driver
> teardown; there shouldn't be multiple threads doing their own thing in
> both cases.
>
> Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
> ---
> MAINTAINERS | 8 ++
> rust/kernel/hw_random.rs | 320 +++++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs | 2 +
> 3 files changed, 330 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4f60b323c796fc0968fd67d1c7afee6802990572..a3b372ccbd07c4ae2c735ba31f2acf40472b384a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11304,6 +11304,14 @@ F: Documentation/devicetree/bindings/rng/
> F: drivers/char/hw_random/
> F: include/linux/hw_random.h
>
> +HARDWARE RANDOM NUMBER GENERATOR CORE [RUST]
> +M: Manos Pitsidianakis <manos@pitsidianak.is>
> +M: Herbert Xu <herbert@gondor.apana.org.au>
> +L: linux-crypto@vger.kernel.org
> +L: rust-for-linux@vger.kernel.org
> +S: Maintained
> +F: rust/kernel/hw_random.rs
> +
> HARDWARE SPINLOCK CORE
> M: Bjorn Andersson <andersson@kernel.org>
> R: Baolin Wang <baolin.wang7@gmail.com>
> diff --git a/rust/kernel/hw_random.rs b/rust/kernel/hw_random.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..29fc180b4a3b4157a45c8fdb2d94bf1d9d781a3c
> --- /dev/null
> +++ b/rust/kernel/hw_random.rs
> @@ -0,0 +1,320 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Author: Manos Pitsidianakis <manos@pitsidianak.is>
> +
> +//! Hardware Random Number Generators
> +//!
> +//! This module provides an abstraction for implementing a hardware random number generator and
> +//! using it with the kernel's `hw_random` system.
> +//!
> +//! # Example
> +//!
> +//! ```no_run
> +//!# fn no_run() {
> +//!# use kernel::hw_random::*;
> +//!# use kernel::str::CString;
> +//!# use kernel::prelude::*;
> +//! #[pin_data]
> +//! struct ExampleHwRng {}
> +//!
> +//! #[vtable]
> +//! impl HwRngImpl for ExampleHwRng {
> +//! fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()> {
> +//! // write zeroes - in your driver, this should write actual data from your hardware.
> +//! data.write(&[0_u8; 8]);
> +//! Ok(())
> +//! }
> +//! }
> +//!
> +//! let name = CString::try_from(c"example_hwrng").unwrap();
> +//! let my_rng = KBox::pin_init(
> +//! HwRng::new(
> +//! name,
> +//! 0,
> +//! try_pin_init!(ExampleHwRng {})
> +//! ),
> +//! GFP_KERNEL
> +//! ).unwrap();
> +//! // Register `my_rng`: after this succeeds, the kernel may call our `HwRngImpl` method at any
> +//! // time.
> +//! my_rng.register().unwrap();
> +//!
> +//! // ...
> +//!
> +//! my_rng.unregister();
> +//!# }
> +//!```
> +
> +use crate::{
> + error::{
> + from_result, //
> + to_result, //
> + VTABLE_DEFAULT_ERROR, //
> + },
> + prelude::*, //
> + str::{
> + CString, //
> + },
> + types::{
> + Opaque, //
> + },
> +};
> +
> +use core::{
> + ffi::{
> + c_int, //
> + c_ushort, //
> + c_void, //
> + },
> + mem::{
> + MaybeUninit, //
> + },
> + ptr::{
> + slice_from_raw_parts, //
> + slice_from_raw_parts_mut, //
> + },
> + sync::atomic::{
> + AtomicBool, //
> + Ordering, //
> + },
> +};
> +
> +use pin_init::pin_init_from_closure;
> +
> +/// A buffer to write random bytes in using [`Buffer::write`] that tracks how many bytes were
> +/// written.
> +///
> +/// See also [`HwRngImpl::read`].
> +pub struct Buffer<'a> {
> + inner: &'a mut [MaybeUninit<u8>],
> + written: usize,
> +}
> +
> +impl Buffer<'_> {
> + /// Returns `true` if the buffer has been filled.
> + #[inline]
> + pub const fn is_empty(&self) -> bool {
> + self.written == self.inner.len()
> + }
> +
> + /// Returns the number of bytes that can be written.
> + #[inline]
> + pub const fn len(&self) -> usize {
This name is quite confusing for what it actually does. `len()` is a very common
API across many types and readers would usually expect it to return the total
length of the buffer. A more explicit name like `remaining_len()` or
`writable_len()` would make it much clearer.
> + self.inner.len() - self.written
> + }
> +
> + /// Writes bytes from `buf` into buffer and returns the amount of bytes written.
> + #[inline]
> + pub fn write(&mut self, buf: &[u8]) -> usize {
> + let to_copy = self.len().min(buf.len());
> + let ptr = buf.as_ptr();
> + // SAFETY: u8 and MaybeUninit<u8> have the same layout
> + let buf = unsafe { &*slice_from_raw_parts(ptr.cast::<MaybeUninit<u8>>(), to_copy) };
> + self.inner[self.written..][..to_copy].copy_from_slice(buf);
> + self.written += to_copy;
> + to_copy
> + }
> +}
> +
> +/// An adapter type for the registration of hardware random number generators drivers.
> +///
> +/// [`struct hwrng`]: srctree/include/linux/hw_random.h
> +#[pin_data(PinnedDrop)]
> +pub struct HwRng<T: HwRngImpl + 'static> {
> + #[pin]
> + registration: Opaque<bindings::hwrng>,
> + registered: AtomicBool,
> + #[pin]
> + name: CString,
> + #[pin]
> + inner: T,
> +}
> +
> +impl<T: HwRngImpl + 'static> core::ops::Deref for HwRng<T> {
> + type Target = T;
> +
> + #[inline]
> + fn deref(&self) -> &Self::Target {
> + &self.inner
> + }
> +}
> +
> +// SAFETY: HwRng contains a `*const u8` reference but it is opaque for us in Rust.
> +unsafe impl<T: HwRngImpl + 'static> Send for HwRng<T> {}
> +
> +// SAFETY: `HwRng` has no interior mutability from Rust, and C manages it with the rng_mutex lock.
> +unsafe impl<T: HwRngImpl + 'static> Sync for HwRng<T> {}
> +
> +#[pinned_drop]
> +impl<T: HwRngImpl> PinnedDrop for HwRng<T> {
> + fn drop(self: Pin<&mut Self>) {
> + self.unregister();
> + }
> +}
> +
> +#[vtable]
> +/// Trait for the implementation of hardware RNGs.
> +pub trait HwRngImpl: Send + Sync {
> + #[inline]
> + /// Initialization callback, can be optionally implemented.
> + fn init(&self) -> Result {
> + build_error!(VTABLE_DEFAULT_ERROR)
> + }
> +
> + #[inline]
> + /// Cleanup callback, can be optionally implemented.
> + fn cleanup(&self) {
> + build_error!(VTABLE_DEFAULT_ERROR)
> + }
> +
> + /// Places random bytes in `data`.
> + fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()>;
> +}
> +
> +impl<T: HwRngImpl + 'static> HwRng<T> {
> + /// Create a new [`HwRng`] without registering it.
> + pub fn new(
> + name: CString,
> + quality: c_ushort,
> + inner: impl PinInit<T, Error>,
> + ) -> impl PinInit<Self, Error> {
> + // We use pin_init_from_closure because we need to store the `slot` address as `priv` field
> + // of `hwrng` struct.
> +
> + // SAFETY:
> + // - when the closure returns `Ok(())`, then it has successfully initialized all fields,
> + // - when it returns `Err(e)`, it does not need to perform any cleanup.
> + unsafe {
> + pin_init_from_closure(move |slot: *mut Self| {
> + inner.__pinned_init(&raw mut (*slot).inner)?;
> +
> + let registration = (&raw mut (*slot).registration).cast::<bindings::hwrng>();
> + registration.write(bindings::hwrng {
> + name: name.as_char_ptr(),
> + read: Some(Self::read_callback),
> + init: if <T as HwRngImpl>::HAS_INIT {
> + Some(Self::init_callback)
> + } else {
> + None
> + },
> + cleanup: if <T as HwRngImpl>::HAS_CLEANUP {
> + Some(Self::cleanup_callback)
> + } else {
> + None
> + },
> + quality,
> + priv_: slot as usize,
> + ..Default::default()
> + });
> +
> + let name_ptr = &raw mut (*slot).name;
> + name_ptr.write(name);
> +
> + let registered = &raw mut (*slot).registered;
> + registered.write(AtomicBool::new(false));
> +
> + // All fields of `HwRng` have been initialized
> + Ok(())
> + })
> + }
> + }
> +
> + /// Register `self` with the `hwrng` subsystem.
> + ///
> + /// After this function successfully returns, the `hwrng` subsystem can start calling the
> + /// [`HwRngImpl`] methods at any time.
> + ///
> + /// [`hwrng_register`]: srctree/include/linux/hw_random.h
> + #[inline]
> + #[doc(alias = "hwrng_register")]
> + pub fn register(&self) -> Result {
> + if self
> + .registered
> + .compare_exchange(false, true, Ordering::SeqCst, Ordering::Acquire)
> + .is_ok()
> + {
> + // SAFETY: `registration` is properly initialized.
> + if let Err(err) = to_result(unsafe {
> + bindings::hwrng_register(self.registration.get().cast::<bindings::hwrng>())
> + }) {
> + self.registered.store(false, Ordering::Release);
> + return Err(err);
> + }
> + }
> + Ok(())
> + }
> +
> + /// Unregister `self` from `hwrng` subsystem.
> + ///
> + /// [`hwrng_unregister`]: srctree/include/linux/hw_random.h
> + #[inline]
> + #[doc(alias = "hwrng_unregister")]
> + pub fn unregister(&self) {
> + if self
> + .registered
> + .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acquire)
> + .is_ok()
> + {
> + // SAFETY: Since `registration` is properly initialized and registered, destroying is
> + // safe.
> + unsafe {
> + bindings::hwrng_unregister(self.registration.get().cast::<bindings::hwrng>())
> + };
> + }
> + }
> +}
> +
> +impl<T: HwRngImpl + 'static> HwRng<T> {
> + extern "C" fn init_callback(ptr: *mut bindings::hwrng) -> c_int {
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
> + let priv_ = unsafe { (*ptr).priv_ };
> + let this_ptr = priv_ as *mut Self;
> +
> + // SAFETY: we set `inner` to point to a valid `T` when initializing.
> + let inner: &T = unsafe { &(*this_ptr).inner };
> + from_result(|| {
> + inner.init()?;
> + Ok(0)
> + })
> + }
> +
> + extern "C" fn cleanup_callback(ptr: *mut bindings::hwrng) {
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
> + let priv_ = unsafe { (*ptr).priv_ };
> + let this_ptr = priv_ as *mut Self;
> +
> + // SAFETY: we set `inner` to point to a valid `T` when initializing.
> + let inner: &T = unsafe { &(*this_ptr).inner };
> + inner.cleanup();
> + }
> +
> + extern "C" fn read_callback(
> + ptr: *mut bindings::hwrng,
> + data: *mut c_void,
> + max: usize,
> + wait: bool,
> + ) -> c_int {
> + if data.is_null() || max == 0 {
> + return 0;
> + }
> +
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
> + let priv_ = unsafe { (*ptr).priv_ };
> + let this_ptr = priv_ as *mut Self;
> +
> + let buf_ptr = slice_from_raw_parts_mut(data.cast::<MaybeUninit<u8>>(), max);
> + // SAFETY: By the hw_random API contract, data points to a bytes buffer `max` bytes long.
> + let buf_ref = unsafe { &mut *buf_ptr };
> +
> + let mut buffer = Buffer {
> + inner: buf_ref,
> + written: 0,
> + };
> +
> + // SAFETY: we set `inner` to point to a valid `T` when initializing.
> + let inner: &T = unsafe { &(*this_ptr).inner };
> + from_result(|| {
> + inner.read(&mut buffer, wait)?;
> + Ok(buffer.written.try_into().unwrap_or(c_int::MAX))
> + })
> + }
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index ea08641919c26faba97cf5dd9b67b0df55fcd698..096b6d9d57d20612864289e87a359331058fb01c 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -74,6 +74,8 @@
> pub mod fs;
> #[cfg(CONFIG_GPU_BUDDY = "y")]
> pub mod gpu;
> +#[cfg(CONFIG_HW_RANDOM = "y")]
> +pub mod hw_random;
> #[cfg(CONFIG_I2C = "y")]
> pub mod i2c;
> pub mod id_pool;
>
> --
> 2.47.3
>
^ permalink raw reply
* Re: [PATCH 2/2] rust: add hw_random module
From: Onur Özkan @ 2026-05-29 19:48 UTC (permalink / raw)
To: Manos Pitsidianakis
Cc: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu, rust-for-linux, linux-kernel,
linux-crypto, manos.pitsidianakis
In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-2-b3153dd90311@pitsidianak.is>
On Fri, 29 May 2026 18:50:27 +0300
Manos Pitsidianakis <manos@pitsidianak.is> wrote:
> Add abstraction for the hardware random number generator core subsystem.
>
> The registration is guarded by an atomic boolean, because we cannot yet
> use IRQ disabling spinlocks in Rust. Once they are supported, we should
> switch to that, because it's theoretically possible to construct a data
> race. In practice I do not think it's possible, since registration
> happens once in driver probe and unregistration happens on driver
> teardown; there shouldn't be multiple threads doing their own thing in
> both cases.
hw_random/core.c seem to use Mutex, why are you not using Mutex<bool> instead of
flipping atomics which doesn't really serialize register & unregister properly?
>
> Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
> ---
> MAINTAINERS | 8 ++
> rust/kernel/hw_random.rs | 320 +++++++++++++++++++++++++++++++++++++++++++++++
> rust/kernel/lib.rs | 2 +
> 3 files changed, 330 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 4f60b323c796fc0968fd67d1c7afee6802990572..a3b372ccbd07c4ae2c735ba31f2acf40472b384a 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -11304,6 +11304,14 @@ F: Documentation/devicetree/bindings/rng/
> F: drivers/char/hw_random/
> F: include/linux/hw_random.h
>
> +HARDWARE RANDOM NUMBER GENERATOR CORE [RUST]
> +M: Manos Pitsidianakis <manos@pitsidianak.is>
> +M: Herbert Xu <herbert@gondor.apana.org.au>
> +L: linux-crypto@vger.kernel.org
> +L: rust-for-linux@vger.kernel.org
> +S: Maintained
> +F: rust/kernel/hw_random.rs
> +
> HARDWARE SPINLOCK CORE
> M: Bjorn Andersson <andersson@kernel.org>
> R: Baolin Wang <baolin.wang7@gmail.com>
> diff --git a/rust/kernel/hw_random.rs b/rust/kernel/hw_random.rs
> new file mode 100644
> index 0000000000000000000000000000000000000000..29fc180b4a3b4157a45c8fdb2d94bf1d9d781a3c
> --- /dev/null
> +++ b/rust/kernel/hw_random.rs
> @@ -0,0 +1,320 @@
> +// SPDX-License-Identifier: GPL-2.0
> +// Author: Manos Pitsidianakis <manos@pitsidianak.is>
> +
> +//! Hardware Random Number Generators
> +//!
> +//! This module provides an abstraction for implementing a hardware random number generator and
> +//! using it with the kernel's `hw_random` system.
> +//!
> +//! # Example
> +//!
> +//! ```no_run
> +//!# fn no_run() {
> +//!# use kernel::hw_random::*;
> +//!# use kernel::str::CString;
> +//!# use kernel::prelude::*;
> +//! #[pin_data]
> +//! struct ExampleHwRng {}
> +//!
> +//! #[vtable]
> +//! impl HwRngImpl for ExampleHwRng {
> +//! fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()> {
> +//! // write zeroes - in your driver, this should write actual data from your hardware.
> +//! data.write(&[0_u8; 8]);
> +//! Ok(())
> +//! }
> +//! }
> +//!
> +//! let name = CString::try_from(c"example_hwrng").unwrap();
> +//! let my_rng = KBox::pin_init(
> +//! HwRng::new(
> +//! name,
> +//! 0,
> +//! try_pin_init!(ExampleHwRng {})
> +//! ),
> +//! GFP_KERNEL
> +//! ).unwrap();
> +//! // Register `my_rng`: after this succeeds, the kernel may call our `HwRngImpl` method at any
> +//! // time.
> +//! my_rng.register().unwrap();
> +//!
> +//! // ...
> +//!
> +//! my_rng.unregister();
> +//!# }
> +//!```
> +
> +use crate::{
> + error::{
> + from_result, //
> + to_result, //
> + VTABLE_DEFAULT_ERROR, //
> + },
> + prelude::*, //
> + str::{
> + CString, //
> + },
> + types::{
> + Opaque, //
> + },
> +};
> +
> +use core::{
> + ffi::{
> + c_int, //
> + c_ushort, //
> + c_void, //
You don't need to put "//" to every line. You can simply do:
a,
b,
c,
//
> + },
> + mem::{
> + MaybeUninit, //
> + },
> + ptr::{
> + slice_from_raw_parts, //
> + slice_from_raw_parts_mut, //
> + },
> + sync::atomic::{
> + AtomicBool, //
> + Ordering, //
> + },
> +};
> +
> +use pin_init::pin_init_from_closure;
> +
> +/// A buffer to write random bytes in using [`Buffer::write`] that tracks how many bytes were
> +/// written.
> +///
> +/// See also [`HwRngImpl::read`].
> +pub struct Buffer<'a> {
> + inner: &'a mut [MaybeUninit<u8>],
> + written: usize,
> +}
> +
> +impl Buffer<'_> {
> + /// Returns `true` if the buffer has been filled.
Either the doc or function name is wrong. Looking at the function logic, this
should be called "is_full"?
> + #[inline]
> + pub const fn is_empty(&self) -> bool {
> + self.written == self.inner.len()
> + }
> +
> + /// Returns the number of bytes that can be written.
> + #[inline]
> + pub const fn len(&self) -> usize {
> + self.inner.len() - self.written
> + }
> +
> + /// Writes bytes from `buf` into buffer and returns the amount of bytes written.
> + #[inline]
> + pub fn write(&mut self, buf: &[u8]) -> usize {
> + let to_copy = self.len().min(buf.len());
> + let ptr = buf.as_ptr();
> + // SAFETY: u8 and MaybeUninit<u8> have the same layout
> + let buf = unsafe { &*slice_from_raw_parts(ptr.cast::<MaybeUninit<u8>>(), to_copy) };
> + self.inner[self.written..][..to_copy].copy_from_slice(buf);
> + self.written += to_copy;
> + to_copy
> + }
> +}
> +
> +/// An adapter type for the registration of hardware random number generators drivers.
> +///
> +/// [`struct hwrng`]: srctree/include/linux/hw_random.h
> +#[pin_data(PinnedDrop)]
> +pub struct HwRng<T: HwRngImpl + 'static> {
> + #[pin]
> + registration: Opaque<bindings::hwrng>,
> + registered: AtomicBool,
> + #[pin]
> + name: CString,
> + #[pin]
> + inner: T,
> +}
> +
> +impl<T: HwRngImpl + 'static> core::ops::Deref for HwRng<T> {
> + type Target = T;
> +
> + #[inline]
> + fn deref(&self) -> &Self::Target {
> + &self.inner
> + }
> +}
> +
> +// SAFETY: HwRng contains a `*const u8` reference but it is opaque for us in Rust.
> +unsafe impl<T: HwRngImpl + 'static> Send for HwRng<T> {}
> +
> +// SAFETY: `HwRng` has no interior mutability from Rust, and C manages it with the rng_mutex lock.
> +unsafe impl<T: HwRngImpl + 'static> Sync for HwRng<T> {}
> +
> +#[pinned_drop]
> +impl<T: HwRngImpl> PinnedDrop for HwRng<T> {
> + fn drop(self: Pin<&mut Self>) {
> + self.unregister();
> + }
> +}
> +
> +#[vtable]
> +/// Trait for the implementation of hardware RNGs.
Doc-comment should come first.
> +pub trait HwRngImpl: Send + Sync {
> + #[inline]
> + /// Initialization callback, can be optionally implemented.
> + fn init(&self) -> Result {
> + build_error!(VTABLE_DEFAULT_ERROR)
> + }
> +
> + #[inline]
> + /// Cleanup callback, can be optionally implemented.
> + fn cleanup(&self) {
> + build_error!(VTABLE_DEFAULT_ERROR)
> + }
> +
> + /// Places random bytes in `data`.
> + fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()>;
> +}
> +
> +impl<T: HwRngImpl + 'static> HwRng<T> {
> + /// Create a new [`HwRng`] without registering it.
> + pub fn new(
> + name: CString,
> + quality: c_ushort,
> + inner: impl PinInit<T, Error>,
> + ) -> impl PinInit<Self, Error> {
> + // We use pin_init_from_closure because we need to store the `slot` address as `priv` field
> + // of `hwrng` struct.
> +
> + // SAFETY:
> + // - when the closure returns `Ok(())`, then it has successfully initialized all fields,
> + // - when it returns `Err(e)`, it does not need to perform any cleanup.
> + unsafe {
> + pin_init_from_closure(move |slot: *mut Self| {
> + inner.__pinned_init(&raw mut (*slot).inner)?;
> +
> + let registration = (&raw mut (*slot).registration).cast::<bindings::hwrng>();
> + registration.write(bindings::hwrng {
> + name: name.as_char_ptr(),
> + read: Some(Self::read_callback),
> + init: if <T as HwRngImpl>::HAS_INIT {
> + Some(Self::init_callback)
> + } else {
> + None
> + },
> + cleanup: if <T as HwRngImpl>::HAS_CLEANUP {
> + Some(Self::cleanup_callback)
> + } else {
> + None
> + },
> + quality,
> + priv_: slot as usize,
> + ..Default::default()
> + });
> +
> + let name_ptr = &raw mut (*slot).name;
> + name_ptr.write(name);
> +
> + let registered = &raw mut (*slot).registered;
> + registered.write(AtomicBool::new(false));
> +
> + // All fields of `HwRng` have been initialized
> + Ok(())
> + })
> + }
> + }
> +
> + /// Register `self` with the `hwrng` subsystem.
> + ///
> + /// After this function successfully returns, the `hwrng` subsystem can start calling the
> + /// [`HwRngImpl`] methods at any time.
> + ///
> + /// [`hwrng_register`]: srctree/include/linux/hw_random.h
> + #[inline]
> + #[doc(alias = "hwrng_register")]
> + pub fn register(&self) -> Result {
> + if self
> + .registered
> + .compare_exchange(false, true, Ordering::SeqCst, Ordering::Acquire)
> + .is_ok()
> + {
> + // SAFETY: `registration` is properly initialized.
> + if let Err(err) = to_result(unsafe {
> + bindings::hwrng_register(self.registration.get().cast::<bindings::hwrng>())
> + }) {
> + self.registered.store(false, Ordering::Release);
> + return Err(err);
> + }
> + }
> + Ok(())
> + }
> +
> + /// Unregister `self` from `hwrng` subsystem.
> + ///
> + /// [`hwrng_unregister`]: srctree/include/linux/hw_random.h
> + #[inline]
> + #[doc(alias = "hwrng_unregister")]
> + pub fn unregister(&self) {
> + if self
> + .registered
> + .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acquire)
> + .is_ok()
> + {
> + // SAFETY: Since `registration` is properly initialized and registered, destroying is
> + // safe.
> + unsafe {
> + bindings::hwrng_unregister(self.registration.get().cast::<bindings::hwrng>())
> + };
> + }
> + }
> +}
> +
> +impl<T: HwRngImpl + 'static> HwRng<T> {
> + extern "C" fn init_callback(ptr: *mut bindings::hwrng) -> c_int {
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
> + let priv_ = unsafe { (*ptr).priv_ };
> + let this_ptr = priv_ as *mut Self;
> +
> + // SAFETY: we set `inner` to point to a valid `T` when initializing.
> + let inner: &T = unsafe { &(*this_ptr).inner };
> + from_result(|| {
> + inner.init()?;
> + Ok(0)
> + })
> + }
> +
> + extern "C" fn cleanup_callback(ptr: *mut bindings::hwrng) {
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
> + let priv_ = unsafe { (*ptr).priv_ };
> + let this_ptr = priv_ as *mut Self;
> +
> + // SAFETY: we set `inner` to point to a valid `T` when initializing.
> + let inner: &T = unsafe { &(*this_ptr).inner };
> + inner.cleanup();
> + }
> +
> + extern "C" fn read_callback(
> + ptr: *mut bindings::hwrng,
> + data: *mut c_void,
> + max: usize,
> + wait: bool,
> + ) -> c_int {
> + if data.is_null() || max == 0 {
> + return 0;
> + }
> +
> + // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
> + let priv_ = unsafe { (*ptr).priv_ };
> + let this_ptr = priv_ as *mut Self;
> +
> + let buf_ptr = slice_from_raw_parts_mut(data.cast::<MaybeUninit<u8>>(), max);
> + // SAFETY: By the hw_random API contract, data points to a bytes buffer `max` bytes long.
> + let buf_ref = unsafe { &mut *buf_ptr };
> +
> + let mut buffer = Buffer {
> + inner: buf_ref,
> + written: 0,
> + };
> +
> + // SAFETY: we set `inner` to point to a valid `T` when initializing.
> + let inner: &T = unsafe { &(*this_ptr).inner };
> + from_result(|| {
> + inner.read(&mut buffer, wait)?;
> + Ok(buffer.written.try_into().unwrap_or(c_int::MAX))
> + })
> + }
> +}
> diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
> index ea08641919c26faba97cf5dd9b67b0df55fcd698..096b6d9d57d20612864289e87a359331058fb01c 100644
> --- a/rust/kernel/lib.rs
> +++ b/rust/kernel/lib.rs
> @@ -74,6 +74,8 @@
> pub mod fs;
> #[cfg(CONFIG_GPU_BUDDY = "y")]
> pub mod gpu;
> +#[cfg(CONFIG_HW_RANDOM = "y")]
> +pub mod hw_random;
> #[cfg(CONFIG_I2C = "y")]
> pub mod i2c;
> pub mod id_pool;
>
> --
> 2.47.3
>
^ permalink raw reply
* Re: [PATCH v2] crypto: sun4i-ss - clamp PRNG seed length to prevent heap overflow
From: Eric Biggers @ 2026-05-29 19:41 UTC (permalink / raw)
To: Corentin Labbe
Cc: Tianchu Chen, herbert, davem, wens, jernej.skrabec, samuel,
linux-crypto, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <20260529173341.GA566433@google.com>
On Fri, May 29, 2026 at 05:33:41PM +0000, Eric Biggers wrote:
> On Fri, May 29, 2026 at 07:10:06PM +0200, Corentin Labbe wrote:
> > Le Fri, May 29, 2026 at 09:10:57AM -0700, Eric Biggers a écrit :
> > > On Fri, May 29, 2026 at 08:08:01AM +0000, Tianchu Chen wrote:
> > > > From: Tianchu Chen <flynnnchen@tencent.com>
> > > >
> > > > sun4i_ss_prng_seed() copies the user-supplied seed into ss->seed
> > > > using the user-provided length with no bounds check. The crypto core
> > > > does not enforce slen <= seedsize before calling into the driver, so a
> > > > userspace caller via AF_ALG setsockopt(ALG_SET_KEY) can pass up to
> > > > sysctl_optmem_max bytes, overflowing the fixed-size buffer and
> > > > corrupting adjacent heap memory.
> > > >
> > > > Clamp the copy length to the buffer size, matching the approach used by
> > > > loongson-rng for oversized seeds.
> > > >
> > > > Discovered by Atuin - Automated Vulnerability Discovery Engine.
> > > >
> > > > Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator")
> > > > Cc: stable@vger.kernel.org
> > > > Signed-off-by: Tianchu Chen <flynnnchen@tencent.com>
> > > > ---
> > > > v2: Silently clamp oversized seeds with min_t instead of returning
> > > > -EINVAL (Herbert Xu).
> > >
> > > sun4i-ss-prng.c is useless, is still broken, and should just be deleted.
> >
> > Hello
> >
> > useless ? clearly no, it helped a lot on devices where it is.
>
> The only way this code is reachable is via "rng" algorithm type in
> AF_ALG, which is almost never used. Everyone just uses the regular
> Linux RNG (/dev/random etc) instead, as they should.
>
> In fact, anyone were to accidentally use this it would be a security
> vulnerability, seeing as sun4i_ss_prng_generate() doesn't actually fill
> in all the bytes that were requested. It also doesn't wait for the FIFO
> to be ready when reading data from it.
>
> Is it possible that there's a misunderstanding here and you think this
> provides entropy to the regular Linux RNG? It doesn't. hwrng does
> that, crypto_rng does not.
>
> The correct fix is to mark CRYPTO_DEV_SUN8I_CE_PRNG as BROKEN or remove
> it entirely. Doing otherwise is not responsible.
Looking into it a bit more, just removing CRYPTO_DEV_SUN4I_SS_PRNG is
clearly the way to go. This patch does it:
https://lore.kernel.org/linux-crypto/20260529193648.18172-1-ebiggers@kernel.org
- Eric
^ permalink raw reply
* [PATCH] crypto: sun4i-ss - Remove insecure and unused rng_alg
From: Eric Biggers @ 2026-05-29 19:36 UTC (permalink / raw)
To: linux-crypto, Herbert Xu
Cc: linux-sunxi, linux-arm-kernel, linux-kernel, Chen-Yu Tsai,
Jernej Skrabec, Samuel Holland, Corentin Labbe, Eric Biggers,
stable
Remove sun4i_ss_rng, as it is insecure and unused:
- It has multiple vulnerabilities. sun4i_ss_prng_seed() is missing
locking and has a buffer overflow. sun4i_ss_prng_generate() fails to
fill the entire buffer with cryptographic random bytes, because it
rounds the destination length down and also doesn't actually wait for
the hardware to be ready before pulling bytes from it.
- No user of this code is known. It's usable only theoretically via the
"rng" algorithm type of AF_ALG. But userspace actually just uses the
actual Linux RNG (/dev/random etc) instead. And rng_algs don't
contribute entropy to the actual Linux RNG either. (This may have
been confused with hwrng, which does contribute entropy.)
Fixes: b8ae5c7387ad ("crypto: sun4i-ss - support the Security System PRNG")
Cc: stable@vger.kernel.org
Cc: Corentin Labbe <clabbe.montjoie@gmail.com>
Signed-off-by: Eric Biggers <ebiggers@kernel.org>
---
arch/arm/configs/sunxi_defconfig | 1 -
drivers/crypto/allwinner/Kconfig | 8 ---
drivers/crypto/allwinner/sun4i-ss/Makefile | 1 -
.../crypto/allwinner/sun4i-ss/sun4i-ss-core.c | 44 ------------
.../crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 69 -------------------
drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h | 20 ------
6 files changed, 143 deletions(-)
delete mode 100644 drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
diff --git a/arch/arm/configs/sunxi_defconfig b/arch/arm/configs/sunxi_defconfig
index a83d29fed175..f4b8d8f7dbef 100644
--- a/arch/arm/configs/sunxi_defconfig
+++ b/arch/arm/configs/sunxi_defconfig
@@ -168,11 +168,10 @@ CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ISO8859_1=y
CONFIG_CRYPTO_DEV_SUN4I_SS=y
-CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG=y
CONFIG_CRYPTO_DEV_SUN8I_CE=y
CONFIG_CRYPTO_DEV_SUN8I_SS=y
CONFIG_DMA_CMA=y
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_FS=y
diff --git a/drivers/crypto/allwinner/Kconfig b/drivers/crypto/allwinner/Kconfig
index b8e75210a0e3..06ea0e9fe6f2 100644
--- a/drivers/crypto/allwinner/Kconfig
+++ b/drivers/crypto/allwinner/Kconfig
@@ -22,18 +22,10 @@ config CRYPTO_DEV_SUN4I_SS
and SHA1 and MD5 hash algorithms.
To compile this driver as a module, choose M here: the module
will be called sun4i-ss.
-config CRYPTO_DEV_SUN4I_SS_PRNG
- bool "Support for Allwinner Security System PRNG"
- depends on CRYPTO_DEV_SUN4I_SS
- select CRYPTO_RNG
- help
- Select this option if you want to provide kernel-side support for
- the Pseudo-Random Number Generator found in the Security System.
-
config CRYPTO_DEV_SUN4I_SS_DEBUG
bool "Enable sun4i-ss stats"
depends on CRYPTO_DEV_SUN4I_SS
depends on DEBUG_FS
help
diff --git a/drivers/crypto/allwinner/sun4i-ss/Makefile b/drivers/crypto/allwinner/sun4i-ss/Makefile
index c0a2797d3168..06a9ae81f9f8 100644
--- a/drivers/crypto/allwinner/sun4i-ss/Makefile
+++ b/drivers/crypto/allwinner/sun4i-ss/Makefile
@@ -1,4 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_CRYPTO_DEV_SUN4I_SS) += sun4i-ss.o
sun4i-ss-y += sun4i-ss-core.o sun4i-ss-hash.o sun4i-ss-cipher.o
-sun4i-ss-$(CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG) += sun4i-ss-prng.o
diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
index 813c4bc6312a..35ef0930e77f 100644
--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
+++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-core.c
@@ -211,27 +211,10 @@ static struct sun4i_ss_alg_template ss_algs[] = {
.cra_init = sun4i_ss_cipher_init,
.cra_exit = sun4i_ss_cipher_exit,
}
}
},
-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
-{
- .type = CRYPTO_ALG_TYPE_RNG,
- .alg.rng = {
- .base = {
- .cra_name = "stdrng",
- .cra_driver_name = "sun4i_ss_rng",
- .cra_priority = 300,
- .cra_ctxsize = 0,
- .cra_module = THIS_MODULE,
- },
- .generate = sun4i_ss_prng_generate,
- .seed = sun4i_ss_prng_seed,
- .seedsize = SS_SEED_LEN / BITS_PER_BYTE,
- }
-},
-#endif
};
static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
{
unsigned int i;
@@ -245,18 +228,10 @@ static int sun4i_ss_debugfs_show(struct seq_file *seq, void *v)
ss_algs[i].alg.crypto.base.cra_driver_name,
ss_algs[i].alg.crypto.base.cra_name,
ss_algs[i].stat_req, ss_algs[i].stat_opti, ss_algs[i].stat_fb,
ss_algs[i].stat_bytes);
break;
-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
- case CRYPTO_ALG_TYPE_RNG:
- seq_printf(seq, "%s %s reqs=%lu tsize=%lu\n",
- ss_algs[i].alg.rng.base.cra_driver_name,
- ss_algs[i].alg.rng.base.cra_name,
- ss_algs[i].stat_req, ss_algs[i].stat_bytes);
- break;
-#endif
case CRYPTO_ALG_TYPE_AHASH:
seq_printf(seq, "%s %s reqs=%lu\n",
ss_algs[i].alg.hash.halg.base.cra_driver_name,
ss_algs[i].alg.hash.halg.base.cra_name,
ss_algs[i].stat_req);
@@ -471,19 +446,10 @@ static int sun4i_ss_probe(struct platform_device *pdev)
dev_err(ss->dev, "Fail to register %s\n",
ss_algs[i].alg.hash.halg.base.cra_name);
goto error_alg;
}
break;
-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
- case CRYPTO_ALG_TYPE_RNG:
- err = crypto_register_rng(&ss_algs[i].alg.rng);
- if (err) {
- dev_err(ss->dev, "Fail to register %s\n",
- ss_algs[i].alg.rng.base.cra_name);
- }
- break;
-#endif
}
}
/* Ignore error of debugfs */
ss->dbgfs_dir = debugfs_create_dir("sun4i-ss", NULL);
@@ -499,15 +465,10 @@ static int sun4i_ss_probe(struct platform_device *pdev)
crypto_unregister_skcipher(&ss_algs[i].alg.crypto);
break;
case CRYPTO_ALG_TYPE_AHASH:
crypto_unregister_ahash(&ss_algs[i].alg.hash);
break;
-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
- case CRYPTO_ALG_TYPE_RNG:
- crypto_unregister_rng(&ss_algs[i].alg.rng);
- break;
-#endif
}
}
error_pm:
sun4i_ss_pm_exit(ss);
return err;
@@ -524,15 +485,10 @@ static void sun4i_ss_remove(struct platform_device *pdev)
crypto_unregister_skcipher(&ss_algs[i].alg.crypto);
break;
case CRYPTO_ALG_TYPE_AHASH:
crypto_unregister_ahash(&ss_algs[i].alg.hash);
break;
-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
- case CRYPTO_ALG_TYPE_RNG:
- crypto_unregister_rng(&ss_algs[i].alg.rng);
- break;
-#endif
}
}
sun4i_ss_pm_exit(ss);
}
diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
deleted file mode 100644
index 491fcb7b81b4..000000000000
--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+++ /dev/null
@@ -1,69 +0,0 @@
-// SPDX-License-Identifier: GPL-2.0-or-later
-#include "sun4i-ss.h"
-
-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
- unsigned int slen)
-{
- struct sun4i_ss_alg_template *algt;
- struct rng_alg *alg = crypto_rng_alg(tfm);
-
- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
- memcpy(algt->ss->seed, seed, slen);
-
- return 0;
-}
-
-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int dlen)
-{
- struct sun4i_ss_alg_template *algt;
- struct rng_alg *alg = crypto_rng_alg(tfm);
- int i, err;
- u32 v;
- u32 *data = (u32 *)dst;
- const u32 mode = SS_OP_PRNG | SS_PRNG_CONTINUE | SS_ENABLED;
- size_t len;
- struct sun4i_ss_ctx *ss;
- unsigned int todo = (dlen / 4) * 4;
-
- algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
- ss = algt->ss;
-
- err = pm_runtime_resume_and_get(ss->dev);
- if (err < 0)
- return err;
-
- if (IS_ENABLED(CONFIG_CRYPTO_DEV_SUN4I_SS_DEBUG)) {
- algt->stat_req++;
- algt->stat_bytes += todo;
- }
-
- spin_lock_bh(&ss->slock);
-
- writel(mode, ss->base + SS_CTL);
-
- while (todo > 0) {
- /* write the seed */
- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++)
- writel(ss->seed[i], ss->base + SS_KEY0 + i * 4);
-
- /* Read the random data */
- len = min_t(size_t, SS_DATA_LEN / BITS_PER_BYTE, todo);
- readsl(ss->base + SS_TXFIFO, data, len / 4);
- data += len / 4;
- todo -= len;
-
- /* Update the seed */
- for (i = 0; i < SS_SEED_LEN / BITS_PER_LONG; i++) {
- v = readl(ss->base + SS_KEY0 + i * 4);
- ss->seed[i] = v;
- }
- }
-
- writel(0, ss->base + SS_CTL);
- spin_unlock_bh(&ss->slock);
-
- pm_runtime_put(ss->dev);
-
- return 0;
-}
diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
index 6c5d4aa6453c..f7d1c79ac677 100644
--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
+++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss.h
@@ -29,12 +29,10 @@
#include <crypto/hash.h>
#include <crypto/internal/hash.h>
#include <crypto/internal/skcipher.h>
#include <crypto/aes.h>
#include <crypto/internal/des.h>
-#include <crypto/internal/rng.h>
-#include <crypto/rng.h>
#define SS_CTL 0x00
#define SS_KEY0 0x04
#define SS_KEY1 0x08
#define SS_KEY2 0x0C
@@ -60,14 +58,10 @@
#define SS_RXFIFO 0x200
#define SS_TXFIFO 0x204
/* SS_CTL configuration values */
-/* PRNG generator mode - bit 15 */
-#define SS_PRNG_ONESHOT (0 << 15)
-#define SS_PRNG_CONTINUE (1 << 15)
-
/* IV mode for hash */
#define SS_IV_ARBITRARY (1 << 14)
/* SS operation mode - bits 12-13 */
#define SS_ECB (0 << 12)
@@ -92,18 +86,14 @@
#define SS_OP_AES (0 << 4)
#define SS_OP_DES (1 << 4)
#define SS_OP_3DES (2 << 4)
#define SS_OP_SHA1 (3 << 4)
#define SS_OP_MD5 (4 << 4)
-#define SS_OP_PRNG (5 << 4)
/* Data end bit - bit 2 */
#define SS_DATA_END (1 << 2)
-/* PRNG start bit - bit 1 */
-#define SS_PRNG_START (1 << 1)
-
/* SS Enable bit - bit 0 */
#define SS_DISABLED (0 << 0)
#define SS_ENABLED (1 << 0)
/* SS_FCSR configuration values */
@@ -126,13 +116,10 @@
#define SS_RXFIFO_EMP_INT_PENDING (1 << 10)
#define SS_TXFIFO_AVA_INT_PENDING (1 << 8)
#define SS_RXFIFO_EMP_INT_ENABLE (1 << 2)
#define SS_TXFIFO_AVA_INT_ENABLE (1 << 0)
-#define SS_SEED_LEN 192
-#define SS_DATA_LEN 160
-
/*
* struct ss_variant - Describe SS hardware variant
* @sha1_in_be: The SHA1 digest is given by SS in BE, and so need to be inverted.
*/
struct ss_variant {
@@ -149,24 +136,20 @@ struct sun4i_ss_ctx {
struct device *dev;
struct resource *res;
char buf[4 * SS_RX_MAX];/* buffer for linearize SG src */
char bufo[4 * SS_TX_MAX]; /* buffer for linearize SG dst */
spinlock_t slock; /* control the use of the device */
-#ifdef CONFIG_CRYPTO_DEV_SUN4I_SS_PRNG
- u32 seed[SS_SEED_LEN / BITS_PER_LONG];
-#endif
struct dentry *dbgfs_dir;
struct dentry *dbgfs_stats;
};
struct sun4i_ss_alg_template {
u32 type;
u32 mode;
union {
struct skcipher_alg crypto;
struct ahash_alg hash;
- struct rng_alg rng;
} alg;
struct sun4i_ss_ctx *ss;
unsigned long stat_req;
unsigned long stat_fb;
unsigned long stat_bytes;
@@ -229,8 +212,5 @@ int sun4i_ss_aes_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
int sun4i_ss_des_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
int sun4i_ss_des3_setkey(struct crypto_skcipher *tfm, const u8 *key,
unsigned int keylen);
-int sun4i_ss_prng_generate(struct crypto_rng *tfm, const u8 *src,
- unsigned int slen, u8 *dst, unsigned int dlen);
-int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed, unsigned int slen);
base-commit: 49e05bb00f2e8168695f7af4d694c39e1423e8a2
--
2.54.0
^ permalink raw reply related
* Re: [PATCH v2] crypto: sun4i-ss - clamp PRNG seed length to prevent heap overflow
From: Eric Biggers @ 2026-05-29 17:33 UTC (permalink / raw)
To: Corentin Labbe
Cc: Tianchu Chen, herbert, davem, wens, jernej.skrabec, samuel,
linux-crypto, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <ahnIbpBLyn5z_siT@Red>
On Fri, May 29, 2026 at 07:10:06PM +0200, Corentin Labbe wrote:
> Le Fri, May 29, 2026 at 09:10:57AM -0700, Eric Biggers a écrit :
> > On Fri, May 29, 2026 at 08:08:01AM +0000, Tianchu Chen wrote:
> > > From: Tianchu Chen <flynnnchen@tencent.com>
> > >
> > > sun4i_ss_prng_seed() copies the user-supplied seed into ss->seed
> > > using the user-provided length with no bounds check. The crypto core
> > > does not enforce slen <= seedsize before calling into the driver, so a
> > > userspace caller via AF_ALG setsockopt(ALG_SET_KEY) can pass up to
> > > sysctl_optmem_max bytes, overflowing the fixed-size buffer and
> > > corrupting adjacent heap memory.
> > >
> > > Clamp the copy length to the buffer size, matching the approach used by
> > > loongson-rng for oversized seeds.
> > >
> > > Discovered by Atuin - Automated Vulnerability Discovery Engine.
> > >
> > > Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator")
> > > Cc: stable@vger.kernel.org
> > > Signed-off-by: Tianchu Chen <flynnnchen@tencent.com>
> > > ---
> > > v2: Silently clamp oversized seeds with min_t instead of returning
> > > -EINVAL (Herbert Xu).
> >
> > sun4i-ss-prng.c is useless, is still broken, and should just be deleted.
>
> Hello
>
> useless ? clearly no, it helped a lot on devices where it is.
The only way this code is reachable is via "rng" algorithm type in
AF_ALG, which is almost never used. Everyone just uses the regular
Linux RNG (/dev/random etc) instead, as they should.
In fact, anyone were to accidentally use this it would be a security
vulnerability, seeing as sun4i_ss_prng_generate() doesn't actually fill
in all the bytes that were requested. It also doesn't wait for the FIFO
to be ready when reading data from it.
Is it possible that there's a misunderstanding here and you think this
provides entropy to the regular Linux RNG? It doesn't. hwrng does
that, crypto_rng does not.
The correct fix is to mark CRYPTO_DEV_SUN8I_CE_PRNG as BROKEN or remove
it entirely. Doing otherwise is not responsible.
- Eric
^ permalink raw reply
* Re: [PATCH v2] crypto: sun4i-ss - clamp PRNG seed length to prevent heap overflow
From: Corentin Labbe @ 2026-05-29 17:10 UTC (permalink / raw)
To: Eric Biggers
Cc: Tianchu Chen, herbert, davem, wens, jernej.skrabec, samuel,
linux-crypto, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <20260529161057.GA2706@sol>
Le Fri, May 29, 2026 at 09:10:57AM -0700, Eric Biggers a écrit :
> On Fri, May 29, 2026 at 08:08:01AM +0000, Tianchu Chen wrote:
> > From: Tianchu Chen <flynnnchen@tencent.com>
> >
> > sun4i_ss_prng_seed() copies the user-supplied seed into ss->seed
> > using the user-provided length with no bounds check. The crypto core
> > does not enforce slen <= seedsize before calling into the driver, so a
> > userspace caller via AF_ALG setsockopt(ALG_SET_KEY) can pass up to
> > sysctl_optmem_max bytes, overflowing the fixed-size buffer and
> > corrupting adjacent heap memory.
> >
> > Clamp the copy length to the buffer size, matching the approach used by
> > loongson-rng for oversized seeds.
> >
> > Discovered by Atuin - Automated Vulnerability Discovery Engine.
> >
> > Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator")
> > Cc: stable@vger.kernel.org
> > Signed-off-by: Tianchu Chen <flynnnchen@tencent.com>
> > ---
> > v2: Silently clamp oversized seeds with min_t instead of returning
> > -EINVAL (Herbert Xu).
>
> sun4i-ss-prng.c is useless, is still broken, and should just be deleted.
Hello
useless ? clearly no, it helped a lot on devices where it is.
Regards
^ permalink raw reply
* Re: [PATCH 05/29] crypto: talitos - Prepare crypto implementation file splitting
From: David Laight @ 2026-05-29 16:24 UTC (permalink / raw)
To: Christophe Leroy (CS GROUP)
Cc: Paul Louvel, Herbert Xu, David S. Miller, Thomas Petazzoni,
Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <22245899-e046-41f1-8707-94f172b310e9@kernel.org>
On Fri, 29 May 2026 15:21:39 +0200
"Christophe Leroy (CS GROUP)" <chleroy@kernel.org> wrote:
> Hi Paul,
>
> Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> > Remove the static qualifier on multiple function that will be called
> > inside each crypto implementation file.
> > Add them to the main driver header file.
>
> I didn't have time to look at the generated text yet but I'm a bit
> sceptic with this change, or more than the change itself, about its
> purpose. And even more when I see patches 24 and 25.
>
> Most functions here are small helpers. To be shared between several C
> files they deserve becoming static inlines in talitos.h, not global
> functions.
>
> Indeed, most of the time is_sec1 is known at build time because in most
> cases has_ftr_sec1() will constant fold into true or false during build.
> This is because it is very unlikely that someone build a kernel to run
> on both MPC 82xx and MPC 83xx at the same time. Therefore it is really
> unlikely that this in built with both CRYPTO_DEV_TALITOS1 and
> CRYPTO_DEV_TALITOS2 at the same time.
>
> I can understand for a function like talitos_submit() but not for
> functions like to_talitos_ptr() or to_talitos_ptr_ext_set() whose
> purpose is really to get inlined into the caller.
I also spotted a couple of indirect calls being added.
They will be slower than you might think.
If there are only two options it is better to use an 'if'.
-- David
>
> Christophe
>
>
> >
> > Add the common structures too.
> >
> > Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
> > ---
> > drivers/crypto/talitos/talitos.c | 123 ++++++++++++++-------------------------
> > drivers/crypto/talitos/talitos.h | 91 +++++++++++++++++++++++++++++
> > 2 files changed, 135 insertions(+), 79 deletions(-)
> >
> > diff --git a/drivers/crypto/talitos/talitos.c b/drivers/crypto/talitos/talitos.c
> > index f5feff8f7d3d..3fc1069062da 100644
> > --- a/drivers/crypto/talitos/talitos.c
> > +++ b/drivers/crypto/talitos/talitos.c
> > @@ -40,8 +40,8 @@
> >
> > #include "talitos.h"
> >
> > -static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> > - unsigned int len, bool is_sec1)
> > +void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> > + unsigned int len, bool is_sec1)
> > {
> > ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr));
> > if (is_sec1) {
> > @@ -52,8 +52,8 @@ static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> > }
> > }
> >
> > -static void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
> > - struct talitos_ptr *src_ptr, bool is_sec1)
> > +void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
> > + struct talitos_ptr *src_ptr, bool is_sec1)
> > {
> > dst_ptr->ptr = src_ptr->ptr;
> > if (is_sec1) {
> > @@ -64,8 +64,8 @@ static void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
> > }
> > }
> >
> > -static unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr,
> > - bool is_sec1)
> > +unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr,
> > + bool is_sec1)
> > {
> > if (is_sec1)
> > return be16_to_cpu(ptr->len1);
> > @@ -73,14 +73,14 @@ static unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr,
> > return be16_to_cpu(ptr->len);
> > }
> >
> > -static void to_talitos_ptr_ext_set(struct talitos_ptr *ptr, u8 val,
> > - bool is_sec1)
> > +void to_talitos_ptr_ext_set(struct talitos_ptr *ptr, u8 val,
> > + bool is_sec1)
> > {
> > if (!is_sec1)
> > ptr->j_extent = val;
> > }
> >
> > -static void to_talitos_ptr_ext_or(struct talitos_ptr *ptr, u8 val, bool is_sec1)
> > +void to_talitos_ptr_ext_or(struct talitos_ptr *ptr, u8 val, bool is_sec1)
> > {
> > if (!is_sec1)
> > ptr->j_extent |= val;
> > @@ -102,15 +102,15 @@ static void __map_single_talitos_ptr(struct device *dev,
> > to_talitos_ptr(ptr, dma_addr, len, is_sec1);
> > }
> >
> > -static void map_single_talitos_ptr(struct device *dev,
> > - struct talitos_ptr *ptr,
> > - unsigned int len, void *data,
> > - enum dma_data_direction dir)
> > +void map_single_talitos_ptr(struct device *dev,
> > + struct talitos_ptr *ptr,
> > + unsigned int len, void *data,
> > + enum dma_data_direction dir)
> > {
> > __map_single_talitos_ptr(dev, ptr, len, data, dir, 0);
> > }
> >
> > -static void map_single_talitos_ptr_nosync(struct device *dev,
> > +void map_single_talitos_ptr_nosync(struct device *dev,
> > struct talitos_ptr *ptr,
> > unsigned int len, void *data,
> > enum dma_data_direction dir)
> > @@ -122,9 +122,9 @@ static void map_single_talitos_ptr_nosync(struct device *dev,
> > /*
> > * unmap bus single (contiguous) h/w descriptor pointer
> > */
> > -static void unmap_single_talitos_ptr(struct device *dev,
> > - struct talitos_ptr *ptr,
> > - enum dma_data_direction dir)
> > +void unmap_single_talitos_ptr(struct device *dev,
> > + struct talitos_ptr *ptr,
> > + enum dma_data_direction dir)
> > {
> > struct talitos_private *priv = dev_get_drvdata(dev);
> > bool is_sec1 = has_ftr_sec1(priv);
> > @@ -303,11 +303,11 @@ static void dma_map_request(struct device *dev, struct talitos_request *request,
> > * callback must check err and feedback in descriptor header
> > * for device processing status.
> > */
> > -static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
> > - void (*callback)(struct device *dev,
> > - struct talitos_desc *desc,
> > - void *context, int error),
> > - void *context)
> > +int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
> > + void (*callback)(struct device *dev,
> > + struct talitos_desc *desc,
> > + void *context, int error),
> > + void *context)
> > {
> > struct talitos_private *priv = dev_get_drvdata(dev);
> > struct talitos_request *request;
> > @@ -830,24 +830,6 @@ DEF_TALITOS2_INTERRUPT(ch1_3, TALITOS2_ISR_CH_1_3_DONE, TALITOS2_ISR_CH_1_3_ERR,
> > * HMAC_SNOOP_NO_AFEA (HSNA) instead of type IPSEC_ESP
> > */
> > #define TALITOS_CRA_PRIORITY_AEAD_HSNA (TALITOS_CRA_PRIORITY - 1)
> > -#ifdef CONFIG_CRYPTO_DEV_TALITOS2
> > -#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE)
> > -#else
> > -#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA256_BLOCK_SIZE)
> > -#endif
> > -#define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
> > -
> > -struct talitos_ctx {
> > - struct device *dev;
> > - int ch;
> > - __be32 desc_hdr_template;
> > - u8 key[TALITOS_MAX_KEY_SIZE];
> > - u8 iv[TALITOS_MAX_IV_LENGTH];
> > - dma_addr_t dma_key;
> > - unsigned int keylen;
> > - unsigned int enckeylen;
> > - unsigned int authkeylen;
> > -};
> >
> > #define HASH_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE
> > #define TALITOS_MDEU_MAX_CONTEXT_SIZE TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512
> > @@ -939,7 +921,7 @@ static int aead_des3_setkey(struct crypto_aead *authenc,
> > return err;
> > }
> >
> > -static void talitos_sg_unmap(struct device *dev,
> > +void talitos_sg_unmap(struct device *dev,
> > struct talitos_edesc *edesc,
> > struct scatterlist *src,
> > struct scatterlist *dst,
> > @@ -1124,7 +1106,7 @@ static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count,
> > return count;
> > }
> >
> > -static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> > +int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> > unsigned int len, struct talitos_edesc *edesc,
> > struct talitos_ptr *ptr, int sg_count,
> > unsigned int offset, int tbl_off, int elen,
> > @@ -1161,7 +1143,7 @@ static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> > return sg_count;
> > }
> >
> > -static int talitos_sg_map(struct device *dev, struct scatterlist *src,
> > +int talitos_sg_map(struct device *dev, struct scatterlist *src,
> > unsigned int len, struct talitos_edesc *edesc,
> > struct talitos_ptr *ptr, int sg_count,
> > unsigned int offset, int tbl_off)
> > @@ -1299,17 +1281,17 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
> > /*
> > * allocate and map the extended descriptor
> > */
> > -static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
> > - struct scatterlist *src,
> > - struct scatterlist *dst,
> > - u8 *iv,
> > - unsigned int assoclen,
> > - unsigned int cryptlen,
> > - unsigned int authsize,
> > - unsigned int ivsize,
> > - int icv_stashing,
> > - u32 cryptoflags,
> > - bool encrypt)
> > +struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
> > + struct scatterlist *src,
> > + struct scatterlist *dst,
> > + u8 *iv,
> > + unsigned int assoclen,
> > + unsigned int cryptlen,
> > + unsigned int authsize,
> > + unsigned int ivsize,
> > + int icv_stashing,
> > + u32 cryptoflags,
> > + bool encrypt)
> > {
> > struct talitos_edesc *edesc;
> > int src_nents, dst_nents, alloc_len, dma_len, src_len, dst_len;
> > @@ -2172,18 +2154,6 @@ static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
> > return 0;
> > }
> >
> > -
> > -struct talitos_alg_template {
> > - u32 type;
> > - u32 priority;
> > - union {
> > - struct skcipher_alg skcipher;
> > - struct ahash_alg hash;
> > - struct aead_alg aead;
> > - } alg;
> > - __be32 desc_hdr_template;
> > -};
> > -
> > static struct talitos_alg_template driver_algs[] = {
> > /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */
> > { .type = CRYPTO_ALG_TYPE_AEAD,
> > @@ -2998,14 +2968,8 @@ static struct talitos_alg_template driver_algs[] = {
> > }
> > };
> >
> > -struct talitos_crypto_alg {
> > - struct list_head entry;
> > - struct device *dev;
> > - struct talitos_alg_template algt;
> > -};
> > -
> > -static int talitos_init_common(struct talitos_ctx *ctx,
> > - struct talitos_crypto_alg *talitos_alg)
> > +int talitos_init_common(struct talitos_ctx *ctx,
> > + struct talitos_crypto_alg *talitos_alg)
> > {
> > struct talitos_private *priv;
> >
> > @@ -3066,7 +3030,7 @@ static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
> > return talitos_init_common(ctx, talitos_alg);
> > }
> >
> > -static void talitos_cra_exit(struct crypto_tfm *tfm)
> > +void talitos_cra_exit(struct crypto_tfm *tfm)
> > {
> > struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
> > struct device *dev = ctx->dev;
> > @@ -3080,7 +3044,7 @@ static void talitos_cra_exit(struct crypto_tfm *tfm)
> > * type and primary/secondary execution units required match the hw
> > * capabilities description provided in the device tree node.
> > */
> > -static int hw_supports(struct device *dev, __be32 desc_hdr_template)
> > +int talitos_hw_supports(struct device *dev, __be32 desc_hdr_template)
> > {
> > struct talitos_private *priv = dev_get_drvdata(dev);
> > int ret;
> > @@ -3117,7 +3081,7 @@ static void talitos_remove(struct platform_device *ofdev)
> > list_del(&t_alg->entry);
> > }
> >
> > - if (hw_supports(dev, DESC_HDR_SEL0_RNG))
> > + if (talitos_hw_supports(dev, DESC_HDR_SEL0_RNG))
> > talitos_unregister_rng(dev);
> >
> > for (i = 0; i < 2; i++)
> > @@ -3426,7 +3390,7 @@ static int talitos_probe(struct platform_device *ofdev)
> > }
> >
> > /* register the RNG, if available */
> > - if (hw_supports(dev, DESC_HDR_SEL0_RNG)) {
> > + if (talitos_hw_supports(dev, DESC_HDR_SEL0_RNG)) {
> > err = talitos_register_rng(dev);
> > if (err) {
> > dev_err(dev, "failed to register hwrng: %d\n", err);
> > @@ -3437,7 +3401,8 @@ static int talitos_probe(struct platform_device *ofdev)
> >
> > /* register crypto algorithms the device supports */
> > for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
> > - if (hw_supports(dev, driver_algs[i].desc_hdr_template)) {
> > + if (talitos_hw_supports(dev,
> > + driver_algs[i].desc_hdr_template)) {
> > struct talitos_crypto_alg *t_alg;
> > struct crypto_alg *alg = NULL;
> >
> > diff --git a/drivers/crypto/talitos/talitos.h b/drivers/crypto/talitos/talitos.h
> > index fa8c71b1f90f..1f81d336dae8 100644
> > --- a/drivers/crypto/talitos/talitos.h
> > +++ b/drivers/crypto/talitos/talitos.h
> > @@ -5,7 +5,13 @@
> > * Copyright (c) 2006-2011 Freescale Semiconductor, Inc.
> > */
> >
> > +#include <crypto/aes.h>
> > +#include <crypto/internal/aead.h>
> > +#include <crypto/internal/hash.h>
> > +#include <crypto/internal/skcipher.h>
> > +#include <crypto/sha2.h>
> > #include <linux/device.h>
> > +#include <linux/dma-mapping.h>
> > #include <linux/hw_random.h>
> > #include <linux/interrupt.h>
> > #include <linux/scatterlist.h>
> > @@ -19,6 +25,13 @@
> > #define PRIMARY_EU(desc_hdr) ((be32_to_cpu(desc_hdr) >> 28) & 0xf)
> > #define SECONDARY_EU(desc_hdr) ((be32_to_cpu(desc_hdr) >> 16) & 0xf)
> >
> > +#ifdef CONFIG_CRYPTO_DEV_TALITOS2
> > +#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE)
> > +#else
> > +#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA256_BLOCK_SIZE)
> > +#endif
> > +#define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
> > +
> > /* descriptor pointer entry */
> > struct talitos_ptr {
> > union {
> > @@ -174,6 +187,35 @@ struct talitos_private {
> >
> > };
> >
> > +struct talitos_ctx {
> > + struct device *dev;
> > + int ch;
> > + __be32 desc_hdr_template;
> > + u8 key[TALITOS_MAX_KEY_SIZE];
> > + u8 iv[TALITOS_MAX_IV_LENGTH];
> > + dma_addr_t dma_key;
> > + unsigned int keylen;
> > + unsigned int enckeylen;
> > + unsigned int authkeylen;
> > +};
> > +
> > +struct talitos_alg_template {
> > + u32 type;
> > + u32 priority;
> > + union {
> > + struct skcipher_alg skcipher;
> > + struct ahash_alg hash;
> > + struct aead_alg aead;
> > + } alg;
> > + __be32 desc_hdr_template;
> > +};
> > +
> > +struct talitos_crypto_alg {
> > + struct list_head entry;
> > + struct device *dev;
> > + struct talitos_alg_template algt;
> > +};
> > +
> > /* .features flag */
> > #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001
> > #define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
> > @@ -432,6 +474,55 @@ static inline bool has_ftr_sec1(struct talitos_private *priv)
> > #define DESC_PTR_LNKTBL_RET 0x02
> > #define DESC_PTR_LNKTBL_NEXT 0x01
> >
> > +void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> > + unsigned int len, bool is_sec1);
> > +void copy_talitos_ptr(struct talitos_ptr *dst_ptr, struct talitos_ptr *src_ptr,
> > + bool is_sec1);
> > +unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr, bool is_sec1);
> > +void to_talitos_ptr_ext_set(struct talitos_ptr *ptr, u8 val, bool is_sec1);
> > +void to_talitos_ptr_ext_or(struct talitos_ptr *ptr, u8 val, bool is_sec1);
> > +
> > +void map_single_talitos_ptr(struct device *dev, struct talitos_ptr *ptr,
> > + unsigned int len, void *data,
> > + enum dma_data_direction dir);
> > +void map_single_talitos_ptr_nosync(struct device *dev, struct talitos_ptr *ptr,
> > + unsigned int len, void *data,
> > + enum dma_data_direction dir);
> > +void unmap_single_talitos_ptr(struct device *dev, struct talitos_ptr *ptr,
> > + enum dma_data_direction dir);
> > +
> > +int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
> > + void (*callback)(struct device *dev,
> > + struct talitos_desc *desc, void *context,
> > + int error),
> > + void *context);
> > +
> > +void talitos_sg_unmap(struct device *dev, struct talitos_edesc *edesc,
> > + struct scatterlist *src, struct scatterlist *dst,
> > + unsigned int len, unsigned int offset);
> > +int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> > + unsigned int len, struct talitos_edesc *edesc,
> > + struct talitos_ptr *ptr, int sg_count,
> > + unsigned int offset, int tbl_off, int elen, bool force,
> > + int align);
> > +int talitos_sg_map(struct device *dev, struct scatterlist *src,
> > + unsigned int len, struct talitos_edesc *edesc,
> > + struct talitos_ptr *ptr, int sg_count, unsigned int offset,
> > + int tbl_off);
> > +
> > +struct talitos_edesc *
> > +talitos_edesc_alloc(struct device *dev, struct scatterlist *src,
> > + struct scatterlist *dst, u8 *iv, unsigned int assoclen,
> > + unsigned int cryptlen, unsigned int authsize,
> > + unsigned int ivsize, int icv_stashing, u32 cryptoflags,
> > + bool encrypt);
> > +
> > +int talitos_hw_supports(struct device *dev, __be32 desc_hdr_template);
> > +
> > +int talitos_init_common(struct talitos_ctx *ctx,
> > + struct talitos_crypto_alg *talitos_alg);
> > +void talitos_cra_exit(struct crypto_tfm *tfm);
> > +
> > /* Hardware RNG */
> >
> > int talitos_register_rng(struct device *dev);
> >
>
>
^ permalink raw reply
* Re: [PATCH v19 00/14] crypto/dmaengine: qce: introduce BAM locking and use DMA for register I/O
From: Eric Biggers @ 2026-05-29 16:22 UTC (permalink / raw)
To: Bartosz Golaszewski
Cc: Vinod Koul, Jonathan Corbet, Thara Gopinath, Herbert Xu,
David S. Miller, Udit Tiwari, Md Sadre Alam, Dmitry Baryshkov,
Manivannan Sadhasivam, Stephan Gerhold, Bjorn Andersson,
Peter Ujfalusi, Michal Simek, Frank Li, Andy Gross,
Neil Armstrong, dmaengine, linux-doc, linux-kernel, linux-arm-msm,
linux-crypto, linux-arm-kernel, brgl, Bartosz Golaszewski,
Dmitry Baryshkov, Konrad Dybcio
In-Reply-To: <20260526-qcom-qce-cmd-descr-v19-0-08472fdcbf4a@oss.qualcomm.com>
On Tue, May 26, 2026 at 03:10:48PM +0200, Bartosz Golaszewski wrote:
> I feel like I fell into the trap of trying to address pre-existing
> issues reported by sashiko and in the process provoking more reports so
> let this be the last iteration where I do this. Vinod can we get this
> queued for v7.2 now and iron out any previously existing problems in
> tree?
>
> Merging strategy: there are build-time dependencies between the crypto
> and DMA patches so the best approach is for Vinod to create an immutable
> branch with the DMA part pulled in by the crypto tree.
>
> This iteration continues to build on top of v12 but uses the BAM's NWD
> bit on data descriptors as suggested by Stephan. To that end, there are
> some more changes like reversing the order of command and data
> descriptors queuedy by the QCE driver.
>
> Currently the QCE crypto driver accesses the crypto engine registers
> directly via CPU. Trust Zone may perform crypto operations simultaneously
> resulting in a race condition. To remedy that, let's introduce support
> for BAM locking/unlocking to the driver. The BAM driver will now wrap
> any existing issued descriptor chains with additional descriptors
> performing the locking when the client starts the transaction
> (dmaengine_issue_pending()). The client wanting to profit from locking
> needs to switch to performing register I/O over DMA and communicate the
> address to which to perform the dummy writes via a call to
> dmaengine_desc_attach_metadata().
>
> In the specific case of the BAM DMA this translates to sending command
> descriptors performing dummy writes with the relevant flags set. The BAM
> will then lock all other pipes not related to the current pipe group, and
> keep handling the current pipe only until it sees the the unlock bit.
>
> In order for the locking to work correctly, we also need to switch to
> using DMA for all register I/O.
>
> On top of this, the series contains some additional tweaks and
> refactoring.
>
> The goal of this is not to improve the performance but to prepare the
> driver for supporting decryption into secure buffers in the future.
>
> Tested with tcrypt.ko, kcapi and cryptsetup.
>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@linaro.org>
> Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
None of these fixes are Cc'ed to stable, so stable kernels will remain
vulnerable to these race conditions.
Shouldn't this be preceded by a patch, Cc'ed to stable, that marks the
driver as BROKEN? As discussed in the other thread
(https://lore.kernel.org/linux-crypto/20260515-shikra_qcrypto-v1-0-80f07b345c29@oss.qualcomm.com/T/#u),
none of the current functionality of this driver is actually useful in
Linux. It's just been causing problems.
- Eric
^ permalink raw reply
* Re: [PATCH v2] crypto: sun4i-ss - clamp PRNG seed length to prevent heap overflow
From: Eric Biggers @ 2026-05-29 16:10 UTC (permalink / raw)
To: Tianchu Chen
Cc: clabbe.montjoie, herbert, davem, wens, jernej.skrabec, samuel,
linux-crypto, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <4d4407c05835a50413fa1e974e3aa3f4abfe2d5b@linux.dev>
On Fri, May 29, 2026 at 08:08:01AM +0000, Tianchu Chen wrote:
> From: Tianchu Chen <flynnnchen@tencent.com>
>
> sun4i_ss_prng_seed() copies the user-supplied seed into ss->seed
> using the user-provided length with no bounds check. The crypto core
> does not enforce slen <= seedsize before calling into the driver, so a
> userspace caller via AF_ALG setsockopt(ALG_SET_KEY) can pass up to
> sysctl_optmem_max bytes, overflowing the fixed-size buffer and
> corrupting adjacent heap memory.
>
> Clamp the copy length to the buffer size, matching the approach used by
> loongson-rng for oversized seeds.
>
> Discovered by Atuin - Automated Vulnerability Discovery Engine.
>
> Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator")
> Cc: stable@vger.kernel.org
> Signed-off-by: Tianchu Chen <flynnnchen@tencent.com>
> ---
> v2: Silently clamp oversized seeds with min_t instead of returning
> -EINVAL (Herbert Xu).
sun4i-ss-prng.c is useless, is still broken, and should just be deleted.
- Eric
^ permalink raw reply
* Re: [PATCH 0/3] Add support for qcrypto on shikra
From: Bartosz Golaszewski @ 2026-05-29 15:58 UTC (permalink / raw)
To: Eric Biggers
Cc: Dmitry Baryshkov, Kuldeep Singh, Thara Gopinath, Herbert Xu,
David S. Miller, Rob Herring, Krzysztof Kozlowski, Conor Dooley,
Bjorn Andersson, Konrad Dybcio, Vinod Koul, Frank Li, Andy Gross,
linux-arm-msm, linux-crypto, devicetree, linux-kernel, dmaengine,
Bartosz Golaszewski, Gaurav Kashyap, Neeraj Soni
In-Reply-To: <20260528175214.GA3936298@google.com>
On Thu, May 28, 2026 at 7:52 PM Eric Biggers <ebiggers@kernel.org> wrote:
>
> On Thu, May 28, 2026 at 11:13:47AM -0400, Bartosz Golaszewski wrote:
> > On Thu, 28 May 2026 15:50:10 +0200, Dmitry Baryshkov
> > <dmitry.baryshkov@oss.qualcomm.com> said:
> > > On Thu, May 28, 2026 at 09:13:23AM -0400, Bartosz Golaszewski wrote:
> > >> On Thu, 28 May 2026 13:54:51 +0200, Kuldeep Singh
> > >> <kuldeep.singh@oss.qualcomm.com> said:
> > >> >>> +Bartosz, Gaurav, Neeraj
> > >>
> > >> I know about the self-tests etc., I will address them next.
> > >
> > > My 2c, the self-tests would be more important, as they are fixes. Doing
> > > the crypto in a wrong way is a bad idea...
> > >
> >
> > Then let that be "in parallel". :)
>
> The race conditions between Linux and other environments (modem, TEE,
> etc) are of course about correctness as well, even though the self-tests
> don't expose race condition bugs. The self-tests have always just done
> a few serialized tests. That's sufficient for CPU-based code, but not
> for offload drivers, which need to be stress-tested to find the
> concurrency bugs that occur during actual use.
>
> Is there a plan to improve the tests to do stress testing as well?
>
I'm not sure if we can easily implement linux-only tests using
multiple execution environments. I will look into it and come back
with an answer.
> It's kind of odd that they don't do that yet. But it makes sense: the
> CPU-based code doesn't need it, while the offload driver authors have
> never cared enough about correctness and test coverage to add it.
>
> I still don't really see a path forward here, given the track record and
> poor performance numbers. This approach just doesn't work.
>
Sorry but I'm not sure what your point is. What this series does is:
it documents the compatible for the crypto engine that very much *does
exist* on the SoC and describes how it's wired up as a real HW
component in devicetree. Whatever the state of the driver is, it's not
grounds for NAKing HW description. The IP *is* there, we're allowed to
describe it in DTS.
Qualcomm wants to use this IP and I will keep on improving it. I think
that - given the BAM locking series is at v19 now and has been
initially posted in 2023 - I've a proven track record of not
abandoning it. :)
I'm away next week but will look into self-tests the week after. This
series - once fixed - should go upstream independently.
Bart
^ permalink raw reply
* [PATCH 2/2] rust: add hw_random module
From: Manos Pitsidianakis @ 2026-05-29 15:50 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu
Cc: rust-for-linux, linux-kernel, linux-crypto, manos.pitsidianakis
In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-0-b3153dd90311@pitsidianak.is>
Add abstraction for the hardware random number generator core subsystem.
The registration is guarded by an atomic boolean, because we cannot yet
use IRQ disabling spinlocks in Rust. Once they are supported, we should
switch to that, because it's theoretically possible to construct a data
race. In practice I do not think it's possible, since registration
happens once in driver probe and unregistration happens on driver
teardown; there shouldn't be multiple threads doing their own thing in
both cases.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
MAINTAINERS | 8 ++
rust/kernel/hw_random.rs | 320 +++++++++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 2 +
3 files changed, 330 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 4f60b323c796fc0968fd67d1c7afee6802990572..a3b372ccbd07c4ae2c735ba31f2acf40472b384a 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11304,6 +11304,14 @@ F: Documentation/devicetree/bindings/rng/
F: drivers/char/hw_random/
F: include/linux/hw_random.h
+HARDWARE RANDOM NUMBER GENERATOR CORE [RUST]
+M: Manos Pitsidianakis <manos@pitsidianak.is>
+M: Herbert Xu <herbert@gondor.apana.org.au>
+L: linux-crypto@vger.kernel.org
+L: rust-for-linux@vger.kernel.org
+S: Maintained
+F: rust/kernel/hw_random.rs
+
HARDWARE SPINLOCK CORE
M: Bjorn Andersson <andersson@kernel.org>
R: Baolin Wang <baolin.wang7@gmail.com>
diff --git a/rust/kernel/hw_random.rs b/rust/kernel/hw_random.rs
new file mode 100644
index 0000000000000000000000000000000000000000..29fc180b4a3b4157a45c8fdb2d94bf1d9d781a3c
--- /dev/null
+++ b/rust/kernel/hw_random.rs
@@ -0,0 +1,320 @@
+// SPDX-License-Identifier: GPL-2.0
+// Author: Manos Pitsidianakis <manos@pitsidianak.is>
+
+//! Hardware Random Number Generators
+//!
+//! This module provides an abstraction for implementing a hardware random number generator and
+//! using it with the kernel's `hw_random` system.
+//!
+//! # Example
+//!
+//! ```no_run
+//!# fn no_run() {
+//!# use kernel::hw_random::*;
+//!# use kernel::str::CString;
+//!# use kernel::prelude::*;
+//! #[pin_data]
+//! struct ExampleHwRng {}
+//!
+//! #[vtable]
+//! impl HwRngImpl for ExampleHwRng {
+//! fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()> {
+//! // write zeroes - in your driver, this should write actual data from your hardware.
+//! data.write(&[0_u8; 8]);
+//! Ok(())
+//! }
+//! }
+//!
+//! let name = CString::try_from(c"example_hwrng").unwrap();
+//! let my_rng = KBox::pin_init(
+//! HwRng::new(
+//! name,
+//! 0,
+//! try_pin_init!(ExampleHwRng {})
+//! ),
+//! GFP_KERNEL
+//! ).unwrap();
+//! // Register `my_rng`: after this succeeds, the kernel may call our `HwRngImpl` method at any
+//! // time.
+//! my_rng.register().unwrap();
+//!
+//! // ...
+//!
+//! my_rng.unregister();
+//!# }
+//!```
+
+use crate::{
+ error::{
+ from_result, //
+ to_result, //
+ VTABLE_DEFAULT_ERROR, //
+ },
+ prelude::*, //
+ str::{
+ CString, //
+ },
+ types::{
+ Opaque, //
+ },
+};
+
+use core::{
+ ffi::{
+ c_int, //
+ c_ushort, //
+ c_void, //
+ },
+ mem::{
+ MaybeUninit, //
+ },
+ ptr::{
+ slice_from_raw_parts, //
+ slice_from_raw_parts_mut, //
+ },
+ sync::atomic::{
+ AtomicBool, //
+ Ordering, //
+ },
+};
+
+use pin_init::pin_init_from_closure;
+
+/// A buffer to write random bytes in using [`Buffer::write`] that tracks how many bytes were
+/// written.
+///
+/// See also [`HwRngImpl::read`].
+pub struct Buffer<'a> {
+ inner: &'a mut [MaybeUninit<u8>],
+ written: usize,
+}
+
+impl Buffer<'_> {
+ /// Returns `true` if the buffer has been filled.
+ #[inline]
+ pub const fn is_empty(&self) -> bool {
+ self.written == self.inner.len()
+ }
+
+ /// Returns the number of bytes that can be written.
+ #[inline]
+ pub const fn len(&self) -> usize {
+ self.inner.len() - self.written
+ }
+
+ /// Writes bytes from `buf` into buffer and returns the amount of bytes written.
+ #[inline]
+ pub fn write(&mut self, buf: &[u8]) -> usize {
+ let to_copy = self.len().min(buf.len());
+ let ptr = buf.as_ptr();
+ // SAFETY: u8 and MaybeUninit<u8> have the same layout
+ let buf = unsafe { &*slice_from_raw_parts(ptr.cast::<MaybeUninit<u8>>(), to_copy) };
+ self.inner[self.written..][..to_copy].copy_from_slice(buf);
+ self.written += to_copy;
+ to_copy
+ }
+}
+
+/// An adapter type for the registration of hardware random number generators drivers.
+///
+/// [`struct hwrng`]: srctree/include/linux/hw_random.h
+#[pin_data(PinnedDrop)]
+pub struct HwRng<T: HwRngImpl + 'static> {
+ #[pin]
+ registration: Opaque<bindings::hwrng>,
+ registered: AtomicBool,
+ #[pin]
+ name: CString,
+ #[pin]
+ inner: T,
+}
+
+impl<T: HwRngImpl + 'static> core::ops::Deref for HwRng<T> {
+ type Target = T;
+
+ #[inline]
+ fn deref(&self) -> &Self::Target {
+ &self.inner
+ }
+}
+
+// SAFETY: HwRng contains a `*const u8` reference but it is opaque for us in Rust.
+unsafe impl<T: HwRngImpl + 'static> Send for HwRng<T> {}
+
+// SAFETY: `HwRng` has no interior mutability from Rust, and C manages it with the rng_mutex lock.
+unsafe impl<T: HwRngImpl + 'static> Sync for HwRng<T> {}
+
+#[pinned_drop]
+impl<T: HwRngImpl> PinnedDrop for HwRng<T> {
+ fn drop(self: Pin<&mut Self>) {
+ self.unregister();
+ }
+}
+
+#[vtable]
+/// Trait for the implementation of hardware RNGs.
+pub trait HwRngImpl: Send + Sync {
+ #[inline]
+ /// Initialization callback, can be optionally implemented.
+ fn init(&self) -> Result {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
+ #[inline]
+ /// Cleanup callback, can be optionally implemented.
+ fn cleanup(&self) {
+ build_error!(VTABLE_DEFAULT_ERROR)
+ }
+
+ /// Places random bytes in `data`.
+ fn read(&self, data: &mut Buffer<'_>, can_wait: bool) -> Result<()>;
+}
+
+impl<T: HwRngImpl + 'static> HwRng<T> {
+ /// Create a new [`HwRng`] without registering it.
+ pub fn new(
+ name: CString,
+ quality: c_ushort,
+ inner: impl PinInit<T, Error>,
+ ) -> impl PinInit<Self, Error> {
+ // We use pin_init_from_closure because we need to store the `slot` address as `priv` field
+ // of `hwrng` struct.
+
+ // SAFETY:
+ // - when the closure returns `Ok(())`, then it has successfully initialized all fields,
+ // - when it returns `Err(e)`, it does not need to perform any cleanup.
+ unsafe {
+ pin_init_from_closure(move |slot: *mut Self| {
+ inner.__pinned_init(&raw mut (*slot).inner)?;
+
+ let registration = (&raw mut (*slot).registration).cast::<bindings::hwrng>();
+ registration.write(bindings::hwrng {
+ name: name.as_char_ptr(),
+ read: Some(Self::read_callback),
+ init: if <T as HwRngImpl>::HAS_INIT {
+ Some(Self::init_callback)
+ } else {
+ None
+ },
+ cleanup: if <T as HwRngImpl>::HAS_CLEANUP {
+ Some(Self::cleanup_callback)
+ } else {
+ None
+ },
+ quality,
+ priv_: slot as usize,
+ ..Default::default()
+ });
+
+ let name_ptr = &raw mut (*slot).name;
+ name_ptr.write(name);
+
+ let registered = &raw mut (*slot).registered;
+ registered.write(AtomicBool::new(false));
+
+ // All fields of `HwRng` have been initialized
+ Ok(())
+ })
+ }
+ }
+
+ /// Register `self` with the `hwrng` subsystem.
+ ///
+ /// After this function successfully returns, the `hwrng` subsystem can start calling the
+ /// [`HwRngImpl`] methods at any time.
+ ///
+ /// [`hwrng_register`]: srctree/include/linux/hw_random.h
+ #[inline]
+ #[doc(alias = "hwrng_register")]
+ pub fn register(&self) -> Result {
+ if self
+ .registered
+ .compare_exchange(false, true, Ordering::SeqCst, Ordering::Acquire)
+ .is_ok()
+ {
+ // SAFETY: `registration` is properly initialized.
+ if let Err(err) = to_result(unsafe {
+ bindings::hwrng_register(self.registration.get().cast::<bindings::hwrng>())
+ }) {
+ self.registered.store(false, Ordering::Release);
+ return Err(err);
+ }
+ }
+ Ok(())
+ }
+
+ /// Unregister `self` from `hwrng` subsystem.
+ ///
+ /// [`hwrng_unregister`]: srctree/include/linux/hw_random.h
+ #[inline]
+ #[doc(alias = "hwrng_unregister")]
+ pub fn unregister(&self) {
+ if self
+ .registered
+ .compare_exchange(true, false, Ordering::SeqCst, Ordering::Acquire)
+ .is_ok()
+ {
+ // SAFETY: Since `registration` is properly initialized and registered, destroying is
+ // safe.
+ unsafe {
+ bindings::hwrng_unregister(self.registration.get().cast::<bindings::hwrng>())
+ };
+ }
+ }
+}
+
+impl<T: HwRngImpl + 'static> HwRng<T> {
+ extern "C" fn init_callback(ptr: *mut bindings::hwrng) -> c_int {
+ // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
+ let priv_ = unsafe { (*ptr).priv_ };
+ let this_ptr = priv_ as *mut Self;
+
+ // SAFETY: we set `inner` to point to a valid `T` when initializing.
+ let inner: &T = unsafe { &(*this_ptr).inner };
+ from_result(|| {
+ inner.init()?;
+ Ok(0)
+ })
+ }
+
+ extern "C" fn cleanup_callback(ptr: *mut bindings::hwrng) {
+ // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
+ let priv_ = unsafe { (*ptr).priv_ };
+ let this_ptr = priv_ as *mut Self;
+
+ // SAFETY: we set `inner` to point to a valid `T` when initializing.
+ let inner: &T = unsafe { &(*this_ptr).inner };
+ inner.cleanup();
+ }
+
+ extern "C" fn read_callback(
+ ptr: *mut bindings::hwrng,
+ data: *mut c_void,
+ max: usize,
+ wait: bool,
+ ) -> c_int {
+ if data.is_null() || max == 0 {
+ return 0;
+ }
+
+ // SAFETY: we set `priv_` as the value of `*mut Self` when initializing.
+ let priv_ = unsafe { (*ptr).priv_ };
+ let this_ptr = priv_ as *mut Self;
+
+ let buf_ptr = slice_from_raw_parts_mut(data.cast::<MaybeUninit<u8>>(), max);
+ // SAFETY: By the hw_random API contract, data points to a bytes buffer `max` bytes long.
+ let buf_ref = unsafe { &mut *buf_ptr };
+
+ let mut buffer = Buffer {
+ inner: buf_ref,
+ written: 0,
+ };
+
+ // SAFETY: we set `inner` to point to a valid `T` when initializing.
+ let inner: &T = unsafe { &(*this_ptr).inner };
+ from_result(|| {
+ inner.read(&mut buffer, wait)?;
+ Ok(buffer.written.try_into().unwrap_or(c_int::MAX))
+ })
+ }
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index ea08641919c26faba97cf5dd9b67b0df55fcd698..096b6d9d57d20612864289e87a359331058fb01c 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -74,6 +74,8 @@
pub mod fs;
#[cfg(CONFIG_GPU_BUDDY = "y")]
pub mod gpu;
+#[cfg(CONFIG_HW_RANDOM = "y")]
+pub mod hw_random;
#[cfg(CONFIG_I2C = "y")]
pub mod i2c;
pub mod id_pool;
--
2.47.3
^ permalink raw reply related
* [PATCH 1/2] rust/bindings: add hw_random.h
From: Manos Pitsidianakis @ 2026-05-29 15:50 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu
Cc: rust-for-linux, linux-kernel, linux-crypto, manos.pitsidianakis
In-Reply-To: <20260529-rust-hw_random-virtio-rng-v1-0-b3153dd90311@pitsidianak.is>
Generate bindings for include/linux/hw_random.h.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
rust/bindings/bindings_helper.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helper.h
index 3c8b897041bcef879edefdfb9627ca9cafe90e93..40731a278c1759f2658d04438d051169d074a1ac 100644
--- a/rust/bindings/bindings_helper.h
+++ b/rust/bindings/bindings_helper.h
@@ -60,6 +60,7 @@
#include <linux/file.h>
#include <linux/firmware.h>
#include <linux/fs.h>
+#include <linux/hw_random.h>
#include <linux/i2c.h>
#include <linux/interrupt.h>
#include <linux/io-pgtable.h>
--
2.47.3
^ permalink raw reply related
* [PATCH 0/2] Add hw_random Rust bindings
From: Manos Pitsidianakis @ 2026-05-29 15:50 UTC (permalink / raw)
To: Miguel Ojeda, Boqun Feng, Gary Guo, Björn Roy Baron,
Benno Lossin, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Danilo Krummrich, Herbert Xu
Cc: rust-for-linux, linux-kernel, linux-crypto, manos.pitsidianakis
This series adds Rust abstractions for the hw_random subsystem.
A virtio-rng Rust driver that uses them will be submitted as a separate
series since it also depends on the virtio abstractions series.
Signed-off-by: Manos Pitsidianakis <manos@pitsidianak.is>
---
Manos Pitsidianakis (2):
rust/bindings: add hw_random.h
rust: add hw_random module
MAINTAINERS | 8 +
rust/bindings/bindings_helper.h | 1 +
rust/kernel/hw_random.rs | 320 ++++++++++++++++++++++++++++++++++++++++
rust/kernel/lib.rs | 2 +
4 files changed, 331 insertions(+)
---
base-commit: 8bc67e4db64aa72732c474b44ea8622062c903f0
change-id: 20260525-rust-hw_random-virtio-rng-bd817be189c6
Best regards,
--
Manos Pitsidianakis <manos@pitsidianak.is>
^ permalink raw reply
* Re: [PATCH 1/3] net: Remove support for AIO on sockets
From: Christoph Hellwig @ 2026-05-29 13:59 UTC (permalink / raw)
To: Jens Axboe
Cc: Christoph Hellwig, demiobenour, Herbert Xu, David S. Miller,
Eric Dumazet, Kuniyuki Iwashima, Paolo Abeni, Willem de Bruijn,
Jakub Kicinski, Simon Horman, Peter Zijlstra, Ingo Molnar,
Arnaldo Carvalho de Melo, Namhyung Kim, Mark Rutland,
Alexander Shishkin, Jiri Olsa, Ian Rogers, Adrian Hunter,
James Clark, Jonathan Corbet, Shuah Khan, Eric Biggers,
Ard Biesheuvel, linux-crypto, linux-kernel, io-uring, netdev,
linux-perf-users, linux-doc, Toke Høiland-Jørgensen,
linux-api, David Howells
In-Reply-To: <2cfd6455-7b5b-4974-b8a1-4a0abca69768@kernel.dk>
On Thu, May 28, 2026 at 10:56:06AM -0600, Jens Axboe wrote:
> > Where? And how do make that available to in-kernel users like
> > storage protocols and network file system, which really suffer from
> > the current MSG_SPLICE_PAGES semantics.
>
> For zero copy, on both the receive and send side. Since we have a proper
> notification channel, that's what we use rather than the hack that is
> the error queue.
Can you point me to that notification channel?
> >> , and without needing msg_kiocb or the
> >
> > What do you think is the downside of using a kiocb here like for
> > everything else with async notifications?
>
> Where would the notifications go?
For userspace: io_uring or the error queue for the synchronous calls.
For in-kernel APIs whatever the callers wants to do by doing it from
ki_complete.
> You'd end up inventing something new
> to propagate them to userspace then.
The main aim here is to have a way to get these completions from
kernelspace to get rid of the current horrors around MSG_SPLICE_PAGES.
> The io_uring side does not rely on
> using msg_kiocb, and iirc that part was only ever used for the crypto
> stuff and largely broken. Which is why I do agree with just yanking it
> out.
I'm not arguing for how msg_kiocb as that is a mess. But having an
explicit kiocb API like all the other async file operations would
make things a lot simpler.
^ permalink raw reply
* Re: [PATCH 05/29] crypto: talitos - Prepare crypto implementation file splitting
From: Christophe Leroy (CS GROUP) @ 2026-05-29 13:21 UTC (permalink / raw)
To: Paul Louvel, Herbert Xu, David S. Miller
Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-5-cb1ad6cdea49@bootlin.com>
Hi Paul,
Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> Remove the static qualifier on multiple function that will be called
> inside each crypto implementation file.
> Add them to the main driver header file.
I didn't have time to look at the generated text yet but I'm a bit
sceptic with this change, or more than the change itself, about its
purpose. And even more when I see patches 24 and 25.
Most functions here are small helpers. To be shared between several C
files they deserve becoming static inlines in talitos.h, not global
functions.
Indeed, most of the time is_sec1 is known at build time because in most
cases has_ftr_sec1() will constant fold into true or false during build.
This is because it is very unlikely that someone build a kernel to run
on both MPC 82xx and MPC 83xx at the same time. Therefore it is really
unlikely that this in built with both CRYPTO_DEV_TALITOS1 and
CRYPTO_DEV_TALITOS2 at the same time.
I can understand for a function like talitos_submit() but not for
functions like to_talitos_ptr() or to_talitos_ptr_ext_set() whose
purpose is really to get inlined into the caller.
Christophe
>
> Add the common structures too.
>
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
> ---
> drivers/crypto/talitos/talitos.c | 123 ++++++++++++++-------------------------
> drivers/crypto/talitos/talitos.h | 91 +++++++++++++++++++++++++++++
> 2 files changed, 135 insertions(+), 79 deletions(-)
>
> diff --git a/drivers/crypto/talitos/talitos.c b/drivers/crypto/talitos/talitos.c
> index f5feff8f7d3d..3fc1069062da 100644
> --- a/drivers/crypto/talitos/talitos.c
> +++ b/drivers/crypto/talitos/talitos.c
> @@ -40,8 +40,8 @@
>
> #include "talitos.h"
>
> -static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> - unsigned int len, bool is_sec1)
> +void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> + unsigned int len, bool is_sec1)
> {
> ptr->ptr = cpu_to_be32(lower_32_bits(dma_addr));
> if (is_sec1) {
> @@ -52,8 +52,8 @@ static void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> }
> }
>
> -static void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
> - struct talitos_ptr *src_ptr, bool is_sec1)
> +void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
> + struct talitos_ptr *src_ptr, bool is_sec1)
> {
> dst_ptr->ptr = src_ptr->ptr;
> if (is_sec1) {
> @@ -64,8 +64,8 @@ static void copy_talitos_ptr(struct talitos_ptr *dst_ptr,
> }
> }
>
> -static unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr,
> - bool is_sec1)
> +unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr,
> + bool is_sec1)
> {
> if (is_sec1)
> return be16_to_cpu(ptr->len1);
> @@ -73,14 +73,14 @@ static unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr,
> return be16_to_cpu(ptr->len);
> }
>
> -static void to_talitos_ptr_ext_set(struct talitos_ptr *ptr, u8 val,
> - bool is_sec1)
> +void to_talitos_ptr_ext_set(struct talitos_ptr *ptr, u8 val,
> + bool is_sec1)
> {
> if (!is_sec1)
> ptr->j_extent = val;
> }
>
> -static void to_talitos_ptr_ext_or(struct talitos_ptr *ptr, u8 val, bool is_sec1)
> +void to_talitos_ptr_ext_or(struct talitos_ptr *ptr, u8 val, bool is_sec1)
> {
> if (!is_sec1)
> ptr->j_extent |= val;
> @@ -102,15 +102,15 @@ static void __map_single_talitos_ptr(struct device *dev,
> to_talitos_ptr(ptr, dma_addr, len, is_sec1);
> }
>
> -static void map_single_talitos_ptr(struct device *dev,
> - struct talitos_ptr *ptr,
> - unsigned int len, void *data,
> - enum dma_data_direction dir)
> +void map_single_talitos_ptr(struct device *dev,
> + struct talitos_ptr *ptr,
> + unsigned int len, void *data,
> + enum dma_data_direction dir)
> {
> __map_single_talitos_ptr(dev, ptr, len, data, dir, 0);
> }
>
> -static void map_single_talitos_ptr_nosync(struct device *dev,
> +void map_single_talitos_ptr_nosync(struct device *dev,
> struct talitos_ptr *ptr,
> unsigned int len, void *data,
> enum dma_data_direction dir)
> @@ -122,9 +122,9 @@ static void map_single_talitos_ptr_nosync(struct device *dev,
> /*
> * unmap bus single (contiguous) h/w descriptor pointer
> */
> -static void unmap_single_talitos_ptr(struct device *dev,
> - struct talitos_ptr *ptr,
> - enum dma_data_direction dir)
> +void unmap_single_talitos_ptr(struct device *dev,
> + struct talitos_ptr *ptr,
> + enum dma_data_direction dir)
> {
> struct talitos_private *priv = dev_get_drvdata(dev);
> bool is_sec1 = has_ftr_sec1(priv);
> @@ -303,11 +303,11 @@ static void dma_map_request(struct device *dev, struct talitos_request *request,
> * callback must check err and feedback in descriptor header
> * for device processing status.
> */
> -static int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
> - void (*callback)(struct device *dev,
> - struct talitos_desc *desc,
> - void *context, int error),
> - void *context)
> +int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
> + void (*callback)(struct device *dev,
> + struct talitos_desc *desc,
> + void *context, int error),
> + void *context)
> {
> struct talitos_private *priv = dev_get_drvdata(dev);
> struct talitos_request *request;
> @@ -830,24 +830,6 @@ DEF_TALITOS2_INTERRUPT(ch1_3, TALITOS2_ISR_CH_1_3_DONE, TALITOS2_ISR_CH_1_3_ERR,
> * HMAC_SNOOP_NO_AFEA (HSNA) instead of type IPSEC_ESP
> */
> #define TALITOS_CRA_PRIORITY_AEAD_HSNA (TALITOS_CRA_PRIORITY - 1)
> -#ifdef CONFIG_CRYPTO_DEV_TALITOS2
> -#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE)
> -#else
> -#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA256_BLOCK_SIZE)
> -#endif
> -#define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
> -
> -struct talitos_ctx {
> - struct device *dev;
> - int ch;
> - __be32 desc_hdr_template;
> - u8 key[TALITOS_MAX_KEY_SIZE];
> - u8 iv[TALITOS_MAX_IV_LENGTH];
> - dma_addr_t dma_key;
> - unsigned int keylen;
> - unsigned int enckeylen;
> - unsigned int authkeylen;
> -};
>
> #define HASH_MAX_BLOCK_SIZE SHA512_BLOCK_SIZE
> #define TALITOS_MDEU_MAX_CONTEXT_SIZE TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512
> @@ -939,7 +921,7 @@ static int aead_des3_setkey(struct crypto_aead *authenc,
> return err;
> }
>
> -static void talitos_sg_unmap(struct device *dev,
> +void talitos_sg_unmap(struct device *dev,
> struct talitos_edesc *edesc,
> struct scatterlist *src,
> struct scatterlist *dst,
> @@ -1124,7 +1106,7 @@ static int sg_to_link_tbl_offset(struct scatterlist *sg, int sg_count,
> return count;
> }
>
> -static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> +int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> unsigned int len, struct talitos_edesc *edesc,
> struct talitos_ptr *ptr, int sg_count,
> unsigned int offset, int tbl_off, int elen,
> @@ -1161,7 +1143,7 @@ static int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> return sg_count;
> }
>
> -static int talitos_sg_map(struct device *dev, struct scatterlist *src,
> +int talitos_sg_map(struct device *dev, struct scatterlist *src,
> unsigned int len, struct talitos_edesc *edesc,
> struct talitos_ptr *ptr, int sg_count,
> unsigned int offset, int tbl_off)
> @@ -1299,17 +1281,17 @@ static int ipsec_esp(struct talitos_edesc *edesc, struct aead_request *areq,
> /*
> * allocate and map the extended descriptor
> */
> -static struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
> - struct scatterlist *src,
> - struct scatterlist *dst,
> - u8 *iv,
> - unsigned int assoclen,
> - unsigned int cryptlen,
> - unsigned int authsize,
> - unsigned int ivsize,
> - int icv_stashing,
> - u32 cryptoflags,
> - bool encrypt)
> +struct talitos_edesc *talitos_edesc_alloc(struct device *dev,
> + struct scatterlist *src,
> + struct scatterlist *dst,
> + u8 *iv,
> + unsigned int assoclen,
> + unsigned int cryptlen,
> + unsigned int authsize,
> + unsigned int ivsize,
> + int icv_stashing,
> + u32 cryptoflags,
> + bool encrypt)
> {
> struct talitos_edesc *edesc;
> int src_nents, dst_nents, alloc_len, dma_len, src_len, dst_len;
> @@ -2172,18 +2154,6 @@ static int ahash_setkey(struct crypto_ahash *tfm, const u8 *key,
> return 0;
> }
>
> -
> -struct talitos_alg_template {
> - u32 type;
> - u32 priority;
> - union {
> - struct skcipher_alg skcipher;
> - struct ahash_alg hash;
> - struct aead_alg aead;
> - } alg;
> - __be32 desc_hdr_template;
> -};
> -
> static struct talitos_alg_template driver_algs[] = {
> /* AEAD algorithms. These use a single-pass ipsec_esp descriptor */
> { .type = CRYPTO_ALG_TYPE_AEAD,
> @@ -2998,14 +2968,8 @@ static struct talitos_alg_template driver_algs[] = {
> }
> };
>
> -struct talitos_crypto_alg {
> - struct list_head entry;
> - struct device *dev;
> - struct talitos_alg_template algt;
> -};
> -
> -static int talitos_init_common(struct talitos_ctx *ctx,
> - struct talitos_crypto_alg *talitos_alg)
> +int talitos_init_common(struct talitos_ctx *ctx,
> + struct talitos_crypto_alg *talitos_alg)
> {
> struct talitos_private *priv;
>
> @@ -3066,7 +3030,7 @@ static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
> return talitos_init_common(ctx, talitos_alg);
> }
>
> -static void talitos_cra_exit(struct crypto_tfm *tfm)
> +void talitos_cra_exit(struct crypto_tfm *tfm)
> {
> struct talitos_ctx *ctx = crypto_tfm_ctx(tfm);
> struct device *dev = ctx->dev;
> @@ -3080,7 +3044,7 @@ static void talitos_cra_exit(struct crypto_tfm *tfm)
> * type and primary/secondary execution units required match the hw
> * capabilities description provided in the device tree node.
> */
> -static int hw_supports(struct device *dev, __be32 desc_hdr_template)
> +int talitos_hw_supports(struct device *dev, __be32 desc_hdr_template)
> {
> struct talitos_private *priv = dev_get_drvdata(dev);
> int ret;
> @@ -3117,7 +3081,7 @@ static void talitos_remove(struct platform_device *ofdev)
> list_del(&t_alg->entry);
> }
>
> - if (hw_supports(dev, DESC_HDR_SEL0_RNG))
> + if (talitos_hw_supports(dev, DESC_HDR_SEL0_RNG))
> talitos_unregister_rng(dev);
>
> for (i = 0; i < 2; i++)
> @@ -3426,7 +3390,7 @@ static int talitos_probe(struct platform_device *ofdev)
> }
>
> /* register the RNG, if available */
> - if (hw_supports(dev, DESC_HDR_SEL0_RNG)) {
> + if (talitos_hw_supports(dev, DESC_HDR_SEL0_RNG)) {
> err = talitos_register_rng(dev);
> if (err) {
> dev_err(dev, "failed to register hwrng: %d\n", err);
> @@ -3437,7 +3401,8 @@ static int talitos_probe(struct platform_device *ofdev)
>
> /* register crypto algorithms the device supports */
> for (i = 0; i < ARRAY_SIZE(driver_algs); i++) {
> - if (hw_supports(dev, driver_algs[i].desc_hdr_template)) {
> + if (talitos_hw_supports(dev,
> + driver_algs[i].desc_hdr_template)) {
> struct talitos_crypto_alg *t_alg;
> struct crypto_alg *alg = NULL;
>
> diff --git a/drivers/crypto/talitos/talitos.h b/drivers/crypto/talitos/talitos.h
> index fa8c71b1f90f..1f81d336dae8 100644
> --- a/drivers/crypto/talitos/talitos.h
> +++ b/drivers/crypto/talitos/talitos.h
> @@ -5,7 +5,13 @@
> * Copyright (c) 2006-2011 Freescale Semiconductor, Inc.
> */
>
> +#include <crypto/aes.h>
> +#include <crypto/internal/aead.h>
> +#include <crypto/internal/hash.h>
> +#include <crypto/internal/skcipher.h>
> +#include <crypto/sha2.h>
> #include <linux/device.h>
> +#include <linux/dma-mapping.h>
> #include <linux/hw_random.h>
> #include <linux/interrupt.h>
> #include <linux/scatterlist.h>
> @@ -19,6 +25,13 @@
> #define PRIMARY_EU(desc_hdr) ((be32_to_cpu(desc_hdr) >> 28) & 0xf)
> #define SECONDARY_EU(desc_hdr) ((be32_to_cpu(desc_hdr) >> 16) & 0xf)
>
> +#ifdef CONFIG_CRYPTO_DEV_TALITOS2
> +#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA512_BLOCK_SIZE)
> +#else
> +#define TALITOS_MAX_KEY_SIZE (AES_MAX_KEY_SIZE + SHA256_BLOCK_SIZE)
> +#endif
> +#define TALITOS_MAX_IV_LENGTH 16 /* max of AES_BLOCK_SIZE, DES3_EDE_BLOCK_SIZE */
> +
> /* descriptor pointer entry */
> struct talitos_ptr {
> union {
> @@ -174,6 +187,35 @@ struct talitos_private {
>
> };
>
> +struct talitos_ctx {
> + struct device *dev;
> + int ch;
> + __be32 desc_hdr_template;
> + u8 key[TALITOS_MAX_KEY_SIZE];
> + u8 iv[TALITOS_MAX_IV_LENGTH];
> + dma_addr_t dma_key;
> + unsigned int keylen;
> + unsigned int enckeylen;
> + unsigned int authkeylen;
> +};
> +
> +struct talitos_alg_template {
> + u32 type;
> + u32 priority;
> + union {
> + struct skcipher_alg skcipher;
> + struct ahash_alg hash;
> + struct aead_alg aead;
> + } alg;
> + __be32 desc_hdr_template;
> +};
> +
> +struct talitos_crypto_alg {
> + struct list_head entry;
> + struct device *dev;
> + struct talitos_alg_template algt;
> +};
> +
> /* .features flag */
> #define TALITOS_FTR_SRC_LINK_TBL_LEN_INCLUDES_EXTENT 0x00000001
> #define TALITOS_FTR_HW_AUTH_CHECK 0x00000002
> @@ -432,6 +474,55 @@ static inline bool has_ftr_sec1(struct talitos_private *priv)
> #define DESC_PTR_LNKTBL_RET 0x02
> #define DESC_PTR_LNKTBL_NEXT 0x01
>
> +void to_talitos_ptr(struct talitos_ptr *ptr, dma_addr_t dma_addr,
> + unsigned int len, bool is_sec1);
> +void copy_talitos_ptr(struct talitos_ptr *dst_ptr, struct talitos_ptr *src_ptr,
> + bool is_sec1);
> +unsigned short from_talitos_ptr_len(struct talitos_ptr *ptr, bool is_sec1);
> +void to_talitos_ptr_ext_set(struct talitos_ptr *ptr, u8 val, bool is_sec1);
> +void to_talitos_ptr_ext_or(struct talitos_ptr *ptr, u8 val, bool is_sec1);
> +
> +void map_single_talitos_ptr(struct device *dev, struct talitos_ptr *ptr,
> + unsigned int len, void *data,
> + enum dma_data_direction dir);
> +void map_single_talitos_ptr_nosync(struct device *dev, struct talitos_ptr *ptr,
> + unsigned int len, void *data,
> + enum dma_data_direction dir);
> +void unmap_single_talitos_ptr(struct device *dev, struct talitos_ptr *ptr,
> + enum dma_data_direction dir);
> +
> +int talitos_submit(struct device *dev, int ch, struct talitos_desc *desc,
> + void (*callback)(struct device *dev,
> + struct talitos_desc *desc, void *context,
> + int error),
> + void *context);
> +
> +void talitos_sg_unmap(struct device *dev, struct talitos_edesc *edesc,
> + struct scatterlist *src, struct scatterlist *dst,
> + unsigned int len, unsigned int offset);
> +int talitos_sg_map_ext(struct device *dev, struct scatterlist *src,
> + unsigned int len, struct talitos_edesc *edesc,
> + struct talitos_ptr *ptr, int sg_count,
> + unsigned int offset, int tbl_off, int elen, bool force,
> + int align);
> +int talitos_sg_map(struct device *dev, struct scatterlist *src,
> + unsigned int len, struct talitos_edesc *edesc,
> + struct talitos_ptr *ptr, int sg_count, unsigned int offset,
> + int tbl_off);
> +
> +struct talitos_edesc *
> +talitos_edesc_alloc(struct device *dev, struct scatterlist *src,
> + struct scatterlist *dst, u8 *iv, unsigned int assoclen,
> + unsigned int cryptlen, unsigned int authsize,
> + unsigned int ivsize, int icv_stashing, u32 cryptoflags,
> + bool encrypt);
> +
> +int talitos_hw_supports(struct device *dev, __be32 desc_hdr_template);
> +
> +int talitos_init_common(struct talitos_ctx *ctx,
> + struct talitos_crypto_alg *talitos_alg);
> +void talitos_cra_exit(struct crypto_tfm *tfm);
> +
> /* Hardware RNG */
>
> int talitos_register_rng(struct device *dev);
>
^ permalink raw reply
* Re: [PATCH 04/29] crypto: talitos/hwrng - Move into separate file
From: Christophe Leroy (CS GROUP) @ 2026-05-29 11:26 UTC (permalink / raw)
To: Paul Louvel, Herbert Xu, David S. Miller
Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-4-cb1ad6cdea49@bootlin.com>
Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> Move the hardware random number generator implementation from
> talitos.c into a dedicated talitos-rng.c file.
>
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> ---
> drivers/crypto/talitos/Makefile | 2 +
> drivers/crypto/talitos/talitos-rng.c | 93 ++++++++++++++++++++++++++++++++++++
> drivers/crypto/talitos/talitos.c | 83 --------------------------------
> drivers/crypto/talitos/talitos.h | 5 ++
> 4 files changed, 100 insertions(+), 83 deletions(-)
>
> diff --git a/drivers/crypto/talitos/Makefile b/drivers/crypto/talitos/Makefile
> index fcc5db5e63c2..901ec681f010 100644
> --- a/drivers/crypto/talitos/Makefile
> +++ b/drivers/crypto/talitos/Makefile
> @@ -1 +1,3 @@
> obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
> +
> +talitos-y := talitos.o talitos-rng.o
> diff --git a/drivers/crypto/talitos/talitos-rng.c b/drivers/crypto/talitos/talitos-rng.c
> new file mode 100644
> index 000000000000..3aa00de33b25
> --- /dev/null
> +++ b/drivers/crypto/talitos/talitos-rng.c
> @@ -0,0 +1,93 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +
> +/*
> + * Freescale SEC (talitos) device hardware random number generator implementation
> + *
> + * Copyright (c) 2006-2011 Freescale Semiconductor, Inc.
> + */
> +
> +#include <linux/delay.h>
> +#include <linux/io.h>
> +
> +#include "talitos.h"
> +
> +static int talitos_rng_data_present(struct hwrng *rng, int wait)
> +{
> + struct device *dev = (struct device *)rng->priv;
> + struct talitos_private *priv = dev_get_drvdata(dev);
> + u32 ofl;
> + int i;
> +
> + for (i = 0; i < 20; i++) {
> + ofl = in_be32(priv->reg_rngu + TALITOS_EUSR_LO) &
> + TALITOS_RNGUSR_LO_OFL;
> + if (ofl || !wait)
> + break;
> + udelay(10);
> + }
> +
> + return !!ofl;
> +}
> +
> +static int talitos_rng_data_read(struct hwrng *rng, u32 *data)
> +{
> + struct device *dev = (struct device *)rng->priv;
> + struct talitos_private *priv = dev_get_drvdata(dev);
> +
> + /* rng fifo requires 64-bit accesses */
> + *data = in_be32(priv->reg_rngu + TALITOS_EU_FIFO);
> + *data = in_be32(priv->reg_rngu + TALITOS_EU_FIFO_LO);
> +
> + return sizeof(u32);
> +}
> +
> +static int talitos_rng_init(struct hwrng *rng)
> +{
> + struct device *dev = (struct device *)rng->priv;
> + struct talitos_private *priv = dev_get_drvdata(dev);
> + unsigned int timeout = TALITOS_TIMEOUT;
> +
> + setbits32(priv->reg_rngu + TALITOS_EURCR_LO, TALITOS_RNGURCR_LO_SR);
> + while (!(in_be32(priv->reg_rngu + TALITOS_EUSR_LO)
> + & TALITOS_RNGUSR_LO_RD)
> + && --timeout)
> + cpu_relax();
> + if (timeout == 0) {
> + dev_err(dev, "failed to reset rng hw\n");
> + return -ENODEV;
> + }
> +
> + /* start generating */
> + setbits32(priv->reg_rngu + TALITOS_EUDSR_LO, 0);
> +
> + return 0;
> +}
> +
> +int talitos_register_rng(struct device *dev)
> +{
> + struct talitos_private *priv = dev_get_drvdata(dev);
> + int err;
> +
> + priv->rng.name = dev_driver_string(dev);
> + priv->rng.init = talitos_rng_init;
> + priv->rng.data_present = talitos_rng_data_present;
> + priv->rng.data_read = talitos_rng_data_read;
> + priv->rng.priv = (unsigned long)dev;
> +
> + err = hwrng_register(&priv->rng);
> + if (!err)
> + priv->rng_registered = true;
> +
> + return err;
> +}
> +
> +void talitos_unregister_rng(struct device *dev)
> +{
> + struct talitos_private *priv = dev_get_drvdata(dev);
> +
> + if (!priv->rng_registered)
> + return;
> +
> + hwrng_unregister(&priv->rng);
> + priv->rng_registered = false;
> +}
> diff --git a/drivers/crypto/talitos/talitos.c b/drivers/crypto/talitos/talitos.c
> index 8ca587b98d92..f5feff8f7d3d 100644
> --- a/drivers/crypto/talitos/talitos.c
> +++ b/drivers/crypto/talitos/talitos.c
> @@ -820,89 +820,6 @@ DEF_TALITOS2_INTERRUPT(ch0_2, TALITOS2_ISR_CH_0_2_DONE, TALITOS2_ISR_CH_0_2_ERR,
> DEF_TALITOS2_INTERRUPT(ch1_3, TALITOS2_ISR_CH_1_3_DONE, TALITOS2_ISR_CH_1_3_ERR,
> 1)
>
> -/*
> - * hwrng
> - */
> -static int talitos_rng_data_present(struct hwrng *rng, int wait)
> -{
> - struct device *dev = (struct device *)rng->priv;
> - struct talitos_private *priv = dev_get_drvdata(dev);
> - u32 ofl;
> - int i;
> -
> - for (i = 0; i < 20; i++) {
> - ofl = in_be32(priv->reg_rngu + TALITOS_EUSR_LO) &
> - TALITOS_RNGUSR_LO_OFL;
> - if (ofl || !wait)
> - break;
> - udelay(10);
> - }
> -
> - return !!ofl;
> -}
> -
> -static int talitos_rng_data_read(struct hwrng *rng, u32 *data)
> -{
> - struct device *dev = (struct device *)rng->priv;
> - struct talitos_private *priv = dev_get_drvdata(dev);
> -
> - /* rng fifo requires 64-bit accesses */
> - *data = in_be32(priv->reg_rngu + TALITOS_EU_FIFO);
> - *data = in_be32(priv->reg_rngu + TALITOS_EU_FIFO_LO);
> -
> - return sizeof(u32);
> -}
> -
> -static int talitos_rng_init(struct hwrng *rng)
> -{
> - struct device *dev = (struct device *)rng->priv;
> - struct talitos_private *priv = dev_get_drvdata(dev);
> - unsigned int timeout = TALITOS_TIMEOUT;
> -
> - setbits32(priv->reg_rngu + TALITOS_EURCR_LO, TALITOS_RNGURCR_LO_SR);
> - while (!(in_be32(priv->reg_rngu + TALITOS_EUSR_LO)
> - & TALITOS_RNGUSR_LO_RD)
> - && --timeout)
> - cpu_relax();
> - if (timeout == 0) {
> - dev_err(dev, "failed to reset rng hw\n");
> - return -ENODEV;
> - }
> -
> - /* start generating */
> - setbits32(priv->reg_rngu + TALITOS_EUDSR_LO, 0);
> -
> - return 0;
> -}
> -
> -static int talitos_register_rng(struct device *dev)
> -{
> - struct talitos_private *priv = dev_get_drvdata(dev);
> - int err;
> -
> - priv->rng.name = dev_driver_string(dev);
> - priv->rng.init = talitos_rng_init;
> - priv->rng.data_present = talitos_rng_data_present;
> - priv->rng.data_read = talitos_rng_data_read;
> - priv->rng.priv = (unsigned long)dev;
> -
> - err = hwrng_register(&priv->rng);
> - if (!err)
> - priv->rng_registered = true;
> -
> - return err;
> -}
> -
> -static void talitos_unregister_rng(struct device *dev)
> -{
> - struct talitos_private *priv = dev_get_drvdata(dev);
> -
> - if (!priv->rng_registered)
> - return;
> -
> - hwrng_unregister(&priv->rng);
> - priv->rng_registered = false;
> -}
>
> /*
> * crypto alg
> diff --git a/drivers/crypto/talitos/talitos.h b/drivers/crypto/talitos/talitos.h
> index 56e36a65ddcc..fa8c71b1f90f 100644
> --- a/drivers/crypto/talitos/talitos.h
> +++ b/drivers/crypto/talitos/talitos.h
> @@ -431,3 +431,8 @@ static inline bool has_ftr_sec1(struct talitos_private *priv)
> #define DESC_PTR_LNKTBL_JUMP 0x80
> #define DESC_PTR_LNKTBL_RET 0x02
> #define DESC_PTR_LNKTBL_NEXT 0x01
> +
> +/* Hardware RNG */
> +
> +int talitos_register_rng(struct device *dev);
> +void talitos_unregister_rng(struct device *dev);
>
^ permalink raw reply
* Re: [PATCH 03/29] crypto: talitos - Add missing includes to driver header file
From: Christophe Leroy (CS GROUP) @ 2026-05-29 11:26 UTC (permalink / raw)
To: Paul Louvel, Herbert Xu, David S. Miller
Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-3-cb1ad6cdea49@bootlin.com>
Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> Add explicit includes for types used by the header file to make
> it self-contained and fix implicit include dependencies.
>
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> ---
> drivers/crypto/talitos/talitos.c | 3 ---
> drivers/crypto/talitos/talitos.h | 6 ++++++
> 2 files changed, 6 insertions(+), 3 deletions(-)
>
> diff --git a/drivers/crypto/talitos/talitos.c b/drivers/crypto/talitos/talitos.c
> index 3610d9f6d5ea..8ca587b98d92 100644
> --- a/drivers/crypto/talitos/talitos.c
> +++ b/drivers/crypto/talitos/talitos.c
> @@ -15,10 +15,7 @@
> #include <linux/kernel.h>
> #include <linux/module.h>
> #include <linux/mod_devicetable.h>
> -#include <linux/device.h>
> -#include <linux/interrupt.h>
> #include <linux/crypto.h>
> -#include <linux/hw_random.h>
> #include <linux/of.h>
> #include <linux/of_irq.h>
> #include <linux/platform_device.h>
> diff --git a/drivers/crypto/talitos/talitos.h b/drivers/crypto/talitos/talitos.h
> index d4ff8d589f46..56e36a65ddcc 100644
> --- a/drivers/crypto/talitos/talitos.h
> +++ b/drivers/crypto/talitos/talitos.h
> @@ -5,6 +5,12 @@
> * Copyright (c) 2006-2011 Freescale Semiconductor, Inc.
> */
>
> +#include <linux/device.h>
> +#include <linux/hw_random.h>
> +#include <linux/interrupt.h>
> +#include <linux/scatterlist.h>
> +#include <linux/types.h>
> +
> #define TALITOS_TIMEOUT 100000
> #define TALITOS1_MAX_DATA_LEN 32768
> #define TALITOS2_MAX_DATA_LEN 65535
>
^ permalink raw reply
* Re: [PATCH 02/29] crypto: talitos - Move driver into dedicated directory
From: Christophe Leroy (CS GROUP) @ 2026-05-29 11:25 UTC (permalink / raw)
To: Paul Louvel, Herbert Xu, David S. Miller
Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-2-cb1ad6cdea49@bootlin.com>
Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> Move the talitos driver files from drivers/crypto/ into
> drivers/crypto/talitos/ to accommodate upcoming code
> reorganization.
>
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> ---
> drivers/crypto/Kconfig | 38 +---------------------------------
> drivers/crypto/Makefile | 2 +-
> drivers/crypto/talitos/Kconfig | 36 ++++++++++++++++++++++++++++++++
> drivers/crypto/talitos/Makefile | 1 +
> drivers/crypto/{ => talitos}/talitos.c | 0
> drivers/crypto/{ => talitos}/talitos.h | 0
> 6 files changed, 39 insertions(+), 38 deletions(-)
>
> diff --git a/drivers/crypto/Kconfig b/drivers/crypto/Kconfig
> index d23b58b81ca3..783b5dc42a42 100644
> --- a/drivers/crypto/Kconfig
> +++ b/drivers/crypto/Kconfig
> @@ -253,43 +253,7 @@ config CRYPTO_DEV_HIFN_795X_RNG
> on the HIFN 795x crypto adapters.
>
> source "drivers/crypto/caam/Kconfig"
> -
> -config CRYPTO_DEV_TALITOS
> - tristate "Talitos Freescale Security Engine (SEC)"
> - select CRYPTO_AEAD
> - select CRYPTO_AUTHENC
> - select CRYPTO_SKCIPHER
> - select CRYPTO_HASH
> - select CRYPTO_LIB_DES
> - select HW_RANDOM
> - depends on FSL_SOC
> - help
> - Say 'Y' here to use the Freescale Security Engine (SEC)
> - to offload cryptographic algorithm computation.
> -
> - The Freescale SEC is present on PowerQUICC 'E' processors, such
> - as the MPC8349E and MPC8548E.
> -
> - To compile this driver as a module, choose M here: the module
> - will be called talitos.
> -
> -config CRYPTO_DEV_TALITOS1
> - bool "SEC1 (SEC 1.0 and SEC Lite 1.2)"
> - depends on CRYPTO_DEV_TALITOS
> - depends on PPC_8xx || PPC_82xx
> - default y
> - help
> - Say 'Y' here to use the Freescale Security Engine (SEC) version 1.0
> - found on MPC82xx or the Freescale Security Engine (SEC Lite)
> - version 1.2 found on MPC8xx
> -
> -config CRYPTO_DEV_TALITOS2
> - bool "SEC2+ (SEC version 2.0 or upper)"
> - depends on CRYPTO_DEV_TALITOS
> - default y if !PPC_8xx
> - help
> - Say 'Y' here to use the Freescale Security Engine (SEC)
> - version 2 and following as found on MPC83xx, MPC85xx, etc ...
> +source "drivers/crypto/talitos/Kconfig"
>
> config CRYPTO_DEV_PPC4XX
> tristate "Driver AMCC PPC4xx crypto accelerator"
> diff --git a/drivers/crypto/Makefile b/drivers/crypto/Makefile
> index 283bbc650b5b..a059139d4a75 100644
> --- a/drivers/crypto/Makefile
> +++ b/drivers/crypto/Makefile
> @@ -35,7 +35,7 @@ obj-$(CONFIG_CRYPTO_DEV_SA2UL) += sa2ul.o
> obj-$(CONFIG_CRYPTO_DEV_SAHARA) += sahara.o
> obj-$(CONFIG_CRYPTO_DEV_SL3516) += gemini/
> obj-y += stm32/
> -obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
> +obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos/
> obj-$(CONFIG_CRYPTO_DEV_TEGRA) += tegra/
> obj-$(CONFIG_CRYPTO_DEV_VIRTIO) += virtio/
> obj-$(CONFIG_CRYPTO_DEV_BCM_SPU) += bcm/
> diff --git a/drivers/crypto/talitos/Kconfig b/drivers/crypto/talitos/Kconfig
> new file mode 100644
> index 000000000000..c3470553a966
> --- /dev/null
> +++ b/drivers/crypto/talitos/Kconfig
> @@ -0,0 +1,36 @@
> +config CRYPTO_DEV_TALITOS
> + tristate "Talitos Freescale Security Engine (SEC)"
> + select CRYPTO_AEAD
> + select CRYPTO_AUTHENC
> + select CRYPTO_SKCIPHER
> + select CRYPTO_HASH
> + select CRYPTO_LIB_DES
> + select HW_RANDOM
> + depends on FSL_SOC
> + help
> + Say 'Y' here to use the Freescale Security Engine (SEC)
> + to offload cryptographic algorithm computation.
> +
> + The Freescale SEC is present on PowerQUICC 'E' processors, such
> + as the MPC8349E and MPC8548E.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called talitos.
> +
> +config CRYPTO_DEV_TALITOS1
> + bool "SEC1 (SEC 1.0 and SEC Lite 1.2)"
> + depends on CRYPTO_DEV_TALITOS
> + depends on PPC_8xx || PPC_82xx
> + default y
> + help
> + Say 'Y' here to use the Freescale Security Engine (SEC) version 1.0
> + found on MPC82xx or the Freescale Security Engine (SEC Lite)
> + version 1.2 found on MPC8xx
> +
> +config CRYPTO_DEV_TALITOS2
> + bool "SEC2+ (SEC version 2.0 or upper)"
> + depends on CRYPTO_DEV_TALITOS
> + default y if !PPC_8xx
> + help
> + Say 'Y' here to use the Freescale Security Engine (SEC)
> + version 2 and following as found on MPC83xx, MPC85xx, etc ...
> diff --git a/drivers/crypto/talitos/Makefile b/drivers/crypto/talitos/Makefile
> new file mode 100644
> index 000000000000..fcc5db5e63c2
> --- /dev/null
> +++ b/drivers/crypto/talitos/Makefile
> @@ -0,0 +1 @@
> +obj-$(CONFIG_CRYPTO_DEV_TALITOS) += talitos.o
> diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos/talitos.c
> similarity index 100%
> rename from drivers/crypto/talitos.c
> rename to drivers/crypto/talitos/talitos.c
> diff --git a/drivers/crypto/talitos.h b/drivers/crypto/talitos/talitos.h
> similarity index 100%
> rename from drivers/crypto/talitos.h
> rename to drivers/crypto/talitos/talitos.h
>
^ permalink raw reply
* Re: [PATCH 01/29] crypto: talitos/hash - Use CRYPTO_AHASH_BLOCK_ONLY API
From: Christophe Leroy (CS GROUP) @ 2026-05-29 11:25 UTC (permalink / raw)
To: Paul Louvel, Herbert Xu, David S. Miller
Cc: Thomas Petazzoni, Herve Codina, linux-crypto, linux-kernel
In-Reply-To: <20260528-7-1-rc1_talitos_cleanup-v1-1-cb1ad6cdea49@bootlin.com>
Le 28/05/2026 à 11:08, Paul Louvel a écrit :
> The hash implementation maintained a software buffer to accumulate
> partial blocks across update() calls, copying data to/from scatterlists
> with sg_copy_to_buffer()/sg_pcopy_to_buffer() and chaining in a virtual
> scatterlist entry. This is unnecessary now with
> CRYPTO_AHASH_ALG_BLOCK_ONLY flag.
>
> Remove unnecessary fields in the request and export structure. On
> completion, pass any remaining tail bytes back via
> ahash_request_complete() so that the core re-submits them with the next
> request.
>
> Signed-off-by: Paul Louvel <paul.louvel@bootlin.com>
Reviewed-by: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
> ---
> drivers/crypto/talitos.c | 149 ++++++++++++++++++-----------------------------
> 1 file changed, 57 insertions(+), 92 deletions(-)
>
> diff --git a/drivers/crypto/talitos.c b/drivers/crypto/talitos.c
> index 584508963241..3610d9f6d5ea 100644
> --- a/drivers/crypto/talitos.c
> +++ b/drivers/crypto/talitos.c
> @@ -941,25 +941,18 @@ struct talitos_ctx {
> struct talitos_ahash_req_ctx {
> u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
> unsigned int hw_context_size;
> - u8 buf[2][HASH_MAX_BLOCK_SIZE];
> - int buf_idx;
> unsigned int swinit;
> unsigned int first_request;
> unsigned int last_request;
> unsigned int to_hash_later;
> - unsigned int nbuf;
> - struct scatterlist bufsl[2];
> - struct scatterlist *psrc;
> };
>
> struct talitos_export_state {
> u32 hw_context[TALITOS_MDEU_MAX_CONTEXT_SIZE / sizeof(u32)];
> - u8 buf[HASH_MAX_BLOCK_SIZE];
> unsigned int swinit;
> unsigned int first_request;
> unsigned int last_request;
> unsigned int to_hash_later;
> - unsigned int nbuf;
> };
>
> static int aead_setkey(struct crypto_aead *authenc,
> @@ -1826,14 +1819,8 @@ static void ahash_done(struct device *dev,
> struct talitos_edesc *next;
>
> if (is_sec1) {
> - if (!req_ctx->last_request && req_ctx->to_hash_later) {
> - /* Position any partial block for next update/final/finup */
> - req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
> - req_ctx->nbuf = req_ctx->to_hash_later;
> - }
> -
> free_edesc_list_from(areq, edesc);
> - ahash_request_complete(areq, err);
> + ahash_request_complete(areq, err ?: req_ctx->to_hash_later);
> } else {
> next = edesc->next_desc;
>
> @@ -1851,14 +1838,9 @@ static void ahash_done(struct device *dev,
> return;
> }
> out:
> - if (!req_ctx->last_request && req_ctx->to_hash_later) {
> - /* Position any partial block for next update/final/finup */
> - req_ctx->buf_idx = (req_ctx->buf_idx + 1) & 1;
> - req_ctx->nbuf = req_ctx->to_hash_later;
> - }
> if (err && next)
> free_edesc_list_from(areq, next);
> - ahash_request_complete(areq, err);
> + ahash_request_complete(areq, err ?: req_ctx->to_hash_later);
> }
> }
>
> @@ -1978,7 +1960,7 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes,
> size_t offset = 0;
>
> do {
> - src = scatterwalk_ffwd(tmp, req_ctx->psrc, offset);
> + src = scatterwalk_ffwd(tmp, areq->src, offset);
>
> to_hash_this_desc =
> min(nbytes, ALIGN_DOWN(desc_max, blocksize));
> @@ -1991,8 +1973,7 @@ ahash_process_req_prepare(struct ahash_request *areq, unsigned int nbytes,
> return edesc;
> }
>
> - edesc->src =
> - scatterwalk_ffwd(edesc->bufsl, req_ctx->psrc, offset);
> + edesc->src = scatterwalk_ffwd(edesc->bufsl, areq->src, offset);
> edesc->desc.hdr = ctx->desc_hdr_template;
> edesc->first = offset == 0;
> edesc->last = nbytes - to_hash_this_desc == 0;
> @@ -2045,62 +2026,17 @@ static int ahash_process_req(struct ahash_request *areq, unsigned int nbytes)
> bool is_sec1 = has_ftr_sec1(dev_get_drvdata(ctx->dev));
> unsigned int nbytes_to_hash;
> unsigned int to_hash_later;
> - unsigned int nsg;
> - int nents;
> struct device *dev = ctx->dev;
> - u8 *ctx_buf = req_ctx->buf[req_ctx->buf_idx];
> int ret;
>
> - if (!req_ctx->last_request && (nbytes + req_ctx->nbuf <= blocksize)) {
> - /* Buffer up to one whole block */
> - nents = sg_nents_for_len(areq->src, nbytes);
> - if (nents < 0) {
> - dev_err(dev, "Invalid number of src SG.\n");
> - return nents;
> - }
> - sg_copy_to_buffer(areq->src, nents,
> - ctx_buf + req_ctx->nbuf, nbytes);
> - req_ctx->nbuf += nbytes;
> - return 0;
> - }
> -
> - /* At least (blocksize + 1) bytes are available to hash */
> - nbytes_to_hash = nbytes + req_ctx->nbuf;
> - to_hash_later = nbytes_to_hash & (blocksize - 1);
> + nbytes_to_hash = ALIGN_DOWN(nbytes, blocksize);
> + to_hash_later = nbytes - nbytes_to_hash;
>
> - if (req_ctx->last_request)
> + if (req_ctx->last_request) {
> + nbytes_to_hash = nbytes;
> to_hash_later = 0;
> - else if (to_hash_later)
> - /* There is a partial block. Hash the full block(s) now */
> - nbytes_to_hash -= to_hash_later;
> - else {
> - /* Keep one block buffered */
> - nbytes_to_hash -= blocksize;
> - to_hash_later = blocksize;
> - }
> -
> - /* Chain in any previously buffered data */
> - if (req_ctx->nbuf) {
> - nsg = (req_ctx->nbuf < nbytes_to_hash) ? 2 : 1;
> - sg_init_table(req_ctx->bufsl, nsg);
> - sg_set_buf(req_ctx->bufsl, ctx_buf, req_ctx->nbuf);
> - if (nsg > 1)
> - sg_chain(req_ctx->bufsl, 2, areq->src);
> - req_ctx->psrc = req_ctx->bufsl;
> - } else
> - req_ctx->psrc = areq->src;
> -
> - if (to_hash_later) {
> - nents = sg_nents_for_len(areq->src, nbytes);
> - if (nents < 0) {
> - dev_err(dev, "Invalid number of src SG.\n");
> - return nents;
> - }
> - sg_pcopy_to_buffer(areq->src, nents,
> - req_ctx->buf[(req_ctx->buf_idx + 1) & 1],
> - to_hash_later,
> - nbytes - to_hash_later);
> }
> +
> req_ctx->to_hash_later = to_hash_later;
>
> edesc = ahash_process_req_prepare(areq, nbytes_to_hash, blocksize,
> @@ -2125,8 +2061,6 @@ static int ahash_init(struct ahash_request *areq)
> dma_addr_t dma;
>
> /* Initialize the context */
> - req_ctx->buf_idx = 0;
> - req_ctx->nbuf = 0;
> req_ctx->first_request = 1;
> req_ctx->swinit = 0; /* assume h/w init of context */
> size = (crypto_ahash_digestsize(tfm) <= SHA256_DIGEST_SIZE)
> @@ -2223,12 +2157,10 @@ static int ahash_export(struct ahash_request *areq, void *out)
>
> memcpy(export->hw_context, req_ctx->hw_context,
> req_ctx->hw_context_size);
> - memcpy(export->buf, req_ctx->buf[req_ctx->buf_idx], req_ctx->nbuf);
> export->swinit = req_ctx->swinit;
> export->first_request = req_ctx->first_request;
> export->last_request = req_ctx->last_request;
> export->to_hash_later = req_ctx->to_hash_later;
> - export->nbuf = req_ctx->nbuf;
>
> return 0;
> }
> @@ -2249,12 +2181,10 @@ static int ahash_import(struct ahash_request *areq, const void *in)
> : TALITOS_MDEU_CONTEXT_SIZE_SHA384_SHA512;
> req_ctx->hw_context_size = size;
> memcpy(req_ctx->hw_context, export->hw_context, size);
> - memcpy(req_ctx->buf[0], export->buf, export->nbuf);
> req_ctx->swinit = export->swinit;
> req_ctx->first_request = export->first_request;
> req_ctx->last_request = export->last_request;
> req_ctx->to_hash_later = export->to_hash_later;
> - req_ctx->nbuf = export->nbuf;
>
> dma = dma_map_single(dev, req_ctx->hw_context, req_ctx->hw_context_size,
> DMA_TO_DEVICE);
> @@ -2932,8 +2862,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "md5",
> .cra_driver_name = "md5-talitos",
> .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2948,8 +2881,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "sha1",
> .cra_driver_name = "sha1-talitos",
> .cra_blocksize = SHA1_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2964,8 +2900,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "sha224",
> .cra_driver_name = "sha224-talitos",
> .cra_blocksize = SHA224_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2980,8 +2919,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "sha256",
> .cra_driver_name = "sha256-talitos",
> .cra_blocksize = SHA256_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -2996,8 +2938,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "sha384",
> .cra_driver_name = "sha384-talitos",
> .cra_blocksize = SHA384_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3012,8 +2957,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "sha512",
> .cra_driver_name = "sha512-talitos",
> .cra_blocksize = SHA512_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3028,8 +2976,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "hmac(md5)",
> .cra_driver_name = "hmac-md5-talitos",
> .cra_blocksize = MD5_HMAC_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3044,8 +2995,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "hmac(sha1)",
> .cra_driver_name = "hmac-sha1-talitos",
> .cra_blocksize = SHA1_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3060,8 +3014,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "hmac(sha224)",
> .cra_driver_name = "hmac-sha224-talitos",
> .cra_blocksize = SHA224_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3076,8 +3033,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "hmac(sha256)",
> .cra_driver_name = "hmac-sha256-talitos",
> .cra_blocksize = SHA256_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3092,8 +3052,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "hmac(sha384)",
> .cra_driver_name = "hmac-sha384-talitos",
> .cra_blocksize = SHA384_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3108,8 +3071,11 @@ static struct talitos_alg_template driver_algs[] = {
> .cra_name = "hmac(sha512)",
> .cra_driver_name = "hmac-sha512-talitos",
> .cra_blocksize = SHA512_BLOCK_SIZE,
> + .cra_reqsize = sizeof(struct talitos_ahash_req_ctx),
> .cra_flags = CRYPTO_ALG_ASYNC |
> - CRYPTO_ALG_ALLOCATES_MEMORY,
> + CRYPTO_ALG_ALLOCATES_MEMORY |
> + CRYPTO_AHASH_ALG_BLOCK_ONLY |
> + CRYPTO_AHASH_ALG_FINAL_NONZERO,
> }
> },
> .desc_hdr_template = DESC_HDR_TYPE_COMMON_NONSNOOP_NO_AFEU |
> @@ -3181,7 +3147,6 @@ static int talitos_cra_init_ahash(struct crypto_tfm *tfm)
> algt.alg.hash);
>
> ctx->keylen = 0;
> - crypto_ahash_set_reqsize(__crypto_ahash_cast(tfm),
> sizeof(struct talitos_ahash_req_ctx));
>
> return talitos_init_common(ctx, talitos_alg);
>
^ permalink raw reply
* [PATCH 1/1] crypto: atmel-sha204a - fix heap info leak on I2C transfer failure
From: Lothar Rubusch @ 2026-05-29 9:43 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, ardb, krzk+dt
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
When a non-blocking read operation is requested, the driver dynamically
allocates memory to track asynchronous transfer status. If the underlying
I2C transmission fails, atmel_sha204a_rng_done() logs a rate-limited
warning but incorrectly proceeds to cache the pointer to this uninitialized
buffer inside the rng->priv data field anyway.
On subsequent execution passes, atmel_sha204a_rng_read_nonblocking()
detects the stale rng->priv value, skips executing a hardware data read,
and copies up to 32 bytes of uninitialized kernel heap data from this
garbage memory pool straight back into the system's hwrng data stream.
Fix this information disclosure vector by immediately releasing the
allocated asynchronous work data buffer and explicitly clearing the
tracking pointer context whenever an I2C transaction returns a non-zero
error status.
Additionally, duplicate the tfm counter decrement within the new error
path to ensure the reference counter is properly released before executing
the early return, maintaining the driver's availability for subsequent
requests.
Fixes: da001fb651b0 ("crypto: atmel-i2c - add support for SHA204A random number generator")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-sha204a.c | 7 ++++++-
1 file changed, 6 insertions(+), 1 deletion(-)
diff --git a/drivers/crypto/atmel-sha204a.c b/drivers/crypto/atmel-sha204a.c
index 4c9af737b33a..20cd915ea8a3 100644
--- a/drivers/crypto/atmel-sha204a.c
+++ b/drivers/crypto/atmel-sha204a.c
@@ -31,10 +31,15 @@ static void atmel_sha204a_rng_done(struct atmel_i2c_work_data *work_data,
struct atmel_i2c_client_priv *i2c_priv = work_data->ctx;
struct hwrng *rng = areq;
- if (status)
+ if (status) {
dev_warn_ratelimited(&i2c_priv->client->dev,
"i2c transaction failed (%d)\n",
status);
+ kfree(work_data);
+ rng->priv = 0;
+ atomic_dec(&i2c_priv->tfm_count);
+ return;
+ }
rng->priv = (unsigned long)work_data;
atomic_dec(&i2c_priv->tfm_count);
base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
--
2.53.0
^ permalink raw reply related
* [PATCH 1/1] crypto: atmel-ecc - fix use after free situation
From: Lothar Rubusch @ 2026-05-29 9:27 UTC (permalink / raw)
To: thorsten.blum, herbert, davem, nicolas.ferre, alexandre.belloni,
claudiu.beznea, tudor.ambarus, krzk+dt
Cc: linux-crypto, linux-arm-kernel, linux-kernel, l.rubusch
Fixes a possible race condition, when having multiple of such devices
attached (identified by sashiko feedback).
The Scenario:
Thread A (Device 1 Probe): Successfully adds i2c_priv to the global
list (Line 324). The lock is released.
Thread B (An active crypto request): Concurrently calls
atmel_ecc_i2c_client_alloc(). It scans the global list, sees
Device 1, and assigns a crypto job to it.
Thread A: Moves to line 332. crypto_register_kpp() fails (e.g., out of
memory or name clash).
Thread A: Enters the error path. It removes Device 1 from the list and
frees the i2c_priv memory.
Thread B: Is still actively trying to talk to the I2C hardware using
the i2c_priv pointer it grabbed in Step 2. The memory is now
gone. Result: Kernel crash (Use-After-Free).
Fixes: 11105693fa05 ("crypto: atmel-ecc - introduce Microchip / Atmel ECC driver")
Signed-off-by: Lothar Rubusch <l.rubusch@gmail.com>
---
drivers/crypto/atmel-ecc.c | 10 ++++++++++
drivers/crypto/atmel-i2c.h | 2 ++
2 files changed, 12 insertions(+)
diff --git a/drivers/crypto/atmel-ecc.c b/drivers/crypto/atmel-ecc.c
index 0ca02995a1de..d391fe1462f6 100644
--- a/drivers/crypto/atmel-ecc.c
+++ b/drivers/crypto/atmel-ecc.c
@@ -218,6 +218,8 @@ static struct i2c_client *atmel_ecc_i2c_client_alloc(void)
list_for_each_entry(i2c_priv, &driver_data.i2c_client_list,
i2c_client_list_node) {
+ if (!i2c_priv->ready)
+ continue;
tfm_cnt = atomic_read(&i2c_priv->tfm_count);
if (tfm_cnt < min_tfm_cnt) {
min_tfm_cnt = tfm_cnt;
@@ -322,20 +324,24 @@ static int atmel_ecc_probe(struct i2c_client *client)
return ret;
i2c_priv = i2c_get_clientdata(client);
+ i2c_priv->ready = false;
spin_lock(&driver_data.i2c_list_lock);
list_add_tail(&i2c_priv->i2c_client_list_node,
&driver_data.i2c_client_list);
+ i2c_priv->ready = true;
spin_unlock(&driver_data.i2c_list_lock);
ret = crypto_register_kpp(&atmel_ecdh_nist_p256);
if (ret) {
spin_lock(&driver_data.i2c_list_lock);
+ i2c_priv->ready = false;
list_del(&i2c_priv->i2c_client_list_node);
spin_unlock(&driver_data.i2c_list_lock);
dev_err(&client->dev, "%s alg registration failed\n",
atmel_ecdh_nist_p256.base.cra_driver_name);
+ return ret;
} else {
dev_info(&client->dev, "atmel ecc algorithms registered in /proc/crypto\n");
}
@@ -347,6 +353,10 @@ static void atmel_ecc_remove(struct i2c_client *client)
{
struct atmel_i2c_client_priv *i2c_priv = i2c_get_clientdata(client);
+ spin_lock(&driver_data.i2c_list_lock);
+ i2c_priv->ready = false;
+ spin_unlock(&driver_data.i2c_list_lock);
+
/* Return EBUSY if i2c client already allocated. */
if (atomic_read(&i2c_priv->tfm_count)) {
/*
diff --git a/drivers/crypto/atmel-i2c.h b/drivers/crypto/atmel-i2c.h
index 72f04c15682f..e3b12030f9c4 100644
--- a/drivers/crypto/atmel-i2c.h
+++ b/drivers/crypto/atmel-i2c.h
@@ -129,6 +129,7 @@ struct atmel_ecc_driver_data {
* @wake_token_sz : size in bytes of the wake_token
* @tfm_count : number of active crypto transformations on i2c client
* @hwrng : hold the hardware generated rng
+ * @ready : hw client is ready to use
*
* Reads and writes from/to the i2c client are sequential. The first byte
* transmitted to the device is treated as the byte size. Any attempt to send
@@ -145,6 +146,7 @@ struct atmel_i2c_client_priv {
size_t wake_token_sz;
atomic_t tfm_count ____cacheline_aligned;
struct hwrng hwrng;
+ bool ready;
};
/**
base-commit: 5624ea54f3ba5c83d2e5503411a31a8be0278c1e
--
2.53.0
^ permalink raw reply related
* [PATCH v2] crypto: sun4i-ss - clamp PRNG seed length to prevent heap overflow
From: Tianchu Chen @ 2026-05-29 8:08 UTC (permalink / raw)
To: clabbe.montjoie, herbert, davem
Cc: wens, jernej.skrabec, samuel, linux-crypto, linux-arm-kernel,
linux-sunxi, linux-kernel
In-Reply-To: <af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev>
From: Tianchu Chen <flynnnchen@tencent.com>
sun4i_ss_prng_seed() copies the user-supplied seed into ss->seed
using the user-provided length with no bounds check. The crypto core
does not enforce slen <= seedsize before calling into the driver, so a
userspace caller via AF_ALG setsockopt(ALG_SET_KEY) can pass up to
sysctl_optmem_max bytes, overflowing the fixed-size buffer and
corrupting adjacent heap memory.
Clamp the copy length to the buffer size, matching the approach used by
loongson-rng for oversized seeds.
Discovered by Atuin - Automated Vulnerability Discovery Engine.
Fixes: 6298e948215f ("crypto: sunxi-ss - Add Allwinner Security System crypto accelerator")
Cc: stable@vger.kernel.org
Signed-off-by: Tianchu Chen <flynnnchen@tencent.com>
---
v2: Silently clamp oversized seeds with min_t instead of returning
-EINVAL (Herbert Xu).
drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
index 491fcb7b8..7f6a51dd8 100644
--- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
+++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
@@ -8,7 +8,7 @@ int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
struct rng_alg *alg = crypto_rng_alg(tfm);
algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
- memcpy(algt->ss->seed, seed, slen);
+ memcpy(algt->ss->seed, seed, min_t(unsigned int, slen, sizeof(algt->ss->seed)));
return 0;
}
--
2.51.0
^ permalink raw reply related
* Re: [PATCH] crypto: sun4i-ss: restrict PRNG seed length to prevent heap overflow
From: Tianchu Chen @ 2026-05-29 7:05 UTC (permalink / raw)
To: Herbert Xu
Cc: clabbe.montjoie, davem, wens, jernej.skrabec, samuel,
linux-crypto, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <ahkuI-Z2w0sea_ba@gondor.apana.org.au>
May 29, 2026 at 2:11 PM, "Herbert Xu" <herbert@gondor.apana.org.au mailto:herbert@gondor.apana.org.au?to=%22Herbert%20Xu%22%20%3Cherbert%40gondor.apana.org.au%3E > wrote:
>
> On Thu, May 28, 2026 at 02:53:17PM +0000, Tianchu Chen wrote:
>
> >
> > diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
> > index 491fcb7b8..010fa891c 100644
> > --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
> > +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
> > @@ -8,6 +8,8 @@ int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
> > struct rng_alg *alg = crypto_rng_alg(tfm);
> >
> > algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
> > + if (slen > sizeof(algt->ss->seed))
> > + return -EINVAL;
> >
> This should simply ignore the extra data instead of failing.
Thanks for pointing out, silent truncation is more appropriate here.
I'll send a v2 patch with min_t soon.
Best regards,
Tianchu Chen
^ permalink raw reply
* Re: [PATCH] crypto: sun4i-ss: restrict PRNG seed length to prevent heap overflow
From: Herbert Xu @ 2026-05-29 6:11 UTC (permalink / raw)
To: Tianchu Chen
Cc: clabbe.montjoie, davem, wens, jernej.skrabec, samuel,
linux-crypto, linux-arm-kernel, linux-sunxi, linux-kernel
In-Reply-To: <af749a8447bd7f0e9dd26ca6c87e9c6afecb09d9@linux.dev>
On Thu, May 28, 2026 at 02:53:17PM +0000, Tianchu Chen wrote:
>
> diff --git a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
> index 491fcb7b8..010fa891c 100644
> --- a/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
> +++ b/drivers/crypto/allwinner/sun4i-ss/sun4i-ss-prng.c
> @@ -8,6 +8,8 @@ int sun4i_ss_prng_seed(struct crypto_rng *tfm, const u8 *seed,
> struct rng_alg *alg = crypto_rng_alg(tfm);
>
> algt = container_of(alg, struct sun4i_ss_alg_template, alg.rng);
> + if (slen > sizeof(algt->ss->seed))
> + return -EINVAL;
This should simply ignore the extra data instead of failing.
Thanks,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox