mundane/boringssl/
wrapper.rs

1// Copyright 2020 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use std::marker::PhantomData;
6use std::mem::{self, MaybeUninit};
7use std::ptr::NonNull;
8
9/// A trait that can be used to ensure that users of the boringssl module can't
10/// implement a trait.
11///
12/// See the [API Guidelines] for details.
13///
14/// [API Guidelines]: https://rust-lang-nursery.github.io/api-guidelines/future-proofing.html#sealed-traits-protect-against-downstream-implementations-c-sealed
15pub trait Sealed {}
16
17macro_rules! sealed {
18    ($name:ident) => {
19        impl ::boringssl::wrapper::Sealed for ::boringssl::raw::ffi::$name {}
20    };
21}
22
23macro_rules! impl_traits {
24    (@inner $name:ident, CNew => $fn:tt) => {
25        c_new!($name, $fn);
26    };
27    (@inner $name:ident, CUpRef => $fn:tt) => {
28        c_up_ref!($name, $fn);
29    };
30    (@inner $name:ident, CFree => $fn:tt) => {
31        c_free!($name, $fn);
32    };
33    (@inner $name:ident, CInit => $fn:tt) => {
34        c_init!($name, $fn);
35    };
36    (@inner $name:ident, CDestruct => $fn:tt) => {
37        c_destruct!($name, $fn);
38    };
39    (@inner $name:ident, $trait:ident => $fn:tt) => {
40        compile_error!(concat!("unrecognized trait ", stringify!($trait)));
41    };
42    ($name:ident, $($trait:ident => $fn:tt),*) => {
43        sealed!($name);
44        $(impl_traits!(@inner $name, $trait => $fn);)*
45    };
46}
47
48#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181467)
49/// A C object from the BoringSSL API which can be allocated and constructed.
50pub unsafe trait CNew: Sealed {
51    /// Returns a new, constructed, heap-allocated object, or NULL on failure.
52    ///
53    /// This should not be called directly; instead, use `new`.
54    #[deprecated(note = "do not call new_raw directly; instead, call new")]
55    unsafe fn new_raw() -> *mut Self;
56
57    /// Returns a new, constructed, heap-allocated object, or `None` on failure.
58    #[must_use]
59    unsafe fn new() -> Option<NonNull<Self>> {
60        #[allow(deprecated)]
61        NonNull::new(Self::new_raw())
62    }
63}
64
65macro_rules! c_new {
66    ($name:ident, $new:ident) => {
67        unsafe impl ::boringssl::wrapper::CNew for ::boringssl::raw::ffi::$name {
68            unsafe fn new_raw() -> *mut Self {
69                ::boringssl::raw::ffi::$new()
70            }
71        }
72    };
73}
74
75#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
76/// A C object from the BoringSSL API which has a reference count that can be
77/// increased.
78pub unsafe trait CUpRef: Sealed {
79    /// Increases an object's reference count.
80    unsafe fn up_ref(slf: *mut Self);
81}
82
83macro_rules! c_up_ref {
84    ($name:ident, $up_ref:ident) => {
85        unsafe impl ::boringssl::wrapper::CUpRef for ::boringssl::raw::ffi::$name {
86            unsafe fn up_ref(slf: *mut Self) {
87                use boringssl::abort::UnwrapAbort;
88                ::boringssl::raw::one_or_err(
89                    stringify!($up_ref),
90                    ::boringssl::raw::ffi::$up_ref(slf),
91                )
92                .unwrap_abort()
93            }
94        }
95    };
96}
97
98#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
99/// A C object from the BoringSSL API which can be freed.
100pub unsafe trait CFree: Sealed {
101    /// Frees a heap-allocated object.
102    ///
103    /// If this is a reference-counted object, `free` decrements the reference
104    /// count, and frees the object if it reaches zero. Otherwise, if this is
105    /// not a reference-counted object, it frees it.
106    unsafe fn free(slf: *mut Self);
107}
108
109macro_rules! c_free {
110    ($name:ident, $free:ident) => {
111        unsafe impl ::boringssl::wrapper::CFree for ::boringssl::raw::ffi::$name {
112            unsafe fn free(slf: *mut Self) {
113                ::boringssl::raw::ffi::$free(slf)
114            }
115        }
116    };
117}
118
119#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
120/// A C object from the BoringSSL API which can be initialized.
121pub unsafe trait CInit: Sealed {
122    /// Initializes an uninitialized object.
123    ///
124    /// # Safety
125    ///
126    /// `init` must not be called on an initialized object.
127    unsafe fn init(slf: *mut Self);
128}
129
130#[allow(unused)] // TODO: Remove once it's used in the 'raw' module
131macro_rules! c_init {
132    ($name:ident, $init:ident) => {
133        unsafe impl ::boringssl::wrapper::CInit for ::boringssl::raw::ffi::$name {
134            unsafe fn init(slf: *mut Self) {
135                ::boringssl::raw::ffi::$init(slf)
136            }
137        }
138    };
139}
140
141#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
142/// A C object from the BoringSSL API which can be destructed.
143pub unsafe trait CDestruct: Sealed {
144    /// Destructs an initialized object.
145    ///
146    /// # Safety
147    ///
148    /// `slf` must be an initialized object. After a call to `destruct`, `slf`
149    /// is uninitialized.
150    unsafe fn destruct(slf: *mut Self);
151}
152
153macro_rules! c_destruct {
154    ($name:ident, _) => {
155        unsafe impl ::boringssl::wrapper::CDestruct for ::boringssl::raw::ffi::$name {
156            unsafe fn destruct(_slf: *mut Self) {}
157        }
158    };
159    ($name:ident, $destruct:tt) => {
160        unsafe impl ::boringssl::wrapper::CDestruct for ::boringssl::raw::ffi::$name {
161            unsafe fn destruct(slf: *mut Self) {
162                ::boringssl::raw::ffi::$destruct(slf)
163            }
164        }
165    };
166}
167
168/// A wrapper around a pointer to a heap-allocated, constructed C object from
169/// the BoringSSL API.
170///
171/// `CHeapWrapper` maintains the invariant that the object it references is
172/// always allocated and constructed. This means that:
173/// - If the object can be reference counted, `CHeapWrapper` implements `Clone`
174///   by incrementing the reference count, and decrementing on `Drop`.
175/// - If the object cannot be reference counted, `CHeapWrapper` does not
176///   implement `Clone`, but will still free the object on `Drop`.
177///
178/// `CHeapWrapper`s are not thread-safe; they do not implement `Send` or `Sync`.
179pub struct CHeapWrapper<C: CFree> {
180    // NOTE: NonNull ensures that CHeapWrapper is !Send + !Sync. If this struct
181    // is changed, make sure it's still !Send + !Sync.
182    obj: NonNull<C>,
183}
184
185impl<C: CFree> CHeapWrapper<C> {
186    /// Takes ownership of a constructed object.
187    ///
188    /// # Safety
189    ///
190    /// `obj` must point to an allocated, constructed object. The caller must
191    /// ensure that, when the returned `CHeapWrapper` is dropped, it is safe to
192    /// call `C::free` on `obj`. In most cases, this means that the caller
193    /// should not free `obj`, and instead consider ownership of `obj` to have
194    /// transferred to the new `CHeapWrapper`.
195    ///
196    /// The caller must also ensure that no pointers to the object will ever be
197    /// used by other threads so long as this `CHeapWrapper` exists.
198    #[must_use]
199    pub unsafe fn new_from(obj: NonNull<C>) -> CHeapWrapper<C> {
200        CHeapWrapper { obj }
201    }
202
203    #[must_use]
204    pub fn as_mut(&mut self) -> *mut C {
205        self.obj.as_ptr()
206    }
207
208    #[must_use]
209    pub fn as_const(&self) -> *const C {
210        self.obj.as_ptr()
211    }
212
213    /// Consumes this `CHeapWrapper` and return the underlying pointer.
214    ///
215    /// The object will not be freed. Instead, the caller takes logical
216    /// ownership of the object.
217    #[must_use]
218    pub fn into_mut(self) -> *mut C {
219        // NOTE: This method safe for the same reason that mem::forget is safe:
220        // it's equivalent to sending it to a thread that goes to sleep forever
221        // or creating a Rc cycle or some other silly-but-safe behavior.
222        let ptr = self.obj.as_ptr();
223        mem::forget(self);
224        ptr
225    }
226}
227
228impl<C: CNew + CFree> Default for CHeapWrapper<C> {
229    fn default() -> CHeapWrapper<C> {
230        // TODO(joshlf): In order for this to be safe, CNew must provide the
231        // safety guarantee that it's always safe to call CNew::new and then
232        // later to call CFree::free on that object (e.g., see the safety
233        // comment on CStackWrapper::new).
234        unsafe {
235            use boringssl::abort::UnwrapAbort;
236            let obj = C::new().expect_abort("could not allocate object");
237            CHeapWrapper { obj }
238        }
239    }
240}
241
242impl<C: CUpRef + CFree> Clone for CHeapWrapper<C> {
243    fn clone(&self) -> CHeapWrapper<C> {
244        unsafe { C::up_ref(self.obj.as_ptr()) };
245        CHeapWrapper { obj: self.obj }
246    }
247}
248
249impl<C: CFree> Drop for CHeapWrapper<C> {
250    fn drop(&mut self) {
251        unsafe { C::free(self.obj.as_ptr()) };
252    }
253}
254
255/// A wrapper around a pointer to a C object from the BoringSSL API.
256///
257/// Unlike `CHeapWrapper` or `CStackWrapper`, `CRef` does not own the pointed-to
258/// object, but merely borrows it like a normal Rust reference. The only reason
259/// to use `CRef<C>` instead of a `&C` is to make it so that access to the `C`
260/// is unsafe, as `CRef` only exposes a raw pointer accessor for its object.
261///
262/// `CRef` maintains the invariant that the object it references is always
263/// allocated and constructed, and that mutable access to the object is disabled
264/// for the lifetime of the `CRef`.
265pub struct CRef<'a, C> {
266    // NOTE: NonNull ensures that CHeapWrapper is !Send + !Sync. If this struct
267    // is changed, make sure it's still !Send + !Sync.
268    obj: NonNull<C>,
269    // Make sure CRef has the lifetime 'a.
270    _lifetime: PhantomData<&'a ()>,
271}
272
273impl<'a, C> CRef<'a, C> {
274    /// Creates a new `CRef` from a raw pointer.
275    ///
276    /// # Safety
277    ///
278    /// `obj` must point to an allocated, constructed object. The caller must
279    /// ensure that, for the lifetime, `'a`, `obj` will continue to point to the
280    /// same allocated, constructed object, and that mutable access to the
281    /// object will be disallowed.
282    ///
283    /// The caller must also ensure that no other pointers to the object will
284    /// ever be sent to other threads so long as this `CRef` exists.
285    #[must_use]
286    pub unsafe fn new(obj: NonNull<C>) -> CRef<'a, C> {
287        CRef { obj, _lifetime: PhantomData }
288    }
289
290    #[must_use]
291    pub fn as_const(&self) -> *const C {
292        self.obj.as_ptr()
293    }
294}
295
296/// A wrapper around a constructed C object from the BoringSSL API.
297///
298/// `CStackWrapper` maintains the invariant that the object it contains is
299/// always constructed. The object is destructed on `Drop`.
300///
301/// `CStackWrapper`s are not thread-safe; they do not implement `Send` or
302/// `Sync`.
303pub struct CStackWrapper<C: CDestruct> {
304    obj: C,
305    // Make sure CStackWrapper doesn't implement Send or Sync regardless of C.
306    _no_sync: PhantomData<*mut ()>,
307}
308
309impl<C: CDestruct> CStackWrapper<C> {
310    /// Constructs a new `CStackWrapper`.
311    ///
312    /// # Safety
313    ///
314    /// `obj` must be constructed, and it must be safe for `C::destruct` to be
315    /// called on `obj` when this `CStackWrapper` is dropped.
316    #[must_use]
317    pub unsafe fn new(obj: C) -> CStackWrapper<C> {
318        CStackWrapper { obj, _no_sync: PhantomData }
319    }
320
321    #[must_use]
322    pub fn as_c_ref(&mut self) -> CRef<'_, C> {
323        unsafe { CRef::new(NonNull::new_unchecked(&mut self.obj as *mut C)) }
324    }
325
326    #[must_use]
327    pub fn as_mut(&mut self) -> *mut C {
328        &mut self.obj
329    }
330
331    #[must_use]
332    pub fn as_const(&self) -> *const C {
333        &self.obj
334    }
335}
336
337impl<C: CInit + CDestruct> Default for CStackWrapper<C> {
338    // TODO(joshlf): In order for this to be safe, CInit must provide the safety
339    // guarantee that it's always safe to call CInit::init and then later to
340    // call CDestruct::destruct on that object (e.g., see the safety comment on
341    // CStackWrapper::new).
342    fn default() -> CStackWrapper<C> {
343        unsafe {
344            let mut obj = MaybeUninit::<C>::uninit();
345            C::init(obj.as_mut_ptr());
346            CStackWrapper { obj: obj.assume_init(), _no_sync: PhantomData }
347        }
348    }
349}
350
351impl<C: CDestruct> Drop for CStackWrapper<C> {
352    fn drop(&mut self) {
353        unsafe { C::destruct(&mut self.obj) }
354    }
355}
356
357#[cfg(test)]
358mod tests {
359    use super::*;
360    use boringssl::EC_KEY;
361
362    #[test]
363    fn test_heap_wrapper_into_mut() {
364        // Test that CHeapWrapper::into_mut doesn't free the pointer. If it
365        // does, then EC_KEY::free is likely (though not guaranteed) to abort
366        // when it finds the refcount at 0.
367        let key = CHeapWrapper::<EC_KEY>::default();
368        unsafe { EC_KEY::free(key.into_mut()) };
369    }
370}