Skip to content

Commit f935f30

Browse files
committed
null-safe set_boxed_mut_ptr/set_arc_mut_ptr
Previously the `set_boxed_mut_ptr()` and `set_arc_mut_ptr()` helper fns used for assigning out parameters across the FFI boundary took `*mut *mut C` and `*mut *const C` for the destination argument `dst`. Using these safely required callers always verify that `dst != NULL`. In practice it's very easy to forget to do this and danger lurks! We could modify these helpers to do the check itself, but we tend to use these fns near the end of a function to assign a result in a success case and we would prefer `NULL` checking happen at the beginning of the function. One proposed solution is to modify these setter functions to take `&mut *mut C` and `&mut *const C`. By using new helper fns to carefully construct a `&mut` from the input double pointer we can front-load the `NULL` check and the assignment in the set fns can proceed knowing there's no possibility for a `NULL` outer pointer. This commit implements this strategy, updating the argument type of `set_boxed_mut_ptr` and `set_arc_mut_ptr` to take `&mut (*const|*mut) C`. New `try_mut_from_ptr_ptr` and `try_ref_from_ptr_ptr` macros allow converting from `*mut *mut C` and `*mut *const C` to the reference types, bailing early for `NULL`.
1 parent 2316cca commit f935f30

File tree

5 files changed

+82
-35
lines changed

5 files changed

+82
-35
lines changed

src/acceptor.rs

+6-15
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,9 @@ use crate::rslice::{rustls_slice_bytes, rustls_str};
1313
use crate::server::rustls_server_config;
1414
use crate::{
1515
ffi_panic_boundary, free_box, rustls_result, set_boxed_mut_ptr, to_box, to_boxed_mut_ptr,
16-
try_callback, try_clone_arc, try_mut_from_ptr, try_ref_from_ptr, try_take, Castable,
17-
OwnershipBox,
16+
try_callback, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr,
17+
try_take, Castable, OwnershipBox,
1818
};
19-
use rustls_result::NullParameter;
2019

2120
/// A buffer and parser for ClientHello bytes. This allows reading ClientHello
2221
/// before choosing a rustls_server_config. It's useful when the server
@@ -187,12 +186,8 @@ impl rustls_acceptor {
187186
) -> rustls_result {
188187
ffi_panic_boundary! {
189188
let acceptor: &mut Acceptor = try_mut_from_ptr!(acceptor);
190-
if out_accepted.is_null() {
191-
return NullParameter;
192-
}
193-
if out_alert.is_null() {
194-
return NullParameter;
195-
}
189+
let out_accepted = try_mut_from_ptr_ptr!(out_accepted);
190+
let out_alert = try_mut_from_ptr_ptr!(out_alert);
196191
match acceptor.accept() {
197192
Ok(None) => rustls_result::AcceptorNotReady,
198193
Ok(Some(accepted)) => {
@@ -426,12 +421,8 @@ impl rustls_accepted {
426421
let accepted: &mut Option<Accepted> = try_mut_from_ptr!(accepted);
427422
let accepted = try_take!(accepted);
428423
let config: Arc<ServerConfig> = try_clone_arc!(config);
429-
if out_conn.is_null() {
430-
return NullParameter;
431-
}
432-
if out_alert.is_null() {
433-
return NullParameter;
434-
}
424+
let out_conn = try_mut_from_ptr_ptr!(out_conn);
425+
let out_alert = try_mut_from_ptr_ptr!(out_alert);
435426
match accepted.into_connection(config) {
436427
Ok(built) => {
437428
let wrapped = crate::connection::Connection::from_server(built);

src/cipher.rs

+5-4
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ use crate::error::{self, rustls_result};
2222
use crate::rslice::{rustls_slice_bytes, rustls_str};
2323
use crate::{
2424
ffi_panic_boundary, free_arc, free_box, set_arc_mut_ptr, set_boxed_mut_ptr, to_arc_const_ptr,
25-
to_boxed_mut_ptr, try_clone_arc, try_mut_from_ptr, try_ref_from_ptr, try_slice, try_take,
26-
Castable, OwnershipArc, OwnershipBox, OwnershipRef,
25+
to_boxed_mut_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr,
26+
try_ref_from_ptr_ptr, try_slice, try_take, Castable, OwnershipArc, OwnershipBox, OwnershipRef,
2727
};
2828
use rustls_result::{AlreadyUsed, NullParameter};
2929

@@ -592,7 +592,7 @@ impl rustls_root_cert_store_builder {
592592
ffi_panic_boundary! {
593593
let builder: &mut Option<RootCertStoreBuilder> = try_mut_from_ptr!(builder);
594594
let builder = try_take!(builder);
595-
595+
let root_cert_store_out = try_ref_from_ptr_ptr!(root_cert_store_out);
596596
set_arc_mut_ptr(root_cert_store_out, builder.roots);
597597

598598
rustls_result::Ok
@@ -893,6 +893,7 @@ impl rustls_web_pki_client_cert_verifier_builder {
893893
let client_verifier_builder: &mut Option<ClientCertVerifierBuilder> =
894894
try_mut_from_ptr!(builder);
895895
let client_verifier_builder = try_take!(client_verifier_builder);
896+
let verifier_out = try_mut_from_ptr_ptr!(verifier_out);
896897

897898
let mut builder = WebPkiClientVerifier::builder_with_provider(
898899
client_verifier_builder.roots,
@@ -925,7 +926,6 @@ impl rustls_web_pki_client_cert_verifier_builder {
925926
};
926927

927928
set_boxed_mut_ptr(verifier_out, verifier);
928-
929929
rustls_result::Ok
930930
}
931931
}
@@ -1103,6 +1103,7 @@ impl ServerCertVerifierBuilder {
11031103
let server_verifier_builder: &mut Option<ServerCertVerifierBuilder> =
11041104
try_mut_from_ptr!(builder);
11051105
let server_verifier_builder = try_take!(server_verifier_builder);
1106+
let verifier_out = try_mut_from_ptr_ptr!(verifier_out);
11061107

11071108
let mut builder = WebPkiServerVerifier::builder_with_provider(
11081109
server_verifier_builder.roots,

src/client.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,8 @@ use crate::rslice::NulByte;
2323
use crate::rslice::{rustls_slice_bytes, rustls_slice_slice_bytes, rustls_str};
2424
use crate::{
2525
ffi_panic_boundary, free_arc, free_box, set_boxed_mut_ptr, to_arc_const_ptr, to_boxed_mut_ptr,
26-
try_box_from_ptr, try_clone_arc, try_mut_from_ptr, try_ref_from_ptr, try_slice, userdata_get,
27-
Castable, OwnershipArc, OwnershipBox,
26+
try_box_from_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr,
27+
try_slice, userdata_get, Castable, OwnershipArc, OwnershipBox,
2828
};
2929

3030
/// A client config being constructed. A builder can be modified by,
@@ -184,6 +184,8 @@ impl rustls_client_config_builder {
184184
}
185185
}
186186

187+
let builder_out = try_mut_from_ptr_ptr!(builder_out);
188+
187189
let provider = rustls::crypto::CryptoProvider {
188190
cipher_suites: cs_vec,
189191
..rustls::crypto::ring::default_provider()
@@ -575,6 +577,7 @@ impl rustls_client_config {
575577
CStr::from_ptr(server_name)
576578
};
577579
let config: Arc<ClientConfig> = try_clone_arc!(config);
580+
let conn_out = try_mut_from_ptr_ptr!(conn_out);
578581
let server_name: &str = match server_name.to_str() {
579582
Ok(s) => s,
580583
Err(std::str::Utf8Error { .. }) => return rustls_result::InvalidDnsNameError,

src/lib.rs

+61-12
Original file line numberDiff line numberDiff line change
@@ -485,17 +485,11 @@ where
485485
/// Converts a [`Castable`]'s underlying [`Castable::RustType`] to a mutable pointer
486486
/// to a `Box` over the rust type and sets the `dst` out pointer to the resulting mutable `Box`
487487
/// pointer. See [`to_boxed_mut_ptr`] for more information.
488-
///
489-
/// ## Unsafety:
490-
///
491-
/// `dst` must not be `NULL`.
492-
pub(crate) fn set_boxed_mut_ptr<C>(dst: *mut *mut C, src: C::RustType)
488+
pub(crate) fn set_boxed_mut_ptr<C>(dst: &mut *mut C, src: C::RustType)
493489
where
494490
C: Castable<Ownership = OwnershipBox>,
495491
{
496-
unsafe {
497-
*dst = to_boxed_mut_ptr(src);
498-
}
492+
*dst = to_boxed_mut_ptr(src);
499493
}
500494

501495
/// Converts a [`Castable`]'s underlying [`Castable::RustType`] to a const pointer
@@ -505,13 +499,11 @@ where
505499
/// ## Unsafety:
506500
///
507501
/// `dst` must not be `NULL`.
508-
pub(crate) fn set_arc_mut_ptr<C>(dst: *mut *const C, src: C::RustType)
502+
pub(crate) fn set_arc_mut_ptr<C>(dst: &mut *const C, src: C::RustType)
509503
where
510504
C: Castable<Ownership = OwnershipArc>,
511505
{
512-
unsafe {
513-
*dst = to_arc_const_ptr(src);
514-
}
506+
*dst = to_arc_const_ptr(src);
515507
}
516508

517509
/// Converts a mutable pointer to a [`Castable`] to an optional ref to the underlying
@@ -540,6 +532,32 @@ macro_rules! try_mut_from_ptr {
540532

541533
pub(crate) use try_mut_from_ptr;
542534

535+
/// Converts a mutable pointer to a mutable pointer to a [`Castable`] to an optional mutable ref to
536+
/// the mutable pointer to the [`Castable::RustType`].
537+
///
538+
/// Does nothing, returning `None`, when passed `NULL`.
539+
pub(crate) fn try_from_mut_mut<'a, C: Castable>(from: *mut *mut C) -> Option<&'a mut *mut C> {
540+
match from.is_null() {
541+
true => None,
542+
false => unsafe { Some(&mut *from) },
543+
}
544+
}
545+
546+
/// If the provided pointer to a pointer to a [`Castable`] is non-null, convert it to a mutable
547+
/// reference to a pointer using [`try_from_mut_mut`]. Otherwise, return
548+
/// [`rustls_result::NullParameter`], or an appropriate default (`false`, `0`, `NULL`) based on the
549+
/// context. See [`try_from_mut_mut`] for more information.
550+
macro_rules! try_mut_from_ptr_ptr {
551+
( $var:ident ) => {
552+
match $crate::try_from_mut_mut($var) {
553+
Some(c) => c,
554+
None => return $crate::panic::NullParameterOrDefault::value(),
555+
}
556+
};
557+
}
558+
559+
pub(crate) use try_mut_from_ptr_ptr;
560+
543561
/// Converts a const pointer to a [`Castable`] to an optional ref to the underlying
544562
/// [`Castable::RustType`]. See [`cast_const_ptr`] for more information.
545563
///
@@ -569,6 +587,37 @@ macro_rules! try_ref_from_ptr {
569587

570588
pub(crate) use try_ref_from_ptr;
571589

590+
/// Converts a mut pointer to a const pointer to a [`Castable`] to an optional mut ref to the
591+
/// const pointer to the underlying [`Castable::RustType`].
592+
///
593+
/// Does nothing, returning `None` when passed `NULL`.
594+
pub(crate) fn try_from_ptr<'a, C>(from: *mut *const C) -> Option<&'a mut *const C>
595+
where
596+
C: Castable,
597+
{
598+
match from.is_null() {
599+
true => None,
600+
false => unsafe { Some(&mut *from) },
601+
}
602+
}
603+
604+
/// If the provided pointer to pointer to a [`Castable`] is non-null, convert it to a mutable
605+
/// reference to a pointer to the [`Castable`] using
606+
/// [`try_from_ptr`]. Otherwise, return [`rustls_result::NullParameter`], or an appropriate default
607+
/// (`false`, `0`, `NULL`) based on the context;
608+
///
609+
/// See [`try_from_ptr`] for more information.
610+
macro_rules! try_ref_from_ptr_ptr {
611+
( $var:ident ) => {
612+
match $crate::try_from_ptr($var) {
613+
Some(c) => c,
614+
None => return $crate::panic::NullParameterOrDefault::value(),
615+
}
616+
};
617+
}
618+
619+
pub(crate) use try_ref_from_ptr_ptr;
620+
572621
/// If the provided pointer to a [`Castable`] is non-null, convert it to a reference to an `Arc` over
573622
/// the underlying rust type using [`try_arc_from`]. Otherwise, return
574623
/// [`rustls_result::NullParameter`], or an appropriate default (`false`, `0`, `NULL`) based on the

src/server.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@ use crate::session::{
2727
};
2828
use crate::{
2929
ffi_panic_boundary, free_arc, free_box, set_boxed_mut_ptr, to_arc_const_ptr, to_boxed_mut_ptr,
30-
try_box_from_ptr, try_clone_arc, try_mut_from_ptr, try_ref_from_ptr, try_slice, userdata_get,
31-
Castable, OwnershipArc, OwnershipBox, OwnershipRef,
30+
try_box_from_ptr, try_clone_arc, try_mut_from_ptr, try_mut_from_ptr_ptr, try_ref_from_ptr,
31+
try_slice, userdata_get, Castable, OwnershipArc, OwnershipBox, OwnershipRef,
3232
};
3333

3434
/// A server config being constructed. A builder can be modified by,
@@ -141,6 +141,8 @@ impl rustls_server_config_builder {
141141
}
142142
}
143143

144+
let builder_out = try_mut_from_ptr_ptr!(builder_out);
145+
144146
let provider = rustls::crypto::CryptoProvider {
145147
cipher_suites: cs_vec,
146148
..rustls::crypto::ring::default_provider()
@@ -325,6 +327,7 @@ impl rustls_server_config {
325327
return NullParameter;
326328
}
327329
let config: Arc<ServerConfig> = try_clone_arc!(config);
330+
let conn_out = try_mut_from_ptr_ptr!(conn_out);
328331

329332
let server_connection = match ServerConnection::new(config) {
330333
Ok(sc) => sc,

0 commit comments

Comments
 (0)