1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Formatting utilities. 4 //! 5 //! This module is intended to be used in place of `core::fmt` in kernel code. 6 7 use kernel::prelude::*; 8 9 pub use core::fmt::{ 10 Arguments, 11 Debug, 12 Error, 13 Formatter, 14 Result, 15 Write, // 16 }; 17 18 /// Internal adapter used to route and allow implementations of formatting traits for foreign types. 19 /// 20 /// It is inserted automatically by the [`fmt!`] macro and is not meant to be used directly. 21 /// 22 /// [`fmt!`]: crate::prelude::fmt! 23 #[doc(hidden)] 24 pub struct Adapter<T>(pub T); 25 26 macro_rules! impl_fmt_adapter_forward { 27 ($($trait:ident),* $(,)?) => { 28 $( 29 impl<T: $trait> $trait for Adapter<T> { 30 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 31 let Self(t) = self; 32 $trait::fmt(t, f) 33 } 34 } 35 )* 36 }; 37 } 38 39 use core::fmt::{ 40 Binary, 41 LowerExp, 42 LowerHex, 43 Octal, 44 UpperExp, 45 UpperHex, // 46 }; 47 use core::ptr::NonNull; 48 impl_fmt_adapter_forward!(Debug, LowerHex, UpperHex, Octal, Binary, LowerExp, UpperExp); 49 50 /// A copy of [`core::fmt::Pointer`] that allows implementing pointer formatting for foreign types. 51 /// 52 /// Together with the [`Adapter`] type and [`fmt!`] macro, it enables raw pointer formatting to be 53 /// intercepted and routed to [`HashedPtr`] (kernel's `%p` hashed format), preventing kernel address 54 /// leaks. 55 /// 56 /// [`fmt!`]: crate::prelude::fmt! 57 pub trait Pointer { 58 /// Same as [`core::fmt::Pointer::fmt`]. 59 fn fmt(&self, f: &mut Formatter<'_>) -> Result; 60 } 61 62 /// A wrapper for pointers that formats them using kernel's `%p` format specifier. 63 /// 64 /// By default, `%p` prints a hashed representation of the pointer address to prevent kernel address 65 /// leaks. When the `no_hash_pointers` kernel command-line parameter is enabled, the real address is 66 /// printed instead (for debugging purposes). 67 pub struct HashedPtr<T: ?Sized>(pub *const T); 68 69 impl<T: ?Sized> Pointer for HashedPtr<T> { 70 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 71 use crate::str::CStrExt as _; 72 73 let mut buf = [0u8; 32]; 74 75 // Use `%#0*p` for the `0x` prefix and zero-padding; `+2` compensates for 76 // the prefix counting toward the field width. 77 let default_width = (2 * size_of::<usize>() + 2) as c_int; 78 let width = match (f.sign_aware_zero_pad(), f.width()) { 79 (true, Some(w)) if w > 0 => w.min(buf.len() - 1) as c_int, 80 _ => default_width, 81 }; 82 83 // SAFETY: `buf` is a valid, writable 32-byte buffer, sufficient for 84 // all architectures (max 19 bytes for 64-bit under the default width). 85 // The format string is null-terminated; `width` (c_int) and pointer 86 // match the `%*` and `%p` specifiers. 87 let len = unsafe { 88 crate::bindings::scnprintf( 89 buf.as_mut_ptr().cast(), 90 buf.len(), 91 c"%#0*p".as_char_ptr(), 92 width, 93 self.0.cast::<c_void>(), 94 ) 95 }; 96 97 // SAFETY: `%#0*p` produces only ASCII, which is valid UTF-8. 98 let s = unsafe { core::str::from_utf8_unchecked(&buf[..len as usize]) }; 99 100 if f.sign_aware_zero_pad() { 101 // `scnprintf` already applied the width and zero-padding via `%#0*p`. 102 f.write_str(s) 103 } else { 104 f.pad(s) 105 } 106 } 107 } 108 109 // Raw pointers are formatted via `HashedPtr` (kernel `%p`: hashed by default, plain with 110 // `no_hash_pointers`). 111 impl<T: ?Sized> Pointer for *const T { 112 #[inline] 113 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 114 Pointer::fmt(&HashedPtr(*self), f) 115 } 116 } 117 118 impl<T: ?Sized> Pointer for *mut T { 119 #[inline] 120 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 121 Pointer::fmt(&HashedPtr(*self), f) 122 } 123 } 124 125 impl<T: ?Sized> Pointer for &T { 126 #[inline] 127 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 128 Pointer::fmt(&HashedPtr(*self), f) 129 } 130 } 131 132 impl<T: ?Sized> Pointer for &mut T { 133 #[inline] 134 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 135 Pointer::fmt(&HashedPtr(core::ptr::from_ref(*self)), f) 136 } 137 } 138 139 impl<T: ?Sized> Pointer for NonNull<T> { 140 #[inline] 141 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 142 Pointer::fmt(&HashedPtr(self.as_ptr()), f) 143 } 144 } 145 146 // `Adapter<&T>` bridges our `Pointer` trait to `core::fmt::Pointer` 147 impl<T: Pointer> core::fmt::Pointer for Adapter<&T> { 148 #[inline] 149 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 150 Pointer::fmt(self.0, f) 151 } 152 } 153 154 /// A copy of [`core::fmt::Display`] that allows us to implement it for foreign types. 155 /// 156 /// Types should implement this trait rather than [`core::fmt::Display`]. Together with the 157 /// [`Adapter`] type and [`fmt!`] macro, it allows for formatting foreign types (e.g. types from 158 /// core) which do not implement [`core::fmt::Display`] directly. 159 /// 160 /// [`fmt!`]: crate::prelude::fmt! 161 pub trait Display { 162 /// Same as [`core::fmt::Display::fmt`]. 163 fn fmt(&self, f: &mut Formatter<'_>) -> Result; 164 } 165 166 impl<T: ?Sized + Display> Display for &T { 167 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 168 Display::fmt(*self, f) 169 } 170 } 171 172 impl<T: ?Sized + Display> core::fmt::Display for Adapter<&T> { 173 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 174 let Self(t) = self; 175 Display::fmt(t, f) 176 } 177 } 178 179 macro_rules! impl_display_forward { 180 ($( 181 $( { $($generics:tt)* } )? $ty:ty $( { where $($where:tt)* } )? 182 ),* $(,)?) => { 183 $( 184 impl$($($generics)*)? Display for $ty $(where $($where)*)? { 185 fn fmt(&self, f: &mut Formatter<'_>) -> Result { 186 core::fmt::Display::fmt(self, f) 187 } 188 } 189 )* 190 }; 191 } 192 193 impl_display_forward!( 194 bool, 195 char, 196 core::panic::PanicInfo<'_>, 197 Arguments<'_>, 198 i128, 199 i16, 200 i32, 201 i64, 202 i8, 203 isize, 204 str, 205 u128, 206 u16, 207 u32, 208 u64, 209 u8, 210 usize, 211 {<T: ?Sized>} crate::sync::Arc<T> {where crate::sync::Arc<T>: core::fmt::Display}, 212 {<T: ?Sized>} crate::sync::UniqueArc<T> {where crate::sync::UniqueArc<T>: core::fmt::Display}, 213 ); 214 215 #[macros::kunit_tests(rust_kernel_fmt)] 216 mod tests { 217 use crate::{ 218 bindings, 219 prelude::fmt, 220 str::CString, // 221 }; 222 223 #[cfg(CONFIG_64BIT)] 224 mod expected { 225 pub(super) const PTR_VALUE: usize = 0xffffffffdeadbeef; 226 pub(super) const PTR_VAL_NO_CRNG: &str = "(____ptrval____)"; 227 pub(super) const HASHED_PREFIX: &str = "0x00000000"; 228 pub(super) const RAW_POINTER: &str = "0xffffffffdeadbeef"; 229 pub(super) const PADDED_RIGHT: &str = " 0xffffffffdeadbeef"; 230 pub(super) const ZERO_PADDED: &str = "0x000000ffffffffdeadbeef"; 231 pub(super) const HASHED_PADDED_RIGHT_PREFIX: &str = " "; 232 pub(super) const HASHED_ZERO_PADDED_PREFIX: &str = "0x00000000000000"; 233 pub(super) const CLAMPED: &str = "0x0000000000000ffffffffdeadbeef"; 234 } 235 236 #[cfg(not(CONFIG_64BIT))] 237 mod expected { 238 pub(super) const PTR_VALUE: usize = 0xdeadbeef; 239 pub(super) const PTR_VAL_NO_CRNG: &str = "(ptrval)"; 240 pub(super) const HASHED_PREFIX: &str = "0x"; 241 pub(super) const RAW_POINTER: &str = "0xdeadbeef"; 242 pub(super) const PADDED_RIGHT: &str = " 0xdeadbeef"; 243 pub(super) const ZERO_PADDED: &str = "0x00000000000000deadbeef"; 244 pub(super) const HASHED_PADDED_RIGHT_PREFIX: &str = " "; 245 pub(super) const HASHED_ZERO_PADDED_PREFIX: &str = "0x00000000000000"; 246 pub(super) const CLAMPED: &str = "0x0000000000000000000000deadbeef"; 247 } 248 249 #[test] 250 fn test_ptr_formatting() -> core::result::Result<(), crate::error::Error> { 251 let ptr: *const u8 = core::ptr::without_provenance(expected::PTR_VALUE); 252 253 // SAFETY: `no_hash_pointers` is a global variable that is never concurrently modified — 254 // KUnit tests may run at boot (before `mark_readonly()`) or manually afterwards (when the 255 // variable is read-only). Reading is always safe. 256 let no_hash = unsafe { bindings::no_hash_pointers }; 257 258 if no_hash { 259 let cstr = CString::try_from_fmt(fmt!("{:p}", ptr))?; 260 assert_eq!(cstr.to_str()?, expected::RAW_POINTER); 261 262 let cstr = CString::try_from_fmt(fmt!("{:>24p}", ptr))?; 263 assert_eq!(cstr.to_str()?, expected::PADDED_RIGHT); 264 265 let cstr = CString::try_from_fmt(fmt!("{:024p}", ptr))?; 266 assert_eq!(cstr.to_str()?, expected::ZERO_PADDED); 267 268 let cstr = CString::try_from_fmt(fmt!("{:0100p}", ptr))?; 269 assert_eq!(cstr.to_str()?, expected::CLAMPED); 270 } else { 271 let cstr = CString::try_from_fmt(fmt!("{:p}", ptr))?; 272 let formatted = cstr.to_str()?; 273 // If the RNG is not yet ready, `%p` falls back to a placeholder. 274 if formatted == expected::PTR_VAL_NO_CRNG { 275 return Ok(()); 276 } 277 assert!(formatted.starts_with(expected::HASHED_PREFIX)); 278 assert_ne!(formatted, expected::RAW_POINTER); 279 280 let cstr = CString::try_from_fmt(fmt!("{:>24p}", ptr))?; 281 assert!(cstr 282 .to_str()? 283 .starts_with(expected::HASHED_PADDED_RIGHT_PREFIX)); 284 285 let cstr = CString::try_from_fmt(fmt!("{:024p}", ptr))?; 286 assert!(cstr 287 .to_str()? 288 .starts_with(expected::HASHED_ZERO_PADDED_PREFIX)); 289 290 let cstr = CString::try_from_fmt(fmt!("{:0100p}", ptr))?; 291 let output = cstr.to_str()?; 292 assert!(output.starts_with("0x")); 293 assert!(!output[2..].chars().all(|c| c == '0')); 294 } 295 296 Ok(()) 297 } 298 } 299