* [PATCH v5 0/4] rust: Add safe pointer formatting support
@ 2025-12-26 14:07 Ke Sun
2025-12-26 14:07 ` [PATCH v5 1/4] lib/vsprintf: Export ptr_to_hashval for Rust use Ke Sun
` (3 more replies)
0 siblings, 4 replies; 7+ messages in thread
From: Ke Sun @ 2025-12-26 14:07 UTC (permalink / raw)
To: Dirk Behme, Miguel Ojeda, Petr Mladek, Steven Rostedt, Timur Tabi,
Danilo Krummrich, Benno Lossin
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Tamir Duberstein, Ke Sun,
rust-for-linux, Ke Sun
This patch series adds safe pointer formatting support for Rust kernel code,
providing three pointer wrapper types (HashedPtr, RawPtr, RestrictedPtr) that
correspond to C kernel's printk format specifiers %p, %px, and %pK.
The implementation ensures that raw pointers are automatically hashed when
formatted with {:p}, providing safe default behavior that prevents information
leaks about kernel memory layout. Users can also explicitly use wrapper types
when they need specific formatting behavior.
---
v5:
- Format use statements in rust/kernel/ptr.rs and rust/kernel/fmt.rs using kernel
vertical style with alphabetical ordering
- Remove unnecessary SAFETY comment in rust/kernel/ptr.rs (addressed Clippy warning)
- Update type ordering to alphabetical (HashedPtr, RawPtr, RestrictedPtr) in
fmt.rs macro invocation
v4: https://lore.kernel.org/rust-for-linux/20251225225709.3944255-1-sunke@kylinos.cn/
- Use Pointer::fmt() instead of write!(f, "{:p}", ...) to preserve formatting
options (width, alignment, padding characters)
- Improve code structure: reduce unsafe block scope, use early return pattern
- Add doctests with formatting option tests for all pointer wrapper types
- Enhance documentation with detailed formatting options section, including
examples for width, alignment, and padding
- Fix RestrictedPtr example to use pr_info! instead of seq_print! in docs
v3: https://lore.kernel.org/rust-for-linux/20251224081315.729684-1-sunke@kylinos.cn/
- Export ptr_to_hashval() from lib/vsprintf.c for Rust pointer hashing
- Add three pointer wrapper types (HashedPtr, RestrictedPtr, RawPtr) in
rust/kernel/ptr.rs corresponding to %p, %pK, and %px
- Make raw pointers automatically use HashedPtr when formatted with {:p}
- Add documentation for pointer wrapper types
v2: https://lore.kernel.org/rust-for-linux/20251223033018.2814732-1-sunke@kylinos.cn/
- Disabled {:p} raw pointer printing by default to prevent accidental
information leaks
v1: https://lore.kernel.org/rust-for-linux/20251218032709.2184890-1-sunke@kylinos.cn/
- Initial implementation that directly printed raw pointers
---
Ke Sun (4):
lib/vsprintf: Export ptr_to_hashval for Rust use
rust: kernel: Add pointer wrapper types for safe pointer formatting
rust: fmt: Default raw pointer formatting to HashedPtr
docs: rust: Add pointer formatting documentation
Documentation/rust/index.rst | 1 +
Documentation/rust/pointer-formatting.rst | 101 +++++++++
lib/vsprintf.c | 1 +
rust/helpers/fmt.c | 65 ++++++
rust/helpers/helpers.c | 3 +-
rust/kernel/fmt.rs | 69 ++++++-
rust/kernel/ptr.rs | 240 +++++++++++++++++++++-
7 files changed, 475 insertions(+), 5 deletions(-)
create mode 100644 Documentation/rust/pointer-formatting.rst
create mode 100644 rust/helpers/fmt.c
--
2.43.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v5 1/4] lib/vsprintf: Export ptr_to_hashval for Rust use
2025-12-26 14:07 [PATCH v5 0/4] rust: Add safe pointer formatting support Ke Sun
@ 2025-12-26 14:07 ` Ke Sun
2025-12-26 14:07 ` [PATCH v5 2/4] rust: kernel: Add pointer wrapper types for safe pointer formatting Ke Sun
` (2 subsequent siblings)
3 siblings, 0 replies; 7+ messages in thread
From: Ke Sun @ 2025-12-26 14:07 UTC (permalink / raw)
To: Dirk Behme, Miguel Ojeda, Petr Mladek, Steven Rostedt, Timur Tabi,
Danilo Krummrich, Benno Lossin
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Tamir Duberstein, Ke Sun,
rust-for-linux, Ke Sun
Export ptr_to_hashval() with EXPORT_SYMBOL_GPL to allow Rust code
to call this function for pointer hashing, which is needed for the
HashedPtr and RestrictedPtr wrapper types in rust/kernel/ptr.rs.
This function is used to hash kernel pointers before printing them,
preventing information leaks about kernel memory layout.
Signed-off-by: Ke Sun <sunke@kylinos.cn>
---
lib/vsprintf.c | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/vsprintf.c b/lib/vsprintf.c
index a3790c43a0aba..d1c682afd792c 100644
--- a/lib/vsprintf.c
+++ b/lib/vsprintf.c
@@ -811,6 +811,7 @@ int ptr_to_hashval(const void *ptr, unsigned long *hashval_out)
{
return __ptr_to_hashval(ptr, hashval_out);
}
+EXPORT_SYMBOL_GPL(ptr_to_hashval);
static char *ptr_to_id(char *buf, char *end, const void *ptr,
struct printf_spec spec)
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v5 2/4] rust: kernel: Add pointer wrapper types for safe pointer formatting
2025-12-26 14:07 [PATCH v5 0/4] rust: Add safe pointer formatting support Ke Sun
2025-12-26 14:07 ` [PATCH v5 1/4] lib/vsprintf: Export ptr_to_hashval for Rust use Ke Sun
@ 2025-12-26 14:07 ` Ke Sun
2025-12-26 15:10 ` Dirk Behme
2025-12-26 14:07 ` [PATCH v5 3/4] rust: fmt: Default raw pointer formatting to HashedPtr Ke Sun
2025-12-26 14:07 ` [PATCH v5 4/4] docs: rust: Add pointer formatting documentation Ke Sun
3 siblings, 1 reply; 7+ messages in thread
From: Ke Sun @ 2025-12-26 14:07 UTC (permalink / raw)
To: Dirk Behme, Miguel Ojeda, Petr Mladek, Steven Rostedt, Timur Tabi,
Danilo Krummrich, Benno Lossin
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Tamir Duberstein, Ke Sun,
rust-for-linux, Ke Sun
Add three pointer wrapper types (HashedPtr, RestrictedPtr, RawPtr) to
rust/kernel/ptr.rs that correspond to C kernel's printk format specifiers
%p, %pK, and %px. These types provide type-safe pointer formatting that
matches C kernel patterns.
These wrapper types implement core::fmt::Pointer and delegate to the
corresponding kernel formatting functions, enabling safe pointer
formatting in Rust code that prevents information leaks about kernel
memory layout.
Users can explicitly use these types:
pr_info!("{:p}\n", HashedPtr::from(ptr));
pr_info!("{:p}\n", RestrictedPtr::from(ptr));
pr_info!("{:p}\n", RawPtr::from(ptr));
Signed-off-by: Ke Sun <sunke@kylinos.cn>
---
rust/helpers/fmt.c | 65 +++++++++++
rust/helpers/helpers.c | 3 +-
rust/kernel/ptr.rs | 240 ++++++++++++++++++++++++++++++++++++++++-
3 files changed, 304 insertions(+), 4 deletions(-)
create mode 100644 rust/helpers/fmt.c
diff --git a/rust/helpers/fmt.c b/rust/helpers/fmt.c
new file mode 100644
index 0000000000000..4ee716bbfe284
--- /dev/null
+++ b/rust/helpers/fmt.c
@@ -0,0 +1,65 @@
+// SPDX-License-Identifier: GPL-2.0
+
+/*
+ * Copyright (C) 2018 - 2025 KylinSoft Co., Ltd. All rights reserved.
+ * Copyright (C) 2018 - 2025 Ke Sun <sunke@kylinos.cn>
+ */
+
+#include <linux/kernel.h>
+#include <linux/cred.h>
+#include <linux/capability.h>
+#include <linux/hardirq.h>
+#include <linux/printk.h>
+
+/*
+ * Helper function for Rust to format a restricted pointer (%pK).
+ *
+ * This function determines what pointer value should be printed based on the
+ * kptr_restrict sysctl setting:
+ *
+ * - kptr_restrict == 0: Returns the original pointer (will be hashed by caller)
+ * - kptr_restrict == 1: Returns the original pointer if the current process has
+ * CAP_SYSLOG and same euid/egid, NULL otherwise
+ * - kptr_restrict >= 2: Always returns NULL
+ *
+ * Returns:
+ * - The original pointer if it should be printed (case 0 or case 1 with permission)
+ * - NULL if it should not be printed (no permission, IRQ context, or restrict >= 2)
+ */
+const void *rust_helper_kptr_restrict_value(const void *ptr)
+{
+ switch (kptr_restrict) {
+ case 0:
+ /* Handle as %p - return original pointer for hashing */
+ return ptr;
+ case 1: {
+ const struct cred *cred;
+
+ /*
+ * kptr_restrict==1 cannot be used in IRQ context because the
+ * capability check would be meaningless (no process context).
+ */
+ if (in_hardirq() || in_serving_softirq() || in_nmi())
+ return NULL;
+
+ /*
+ * Only return the real pointer value if the current process has
+ * CAP_SYSLOG and is running with the same credentials it started with.
+ * This prevents privilege escalation attacks where a process opens a
+ * file with %pK, then elevates privileges before reading it.
+ */
+ cred = current_cred();
+ if (!has_capability_noaudit(current, CAP_SYSLOG) ||
+ !uid_eq(cred->euid, cred->uid) ||
+ !gid_eq(cred->egid, cred->gid))
+ return NULL;
+ break;
+ }
+ case 2:
+ default:
+ /* Always hide pointer values when kptr_restrict >= 2 */
+ return NULL;
+ }
+
+ return ptr;
+}
diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
index 79c72762ad9c4..b6877fe8dafc0 100644
--- a/rust/helpers/helpers.c
+++ b/rust/helpers/helpers.c
@@ -27,8 +27,9 @@
#include "dma.c"
#include "drm.c"
#include "err.c"
-#include "irq.c"
+#include "fmt.c"
#include "fs.c"
+#include "irq.c"
#include "io.c"
#include "jump_label.c"
#include "kunit.c"
diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
index e3893ed04049d..ed5069c954146 100644
--- a/rust/kernel/ptr.rs
+++ b/rust/kernel/ptr.rs
@@ -1,11 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
//! Types and functions to work with pointers and addresses.
+//!
+//! This module provides wrapper types for formatting kernel pointers that correspond to the
+//! C kernel's printk format specifiers `%p`, `%pK`, and `%px`.
-use core::mem::align_of;
-use core::num::NonZero;
+use core::{
+ fmt,
+ fmt::Pointer,
+ mem::align_of,
+ num::NonZero, //
+};
-use crate::build_assert;
+use crate::{
+ bindings,
+ build_assert,
+ ffi::c_void, //
+};
/// Type representing an alignment, which is always a power of two.
///
@@ -225,3 +236,226 @@ fn align_up(self, alignment: Alignment) -> Option<Self> {
}
impl_alignable_uint!(u8, u16, u32, u64, usize);
+
+/// Placeholder string used when pointer hashing is not ready yet.
+const PTR_PLACEHOLDER: &str = if core::mem::size_of::<*const c_void>() == 8 {
+ "(____ptrval____)"
+} else {
+ "(ptrval)"
+};
+
+/// Macro to implement common methods for pointer wrapper types.
+macro_rules! impl_ptr_wrapper {
+ ($($name:ident),* $(,)?) => {
+ $(
+ impl $name {
+ /// Creates a new instance from a raw pointer.
+ #[inline]
+ pub fn from<T>(ptr: *const T) -> Self {
+ Self(ptr.cast())
+ }
+
+ /// Creates a new instance from a mutable raw pointer.
+ #[inline]
+ pub fn from_mut<T>(ptr: *mut T) -> Self {
+ Self(ptr.cast())
+ }
+
+ /// Returns the inner raw pointer.
+ #[inline]
+ pub fn as_ptr(&self) -> *const c_void {
+ self.0
+ }
+ }
+
+ impl<T> From<*const T> for $name {
+ #[inline]
+ fn from(ptr: *const T) -> Self {
+ Self::from(ptr)
+ }
+ }
+
+ impl<T> From<*mut T> for $name {
+ #[inline]
+ fn from(ptr: *mut T) -> Self {
+ Self::from_mut(ptr)
+ }
+ }
+ )*
+ };
+}
+
+/// Helper function to hash a pointer and format it.
+///
+/// Returns `Ok(())` if the hash was successfully computed and formatted,
+/// or the placeholder string if hashing is not ready yet.
+fn format_hashed_ptr(ptr: *const c_void, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ let mut hashval: crate::ffi::c_ulong = 0;
+ // SAFETY: We're calling the kernel's ptr_to_hashval function which handles
+ // hashing. This is safe as long as ptr is a valid pointer value.
+ let ret = unsafe { bindings::ptr_to_hashval(ptr, core::ptr::addr_of_mut!(hashval)) };
+
+ if ret != 0 {
+ // Hash not ready yet, print placeholder
+ return f.write_str(PTR_PLACEHOLDER);
+ }
+
+ // Successfully got hash value, format it using Pointer::fmt to preserve
+ // formatting options (width, alignment, padding, etc.)
+ Pointer::fmt(&(hashval as *const c_void), f)
+}
+
+/// A pointer that will be hashed when printed (corresponds to `%p`).
+///
+/// This is the default behavior for kernel pointers - they are hashed to prevent
+/// leaking information about the kernel memory layout.
+///
+/// # Example
+///
+/// ```
+/// use kernel::{
+/// prelude::fmt,
+/// ptr::HashedPtr,
+/// str::CString, //
+/// };
+///
+/// let ptr = HashedPtr::from(0x12345678 as *const u8);
+/// pr_info!("Hashed pointer: {:016p}\n", ptr);
+///
+/// // Width option test
+/// let cstr = CString::try_from_fmt(fmt!("{:30p}", ptr))?;
+/// let width_30 = cstr.to_str()?;
+/// assert_eq!(width_30.len(), 30);
+/// # Ok::<(), kernel::error::Error>(())
+/// ```
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug)]
+pub struct HashedPtr(*const c_void);
+
+impl fmt::Pointer for HashedPtr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Handle NULL pointers - print them directly
+ if self.0.is_null() {
+ return Pointer::fmt(&self.0, f);
+ }
+
+ format_hashed_ptr(self.0, f)
+ }
+}
+
+/// A pointer that will be restricted based on `kptr_restrict` when printed (corresponds to `%pK`).
+///
+/// This is intended for use in procfs/sysfs files that are read by userspace.
+/// The behavior depends on the `kptr_restrict` sysctl setting.
+///
+/// # Example
+///
+/// ```
+/// use kernel::{
+/// prelude::fmt,
+/// ptr::RestrictedPtr,
+/// str::CString, //
+/// };
+///
+/// let ptr = RestrictedPtr::from(0x12345678 as *const u8);
+/// pr_info!("Restricted pointer: {:016p}\n", ptr);
+///
+/// // Width option test
+/// let cstr = CString::try_from_fmt(fmt!("{:30p}", ptr))?;
+/// let width_30 = cstr.to_str()?;
+/// assert_eq!(width_30.len(), 30);
+/// # Ok::<(), kernel::error::Error>(())
+/// ```
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug)]
+pub struct RestrictedPtr(*const c_void);
+
+impl fmt::Pointer for RestrictedPtr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Handle NULL pointers
+ if self.0.is_null() {
+ return Pointer::fmt(&self.0, f);
+ }
+
+ // Use kptr_restrict_value to handle all kptr_restrict cases.
+ // SAFETY: kptr_restrict_value handles capability checks and IRQ context.
+ // - Returns NULL if no permission, IRQ context, or kptr_restrict >= 2
+ // - Returns the original pointer if kptr_restrict == 0 (needs hashing)
+ // - Returns the original pointer if kptr_restrict == 1 with permission (print raw)
+ let restricted_ptr = unsafe { bindings::kptr_restrict_value(self.0) };
+
+ if restricted_ptr.is_null() {
+ // No permission, IRQ context, or kptr_restrict >= 2 - print 0
+ return Pointer::fmt(&core::ptr::null::<c_void>(), f);
+ }
+
+ // restricted_ptr is non-null, meaning we should print something.
+ // SAFETY: Reading kptr_restrict is safe as it's a kernel variable.
+ let restrict = unsafe { bindings::kptr_restrict };
+
+ if restrict == 0 {
+ // kptr_restrict == 0: hash the pointer (same as %p)
+ format_hashed_ptr(self.0, f)
+ } else {
+ // kptr_restrict == 1 with permission: print the raw pointer directly (like %px)
+ // This matches C behavior: pointer_string() prints the raw address
+ Pointer::fmt(&restricted_ptr, f)
+ }
+ }
+}
+
+/// A pointer that will be printed as its raw address (corresponds to `%px`).
+///
+/// **Warning**: This exposes the real kernel address and should only be used
+/// for debugging purposes. Consider using [`HashedPtr`] or [`RestrictedPtr`] instead.
+///
+/// # Example
+///
+/// ```
+/// use kernel::{
+/// prelude::fmt,
+/// ptr::RawPtr,
+/// str::CString, //
+/// };
+///
+/// let ptr = RawPtr::from(0x12345678 as *const u8);
+///
+/// // Basic formatting
+/// let cstr = CString::try_from_fmt(fmt!("{:p}", ptr))?;
+/// let formatted = cstr.to_str()?;
+/// assert_eq!(formatted, "0x12345678");
+///
+/// // Right align with zero padding, width 30
+/// let cstr = CString::try_from_fmt(fmt!("{:0>30p}", ptr))?;
+/// let right_zero = cstr.to_str()?;
+/// assert_eq!(right_zero, "000000000000000000000x12345678");
+///
+/// // Left align with zero padding, width 30
+/// let cstr = CString::try_from_fmt(fmt!("{:0<30p}", ptr))?;
+/// let left_zero = cstr.to_str()?;
+/// assert_eq!(left_zero, "0x1234567800000000000000000000");
+///
+/// // Center align with zero padding, width 30
+/// let cstr = CString::try_from_fmt(fmt!("{:0^30p}", ptr))?;
+/// let center_zero = cstr.to_str()?;
+/// assert_eq!(center_zero, "00000000000x123456780000000000");
+/// # Ok::<(), kernel::error::Error>(())
+/// ```
+#[repr(transparent)]
+#[derive(Copy, Clone, Debug)]
+pub struct RawPtr(*const c_void);
+
+impl fmt::Pointer for RawPtr {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // Directly format the raw address - no hashing or restriction.
+ // This corresponds to %px behavior.
+ Pointer::fmt(&self.0, f)
+ }
+}
+
+// Implement common methods for all pointer wrapper types
+impl_ptr_wrapper!(
+ HashedPtr,
+ RawPtr,
+ RestrictedPtr, //
+);
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v5 3/4] rust: fmt: Default raw pointer formatting to HashedPtr
2025-12-26 14:07 [PATCH v5 0/4] rust: Add safe pointer formatting support Ke Sun
2025-12-26 14:07 ` [PATCH v5 1/4] lib/vsprintf: Export ptr_to_hashval for Rust use Ke Sun
2025-12-26 14:07 ` [PATCH v5 2/4] rust: kernel: Add pointer wrapper types for safe pointer formatting Ke Sun
@ 2025-12-26 14:07 ` Ke Sun
2025-12-26 14:07 ` [PATCH v5 4/4] docs: rust: Add pointer formatting documentation Ke Sun
3 siblings, 0 replies; 7+ messages in thread
From: Ke Sun @ 2025-12-26 14:07 UTC (permalink / raw)
To: Dirk Behme, Miguel Ojeda, Petr Mladek, Steven Rostedt, Timur Tabi,
Danilo Krummrich, Benno Lossin
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Tamir Duberstein, Ke Sun,
rust-for-linux, Ke Sun
Make raw pointers (*const T, *mut T) automatically use HashedPtr when
formatted with {:p}, providing safe default behavior for kernel pointers.
This allows users to format raw pointers directly:
pr_info!("{:p}\n", ptr); // Automatically hashed
While still allowing explicit use of wrapper types when needed:
pr_info!("{:p}\n", RestrictedPtr::from(ptr));
pr_info!("{:p}\n", RawPtr::from(ptr));
Signed-off-by: Ke Sun <sunke@kylinos.cn>
---
rust/kernel/fmt.rs | 69 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 68 insertions(+), 1 deletion(-)
diff --git a/rust/kernel/fmt.rs b/rust/kernel/fmt.rs
index 84d634201d90a..197687261b4e9 100644
--- a/rust/kernel/fmt.rs
+++ b/rust/kernel/fmt.rs
@@ -6,6 +6,12 @@
pub use core::fmt::{Arguments, Debug, Error, Formatter, Result, Write};
+use crate::ptr::{
+ HashedPtr,
+ RawPtr,
+ RestrictedPtr, //
+};
+
/// Internal adapter used to route allow implementations of formatting traits for foreign types.
///
/// It is inserted automatically by the [`fmt!`] macro and is not meant to be used directly.
@@ -28,7 +34,68 @@ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
}
use core::fmt::{Binary, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex};
-impl_fmt_adapter_forward!(Debug, LowerHex, UpperHex, Octal, Binary, Pointer, LowerExp, UpperExp);
+impl_fmt_adapter_forward!(Debug, LowerHex, UpperHex, Octal, Binary, LowerExp, UpperExp);
+
+// Special handling for Pointer: default to HashedPtr for raw pointers.
+// This overrides the default Pointer implementation for raw pointers to use hashing,
+// which is the safe default behavior for kernel pointers.
+impl<T> Pointer for Adapter<*const T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(ptr) = self;
+ Pointer::fmt(&HashedPtr::from(*ptr), f)
+ }
+}
+
+impl<T> Pointer for Adapter<*mut T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(ptr) = self;
+ Pointer::fmt(&HashedPtr::from_mut(*ptr), f)
+ }
+}
+
+// Handle references to raw pointers (needed when pointers are passed by reference in macros).
+impl<T> Pointer for Adapter<&*const T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(ptr) = self;
+ Pointer::fmt(&HashedPtr::from(**ptr), f)
+ }
+}
+
+impl<T> Pointer for Adapter<&*mut T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(ptr) = self;
+ Pointer::fmt(&HashedPtr::from_mut(**ptr), f)
+ }
+}
+
+// For wrapper types that implement Pointer (like HashedPtr, RawPtr, RestrictedPtr),
+// forward to their implementation. This allows explicit wrapper types to use their
+// own formatting logic instead of being converted to HashedPtr.
+macro_rules! impl_pointer_adapter_forward {
+ ($($ty:ty),* $(,)?) => {
+ $(
+ impl Pointer for Adapter<$ty> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(t) = self;
+ Pointer::fmt(t, f)
+ }
+ }
+
+ impl Pointer for Adapter<&$ty> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(t) = self;
+ Pointer::fmt(*t, f)
+ }
+ }
+ )*
+ };
+}
+
+impl_pointer_adapter_forward!(
+ HashedPtr,
+ RawPtr,
+ RestrictedPtr, //
+);
/// A copy of [`core::fmt::Display`] that allows us to implement it for foreign types.
///
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v5 4/4] docs: rust: Add pointer formatting documentation
2025-12-26 14:07 [PATCH v5 0/4] rust: Add safe pointer formatting support Ke Sun
` (2 preceding siblings ...)
2025-12-26 14:07 ` [PATCH v5 3/4] rust: fmt: Default raw pointer formatting to HashedPtr Ke Sun
@ 2025-12-26 14:07 ` Ke Sun
3 siblings, 0 replies; 7+ messages in thread
From: Ke Sun @ 2025-12-26 14:07 UTC (permalink / raw)
To: Dirk Behme, Miguel Ojeda, Petr Mladek, Steven Rostedt, Timur Tabi,
Danilo Krummrich, Benno Lossin
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Tamir Duberstein, Ke Sun,
rust-for-linux, Ke Sun
Add a brief documentation for Rust pointer wrapper types (HashedPtr,
RestrictedPtr, RawPtr) that correspond to C kernel's printk format
specifiers %p, %pK, and %px.
The documentation provides:
- Overview of the three wrapper types
- Usage examples for each type
- When to use each type
- Security considerations
This complements the general pointer formatting documentation in
Documentation/core-api/printk-formats.rst.
Signed-off-by: Ke Sun <sunke@kylinos.cn>
---
Documentation/rust/index.rst | 1 +
Documentation/rust/pointer-formatting.rst | 101 ++++++++++++++++++++++
2 files changed, 102 insertions(+)
create mode 100644 Documentation/rust/pointer-formatting.rst
diff --git a/Documentation/rust/index.rst b/Documentation/rust/index.rst
index ec62001c7d8c7..4f4f8b393031e 100644
--- a/Documentation/rust/index.rst
+++ b/Documentation/rust/index.rst
@@ -55,6 +55,7 @@ more details.
coding-guidelines
arch-support
testing
+ pointer-formatting
You can also find learning materials for Rust in its section in
:doc:`../process/kernel-docs`.
diff --git a/Documentation/rust/pointer-formatting.rst b/Documentation/rust/pointer-formatting.rst
new file mode 100644
index 0000000000000..9407307216c9a
--- /dev/null
+++ b/Documentation/rust/pointer-formatting.rst
@@ -0,0 +1,101 @@
+.. SPDX-License-Identifier: GPL-2.0
+
+Pointer Formatting in Rust
+===========================
+
+This document describes how to format kernel pointers safely in Rust code,
+corresponding to the C kernel's printk format specifiers ``%p``, ``%pK``, and ``%px``.
+
+For general information about pointer formatting in the kernel, please refer to
+:doc:`../core-api/printk-formats`.
+
+Overview
+--------
+
+The Rust kernel provides three wrapper types for formatting kernel pointers:
+
+- **``HashedPtr``** → ``%p`` (hashed, default)
+- **``RestrictedPtr``** → ``%pK`` (restricted, respects ``kptr_restrict``)
+- **``RawPtr``** → ``%px`` (raw address, debug only)
+
+When formatting raw pointers (``*const T`` or ``*mut T``) with ``{:p}``,
+they are automatically wrapped with ``HashedPtr``, providing safe default behavior.
+
+HashedPtr (%p)
+--------------
+
+Use ``HashedPtr`` for general kernel logging. Pointers are hashed before printing
+to prevent leaking information about the kernel memory layout.
+
+**Example**::
+
+ use kernel::ptr::HashedPtr;
+
+ pr_info!("Device pointer: {:p}\n", HashedPtr::from(ptr));
+
+RestrictedPtr (%pK)
+-------------------
+
+Use ``RestrictedPtr`` when producing content of a file read by userspace from
+e.g. procfs or sysfs (using e.g. ``seq_print!()``, not ``pr_info!()``). The behavior
+depends on the ``kptr_restrict`` sysctl setting.
+
+**Example**::
+
+ use kernel::ptr::RestrictedPtr;
+
+ seq_print!(seq_file, "Pointer: {:p}\n", RestrictedPtr::from(ptr));
+
+For more details about ``kptr_restrict``, see :doc:`../admin-guide/sysctl/kernel`.
+
+RawPtr (%px)
+------------
+
+**Warning**: This exposes the real kernel address and should **only** be used
+for debugging purposes.
+
+**Example**::
+
+ use kernel::ptr::RawPtr;
+
+ pr_info!("Debug pointer: {:p}\n", RawPtr::from(ptr));
+
+Formatting Options
+------------------
+
+All pointer wrapper types support standard Rust formatting options including
+width, alignment, and padding characters. These options are preserved through
+the formatting system.
+
+The following examples demonstrate formatting options using ``RawPtr`` for
+predictable output. The same options work with ``HashedPtr`` and
+``RestrictedPtr``, though the exact output may vary due to pointer hashing::
+
+ use kernel::ptr::RawPtr;
+
+ // Basic formatting
+ pr_info!("Pointer: {:p}\n", RawPtr::from(ptr));
+
+ // Minimum width
+ pr_info!("Pointer: {:30p}\n", RawPtr::from(ptr));
+
+ // Right align with zero padding
+ pr_info!("Pointer: {:0>30p}\n", RawPtr::from(ptr));
+
+ // Left align with zero padding
+ pr_info!("Pointer: {:0<30p}\n", RawPtr::from(ptr));
+
+ // Center align with zero padding
+ pr_info!("Pointer: {:0^30p}\n", RawPtr::from(ptr));
+
+ // Right align with space padding (default)
+ pr_info!("Pointer: {:>30p}\n", RawPtr::from(ptr));
+
+ // Center align with custom padding character
+ pr_info!("Pointer: {:*^30p}\n", RawPtr::from(ptr));
+
+See Also
+--------
+
+- :doc:`../core-api/printk-formats` - General pointer formatting documentation
+- `rust/kernel/ptr.rs <srctree/rust/kernel/ptr.rs>`_ - Implementation
--
2.43.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v5 2/4] rust: kernel: Add pointer wrapper types for safe pointer formatting
2025-12-26 14:07 ` [PATCH v5 2/4] rust: kernel: Add pointer wrapper types for safe pointer formatting Ke Sun
@ 2025-12-26 15:10 ` Dirk Behme
2025-12-27 2:02 ` Ke Sun
0 siblings, 1 reply; 7+ messages in thread
From: Dirk Behme @ 2025-12-26 15:10 UTC (permalink / raw)
To: Ke Sun, Miguel Ojeda, Petr Mladek, Steven Rostedt, Timur Tabi,
Danilo Krummrich, Benno Lossin
Cc: Boqun Feng, Gary Guo, Björn Roy Baron, Andreas Hindborg,
Alice Ryhl, Trevor Gross, Tamir Duberstein, Ke Sun,
rust-for-linux
On 26.12.25 15:07, Ke Sun wrote:
> Add three pointer wrapper types (HashedPtr, RestrictedPtr, RawPtr) to
> rust/kernel/ptr.rs that correspond to C kernel's printk format specifiers
> %p, %pK, and %px. These types provide type-safe pointer formatting that
> matches C kernel patterns.
>
> These wrapper types implement core::fmt::Pointer and delegate to the
> corresponding kernel formatting functions, enabling safe pointer
> formatting in Rust code that prevents information leaks about kernel
> memory layout.
>
> Users can explicitly use these types:
> pr_info!("{:p}\n", HashedPtr::from(ptr));
> pr_info!("{:p}\n", RestrictedPtr::from(ptr));
> pr_info!("{:p}\n", RawPtr::from(ptr));
>
> Signed-off-by: Ke Sun <sunke@kylinos.cn>
> ---
> rust/helpers/fmt.c | 65 +++++++++++
> rust/helpers/helpers.c | 3 +-
> rust/kernel/ptr.rs | 240 ++++++++++++++++++++++++++++++++++++++++-
> 3 files changed, 304 insertions(+), 4 deletions(-)
> create mode 100644 rust/helpers/fmt.c
....
> diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
> index 79c72762ad9c4..b6877fe8dafc0 100644
> --- a/rust/helpers/helpers.c
> +++ b/rust/helpers/helpers.c
> @@ -27,8 +27,9 @@
> #include "dma.c"
> #include "drm.c"
> #include "err.c"
> -#include "irq.c"
> +#include "fmt.c"
> #include "fs.c"
> +#include "irq.c"
> #include "io.c"
> #include "jump_label.c"
> #include "kunit.c"
> diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
> index e3893ed04049d..ed5069c954146 100644
> --- a/rust/kernel/ptr.rs
> +++ b/rust/kernel/ptr.rs
> @@ -1,11 +1,22 @@
> // SPDX-License-Identifier: GPL-2.0
>
> //! Types and functions to work with pointers and addresses.
> +//!
> +//! This module provides wrapper types for formatting kernel pointers that correspond to the
> +//! C kernel's printk format specifiers `%p`, `%pK`, and `%px`.
>
> -use core::mem::align_of;
> -use core::num::NonZero;
> +use core::{
> + fmt,
> + fmt::Pointer,
> + mem::align_of,
> + num::NonZero, //
> +};
>
> -use crate::build_assert;
> +use crate::{
> + bindings,
> + build_assert,
> + ffi::c_void, //
> +};
>
> /// Type representing an alignment, which is always a power of two.
> ///
> @@ -225,3 +236,226 @@ fn align_up(self, alignment: Alignment) -> Option<Self> {
> }
>
> impl_alignable_uint!(u8, u16, u32, u64, usize);
> +
> +/// Placeholder string used when pointer hashing is not ready yet.
> +const PTR_PLACEHOLDER: &str = if core::mem::size_of::<*const c_void>() == 8 {
> + "(____ptrval____)"
> +} else {
> + "(ptrval)"
> +};
> +
> +/// Macro to implement common methods for pointer wrapper types.
> +macro_rules! impl_ptr_wrapper {
> + ($($name:ident),* $(,)?) => {
> + $(
> + impl $name {
> + /// Creates a new instance from a raw pointer.
> + #[inline]
> + pub fn from<T>(ptr: *const T) -> Self {
> + Self(ptr.cast())
> + }
> +
> + /// Creates a new instance from a mutable raw pointer.
> + #[inline]
> + pub fn from_mut<T>(ptr: *mut T) -> Self {
> + Self(ptr.cast())
> + }
> +
> + /// Returns the inner raw pointer.
> + #[inline]
> + pub fn as_ptr(&self) -> *const c_void {
> + self.0
> + }
> + }
> +
> + impl<T> From<*const T> for $name {
> + #[inline]
> + fn from(ptr: *const T) -> Self {
> + Self::from(ptr)
> + }
> + }
> +
> + impl<T> From<*mut T> for $name {
> + #[inline]
> + fn from(ptr: *mut T) -> Self {
> + Self::from_mut(ptr)
> + }
> + }
> + )*
> + };
> +}
> +
> +/// Helper function to hash a pointer and format it.
> +///
> +/// Returns `Ok(())` if the hash was successfully computed and formatted,
> +/// or the placeholder string if hashing is not ready yet.
> +fn format_hashed_ptr(ptr: *const c_void, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> + let mut hashval: crate::ffi::c_ulong = 0;
> + // SAFETY: We're calling the kernel's ptr_to_hashval function which handles
> + // hashing. This is safe as long as ptr is a valid pointer value.
> + let ret = unsafe { bindings::ptr_to_hashval(ptr, core::ptr::addr_of_mut!(hashval)) };
> +
> + if ret != 0 {
> + // Hash not ready yet, print placeholder
> + return f.write_str(PTR_PLACEHOLDER);
> + }
> +
> + // Successfully got hash value, format it using Pointer::fmt to preserve
> + // formatting options (width, alignment, padding, etc.)
> + Pointer::fmt(&(hashval as *const c_void), f)
> +}
> +
> +/// A pointer that will be hashed when printed (corresponds to `%p`).
> +///
> +/// This is the default behavior for kernel pointers - they are hashed to prevent
> +/// leaking information about the kernel memory layout.
> +///
> +/// # Example
> +///
> +/// ```
> +/// use kernel::{
> +/// prelude::fmt,
> +/// ptr::HashedPtr,
> +/// str::CString, //
> +/// };
> +///
> +/// let ptr = HashedPtr::from(0x12345678 as *const u8);
> +/// pr_info!("Hashed pointer: {:016p}\n", ptr);
> +///
> +/// // Width option test
> +/// let cstr = CString::try_from_fmt(fmt!("{:30p}", ptr))?;
> +/// let width_30 = cstr.to_str()?;
> +/// assert_eq!(width_30.len(), 30);
> +/// # Ok::<(), kernel::error::Error>(())
> +/// ```
Is this intended?
[ 1.932037] # rust_doctest_kernel_ptr_rs_6.location:
rust/kernel/ptr.rs:315
[ 1.932322] rust_doctests_kernel: Hashed pointer: (____ptrval____)
[ 1.933032] # rust_doctest_kernel_ptr_rs_6: ASSERTION FAILED at
rust/kernel/ptr.rs:329
[ 1.933032] Expected width_30.len() == 30 to be true, but is false
[ 1.933892] not ok 179 rust_doctest_kernel_ptr_rs_6
[ 1.934097] # rust_doctest_kernel_ptr_rs_7.location:
rust/kernel/ptr.rs:353
[ 1.934434] rust_doctests_kernel: Restricted pointer: (____ptrval____)
[ 1.934707] # rust_doctest_kernel_ptr_rs_7: ASSERTION FAILED at
rust/kernel/ptr.rs:367
[ 1.934707] Expected width_30.len() == 30 to be true, but is false
[ 1.935156] not ok 180 rust_doctest_kernel_ptr_rs_7
This is v5 on top of v6.19-rc1 with x86_64_defconfig booting on QEMU.
Cheers
Dirk
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v5 2/4] rust: kernel: Add pointer wrapper types for safe pointer formatting
2025-12-26 15:10 ` Dirk Behme
@ 2025-12-27 2:02 ` Ke Sun
0 siblings, 0 replies; 7+ messages in thread
From: Ke Sun @ 2025-12-27 2:02 UTC (permalink / raw)
To: Dirk Behme
Cc: Miguel Ojeda, Petr Mladek, Steven Rostedt, Timur Tabi,
Danilo Krummrich, Benno Lossin, Boqun Feng, Gary Guo,
Björn Roy Baron, Andreas Hindborg, Alice Ryhl, Trevor Gross,
Tamir Duberstein, rust-for-linux
Dirk Behme <dirk.behme@gmail.com> 于2025年12月26日周五 23:10写道:
>
> On 26.12.25 15:07, Ke Sun wrote:
> > Add three pointer wrapper types (HashedPtr, RestrictedPtr, RawPtr) to
> > rust/kernel/ptr.rs that correspond to C kernel's printk format specifiers
> > %p, %pK, and %px. These types provide type-safe pointer formatting that
> > matches C kernel patterns.
> >
> > These wrapper types implement core::fmt::Pointer and delegate to the
> > corresponding kernel formatting functions, enabling safe pointer
> > formatting in Rust code that prevents information leaks about kernel
> > memory layout.
> >
> > Users can explicitly use these types:
> > pr_info!("{:p}\n", HashedPtr::from(ptr));
> > pr_info!("{:p}\n", RestrictedPtr::from(ptr));
> > pr_info!("{:p}\n", RawPtr::from(ptr));
> >
> > Signed-off-by: Ke Sun <sunke@kylinos.cn>
> > ---
> > rust/helpers/fmt.c | 65 +++++++++++
> > rust/helpers/helpers.c | 3 +-
> > rust/kernel/ptr.rs | 240 ++++++++++++++++++++++++++++++++++++++++-
> > 3 files changed, 304 insertions(+), 4 deletions(-)
> > create mode 100644 rust/helpers/fmt.c
> ....
> > diff --git a/rust/helpers/helpers.c b/rust/helpers/helpers.c
> > index 79c72762ad9c4..b6877fe8dafc0 100644
> > --- a/rust/helpers/helpers.c
> > +++ b/rust/helpers/helpers.c
> > @@ -27,8 +27,9 @@
> > #include "dma.c"
> > #include "drm.c"
> > #include "err.c"
> > -#include "irq.c"
> > +#include "fmt.c"
> > #include "fs.c"
> > +#include "irq.c"
> > #include "io.c"
> > #include "jump_label.c"
> > #include "kunit.c"
> > diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
> > index e3893ed04049d..ed5069c954146 100644
> > --- a/rust/kernel/ptr.rs
> > +++ b/rust/kernel/ptr.rs
> > @@ -1,11 +1,22 @@
> > // SPDX-License-Identifier: GPL-2.0
> >
> > //! Types and functions to work with pointers and addresses.
> > +//!
> > +//! This module provides wrapper types for formatting kernel pointers that correspond to the
> > +//! C kernel's printk format specifiers `%p`, `%pK`, and `%px`.
> >
> > -use core::mem::align_of;
> > -use core::num::NonZero;
> > +use core::{
> > + fmt,
> > + fmt::Pointer,
> > + mem::align_of,
> > + num::NonZero, //
> > +};
> >
> > -use crate::build_assert;
> > +use crate::{
> > + bindings,
> > + build_assert,
> > + ffi::c_void, //
> > +};
> >
> > /// Type representing an alignment, which is always a power of two.
> > ///
> > @@ -225,3 +236,226 @@ fn align_up(self, alignment: Alignment) -> Option<Self> {
> > }
> >
> > impl_alignable_uint!(u8, u16, u32, u64, usize);
> > +
> > +/// Placeholder string used when pointer hashing is not ready yet.
> > +const PTR_PLACEHOLDER: &str = if core::mem::size_of::<*const c_void>() == 8 {
> > + "(____ptrval____)"
> > +} else {
> > + "(ptrval)"
> > +};
> > +
> > +/// Macro to implement common methods for pointer wrapper types.
> > +macro_rules! impl_ptr_wrapper {
> > + ($($name:ident),* $(,)?) => {
> > + $(
> > + impl $name {
> > + /// Creates a new instance from a raw pointer.
> > + #[inline]
> > + pub fn from<T>(ptr: *const T) -> Self {
> > + Self(ptr.cast())
> > + }
> > +
> > + /// Creates a new instance from a mutable raw pointer.
> > + #[inline]
> > + pub fn from_mut<T>(ptr: *mut T) -> Self {
> > + Self(ptr.cast())
> > + }
> > +
> > + /// Returns the inner raw pointer.
> > + #[inline]
> > + pub fn as_ptr(&self) -> *const c_void {
> > + self.0
> > + }
> > + }
> > +
> > + impl<T> From<*const T> for $name {
> > + #[inline]
> > + fn from(ptr: *const T) -> Self {
> > + Self::from(ptr)
> > + }
> > + }
> > +
> > + impl<T> From<*mut T> for $name {
> > + #[inline]
> > + fn from(ptr: *mut T) -> Self {
> > + Self::from_mut(ptr)
> > + }
> > + }
> > + )*
> > + };
> > +}
> > +
> > +/// Helper function to hash a pointer and format it.
> > +///
> > +/// Returns `Ok(())` if the hash was successfully computed and formatted,
> > +/// or the placeholder string if hashing is not ready yet.
> > +fn format_hashed_ptr(ptr: *const c_void, f: &mut fmt::Formatter<'_>) -> fmt::Result {
> > + let mut hashval: crate::ffi::c_ulong = 0;
> > + // SAFETY: We're calling the kernel's ptr_to_hashval function which handles
> > + // hashing. This is safe as long as ptr is a valid pointer value.
> > + let ret = unsafe { bindings::ptr_to_hashval(ptr, core::ptr::addr_of_mut!(hashval)) };
> > +
> > + if ret != 0 {
> > + // Hash not ready yet, print placeholder
> > + return f.write_str(PTR_PLACEHOLDER);
Can you try `return f.pad(PTR_PLACEHOLDER);`? I'm testing it.
> > + }
> > +
> > + // Successfully got hash value, format it using Pointer::fmt to preserve
> > + // formatting options (width, alignment, padding, etc.)
> > + Pointer::fmt(&(hashval as *const c_void), f)
> > +}
> > +
> > +/// A pointer that will be hashed when printed (corresponds to `%p`).
> > +///
> > +/// This is the default behavior for kernel pointers - they are hashed to prevent
> > +/// leaking information about the kernel memory layout.
> > +///
> > +/// # Example
> > +///
> > +/// ```
> > +/// use kernel::{
> > +/// prelude::fmt,
> > +/// ptr::HashedPtr,
> > +/// str::CString, //
> > +/// };
> > +///
> > +/// let ptr = HashedPtr::from(0x12345678 as *const u8);
> > +/// pr_info!("Hashed pointer: {:016p}\n", ptr);
> > +///
> > +/// // Width option test
> > +/// let cstr = CString::try_from_fmt(fmt!("{:30p}", ptr))?;
> > +/// let width_30 = cstr.to_str()?;
> > +/// assert_eq!(width_30.len(), 30);
> > +/// # Ok::<(), kernel::error::Error>(())
> > +/// ```
>
>
> Is this intended?
>
> [ 1.932037] # rust_doctest_kernel_ptr_rs_6.location:
> rust/kernel/ptr.rs:315
> [ 1.932322] rust_doctests_kernel: Hashed pointer: (____ptrval____)
> [ 1.933032] # rust_doctest_kernel_ptr_rs_6: ASSERTION FAILED at
> rust/kernel/ptr.rs:329
> [ 1.933032] Expected width_30.len() == 30 to be true, but is false
> [ 1.933892] not ok 179 rust_doctest_kernel_ptr_rs_6
>
>
> [ 1.934097] # rust_doctest_kernel_ptr_rs_7.location:
> rust/kernel/ptr.rs:353
> [ 1.934434] rust_doctests_kernel: Restricted pointer: (____ptrval____)
> [ 1.934707] # rust_doctest_kernel_ptr_rs_7: ASSERTION FAILED at
> rust/kernel/ptr.rs:367
// lib/vsprintf.c
static inline int __ptr_to_hashval(const void *ptr, unsigned long *hashval_out)
{
unsigned long hashval;
if (!READ_ONCE(filled_random_ptr_key)) // filled_random_ptr_key might be false
return -EBUSY;
> [ 1.934707] Expected width_30.len() == 30 to be true, but is false
> [ 1.935156] not ok 180 rust_doctest_kernel_ptr_rs_7
>
> This is v5 on top of v6.19-rc1 with x86_64_defconfig booting on QEMU.
>
> Cheers
>
> Dirk
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-12-27 2:02 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-26 14:07 [PATCH v5 0/4] rust: Add safe pointer formatting support Ke Sun
2025-12-26 14:07 ` [PATCH v5 1/4] lib/vsprintf: Export ptr_to_hashval for Rust use Ke Sun
2025-12-26 14:07 ` [PATCH v5 2/4] rust: kernel: Add pointer wrapper types for safe pointer formatting Ke Sun
2025-12-26 15:10 ` Dirk Behme
2025-12-27 2:02 ` Ke Sun
2025-12-26 14:07 ` [PATCH v5 3/4] rust: fmt: Default raw pointer formatting to HashedPtr Ke Sun
2025-12-26 14:07 ` [PATCH v5 4/4] docs: rust: Add pointer formatting documentation Ke Sun
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.