diff src/libpam/question.rs @ 93:efc2b56c8928

Remove undefined behavior per MIRI. This replaces a bunch of raw pointers with NonNull and removes all the undefined behavior that we can find with MIRI. We also remove the `SecureString` dependency (since it doesn't work with MIRI, and because it's not really necessary).
author Paul Fisher <paul@pfish.zone>
date Mon, 23 Jun 2025 13:02:58 -0400
parents dd3e9c4bcde3
children b87100c5eed4
line wrap: on
line diff
--- a/src/libpam/question.rs	Sun Jun 22 19:29:32 2025 -0400
+++ b/src/libpam/question.rs	Mon Jun 23 13:02:58 2025 -0400
@@ -11,6 +11,7 @@
 use crate::Result;
 use num_enum::{IntoPrimitive, TryFromPrimitive};
 use std::ffi::{c_void, CStr};
+use std::ptr::NonNull;
 use std::{ptr, slice};
 
 /// Abstraction of a collection of questions to be sent in a PAM conversation.
@@ -214,10 +215,9 @@
 
     /// Gets this message's data pointer as borrowed binary data.
     unsafe fn binary_data(&self) -> (&[u8], u8) {
-        self.data
-            .cast::<CBinaryData>()
-            .as_ref()
-            .map(Into::into)
+        NonNull::new(self.data)
+            .map(|nn| nn.cast())
+            .map(|ptr| CBinaryData::data(ptr))
             .unwrap_or_default()
     }
 }
@@ -227,7 +227,7 @@
     fn try_from(msg: &Message) -> Result<Self> {
         let alloc = |style, text| Ok((style, memory::malloc_str(text)?.cast()));
         // We will only allocate heap data if we have a valid input.
-        let (style, data): (_, *mut c_void) = match *msg {
+        let (style, data): (_, NonNull<c_void>) = match *msg {
             Message::MaskedPrompt(p) => alloc(Style::PromptEchoOff, p.question()),
             Message::Prompt(p) => alloc(Style::PromptEchoOn, p.question()),
             Message::Error(p) => alloc(Style::ErrorMsg, p.question()),
@@ -244,7 +244,7 @@
         }?;
         Ok(Self {
             style: style.into(),
-            data,
+            data: data.as_ptr(),
             _marker: Default::default(),
         })
     }
@@ -261,8 +261,8 @@
                 match style {
                     #[cfg(feature = "linux-pam-extensions")]
                     Style::BinaryPrompt => {
-                        if let Some(d) = self.data.cast::<CBinaryData>().as_mut() {
-                            d.zero_contents()
+                        if let Some(d) = NonNull::new(self.data) {
+                            CBinaryData::zero_contents(d.cast())
                         }
                     }
                     #[cfg(feature = "linux-pam-extensions")]
@@ -367,7 +367,7 @@
                 let indirect = interrogation.ptr();
 
                 let remade = unsafe { $typ::borrow_ptr(indirect, interrogation.len()) };
-                let messages: Vec<OwnedMessage> = unsafe { remade }
+                let messages: Vec<OwnedMessage> = remade
                     .map(TryInto::try_into)
                     .collect::<Result<_>>()
                     .unwrap();