diff src/libpam/handle.rs @ 101:94b51fa4f797

Fix memory soundness issues: - Ensure Questions are pinned in memory when sending them through PAM. - Hold on to the PAM conversation struct after we build it. (Linux-PAM is leninent about this and copies the pam_conv structure.)
author Paul Fisher <paul@pfish.zone>
date Tue, 24 Jun 2025 17:54:33 -0400
parents b87100c5eed4
children 94eb11cb1798
line wrap: on
line diff
--- a/src/libpam/handle.rs	Tue Jun 24 17:08:01 2025 -0400
+++ b/src/libpam/handle.rs	Tue Jun 24 17:54:33 2025 -0400
@@ -11,7 +11,6 @@
 use num_enum::{IntoPrimitive, TryFromPrimitive};
 use std::cell::Cell;
 use std::ffi::{c_char, c_int, CString};
-use std::marker::PhantomData;
 use std::ops::{Deref, DerefMut};
 use std::ptr;
 
@@ -33,9 +32,12 @@
 
 /// An owned PAM handle.
 pub struct OwnedLibPamHandle<'a> {
+    /// The handle itself.
     handle: HandleWrap,
+    /// The last return value from the handle.
     last_return: Cell<Result<()>>,
-    _conversation_lifetime: PhantomData<&'a mut ()>,
+    /// If set, the Conversation that this PAM handle owns.
+    conversation: Option<Box<LibPamConversation<'a>>>,
 }
 
 #[derive(Debug, PartialEq)]
@@ -77,20 +79,26 @@
         username: Option<String>,
         conversation: &impl Conversation,
     ) -> Result<Self> {
-        let conv = LibPamConversation::wrap(conversation);
+        let conv = Box::new(LibPamConversation::wrap(conversation));
         let service_cstr = CString::new(service_name).map_err(|_| ErrorCode::ConversationError)?;
         let username_cstr = memory::prompt_ptr(memory::option_cstr(username.as_deref())?.as_ref());
 
         let mut handle: *mut LibPamHandle = ptr::null_mut();
         // SAFETY: We've set everything up properly to call `pam_start`.
         // The returned value will be a valid pointer provided the result is OK.
-        let result =
-            unsafe { pam_ffi::pam_start(service_cstr.as_ptr(), username_cstr, &conv, &mut handle) };
+        let result = unsafe {
+            pam_ffi::pam_start(
+                service_cstr.as_ptr(),
+                username_cstr,
+                conv.as_ref(),
+                &mut handle,
+            )
+        };
         ErrorCode::result_from(result)?;
         Ok(Self {
             handle: HandleWrap(handle),
             last_return: Cell::new(Ok(())),
-            _conversation_lifetime: Default::default(),
+            conversation: Some(conv),
         })
     }
 }