From c47d4cfcb7e331a05d4260be196e0db3f81f02dc Mon Sep 17 00:00:00 2001 From: zhaipeizhe Date: Mon, 4 Nov 2024 16:11:49 +0800 Subject: [PATCH] dded a utility function to ensure rust-openssl never have an issue with 0-length slices from pointers again Signed-off-by: zhaipeizhe Change-Id: I06d3d58ef1640fc3ebc8f6312dcda63165ee4e23 --- openssl/src/asn1.rs | 11 +++++------ openssl/src/bio.rs | 15 +++++++++++++-- openssl/src/ssl/bio.rs | 9 ++++----- openssl/src/ssl/callbacks.rs | 22 +++++++++++----------- openssl/src/ssl/mod.rs | 18 +++++++++--------- openssl/src/util.rs | 27 ++++++++++++++++++++++++++- openssl/src/x509/mod.rs | 7 +++---- 7 files changed, 71 insertions(+), 38 deletions(-) diff --git a/openssl/src/asn1.rs b/openssl/src/asn1.rs index 801310d..421147c 100644 --- a/openssl/src/asn1.rs +++ b/openssl/src/asn1.rs @@ -32,7 +32,6 @@ use std::convert::TryInto; use std::ffi::CString; use std::fmt; use std::ptr; -use std::slice; use std::str; use crate::bio::MemBio; @@ -41,7 +40,7 @@ use crate::error::ErrorStack; use crate::nid::Nid; use crate::stack::Stackable; use crate::string::OpensslString; -use crate::{cvt, cvt_p}; +use crate::{cvt, cvt_p, util}; use openssl_macros::corresponds; foreign_type_and_impl_send_sync! { @@ -457,7 +456,7 @@ impl Asn1StringRef { /// [`as_utf8`]: struct.Asn1String.html#method.as_utf8 #[corresponds(ASN1_STRING_get0_data)] pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } + unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr()), self.len()) } } /// Returns the number of bytes in the string. @@ -597,7 +596,7 @@ impl Asn1BitStringRef { /// Returns the Asn1BitString as a slice. #[corresponds(ASN1_STRING_get0_data)] pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } + unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr() as *mut _), self.len()) } } /// Returns the number of bytes in the string. @@ -637,7 +636,7 @@ impl Asn1OctetStringRef { /// Returns the octet string as an array of bytes. #[corresponds(ASN1_STRING_get0_data)] pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) } + unsafe { util::from_raw_parts(ASN1_STRING_get0_data(self.as_ptr().cast()), self.len()) } } /// Returns the number of bytes in the octet string. @@ -701,7 +700,7 @@ impl Asn1Object { pub fn as_slice(&self) -> &[u8] { unsafe { let len = ffi::OBJ_length(self.as_ptr()); - slice::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len) + util::from_raw_parts(ffi::OBJ_get0_data(self.as_ptr()), len) } } } diff --git a/openssl/src/bio.rs b/openssl/src/bio.rs index 0f54935..170cb7b 100644 --- a/openssl/src/bio.rs +++ b/openssl/src/bio.rs @@ -2,10 +2,10 @@ use cfg_if::cfg_if; use libc::c_int; use std::marker::PhantomData; use std::ptr; -use std::slice; use crate::cvt_p; use crate::error::ErrorStack; +use crate::util; pub struct MemBioSlice<'a>(*mut ffi::BIO, PhantomData<&'a [u8]>); @@ -63,7 +63,7 @@ impl MemBio { unsafe { let mut ptr = ptr::null_mut(); let len = ffi::BIO_get_mem_data(self.0, &mut ptr); - slice::from_raw_parts(ptr as *const _ as *const _, len as usize) + util::from_raw_parts(ptr as *const _ as *const _, len as usize) } } @@ -83,3 +83,14 @@ cfg_if! { } } } + +#[cfg(test)] +mod tests { + use super::MemBio; + + #[test] + fn test_mem_bio_get_buf_empty() { + let b = MemBio::new().unwrap(); + assert_eq!(b.get_buf(), &[]); + } +} \ No newline at end of file diff --git a/openssl/src/ssl/bio.rs b/openssl/src/ssl/bio.rs index 36cea23..5c3a660 100644 --- a/openssl/src/ssl/bio.rs +++ b/openssl/src/ssl/bio.rs @@ -9,10 +9,9 @@ use std::io; use std::io::prelude::*; use std::panic::{catch_unwind, AssertUnwindSafe}; use std::ptr; -use std::slice; - -use crate::cvt_p; + use crate::error::ErrorStack; +use crate::{cvt_p, util}; pub struct StreamState { pub stream: S, @@ -89,7 +88,7 @@ unsafe extern "C" fn bwrite(bio: *mut BIO, buf: *const c_char, len: c_ BIO_clear_retry_flags(bio); let state = state::(bio); - let buf = slice::from_raw_parts(buf as *const _, len as usize); + let buf = util::from_raw_parts(buf as *const _, len as usize); match catch_unwind(AssertUnwindSafe(|| state.stream.write(buf))) { Ok(Ok(len)) => len as c_int, @@ -111,7 +110,7 @@ unsafe extern "C" fn bread(bio: *mut BIO, buf: *mut c_char, len: c_int) BIO_clear_retry_flags(bio); let state = state::(bio); - let buf = slice::from_raw_parts_mut(buf as *mut _, len as usize); + let buf = util::from_raw_parts_mut(buf as *mut _, len as usize); match catch_unwind(AssertUnwindSafe(|| state.stream.read(buf))) { Ok(Ok(len)) => len as c_int, diff --git a/openssl/src/ssl/callbacks.rs b/openssl/src/ssl/callbacks.rs index 091b1fb..bfcbeef 100644 --- a/openssl/src/ssl/callbacks.rs +++ b/openssl/src/ssl/callbacks.rs @@ -10,7 +10,6 @@ use libc::{c_int, c_uchar, c_uint, c_void}; use std::ffi::CStr; use std::mem; use std::ptr; -use std::slice; #[cfg(ossl111)] use std::str; use std::sync::Arc; @@ -28,6 +27,7 @@ use crate::ssl::{ }; #[cfg(ossl111)] use crate::ssl::{ClientHelloResponse, ExtensionContext}; +use crate::util; #[cfg(ossl111)] use crate::util::ForeignTypeRefExt; #[cfg(ossl111)] @@ -85,8 +85,8 @@ where None }; // Give the callback mutable slices into which it can write the identity and psk. - let identity_sl = slice::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize); - let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); + let identity_sl = util::from_raw_parts_mut(identity as *mut u8, max_identity_len as usize); + let psk_sl = util::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); match (*callback)(ssl, hint, identity_sl, psk_sl) { Ok(psk_len) => psk_len as u32, Err(e) => { @@ -124,7 +124,7 @@ where Some(CStr::from_ptr(identity).to_bytes()) }; // Give the callback mutable slices into which it can write the psk. - let psk_sl = slice::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); + let psk_sl = util::from_raw_parts_mut(psk as *mut u8, max_psk_len as usize); match (*callback)(ssl, identity, psk_sl) { Ok(psk_len) => psk_len as u32, Err(e) => { @@ -194,7 +194,7 @@ where .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: alpn callback missing") as *const F; - let protos = slice::from_raw_parts(inbuf as *const u8, inlen as usize); + let protos = util::from_raw_parts(inbuf as *const u8, inlen as usize); match (*callback)(ssl, protos) { Ok(proto) => { @@ -412,7 +412,7 @@ where .expect("BUG: session context missing") .ex_data(SslContext::cached_ex_index::()) .expect("BUG: get session callback missing") as *const F; - let data = slice::from_raw_parts(data as *const u8, len as usize); + let data = util::from_raw_parts(data as *const u8, len as usize); match (*callback)(ssl, data) { Some(session) => { @@ -455,7 +455,7 @@ where .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie generate callback missing") as *const F; - let slice = slice::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize); + let slice = util::from_raw_parts_mut(cookie as *mut u8, ffi::SSL_COOKIE_LENGTH as usize); match (*callback)(ssl, slice) { Ok(len) => { *cookie_len = len as size_t; @@ -482,7 +482,7 @@ where .ssl_context() .ex_data(SslContext::cached_ex_index::()) .expect("BUG: stateless cookie verify callback missing") as *const F; - let slice = slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len); + let slice = util::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len); (*callback)(ssl, slice) as c_int } @@ -504,7 +504,7 @@ where // We subtract 1 from DTLS1_COOKIE_LENGTH as the ostensible value, 256, is erroneous but retained for // compatibility. See comments in dtls1.h. let slice = - slice::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1); + util::from_raw_parts_mut(cookie as *mut u8, ffi::DTLS1_COOKIE_LENGTH as usize - 1); match (*callback)(ssl, slice) { Ok(len) => { *cookie_len = len as c_uint; @@ -543,7 +543,7 @@ where .ex_data(SslContext::cached_ex_index::()) .expect("BUG: cookie verify callback missing") as *const F; let slice = - slice::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); + util::from_raw_parts(cookie as *const c_uchar as *const u8, cookie_len as usize); (*callback)(ssl, slice) as c_int } } @@ -654,7 +654,7 @@ where .ex_data(SslContext::cached_ex_index::()) .expect("BUG: custom ext parse callback missing") as *const F; let ectx = ExtensionContext::from_bits_truncate(context); - let slice = slice::from_raw_parts(input as *const u8, inlen); + let slice = util::from_raw_parts(input as *const u8, inlen); let cert = if ectx.contains(ExtensionContext::TLS1_3_CERTIFICATE) { Some((chainidx, X509Ref::from_ptr(x))) } else { diff --git a/openssl/src/ssl/mod.rs b/openssl/src/ssl/mod.rs index 27e817f..153d57c 100644 --- a/openssl/src/ssl/mod.rs +++ b/openssl/src/ssl/mod.rs @@ -73,6 +73,7 @@ use crate::ssl::bio::BioMethod; use crate::ssl::callbacks::*; use crate::ssl::error::InnerError; use crate::stack::{Stack, StackRef, Stackable}; +use crate::util; use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; use crate::x509::store::{X509Store, X509StoreBuilderRef, X509StoreRef}; #[cfg(any(ossl102, libressl261))] @@ -98,7 +99,6 @@ use std::ops::{Deref, DerefMut}; use std::panic::resume_unwind; use std::path::Path; use std::ptr; -use std::slice; use std::str; use std::sync::{Arc, Mutex}; @@ -695,7 +695,7 @@ pub fn select_next_proto<'a>(server: &[u8], client: &'a [u8]) -> Option<&'a [u8] client.len() as c_uint, ); if r == ffi::OPENSSL_NPN_NEGOTIATED { - Some(slice::from_raw_parts(out as *const u8, outlen as usize)) + Some(util::from_raw_parts(out as *const u8, outlen as usize)) } else { None } @@ -2122,7 +2122,7 @@ impl SslSessionRef { unsafe { let mut len = 0; let p = ffi::SSL_SESSION_get_id(self.as_ptr(), &mut len); - slice::from_raw_parts(p as *const u8, len as usize) + util::from_raw_parts(p as *const u8, len as usize) } } @@ -2612,7 +2612,7 @@ impl SslRef { if data.is_null() { None } else { - Some(slice::from_raw_parts(data, len as usize)) + Some(util::from_raw_parts(data, len as usize)) } } } @@ -2890,7 +2890,7 @@ impl SslRef { if len < 0 { None } else { - Some(slice::from_raw_parts(p as *const u8, len as usize)) + Some(util::from_raw_parts(p as *const u8, len as usize)) } } } @@ -3057,7 +3057,7 @@ impl SslRef { if len == 0 { None } else { - Some(slice::from_raw_parts(ptr, len)) + Some(util::from_raw_parts(ptr, len)) } } } @@ -3076,7 +3076,7 @@ impl SslRef { if len == 0 { None } else { - Some(slice::from_raw_parts(ptr, len)) + Some(util::from_raw_parts(ptr, len)) } } } @@ -3095,7 +3095,7 @@ impl SslRef { if len == 0 { None } else { - Some(slice::from_raw_parts(ptr, len)) + Some(util::from_raw_parts(ptr, len)) } } } @@ -3149,7 +3149,7 @@ impl SslRef { if len == 0 { None } else { - Some(slice::from_raw_parts(ptr, len)) + Some(util::from_raw_parts(ptr, len)) } } } diff --git a/openssl/src/util.rs b/openssl/src/util.rs index d852a4b..78c91e2 100644 --- a/openssl/src/util.rs +++ b/openssl/src/util.rs @@ -1,4 +1,5 @@ use crate::error::ErrorStack; +use crate::util; use foreign_types::{ForeignType, ForeignTypeRef}; use libc::{c_char, c_int, c_void}; use std::any::Any; @@ -49,7 +50,7 @@ where let callback = &mut *(cb_state as *mut CallbackState); let result = panic::catch_unwind(AssertUnwindSafe(|| { - let pass_slice = slice::from_raw_parts_mut(buf as *mut u8, size as usize); + let pass_slice = util::from_raw_parts_mut(buf as *mut u8, size as usize); callback.cb.take().unwrap()(pass_slice) })); @@ -91,3 +92,27 @@ pub trait ForeignTypeRefExt: ForeignTypeRef { } } impl ForeignTypeRefExt for FT {} + +/// The same as `slice::from_raw_parts`, except that `data` may be `NULL` if +/// `len` is 0. +pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + if len == 0 { + &[] + } else { + // Using this to implement the preferred API + #[allow(clippy::disallowed_methods)] + slice::from_raw_parts(data, len) + } +} + +/// The same as `slice::from_raw_parts_mut`, except that `data` may be `NULL` +/// if `len` is 0. +pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + if len == 0 { + &mut [] + } else { + // Using this to implement the preferred API + #[allow(clippy::disallowed_methods)] + slice::from_raw_parts_mut(data, len) + } +} \ No newline at end of file diff --git a/openssl/src/x509/mod.rs b/openssl/src/x509/mod.rs index 4325b13..2abd67b 100644 --- a/openssl/src/x509/mod.rs +++ b/openssl/src/x509/mod.rs @@ -20,7 +20,6 @@ use std::mem; use std::net::IpAddr; use std::path::Path; use std::ptr; -use std::slice; use std::str; use crate::asn1::{ @@ -37,7 +36,7 @@ use crate::pkey::{HasPrivate, HasPublic, PKey, PKeyRef, Public}; use crate::ssl::SslRef; use crate::stack::{Stack, StackRef, Stackable}; use crate::string::OpensslString; -use crate::util::{ForeignTypeExt, ForeignTypeRefExt}; +use crate::util::{self, ForeignTypeExt, ForeignTypeRefExt}; use crate::{cvt, cvt_n, cvt_p}; use openssl_macros::corresponds; @@ -2102,7 +2101,7 @@ impl GeneralNameRef { let ptr = ASN1_STRING_get0_data(d as *mut _); let len = ffi::ASN1_STRING_length(d as *mut _); - let slice = slice::from_raw_parts(ptr as *const u8, len as usize); + let slice = util::from_raw_parts(ptr as *const u8, len as usize); // IA5Strings are stated to be ASCII (specifically IA5). Hopefully // OpenSSL checks that when loading a certificate but if not we'll // use this instead of from_utf8_unchecked just in case. @@ -2155,7 +2154,7 @@ impl GeneralNameRef { let ptr = ASN1_STRING_get0_data(d as *mut _); let len = ffi::ASN1_STRING_length(d as *mut _); - Some(slice::from_raw_parts(ptr as *const u8, len as usize)) + Some(util::from_raw_parts(ptr as *const u8, len as usize)) } } } -- Gitee