lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20260108132141.6cce4827.gary@garyguo.net>
Date: Thu, 8 Jan 2026 13:21:41 +0000
From: Gary Guo <gary@...yguo.net>
To: Gladyshev Ilya <foxido@...ido.dev>
Cc: "foxido @ foxido . dev-cc= Rafael J. Wysocki" <rafael@...nel.org>, Len
 Brown <lenb@...nel.org>, Miguel Ojeda <ojeda@...nel.org>, Boqun Feng
 <boqun.feng@...il.com>, Benno Lossin <lossin@...nel.org>, Andreas Hindborg
 <a.hindborg@...nel.org>, Alice Ryhl <aliceryhl@...gle.com>, Trevor Gross
 <tmgross@...ch.edu>, Danilo Krummrich <dakr@...nel.org>, Tamir Duberstein
 <tamird@...il.com>, Armin Wolf <W_Armin@....de>,
 <platform-driver-x86@...r.kernel.org>, <linux-kernel@...r.kernel.org>,
 <rust-for-linux@...r.kernel.org>, <linux-acpi@...r.kernel.org>
Subject: Re: [PATCH 2/3] rust: implement wrapper for acpi_object

On Wed,  7 Jan 2026 23:35:32 +0300
Gladyshev Ilya <foxido@...ido.dev> wrote:

> ACPI Object is represented via union on C-side. On Rust side, this union
> is transparently wrapped for each ACPI Type, with individual methods and
> Defer implementation to represented type (integer, string, buffer, etc).
> 
> Signed-off-by: Gladyshev Ilya <foxido@...ido.dev>


Hi Gladyshev,

I've checked the `acpi_object` implementation on the C side and it appears
that the buffer is not owned by the object (however managed externally,
could either be resting in ACPI tables directly or be allocated).

Therefore, you might want to carry a lifetime to represent the lifetime of
underlying buffers?

> ---
>  rust/kernel/acpi.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 91 insertions(+)
> 
> diff --git a/rust/kernel/acpi.rs b/rust/kernel/acpi.rs
> index 9b8efa623130..ac1a9f305f6c 100644
> --- a/rust/kernel/acpi.rs
> +++ b/rust/kernel/acpi.rs
> @@ -2,6 +2,8 @@
>  
>  //! Advanced Configuration and Power Interface abstractions.
>  
> +use core::ops::Deref;
> +
>  use crate::{
>      bindings,
>      device_id::{RawDeviceId, RawDeviceIdIndex},
> @@ -63,3 +65,92 @@ macro_rules! acpi_device_table {
>          $crate::module_device_table!("acpi", $module_table_name, $table_name);
>      };
>  }
> +
> +/// An ACPI object.
> +///
> +/// This structure represents the Rust abstraction for a C [`struct acpi_object`].
> +/// You probably want to convert it into actual object type (e.g [`AcpiBuffer`]).
> +///
> +/// # Example
> +/// ```
> +/// # use kernel::prelude::*;
> +/// use kernel::acpi::{AcpiObject, AcpiBuffer};
> +///
> +/// fn read_first_acpi_byte(obj: &AcpiObject) -> Result<u8> {
> +///     let buf: &AcpiBuffer = obj.try_into()?;
> +///
> +///     Ok(buf[0])
> +/// }
> +/// ```
> +///
> +/// [`struct acpi_object`]: srctree/include/acpi/actypes.h
> +#[repr(transparent)]
> +pub struct AcpiObject(bindings::acpi_object);
> +
> +impl AcpiObject {
> +    /// Returns object type id (see [`actypes.h`](srctree/include/acpi/actypes.h)).
> +    pub fn type_id(&self) -> u32 {
> +        // SAFETY: `type` field is valid in all union variants.
> +        unsafe { self.0.type_ }
> +    }

This should probably be an enum instead of just integer.

> +}
> +
> +/// Generate wrapper type for AcpiObject subtype.
> +///
> +/// For given subtype implements
> +/// - `#[repr(transparent)]` type wrapper,
> +/// - `TryFrom<&AcpiObject> for &SubType` trait,
> +/// - unsafe from_unchecked() for 'trusted' conversion.
> +macro_rules! acpi_object_subtype {
> +    ($subtype_name:ident <- ($acpi_type:ident, $field_name:ident, $union_type:ty)) => {
> +        /// Wraps `acpi_object` subtype.
> +        #[repr(transparent)]
> +        pub struct $subtype_name($union_type);

Instead of wrapping the bindgen-generated subtypes, I would rather this to
be a transparent wrapper of `acpi_object`, with an invariant that the
specific union field is active.

This way you do not have to name the bindgen-generated names.

> +
> +        impl<'a> TryFrom<&'a AcpiObject> for &'a $subtype_name {
> +            type Error = Error;
> +
> +            fn try_from(value: &'a AcpiObject) -> core::result::Result<Self, Self::Error> {
> +                if (value.type_id() != $subtype_name::ACPI_TYPE) {
> +                    return Err(EINVAL);
> +                }
> +
> +                // SAFETY: Requested cast is valid because we validated type_id
> +                Ok(unsafe { $subtype_name::from_unchecked(&value) })
> +            }
> +        }

It feels like this can be better implemented by having a sealed trait for
all possible ACPI object types?

> +
> +        impl $subtype_name {
> +            /// Int value, representing this ACPI type (see [`acpitypes.h`]).
> +            ///
> +            /// [`acpitypes.h`]: srctree/include/linux/acpitypes.h
> +            pub const ACPI_TYPE: u32 = bindings::$acpi_type;
> +
> +            /// Converts opaque AcpiObject reference into exact ACPI type reference.
> +            ///
> +            /// # Safety
> +            ///
> +            /// - Requested cast should be valid (value.type_id() is `Self::ACPI_TYPE`).
> +            pub unsafe fn from_unchecked(value: &AcpiObject) -> &Self {
> +                // SAFETY:
> +                // - $field_name is currently active union's field due to external safety contract,
> +                // - Transmuting to `repr(transparent)` wrapper is safe.
> +                unsafe {
> +                    ::core::mem::transmute::<&$union_type, &$subtype_name>(&value.0.$field_name)
> +                }
> +            }
> +        }
> +    };
> +}
> +
> +acpi_object_subtype!(AcpiBuffer
> +    <- (ACPI_TYPE_BUFFER, buffer, bindings::acpi_object__bindgen_ty_3));
> +
> +impl Deref for AcpiBuffer {
> +    type Target = [u8];
> +
> +    fn deref(&self) -> &Self::Target {
> +        // SAFETY: (pointer, length) indeed represents byte slice.
> +        unsafe { ::core::slice::from_raw_parts(self.0.pointer, self.0.length as usize) }
> +    }
> +}


Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ