blob: 864a8b0263223988d2582f50401afddb8fc75dda [file] [log] [blame]
// Copyright 2018 Google LLC
//
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.
use std::marker::PhantomData;
use std::mem;
use std::ptr::NonNull;
/// A trait that can be used to ensure that users of the boringssl module can't
/// implement a trait.
///
/// See the [API Guidelines] for details.
///
/// [API Guidelines]: https://rust-lang-nursery.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
pub trait Sealed {}
macro_rules! sealed {
($name:ident) => {
impl ::boringssl::wrapper::Sealed for ::boringssl::raw::ffi::$name {}
};
}
macro_rules! impl_traits {
(@inner $name:ident, CNew => $fn:tt) => {
c_new!($name, $fn);
};
(@inner $name:ident, CUpRef => $fn:tt) => {
c_up_ref!($name, $fn);
};
(@inner $name:ident, CFree => $fn:tt) => {
c_free!($name, $fn);
};
(@inner $name:ident, CInit => $fn:tt) => {
c_init!($name, $fn);
};
(@inner $name:ident, CDestruct => $fn:tt) => {
c_destruct!($name, $fn);
};
(@inner $name:ident, $trait:ident => $fn:tt) => {
compile_error!(concat!("unrecognized trait ", stringify!($trait)));
};
($name:ident, $($trait:ident => $fn:tt),*) => {
sealed!($name);
$(impl_traits!(@inner $name, $trait => $fn);)*
};
}
/// A C object from the BoringSSL API which can be allocated and constructed.
pub unsafe trait CNew: Sealed {
/// Returns a new, constructed, heap-allocated object, or NULL on failure.
///
/// This should not be called directly; instead, use `new`.
#[deprecated(note = "do not call new_raw directly; instead, call new")]
unsafe fn new_raw() -> *mut Self;
/// Returns a new, constructed, heap-allocated object, or `None` on failure.
#[must_use]
unsafe fn new() -> Option<NonNull<Self>> {
#[allow(deprecated)]
NonNull::new(Self::new_raw())
}
}
macro_rules! c_new {
($name:ident, $new:ident) => {
unsafe impl ::boringssl::wrapper::CNew for ::boringssl::raw::ffi::$name {
unsafe fn new_raw() -> *mut Self {
::boringssl::raw::ffi::$new()
}
}
};
}
/// A C object from the BoringSSL API which has a reference count that can be
/// increased.
pub unsafe trait CUpRef: Sealed {
/// Increases an object's reference count.
unsafe fn up_ref(slf: *mut Self);
}
macro_rules! c_up_ref {
($name:ident, $up_ref:ident) => {
unsafe impl ::boringssl::wrapper::CUpRef for ::boringssl::raw::ffi::$name {
unsafe fn up_ref(slf: *mut Self) {
use boringssl::abort::UnwrapAbort;
::boringssl::raw::one_or_err(
stringify!($up_ref),
::boringssl::raw::ffi::$up_ref(slf),
)
.unwrap_abort()
}
}
};
}
/// A C object from the BoringSSL API which can be freed.
pub unsafe trait CFree: Sealed {
/// Frees a heap-allocated object.
///
/// If this is a reference-counted object, `free` decrements the reference
/// count, and frees the object if it reaches zero. Otherwise, if this is
/// not a reference-counted object, it frees it.
unsafe fn free(slf: *mut Self);
}
macro_rules! c_free {
($name:ident, $free:ident) => {
unsafe impl ::boringssl::wrapper::CFree for ::boringssl::raw::ffi::$name {
unsafe fn free(slf: *mut Self) {
::boringssl::raw::ffi::$free(slf)
}
}
};
}
/// A C object from the BoringSSL API which can be initialized.
pub unsafe trait CInit: Sealed {
/// Initializes an uninitialized object.
///
/// # Safety
///
/// `init` must not be called on an initialized object.
unsafe fn init(slf: *mut Self);
}
#[allow(unused)] // TODO: Remove once it's used in the 'raw' module
macro_rules! c_init {
($name:ident, $init:ident) => {
unsafe impl ::boringssl::wrapper::CInit for ::boringssl::raw::ffi::$name {
unsafe fn init(slf: *mut Self) {
::boringssl::raw::ffi::$init(slf)
}
}
};
}
/// A C object from the BoringSSL API which can be destructed.
pub unsafe trait CDestruct: Sealed {
/// Destructs an initialized object.
///
/// # Safety
///
/// `slf` must be an initialized object. After a call to `destruct`, `slf`
/// is uninitialized.
unsafe fn destruct(slf: *mut Self);
}
macro_rules! c_destruct {
($name:ident, _) => {
unsafe impl ::boringssl::wrapper::CDestruct for ::boringssl::raw::ffi::$name {
unsafe fn destruct(_slf: *mut Self) {}
}
};
($name:ident, $destruct:tt) => {
unsafe impl ::boringssl::wrapper::CDestruct for ::boringssl::raw::ffi::$name {
unsafe fn destruct(slf: *mut Self) {
::boringssl::raw::ffi::$destruct(slf)
}
}
};
}
/// A wrapper around a pointer to a heap-allocated, constructed C object from
/// the BoringSSL API.
///
/// `CHeapWrapper` maintains the invariant that the object it references is
/// always allocated and constructed. This means that:
/// - If the object can be reference counted, `CHeapWrapper` implements `Clone`
/// by incrementing the reference count, and decrementing on `Drop`.
/// - If the object cannot be reference counted, `CHeapWrapper` does not
/// implement `Clone`, but will still free the object on `Drop`.
///
/// `CHeapWrapper`s are not thread-safe; they do not implement `Send` or `Sync`.
pub struct CHeapWrapper<C: CFree> {
// NOTE: NonNull ensures that CHeapWrapper is !Send + !Sync. If this struct
// is changed, make sure it's still !Send + !Sync.
obj: NonNull<C>,
}
impl<C: CFree> CHeapWrapper<C> {
/// Takes ownership of a constructed object.
///
/// # Safety
///
/// `obj` must point to an allocated, constructed object. The caller must
/// ensure that, when the returned `CHeapWrapper` is dropped, it is safe to
/// call `C::free` on `obj`. In most cases, this means that the caller
/// should not free `obj`, and instead consider ownership of `obj` to have
/// transferred to the new `CHeapWrapper`.
///
/// The caller must also ensure that no pointers to the object will ever be
/// used by other threads so long as this `CHeapWrapper` exists.
#[must_use]
pub unsafe fn new_from(obj: NonNull<C>) -> CHeapWrapper<C> {
CHeapWrapper { obj }
}
#[must_use]
pub fn as_mut(&mut self) -> *mut C {
self.obj.as_ptr()
}
#[must_use]
pub fn as_const(&self) -> *const C {
self.obj.as_ptr()
}
/// Consumes this `CHeapWrapper` and return the underlying pointer.
///
/// The object will not be freed. Instead, the caller takes logical
/// ownership of the object.
#[must_use]
pub fn into_mut(self) -> *mut C {
// NOTE: This method safe for the same reason that mem::forget is safe:
// it's equivalent to sending it to a thread that goes to sleep forever
// or creating a Rc cycle or some other silly-but-safe behavior.
let ptr = self.obj.as_ptr();
mem::forget(self);
ptr
}
}
impl<C: CNew + CFree> Default for CHeapWrapper<C> {
fn default() -> CHeapWrapper<C> {
// TODO(joshlf): In order for this to be safe, CNew must provide the
// safety guarantee that it's always safe to call CNew::new and then
// later to call CFree::free on that object (e.g., see the safety
// comment on CStackWrapper::new).
unsafe {
use boringssl::abort::UnwrapAbort;
let obj = C::new().expect_abort("could not allocate object");
CHeapWrapper { obj }
}
}
}
impl<C: CUpRef + CFree> Clone for CHeapWrapper<C> {
fn clone(&self) -> CHeapWrapper<C> {
unsafe { C::up_ref(self.obj.as_ptr()) };
CHeapWrapper { obj: self.obj }
}
}
impl<C: CFree> Drop for CHeapWrapper<C> {
fn drop(&mut self) {
unsafe { C::free(self.obj.as_ptr()) };
}
}
/// A wrapper around a pointer to a C object from the BoringSSL API.
///
/// Unlike `CHeapWrapper` or `CStackWrapper`, `CRef` does not own the pointed-to
/// object, but merely borrows it like a normal Rust reference. The only reason
/// to use `CRef<C>` instead of a `&C` is to make it so that access to the `C`
/// is unsafe, as `CRef` only exposes a raw pointer accessor for its object.
///
/// `CRef` maintains the invariant that the object it references is always
/// allocated and constructed, and that mutable access to the object is disabled
/// for the lifetime of the `CRef`.
pub struct CRef<'a, C> {
// NOTE: NonNull ensures that CHeapWrapper is !Send + !Sync. If this struct
// is changed, make sure it's still !Send + !Sync.
obj: NonNull<C>,
// Make sure CRef has the lifetime 'a.
_lifetime: PhantomData<&'a ()>,
}
impl<'a, C> CRef<'a, C> {
/// Creates a new `CRef` from a raw pointer.
///
/// # Safety
///
/// `obj` must point to an allocated, constructed object. The caller must
/// ensure that, for the lifetime, `'a`, `obj` will continue to point to the
/// same allocated, constructed object, and that mutable access to the
/// object will be disallowed.
///
/// The caller must also ensure that no other pointers to the object will
/// ever be sent to other threads so long as this `CRef` exists.
#[must_use]
pub unsafe fn new(obj: NonNull<C>) -> CRef<'a, C> {
CRef {
obj,
_lifetime: PhantomData,
}
}
#[must_use]
pub fn as_const(&self) -> *const C {
self.obj.as_ptr()
}
}
/// A wrapper around a constructed C object from the BoringSSL API.
///
/// `CStackWrapper` maintains the invariant that the object it contains is
/// always constructed. The object is destructed on `Drop`.
///
/// `CStackWrapper`s are not thread-safe; they do not implement `Send` or
/// `Sync`.
pub struct CStackWrapper<C: CDestruct> {
obj: C,
// Make sure CStackWrapper doesn't implement Send or Sync regardless of C.
_no_sync: PhantomData<*mut ()>,
}
impl<C: CDestruct> CStackWrapper<C> {
/// Constructs a new `CStackWrapper`.
///
/// # Safety
///
/// `obj` must be constructed, and it must be safe for `C::destruct` to be
/// called on `obj` when this `CStackWrapper` is dropped.
#[must_use]
pub unsafe fn new(obj: C) -> CStackWrapper<C> {
CStackWrapper {
obj,
_no_sync: PhantomData,
}
}
#[must_use]
pub fn as_mut(&mut self) -> *mut C {
&mut self.obj
}
#[must_use]
pub fn as_const(&self) -> *const C {
&self.obj
}
}
impl<C: CInit + CDestruct> Default for CStackWrapper<C> {
// TODO(joshlf): In order for this to be safe, CInit must provide the safety
// guarantee that it's always safe to call CInit::init and then later to
// call CDestruct::destruct on that object (e.g., see the safety comment on
// CStackWrapper::new).
fn default() -> CStackWrapper<C> {
unsafe {
let mut obj: C = mem::uninitialized();
C::init(&mut obj);
CStackWrapper {
obj,
_no_sync: PhantomData,
}
}
}
}
impl<C: CDestruct> Drop for CStackWrapper<C> {
fn drop(&mut self) {
unsafe { C::destruct(&mut self.obj) }
}
}
#[cfg(test)]
mod tests {
use super::*;
use boringssl::EC_KEY;
#[test]
fn test_heap_wrapper_into_mut() {
// Test that CHeapWrapper::into_mut doesn't free the pointer. If it
// does, then EC_KEY::free is likely (though not guaranteed) to abort
// when it finds the refcount at 0.
let key = CHeapWrapper::<EC_KEY>::default();
unsafe { EC_KEY::free(key.into_mut()) };
}
}