1 // SPDX-License-Identifier: GPL-2.0
2 
3 // Copyright (C) 2024 Google LLC.
4 
5 //! Linux Security Modules (LSM).
6 //!
7 //! C header: [`include/linux/security.h`](srctree/include/linux/security.h).
8 
9 use crate::{
10     bindings,
11     error::{to_result, Result},
12 };
13 
14 /// A security context string.
15 ///
16 /// # Invariants
17 ///
18 /// The `ctx` field corresponds to a valid security context as returned by a successful call to
19 /// `security_secid_to_secctx`, that has not yet been released by `security_release_secctx`.
20 pub struct SecurityCtx {
21     ctx: bindings::lsm_context,
22 }
23 
24 impl SecurityCtx {
25     /// Get the security context given its id.
26     #[inline]
from_secid(secid: u32) -> Result<Self>27     pub fn from_secid(secid: u32) -> Result<Self> {
28         // SAFETY: `struct lsm_context` can be initialized to all zeros.
29         let mut ctx: bindings::lsm_context = unsafe { core::mem::zeroed() };
30 
31         // SAFETY: Just a C FFI call. The pointer is valid for writes.
32         to_result(unsafe { bindings::security_secid_to_secctx(secid, &mut ctx) })?;
33 
34         // INVARIANT: If the above call did not fail, then we have a valid security context.
35         Ok(Self { ctx })
36     }
37 
38     /// Returns whether the security context is empty.
39     #[inline]
is_empty(&self) -> bool40     pub fn is_empty(&self) -> bool {
41         self.ctx.len == 0
42     }
43 
44     /// Returns the length of this security context.
45     #[inline]
len(&self) -> usize46     pub fn len(&self) -> usize {
47         self.ctx.len as usize
48     }
49 
50     /// Returns the bytes for this security context.
51     #[inline]
as_bytes(&self) -> &[u8]52     pub fn as_bytes(&self) -> &[u8] {
53         let ptr = self.ctx.context;
54         if ptr.is_null() {
55             debug_assert_eq!(self.len(), 0);
56             // We can't pass a null pointer to `slice::from_raw_parts` even if the length is zero.
57             return &[];
58         }
59 
60         // SAFETY: The call to `security_secid_to_secctx` guarantees that the pointer is valid for
61         // `self.len()` bytes. Furthermore, if the length is zero, then we have ensured that the
62         // pointer is not null.
63         unsafe { core::slice::from_raw_parts(ptr.cast(), self.len()) }
64     }
65 }
66 
67 impl Drop for SecurityCtx {
68     #[inline]
drop(&mut self)69     fn drop(&mut self) {
70         // SAFETY: By the invariant of `Self`, this releases an lsm context that came from a
71         // successful call to `security_secid_to_secctx` and has not yet been released.
72         unsafe { bindings::security_release_secctx(&mut self.ctx) };
73     }
74 }
75