mundane/boringssl/
wrapper.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
// Copyright 2020 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

use std::marker::PhantomData;
use std::mem::{self, MaybeUninit};
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);)*
    };
}

#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181467)
/// 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()
            }
        }
    };
}

#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
/// 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()
            }
        }
    };
}

#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
/// 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)
            }
        }
    };
}

#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
/// 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)
            }
        }
    };
}

#[allow(clippy::missing_safety_doc)] // TODO(https://fxbug.dev/42181466)
/// 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_c_ref(&mut self) -> CRef<'_, C> {
        unsafe { CRef::new(NonNull::new_unchecked(&mut self.obj as *mut C)) }
    }

    #[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 = MaybeUninit::<C>::uninit();
            C::init(obj.as_mut_ptr());
            CStackWrapper { obj: obj.assume_init(), _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()) };
    }
}