xref: /aosp_15_r20/system/security/keystore2/selinux/src/lib.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2020, The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker //     http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker 
15*e1997b9aSAndroid Build Coastguard Worker //! This crate provides some safe wrappers around the libselinux API. It is currently limited
16*e1997b9aSAndroid Build Coastguard Worker //! to the API surface that Keystore 2.0 requires to perform permission checks against
17*e1997b9aSAndroid Build Coastguard Worker //! the SEPolicy. Notably, it provides wrappers for:
18*e1997b9aSAndroid Build Coastguard Worker //!  * getcon
19*e1997b9aSAndroid Build Coastguard Worker //!  * selinux_check_access
20*e1997b9aSAndroid Build Coastguard Worker //!  * selabel_lookup for the keystore2_key backend.
21*e1997b9aSAndroid Build Coastguard Worker //!
22*e1997b9aSAndroid Build Coastguard Worker //! And it provides an owning wrapper around context strings `Context`.
23*e1997b9aSAndroid Build Coastguard Worker 
24*e1997b9aSAndroid Build Coastguard Worker // TODO(b/290018030): Remove this and add proper safety comments.
25*e1997b9aSAndroid Build Coastguard Worker #![allow(clippy::undocumented_unsafe_blocks)]
26*e1997b9aSAndroid Build Coastguard Worker 
27*e1997b9aSAndroid Build Coastguard Worker use anyhow::Context as AnyhowContext;
28*e1997b9aSAndroid Build Coastguard Worker use anyhow::{anyhow, Result};
29*e1997b9aSAndroid Build Coastguard Worker pub use selinux::pid_t;
30*e1997b9aSAndroid Build Coastguard Worker use selinux::SELABEL_CTX_ANDROID_KEYSTORE2_KEY;
31*e1997b9aSAndroid Build Coastguard Worker use selinux::SELINUX_CB_LOG;
32*e1997b9aSAndroid Build Coastguard Worker use selinux_bindgen as selinux;
33*e1997b9aSAndroid Build Coastguard Worker use std::ffi::{CStr, CString};
34*e1997b9aSAndroid Build Coastguard Worker use std::fmt;
35*e1997b9aSAndroid Build Coastguard Worker use std::io;
36*e1997b9aSAndroid Build Coastguard Worker use std::marker::{Send, Sync};
37*e1997b9aSAndroid Build Coastguard Worker pub use std::ops::Deref;
38*e1997b9aSAndroid Build Coastguard Worker use std::os::raw::c_char;
39*e1997b9aSAndroid Build Coastguard Worker use std::ptr;
40*e1997b9aSAndroid Build Coastguard Worker use std::sync;
41*e1997b9aSAndroid Build Coastguard Worker 
42*e1997b9aSAndroid Build Coastguard Worker static SELINUX_LOG_INIT: sync::Once = sync::Once::new();
43*e1997b9aSAndroid Build Coastguard Worker 
44*e1997b9aSAndroid Build Coastguard Worker /// `selinux_check_access` is only thread safe if avc_init was called with lock callbacks.
45*e1997b9aSAndroid Build Coastguard Worker /// However, avc_init is deprecated and not exported by androids version of libselinux.
46*e1997b9aSAndroid Build Coastguard Worker /// `selinux_set_callbacks` does not allow setting lock callbacks. So the only option
47*e1997b9aSAndroid Build Coastguard Worker /// that remains right now is to put a big lock around calls into libselinux.
48*e1997b9aSAndroid Build Coastguard Worker /// TODO b/188079221 It should suffice to protect `selinux_check_access` but until we are
49*e1997b9aSAndroid Build Coastguard Worker /// certain of that, we leave the extra locks in place
50*e1997b9aSAndroid Build Coastguard Worker static LIB_SELINUX_LOCK: sync::Mutex<()> = sync::Mutex::new(());
51*e1997b9aSAndroid Build Coastguard Worker 
redirect_selinux_logs_to_logcat()52*e1997b9aSAndroid Build Coastguard Worker fn redirect_selinux_logs_to_logcat() {
53*e1997b9aSAndroid Build Coastguard Worker     // `selinux_set_callback` assigns the static lifetime function pointer
54*e1997b9aSAndroid Build Coastguard Worker     // `selinux_log_callback` to a static lifetime variable.
55*e1997b9aSAndroid Build Coastguard Worker     let cb = selinux::selinux_callback { func_log: Some(selinux::selinux_log_callback) };
56*e1997b9aSAndroid Build Coastguard Worker     unsafe {
57*e1997b9aSAndroid Build Coastguard Worker         selinux::selinux_set_callback(SELINUX_CB_LOG as i32, cb);
58*e1997b9aSAndroid Build Coastguard Worker     }
59*e1997b9aSAndroid Build Coastguard Worker }
60*e1997b9aSAndroid Build Coastguard Worker 
61*e1997b9aSAndroid Build Coastguard Worker // This function must be called before any entry point into lib selinux.
62*e1997b9aSAndroid Build Coastguard Worker // Or leave a comment reasoning why calling this macro is not necessary
63*e1997b9aSAndroid Build Coastguard Worker // for a given entry point.
init_logger_once()64*e1997b9aSAndroid Build Coastguard Worker fn init_logger_once() {
65*e1997b9aSAndroid Build Coastguard Worker     SELINUX_LOG_INIT.call_once(redirect_selinux_logs_to_logcat)
66*e1997b9aSAndroid Build Coastguard Worker }
67*e1997b9aSAndroid Build Coastguard Worker 
68*e1997b9aSAndroid Build Coastguard Worker /// Selinux Error code.
69*e1997b9aSAndroid Build Coastguard Worker #[derive(thiserror::Error, Debug, PartialEq, Eq)]
70*e1997b9aSAndroid Build Coastguard Worker pub enum Error {
71*e1997b9aSAndroid Build Coastguard Worker     /// Indicates that an access check yielded no access.
72*e1997b9aSAndroid Build Coastguard Worker     #[error("Permission Denied")]
73*e1997b9aSAndroid Build Coastguard Worker     PermissionDenied,
74*e1997b9aSAndroid Build Coastguard Worker     /// Indicates an unexpected system error. Nested string provides some details.
75*e1997b9aSAndroid Build Coastguard Worker     #[error("Selinux SystemError: {0}")]
76*e1997b9aSAndroid Build Coastguard Worker     SystemError(String),
77*e1997b9aSAndroid Build Coastguard Worker }
78*e1997b9aSAndroid Build Coastguard Worker 
79*e1997b9aSAndroid Build Coastguard Worker impl Error {
80*e1997b9aSAndroid Build Coastguard Worker     /// Constructs a `PermissionDenied` error.
perm() -> Self81*e1997b9aSAndroid Build Coastguard Worker     pub fn perm() -> Self {
82*e1997b9aSAndroid Build Coastguard Worker         Error::PermissionDenied
83*e1997b9aSAndroid Build Coastguard Worker     }
sys<T: Into<String>>(s: T) -> Self84*e1997b9aSAndroid Build Coastguard Worker     fn sys<T: Into<String>>(s: T) -> Self {
85*e1997b9aSAndroid Build Coastguard Worker         Error::SystemError(s.into())
86*e1997b9aSAndroid Build Coastguard Worker     }
87*e1997b9aSAndroid Build Coastguard Worker }
88*e1997b9aSAndroid Build Coastguard Worker 
89*e1997b9aSAndroid Build Coastguard Worker /// Context represents an SELinux context string. It can take ownership of a raw
90*e1997b9aSAndroid Build Coastguard Worker /// s-string as allocated by `getcon` or `selabel_lookup`. In this case it uses
91*e1997b9aSAndroid Build Coastguard Worker /// `freecon` to free the resources when dropped. In its second variant it stores
92*e1997b9aSAndroid Build Coastguard Worker /// an `std::ffi::CString` that can be initialized from a Rust string slice.
93*e1997b9aSAndroid Build Coastguard Worker #[derive(Debug)]
94*e1997b9aSAndroid Build Coastguard Worker pub enum Context {
95*e1997b9aSAndroid Build Coastguard Worker     /// Wraps a raw context c-string as returned by libselinux.
96*e1997b9aSAndroid Build Coastguard Worker     Raw(*mut ::std::os::raw::c_char),
97*e1997b9aSAndroid Build Coastguard Worker     /// Stores a context string as `std::ffi::CString`.
98*e1997b9aSAndroid Build Coastguard Worker     CString(CString),
99*e1997b9aSAndroid Build Coastguard Worker }
100*e1997b9aSAndroid Build Coastguard Worker 
101*e1997b9aSAndroid Build Coastguard Worker impl PartialEq for Context {
eq(&self, other: &Self) -> bool102*e1997b9aSAndroid Build Coastguard Worker     fn eq(&self, other: &Self) -> bool {
103*e1997b9aSAndroid Build Coastguard Worker         // We dereference both and thereby delegate the comparison
104*e1997b9aSAndroid Build Coastguard Worker         // to `CStr`'s implementation of `PartialEq`.
105*e1997b9aSAndroid Build Coastguard Worker         **self == **other
106*e1997b9aSAndroid Build Coastguard Worker     }
107*e1997b9aSAndroid Build Coastguard Worker }
108*e1997b9aSAndroid Build Coastguard Worker 
109*e1997b9aSAndroid Build Coastguard Worker impl Eq for Context {}
110*e1997b9aSAndroid Build Coastguard Worker 
111*e1997b9aSAndroid Build Coastguard Worker impl fmt::Display for Context {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result112*e1997b9aSAndroid Build Coastguard Worker     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
113*e1997b9aSAndroid Build Coastguard Worker         write!(f, "{}", (**self).to_str().unwrap_or("Invalid context"))
114*e1997b9aSAndroid Build Coastguard Worker     }
115*e1997b9aSAndroid Build Coastguard Worker }
116*e1997b9aSAndroid Build Coastguard Worker 
117*e1997b9aSAndroid Build Coastguard Worker impl Drop for Context {
drop(&mut self)118*e1997b9aSAndroid Build Coastguard Worker     fn drop(&mut self) {
119*e1997b9aSAndroid Build Coastguard Worker         if let Self::Raw(p) = self {
120*e1997b9aSAndroid Build Coastguard Worker             // No need to initialize the logger here, because
121*e1997b9aSAndroid Build Coastguard Worker             // `freecon` cannot run unless `Backend::lookup` or `getcon`
122*e1997b9aSAndroid Build Coastguard Worker             // has run.
123*e1997b9aSAndroid Build Coastguard Worker             unsafe { selinux::freecon(*p) };
124*e1997b9aSAndroid Build Coastguard Worker         }
125*e1997b9aSAndroid Build Coastguard Worker     }
126*e1997b9aSAndroid Build Coastguard Worker }
127*e1997b9aSAndroid Build Coastguard Worker 
128*e1997b9aSAndroid Build Coastguard Worker impl Deref for Context {
129*e1997b9aSAndroid Build Coastguard Worker     type Target = CStr;
130*e1997b9aSAndroid Build Coastguard Worker 
deref(&self) -> &Self::Target131*e1997b9aSAndroid Build Coastguard Worker     fn deref(&self) -> &Self::Target {
132*e1997b9aSAndroid Build Coastguard Worker         match self {
133*e1997b9aSAndroid Build Coastguard Worker             Self::Raw(p) => unsafe { CStr::from_ptr(*p) },
134*e1997b9aSAndroid Build Coastguard Worker             Self::CString(cstr) => cstr,
135*e1997b9aSAndroid Build Coastguard Worker         }
136*e1997b9aSAndroid Build Coastguard Worker     }
137*e1997b9aSAndroid Build Coastguard Worker }
138*e1997b9aSAndroid Build Coastguard Worker 
139*e1997b9aSAndroid Build Coastguard Worker impl Context {
140*e1997b9aSAndroid Build Coastguard Worker     /// Initializes the `Context::CString` variant from a Rust string slice.
new(con: &str) -> Result<Self>141*e1997b9aSAndroid Build Coastguard Worker     pub fn new(con: &str) -> Result<Self> {
142*e1997b9aSAndroid Build Coastguard Worker         Ok(Self::CString(
143*e1997b9aSAndroid Build Coastguard Worker             CString::new(con)
144*e1997b9aSAndroid Build Coastguard Worker                 .with_context(|| format!("Failed to create Context with \"{}\"", con))?,
145*e1997b9aSAndroid Build Coastguard Worker         ))
146*e1997b9aSAndroid Build Coastguard Worker     }
147*e1997b9aSAndroid Build Coastguard Worker }
148*e1997b9aSAndroid Build Coastguard Worker 
149*e1997b9aSAndroid Build Coastguard Worker /// The backend trait provides a uniform interface to all libselinux context backends.
150*e1997b9aSAndroid Build Coastguard Worker /// Currently, we only implement the KeystoreKeyBackend though.
151*e1997b9aSAndroid Build Coastguard Worker pub trait Backend {
152*e1997b9aSAndroid Build Coastguard Worker     /// Implementers use libselinux `selabel_lookup` to lookup the context for the given `key`.
lookup(&self, key: &str) -> Result<Context>153*e1997b9aSAndroid Build Coastguard Worker     fn lookup(&self, key: &str) -> Result<Context>;
154*e1997b9aSAndroid Build Coastguard Worker }
155*e1997b9aSAndroid Build Coastguard Worker 
156*e1997b9aSAndroid Build Coastguard Worker /// Keystore key backend takes onwnership of the SELinux context handle returned by
157*e1997b9aSAndroid Build Coastguard Worker /// `selinux_android_keystore2_key_context_handle` and uses `selabel_close` to free
158*e1997b9aSAndroid Build Coastguard Worker /// the handle when dropped.
159*e1997b9aSAndroid Build Coastguard Worker /// It implements `Backend` to provide keystore_key label lookup functionality.
160*e1997b9aSAndroid Build Coastguard Worker pub struct KeystoreKeyBackend {
161*e1997b9aSAndroid Build Coastguard Worker     handle: *mut selinux::selabel_handle,
162*e1997b9aSAndroid Build Coastguard Worker }
163*e1997b9aSAndroid Build Coastguard Worker 
164*e1997b9aSAndroid Build Coastguard Worker // SAFETY: KeystoreKeyBackend is Sync because selabel_lookup is thread safe.
165*e1997b9aSAndroid Build Coastguard Worker unsafe impl Sync for KeystoreKeyBackend {}
166*e1997b9aSAndroid Build Coastguard Worker // SAFETY: KeystoreKeyBackend is Send because selabel_lookup is thread safe.
167*e1997b9aSAndroid Build Coastguard Worker unsafe impl Send for KeystoreKeyBackend {}
168*e1997b9aSAndroid Build Coastguard Worker 
169*e1997b9aSAndroid Build Coastguard Worker impl KeystoreKeyBackend {
170*e1997b9aSAndroid Build Coastguard Worker     const BACKEND_TYPE: i32 = SELABEL_CTX_ANDROID_KEYSTORE2_KEY as i32;
171*e1997b9aSAndroid Build Coastguard Worker 
172*e1997b9aSAndroid Build Coastguard Worker     /// Creates a new instance representing an SELinux context handle as returned by
173*e1997b9aSAndroid Build Coastguard Worker     /// `selinux_android_keystore2_key_context_handle`.
new() -> Result<Self>174*e1997b9aSAndroid Build Coastguard Worker     pub fn new() -> Result<Self> {
175*e1997b9aSAndroid Build Coastguard Worker         init_logger_once();
176*e1997b9aSAndroid Build Coastguard Worker         let _lock = LIB_SELINUX_LOCK.lock().unwrap();
177*e1997b9aSAndroid Build Coastguard Worker 
178*e1997b9aSAndroid Build Coastguard Worker         let handle = unsafe { selinux::selinux_android_keystore2_key_context_handle() };
179*e1997b9aSAndroid Build Coastguard Worker         if handle.is_null() {
180*e1997b9aSAndroid Build Coastguard Worker             return Err(anyhow!(Error::sys("Failed to open KeystoreKeyBackend")));
181*e1997b9aSAndroid Build Coastguard Worker         }
182*e1997b9aSAndroid Build Coastguard Worker         Ok(KeystoreKeyBackend { handle })
183*e1997b9aSAndroid Build Coastguard Worker     }
184*e1997b9aSAndroid Build Coastguard Worker }
185*e1997b9aSAndroid Build Coastguard Worker 
186*e1997b9aSAndroid Build Coastguard Worker impl Drop for KeystoreKeyBackend {
drop(&mut self)187*e1997b9aSAndroid Build Coastguard Worker     fn drop(&mut self) {
188*e1997b9aSAndroid Build Coastguard Worker         // No need to initialize the logger here because it cannot be called unless
189*e1997b9aSAndroid Build Coastguard Worker         // KeystoreKeyBackend::new has run.
190*e1997b9aSAndroid Build Coastguard Worker         unsafe { selinux::selabel_close(self.handle) };
191*e1997b9aSAndroid Build Coastguard Worker     }
192*e1997b9aSAndroid Build Coastguard Worker }
193*e1997b9aSAndroid Build Coastguard Worker 
194*e1997b9aSAndroid Build Coastguard Worker // Because KeystoreKeyBackend is Sync and Send, member function must never call
195*e1997b9aSAndroid Build Coastguard Worker // non thread safe libselinux functions. As of this writing no non thread safe
196*e1997b9aSAndroid Build Coastguard Worker // functions exist that could be called on a label backend handle.
197*e1997b9aSAndroid Build Coastguard Worker impl Backend for KeystoreKeyBackend {
lookup(&self, key: &str) -> Result<Context>198*e1997b9aSAndroid Build Coastguard Worker     fn lookup(&self, key: &str) -> Result<Context> {
199*e1997b9aSAndroid Build Coastguard Worker         let mut con: *mut c_char = ptr::null_mut();
200*e1997b9aSAndroid Build Coastguard Worker         let c_key = CString::new(key).with_context(|| {
201*e1997b9aSAndroid Build Coastguard Worker             format!("selabel_lookup: Failed to convert key \"{}\" to CString.", key)
202*e1997b9aSAndroid Build Coastguard Worker         })?;
203*e1997b9aSAndroid Build Coastguard Worker         match unsafe {
204*e1997b9aSAndroid Build Coastguard Worker             // No need to initialize the logger here because it cannot run unless
205*e1997b9aSAndroid Build Coastguard Worker             // KeystoreKeyBackend::new has run.
206*e1997b9aSAndroid Build Coastguard Worker             let _lock = LIB_SELINUX_LOCK.lock().unwrap();
207*e1997b9aSAndroid Build Coastguard Worker 
208*e1997b9aSAndroid Build Coastguard Worker             selinux::selabel_lookup(self.handle, &mut con, c_key.as_ptr(), Self::BACKEND_TYPE)
209*e1997b9aSAndroid Build Coastguard Worker         } {
210*e1997b9aSAndroid Build Coastguard Worker             0 => {
211*e1997b9aSAndroid Build Coastguard Worker                 if !con.is_null() {
212*e1997b9aSAndroid Build Coastguard Worker                     Ok(Context::Raw(con))
213*e1997b9aSAndroid Build Coastguard Worker                 } else {
214*e1997b9aSAndroid Build Coastguard Worker                     Err(anyhow!(Error::sys(format!(
215*e1997b9aSAndroid Build Coastguard Worker                         "selabel_lookup returned a NULL context for key \"{}\"",
216*e1997b9aSAndroid Build Coastguard Worker                         key
217*e1997b9aSAndroid Build Coastguard Worker                     ))))
218*e1997b9aSAndroid Build Coastguard Worker                 }
219*e1997b9aSAndroid Build Coastguard Worker             }
220*e1997b9aSAndroid Build Coastguard Worker             _ => Err(anyhow!(io::Error::last_os_error()))
221*e1997b9aSAndroid Build Coastguard Worker                 .with_context(|| format!("selabel_lookup failed for key \"{}\"", key)),
222*e1997b9aSAndroid Build Coastguard Worker         }
223*e1997b9aSAndroid Build Coastguard Worker     }
224*e1997b9aSAndroid Build Coastguard Worker }
225*e1997b9aSAndroid Build Coastguard Worker 
226*e1997b9aSAndroid Build Coastguard Worker /// Safe wrapper around libselinux `getcon`. It initializes the `Context::Raw` variant of the
227*e1997b9aSAndroid Build Coastguard Worker /// returned `Context`.
228*e1997b9aSAndroid Build Coastguard Worker ///
229*e1997b9aSAndroid Build Coastguard Worker /// ## Return
230*e1997b9aSAndroid Build Coastguard Worker ///  * Ok(Context::Raw()) if successful.
231*e1997b9aSAndroid Build Coastguard Worker ///  * Err(Error::sys()) if getcon succeeded but returned a NULL pointer.
232*e1997b9aSAndroid Build Coastguard Worker ///  * Err(io::Error::last_os_error()) if getcon failed.
getcon() -> Result<Context>233*e1997b9aSAndroid Build Coastguard Worker pub fn getcon() -> Result<Context> {
234*e1997b9aSAndroid Build Coastguard Worker     init_logger_once();
235*e1997b9aSAndroid Build Coastguard Worker     let _lock = LIB_SELINUX_LOCK.lock().unwrap();
236*e1997b9aSAndroid Build Coastguard Worker 
237*e1997b9aSAndroid Build Coastguard Worker     let mut con: *mut c_char = ptr::null_mut();
238*e1997b9aSAndroid Build Coastguard Worker     match unsafe { selinux::getcon(&mut con) } {
239*e1997b9aSAndroid Build Coastguard Worker         0 => {
240*e1997b9aSAndroid Build Coastguard Worker             if !con.is_null() {
241*e1997b9aSAndroid Build Coastguard Worker                 Ok(Context::Raw(con))
242*e1997b9aSAndroid Build Coastguard Worker             } else {
243*e1997b9aSAndroid Build Coastguard Worker                 Err(anyhow!(Error::sys("getcon returned a NULL context")))
244*e1997b9aSAndroid Build Coastguard Worker             }
245*e1997b9aSAndroid Build Coastguard Worker         }
246*e1997b9aSAndroid Build Coastguard Worker         _ => Err(anyhow!(io::Error::last_os_error())).context("getcon failed"),
247*e1997b9aSAndroid Build Coastguard Worker     }
248*e1997b9aSAndroid Build Coastguard Worker }
249*e1997b9aSAndroid Build Coastguard Worker 
250*e1997b9aSAndroid Build Coastguard Worker /// Safe wrapper around libselinux `getpidcon`. It initializes the `Context::Raw` variant of the
251*e1997b9aSAndroid Build Coastguard Worker /// returned `Context`.
252*e1997b9aSAndroid Build Coastguard Worker ///
253*e1997b9aSAndroid Build Coastguard Worker /// ## Return
254*e1997b9aSAndroid Build Coastguard Worker ///  * Ok(Context::Raw()) if successful.
255*e1997b9aSAndroid Build Coastguard Worker ///  * Err(Error::sys()) if getpidcon succeeded but returned a NULL pointer.
256*e1997b9aSAndroid Build Coastguard Worker ///  * Err(io::Error::last_os_error()) if getpidcon failed.
getpidcon(pid: selinux::pid_t) -> Result<Context>257*e1997b9aSAndroid Build Coastguard Worker pub fn getpidcon(pid: selinux::pid_t) -> Result<Context> {
258*e1997b9aSAndroid Build Coastguard Worker     init_logger_once();
259*e1997b9aSAndroid Build Coastguard Worker     let _lock = LIB_SELINUX_LOCK.lock().unwrap();
260*e1997b9aSAndroid Build Coastguard Worker 
261*e1997b9aSAndroid Build Coastguard Worker     let mut con: *mut c_char = ptr::null_mut();
262*e1997b9aSAndroid Build Coastguard Worker     match unsafe { selinux::getpidcon(pid, &mut con) } {
263*e1997b9aSAndroid Build Coastguard Worker         0 => {
264*e1997b9aSAndroid Build Coastguard Worker             if !con.is_null() {
265*e1997b9aSAndroid Build Coastguard Worker                 Ok(Context::Raw(con))
266*e1997b9aSAndroid Build Coastguard Worker             } else {
267*e1997b9aSAndroid Build Coastguard Worker                 Err(anyhow!(Error::sys(format!(
268*e1997b9aSAndroid Build Coastguard Worker                     "getpidcon returned a NULL context for pid {}",
269*e1997b9aSAndroid Build Coastguard Worker                     pid
270*e1997b9aSAndroid Build Coastguard Worker                 ))))
271*e1997b9aSAndroid Build Coastguard Worker             }
272*e1997b9aSAndroid Build Coastguard Worker         }
273*e1997b9aSAndroid Build Coastguard Worker         _ => Err(anyhow!(io::Error::last_os_error()))
274*e1997b9aSAndroid Build Coastguard Worker             .context(format!("getpidcon failed for pid {}", pid)),
275*e1997b9aSAndroid Build Coastguard Worker     }
276*e1997b9aSAndroid Build Coastguard Worker }
277*e1997b9aSAndroid Build Coastguard Worker 
278*e1997b9aSAndroid Build Coastguard Worker /// Safe wrapper around selinux_check_access.
279*e1997b9aSAndroid Build Coastguard Worker ///
280*e1997b9aSAndroid Build Coastguard Worker /// ## Return
281*e1997b9aSAndroid Build Coastguard Worker ///  * Ok(()) iff the requested access was granted.
282*e1997b9aSAndroid Build Coastguard Worker ///  * Err(anyhow!(Error::perm()))) if the permission was denied.
283*e1997b9aSAndroid Build Coastguard Worker ///  * Err(anyhow!(ioError::last_os_error())) if any other error occurred while performing
284*e1997b9aSAndroid Build Coastguard Worker ///            the access check.
check_access(source: &CStr, target: &CStr, tclass: &str, perm: &str) -> Result<()>285*e1997b9aSAndroid Build Coastguard Worker pub fn check_access(source: &CStr, target: &CStr, tclass: &str, perm: &str) -> Result<()> {
286*e1997b9aSAndroid Build Coastguard Worker     init_logger_once();
287*e1997b9aSAndroid Build Coastguard Worker 
288*e1997b9aSAndroid Build Coastguard Worker     let c_tclass = CString::new(tclass).with_context(|| {
289*e1997b9aSAndroid Build Coastguard Worker         format!("check_access: Failed to convert tclass \"{}\" to CString.", tclass)
290*e1997b9aSAndroid Build Coastguard Worker     })?;
291*e1997b9aSAndroid Build Coastguard Worker     let c_perm = CString::new(perm).with_context(|| {
292*e1997b9aSAndroid Build Coastguard Worker         format!("check_access: Failed to convert perm \"{}\" to CString.", perm)
293*e1997b9aSAndroid Build Coastguard Worker     })?;
294*e1997b9aSAndroid Build Coastguard Worker 
295*e1997b9aSAndroid Build Coastguard Worker     match unsafe {
296*e1997b9aSAndroid Build Coastguard Worker         let _lock = LIB_SELINUX_LOCK.lock().unwrap();
297*e1997b9aSAndroid Build Coastguard Worker 
298*e1997b9aSAndroid Build Coastguard Worker         selinux::selinux_check_access(
299*e1997b9aSAndroid Build Coastguard Worker             source.as_ptr(),
300*e1997b9aSAndroid Build Coastguard Worker             target.as_ptr(),
301*e1997b9aSAndroid Build Coastguard Worker             c_tclass.as_ptr(),
302*e1997b9aSAndroid Build Coastguard Worker             c_perm.as_ptr(),
303*e1997b9aSAndroid Build Coastguard Worker             ptr::null_mut(),
304*e1997b9aSAndroid Build Coastguard Worker         )
305*e1997b9aSAndroid Build Coastguard Worker     } {
306*e1997b9aSAndroid Build Coastguard Worker         0 => Ok(()),
307*e1997b9aSAndroid Build Coastguard Worker         _ => {
308*e1997b9aSAndroid Build Coastguard Worker             let e = io::Error::last_os_error();
309*e1997b9aSAndroid Build Coastguard Worker             match e.kind() {
310*e1997b9aSAndroid Build Coastguard Worker                 io::ErrorKind::PermissionDenied => Err(anyhow!(Error::perm())),
311*e1997b9aSAndroid Build Coastguard Worker                 _ => Err(anyhow!(e)),
312*e1997b9aSAndroid Build Coastguard Worker             }
313*e1997b9aSAndroid Build Coastguard Worker             .with_context(|| {
314*e1997b9aSAndroid Build Coastguard Worker                 format!(
315*e1997b9aSAndroid Build Coastguard Worker                     concat!(
316*e1997b9aSAndroid Build Coastguard Worker                         "check_access: Failed with sctx: {:?} tctx: {:?}",
317*e1997b9aSAndroid Build Coastguard Worker                         " with target class: \"{}\" perm: \"{}\""
318*e1997b9aSAndroid Build Coastguard Worker                     ),
319*e1997b9aSAndroid Build Coastguard Worker                     source, target, tclass, perm
320*e1997b9aSAndroid Build Coastguard Worker                 )
321*e1997b9aSAndroid Build Coastguard Worker             })
322*e1997b9aSAndroid Build Coastguard Worker         }
323*e1997b9aSAndroid Build Coastguard Worker     }
324*e1997b9aSAndroid Build Coastguard Worker }
325*e1997b9aSAndroid Build Coastguard Worker 
326*e1997b9aSAndroid Build Coastguard Worker /// Safe wrapper around setcon.
setcon(target: &CStr) -> std::io::Result<()>327*e1997b9aSAndroid Build Coastguard Worker pub fn setcon(target: &CStr) -> std::io::Result<()> {
328*e1997b9aSAndroid Build Coastguard Worker     // SAFETY: `setcon` takes a const char* and only performs read accesses on it
329*e1997b9aSAndroid Build Coastguard Worker     // using strdup and strcmp. `setcon` does not retain a pointer to `target`
330*e1997b9aSAndroid Build Coastguard Worker     // and `target` outlives the call to `setcon`.
331*e1997b9aSAndroid Build Coastguard Worker     if unsafe { selinux::setcon(target.as_ptr()) } != 0 {
332*e1997b9aSAndroid Build Coastguard Worker         Err(std::io::Error::last_os_error())
333*e1997b9aSAndroid Build Coastguard Worker     } else {
334*e1997b9aSAndroid Build Coastguard Worker         Ok(())
335*e1997b9aSAndroid Build Coastguard Worker     }
336*e1997b9aSAndroid Build Coastguard Worker }
337*e1997b9aSAndroid Build Coastguard Worker 
338*e1997b9aSAndroid Build Coastguard Worker /// Represents an SEPolicy permission belonging to a specific class.
339*e1997b9aSAndroid Build Coastguard Worker pub trait ClassPermission {
340*e1997b9aSAndroid Build Coastguard Worker     /// The permission string of the given instance as specified in the class vector.
name(&self) -> &'static str341*e1997b9aSAndroid Build Coastguard Worker     fn name(&self) -> &'static str;
342*e1997b9aSAndroid Build Coastguard Worker     /// The class of the permission.
class_name(&self) -> &'static str343*e1997b9aSAndroid Build Coastguard Worker     fn class_name(&self) -> &'static str;
344*e1997b9aSAndroid Build Coastguard Worker }
345*e1997b9aSAndroid Build Coastguard Worker 
346*e1997b9aSAndroid Build Coastguard Worker /// This macro implements an enum with values mapped to SELinux permission names.
347*e1997b9aSAndroid Build Coastguard Worker /// The example below implements `enum MyPermission with public visibility:
348*e1997b9aSAndroid Build Coastguard Worker ///  * From<i32> and Into<i32> are implemented. Where the implementation of From maps
349*e1997b9aSAndroid Build Coastguard Worker ///    any variant not specified to the default `None` with value `0`.
350*e1997b9aSAndroid Build Coastguard Worker ///  * `MyPermission` implements ClassPermission.
351*e1997b9aSAndroid Build Coastguard Worker ///  * An implicit default values `MyPermission::None` is created with a numeric representation
352*e1997b9aSAndroid Build Coastguard Worker ///    of `0` and a string representation of `"none"`.
353*e1997b9aSAndroid Build Coastguard Worker ///  * Specifying a value is optional. If the value is omitted it is set to the value of the
354*e1997b9aSAndroid Build Coastguard Worker ///    previous variant left shifted by 1.
355*e1997b9aSAndroid Build Coastguard Worker ///
356*e1997b9aSAndroid Build Coastguard Worker /// ## Example
357*e1997b9aSAndroid Build Coastguard Worker /// ```
358*e1997b9aSAndroid Build Coastguard Worker /// implement_class!(
359*e1997b9aSAndroid Build Coastguard Worker ///     /// MyPermission documentation.
360*e1997b9aSAndroid Build Coastguard Worker ///     #[derive(Clone, Copy, Debug, Eq, PartialEq)]
361*e1997b9aSAndroid Build Coastguard Worker ///     #[selinux(class_name = my_class)]
362*e1997b9aSAndroid Build Coastguard Worker ///     pub enum MyPermission {
363*e1997b9aSAndroid Build Coastguard Worker ///         #[selinux(name = foo)]
364*e1997b9aSAndroid Build Coastguard Worker ///         Foo = 1,
365*e1997b9aSAndroid Build Coastguard Worker ///         #[selinux(name = bar)]
366*e1997b9aSAndroid Build Coastguard Worker ///         Bar = 2,
367*e1997b9aSAndroid Build Coastguard Worker ///         #[selinux(name = snafu)]
368*e1997b9aSAndroid Build Coastguard Worker ///         Snafu, // Implicit value: MyPermission::Bar << 1 -> 4
369*e1997b9aSAndroid Build Coastguard Worker ///     }
370*e1997b9aSAndroid Build Coastguard Worker ///     assert_eq!(MyPermission::Foo.name(), &"foo");
371*e1997b9aSAndroid Build Coastguard Worker ///     assert_eq!(MyPermission::Foo.class_name(), &"my_class");
372*e1997b9aSAndroid Build Coastguard Worker ///     assert_eq!(MyPermission::Snafu as i32, 4);
373*e1997b9aSAndroid Build Coastguard Worker /// );
374*e1997b9aSAndroid Build Coastguard Worker /// ```
375*e1997b9aSAndroid Build Coastguard Worker #[macro_export]
376*e1997b9aSAndroid Build Coastguard Worker macro_rules! implement_class {
377*e1997b9aSAndroid Build Coastguard Worker     // First rule: Public interface.
378*e1997b9aSAndroid Build Coastguard Worker     (
379*e1997b9aSAndroid Build Coastguard Worker         $(#[$($enum_meta:tt)+])*
380*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident $body:tt
381*e1997b9aSAndroid Build Coastguard Worker     ) => {
382*e1997b9aSAndroid Build Coastguard Worker         implement_class! {
383*e1997b9aSAndroid Build Coastguard Worker             @extract_class
384*e1997b9aSAndroid Build Coastguard Worker             []
385*e1997b9aSAndroid Build Coastguard Worker             [$(#[$($enum_meta)+])*]
386*e1997b9aSAndroid Build Coastguard Worker             $enum_vis enum $enum_name $body
387*e1997b9aSAndroid Build Coastguard Worker         }
388*e1997b9aSAndroid Build Coastguard Worker     };
389*e1997b9aSAndroid Build Coastguard Worker 
390*e1997b9aSAndroid Build Coastguard Worker     // The next two rules extract the #[selinux(class_name = <name>)] meta field from
391*e1997b9aSAndroid Build Coastguard Worker     // the types meta list.
392*e1997b9aSAndroid Build Coastguard Worker     // This first rule finds the field and terminates the recursion through the meta fields.
393*e1997b9aSAndroid Build Coastguard Worker     (
394*e1997b9aSAndroid Build Coastguard Worker         @extract_class
395*e1997b9aSAndroid Build Coastguard Worker         [$(#[$mout:meta])*]
396*e1997b9aSAndroid Build Coastguard Worker         [
397*e1997b9aSAndroid Build Coastguard Worker             #[selinux(class_name = $class_name:ident)]
398*e1997b9aSAndroid Build Coastguard Worker             $(#[$($mtail:tt)+])*
399*e1997b9aSAndroid Build Coastguard Worker         ]
400*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident {
401*e1997b9aSAndroid Build Coastguard Worker             $(
402*e1997b9aSAndroid Build Coastguard Worker                 $(#[$($emeta:tt)+])*
403*e1997b9aSAndroid Build Coastguard Worker                 $vname:ident$( = $vval:expr)?
404*e1997b9aSAndroid Build Coastguard Worker             ),* $(,)?
405*e1997b9aSAndroid Build Coastguard Worker         }
406*e1997b9aSAndroid Build Coastguard Worker     ) => {
407*e1997b9aSAndroid Build Coastguard Worker         implement_class!{
408*e1997b9aSAndroid Build Coastguard Worker             @extract_perm_name
409*e1997b9aSAndroid Build Coastguard Worker             $class_name
410*e1997b9aSAndroid Build Coastguard Worker             $(#[$mout])*
411*e1997b9aSAndroid Build Coastguard Worker             $(#[$($mtail)+])*
412*e1997b9aSAndroid Build Coastguard Worker             $enum_vis enum $enum_name {
413*e1997b9aSAndroid Build Coastguard Worker                 1;
414*e1997b9aSAndroid Build Coastguard Worker                 []
415*e1997b9aSAndroid Build Coastguard Worker                 [$(
416*e1997b9aSAndroid Build Coastguard Worker                     [] [$(#[$($emeta)+])*]
417*e1997b9aSAndroid Build Coastguard Worker                     $vname$( = $vval)?,
418*e1997b9aSAndroid Build Coastguard Worker                 )*]
419*e1997b9aSAndroid Build Coastguard Worker             }
420*e1997b9aSAndroid Build Coastguard Worker         }
421*e1997b9aSAndroid Build Coastguard Worker     };
422*e1997b9aSAndroid Build Coastguard Worker 
423*e1997b9aSAndroid Build Coastguard Worker     // The second rule iterates through the type global meta fields.
424*e1997b9aSAndroid Build Coastguard Worker     (
425*e1997b9aSAndroid Build Coastguard Worker         @extract_class
426*e1997b9aSAndroid Build Coastguard Worker         [$(#[$mout:meta])*]
427*e1997b9aSAndroid Build Coastguard Worker         [
428*e1997b9aSAndroid Build Coastguard Worker             #[$front:meta]
429*e1997b9aSAndroid Build Coastguard Worker             $(#[$($mtail:tt)+])*
430*e1997b9aSAndroid Build Coastguard Worker         ]
431*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident $body:tt
432*e1997b9aSAndroid Build Coastguard Worker     ) => {
433*e1997b9aSAndroid Build Coastguard Worker         implement_class!{
434*e1997b9aSAndroid Build Coastguard Worker             @extract_class
435*e1997b9aSAndroid Build Coastguard Worker             [
436*e1997b9aSAndroid Build Coastguard Worker                 $(#[$mout])*
437*e1997b9aSAndroid Build Coastguard Worker                 #[$front]
438*e1997b9aSAndroid Build Coastguard Worker             ]
439*e1997b9aSAndroid Build Coastguard Worker             [$(#[$($mtail)+])*]
440*e1997b9aSAndroid Build Coastguard Worker             $enum_vis enum $enum_name $body
441*e1997b9aSAndroid Build Coastguard Worker         }
442*e1997b9aSAndroid Build Coastguard Worker     };
443*e1997b9aSAndroid Build Coastguard Worker 
444*e1997b9aSAndroid Build Coastguard Worker     // The next four rules implement two nested recursions. The outer iterates through
445*e1997b9aSAndroid Build Coastguard Worker     // the enum variants and the inner iterates through the meta fields of each variant.
446*e1997b9aSAndroid Build Coastguard Worker     // The first two rules find the #[selinux(name = <name>)] stanza, terminate the inner
447*e1997b9aSAndroid Build Coastguard Worker     // recursion and descend a level in the outer recursion.
448*e1997b9aSAndroid Build Coastguard Worker     // The first rule matches variants with explicit initializer $vval. And updates the next
449*e1997b9aSAndroid Build Coastguard Worker     // value to ($vval << 1).
450*e1997b9aSAndroid Build Coastguard Worker     (
451*e1997b9aSAndroid Build Coastguard Worker         @extract_perm_name
452*e1997b9aSAndroid Build Coastguard Worker         $class_name:ident
453*e1997b9aSAndroid Build Coastguard Worker         $(#[$enum_meta:meta])*
454*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident {
455*e1997b9aSAndroid Build Coastguard Worker             $next_val:expr;
456*e1997b9aSAndroid Build Coastguard Worker             [$($out:tt)*]
457*e1997b9aSAndroid Build Coastguard Worker             [
458*e1997b9aSAndroid Build Coastguard Worker                 [$(#[$mout:meta])*]
459*e1997b9aSAndroid Build Coastguard Worker                 [
460*e1997b9aSAndroid Build Coastguard Worker                     #[selinux(name = $selinux_name:ident)]
461*e1997b9aSAndroid Build Coastguard Worker                     $(#[$($mtail:tt)+])*
462*e1997b9aSAndroid Build Coastguard Worker                 ]
463*e1997b9aSAndroid Build Coastguard Worker                 $vname:ident = $vval:expr,
464*e1997b9aSAndroid Build Coastguard Worker                 $($tail:tt)*
465*e1997b9aSAndroid Build Coastguard Worker             ]
466*e1997b9aSAndroid Build Coastguard Worker         }
467*e1997b9aSAndroid Build Coastguard Worker     ) => {
468*e1997b9aSAndroid Build Coastguard Worker         implement_class!{
469*e1997b9aSAndroid Build Coastguard Worker             @extract_perm_name
470*e1997b9aSAndroid Build Coastguard Worker             $class_name
471*e1997b9aSAndroid Build Coastguard Worker             $(#[$enum_meta])*
472*e1997b9aSAndroid Build Coastguard Worker             $enum_vis enum $enum_name {
473*e1997b9aSAndroid Build Coastguard Worker                 ($vval << 1);
474*e1997b9aSAndroid Build Coastguard Worker                 [
475*e1997b9aSAndroid Build Coastguard Worker                     $($out)*
476*e1997b9aSAndroid Build Coastguard Worker                     $(#[$mout])*
477*e1997b9aSAndroid Build Coastguard Worker                     $(#[$($mtail)+])*
478*e1997b9aSAndroid Build Coastguard Worker                     $selinux_name $vname = $vval,
479*e1997b9aSAndroid Build Coastguard Worker                 ]
480*e1997b9aSAndroid Build Coastguard Worker                 [$($tail)*]
481*e1997b9aSAndroid Build Coastguard Worker             }
482*e1997b9aSAndroid Build Coastguard Worker         }
483*e1997b9aSAndroid Build Coastguard Worker     };
484*e1997b9aSAndroid Build Coastguard Worker 
485*e1997b9aSAndroid Build Coastguard Worker     // The second rule differs form the previous in that there is no explicit initializer.
486*e1997b9aSAndroid Build Coastguard Worker     // Instead $next_val is used as initializer and the next value is set to (&next_val << 1).
487*e1997b9aSAndroid Build Coastguard Worker     (
488*e1997b9aSAndroid Build Coastguard Worker         @extract_perm_name
489*e1997b9aSAndroid Build Coastguard Worker         $class_name:ident
490*e1997b9aSAndroid Build Coastguard Worker         $(#[$enum_meta:meta])*
491*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident {
492*e1997b9aSAndroid Build Coastguard Worker             $next_val:expr;
493*e1997b9aSAndroid Build Coastguard Worker             [$($out:tt)*]
494*e1997b9aSAndroid Build Coastguard Worker             [
495*e1997b9aSAndroid Build Coastguard Worker                 [$(#[$mout:meta])*]
496*e1997b9aSAndroid Build Coastguard Worker                 [
497*e1997b9aSAndroid Build Coastguard Worker                     #[selinux(name = $selinux_name:ident)]
498*e1997b9aSAndroid Build Coastguard Worker                     $(#[$($mtail:tt)+])*
499*e1997b9aSAndroid Build Coastguard Worker                 ]
500*e1997b9aSAndroid Build Coastguard Worker                 $vname:ident,
501*e1997b9aSAndroid Build Coastguard Worker                 $($tail:tt)*
502*e1997b9aSAndroid Build Coastguard Worker             ]
503*e1997b9aSAndroid Build Coastguard Worker         }
504*e1997b9aSAndroid Build Coastguard Worker     ) => {
505*e1997b9aSAndroid Build Coastguard Worker         implement_class!{
506*e1997b9aSAndroid Build Coastguard Worker             @extract_perm_name
507*e1997b9aSAndroid Build Coastguard Worker             $class_name
508*e1997b9aSAndroid Build Coastguard Worker             $(#[$enum_meta])*
509*e1997b9aSAndroid Build Coastguard Worker             $enum_vis enum $enum_name {
510*e1997b9aSAndroid Build Coastguard Worker                 ($next_val << 1);
511*e1997b9aSAndroid Build Coastguard Worker                 [
512*e1997b9aSAndroid Build Coastguard Worker                     $($out)*
513*e1997b9aSAndroid Build Coastguard Worker                     $(#[$mout])*
514*e1997b9aSAndroid Build Coastguard Worker                     $(#[$($mtail)+])*
515*e1997b9aSAndroid Build Coastguard Worker                     $selinux_name $vname = $next_val,
516*e1997b9aSAndroid Build Coastguard Worker                 ]
517*e1997b9aSAndroid Build Coastguard Worker                 [$($tail)*]
518*e1997b9aSAndroid Build Coastguard Worker             }
519*e1997b9aSAndroid Build Coastguard Worker         }
520*e1997b9aSAndroid Build Coastguard Worker     };
521*e1997b9aSAndroid Build Coastguard Worker 
522*e1997b9aSAndroid Build Coastguard Worker     // The third rule descends a step in the inner recursion.
523*e1997b9aSAndroid Build Coastguard Worker     (
524*e1997b9aSAndroid Build Coastguard Worker         @extract_perm_name
525*e1997b9aSAndroid Build Coastguard Worker         $class_name:ident
526*e1997b9aSAndroid Build Coastguard Worker         $(#[$enum_meta:meta])*
527*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident {
528*e1997b9aSAndroid Build Coastguard Worker             $next_val:expr;
529*e1997b9aSAndroid Build Coastguard Worker             [$($out:tt)*]
530*e1997b9aSAndroid Build Coastguard Worker             [
531*e1997b9aSAndroid Build Coastguard Worker                 [$(#[$mout:meta])*]
532*e1997b9aSAndroid Build Coastguard Worker                 [
533*e1997b9aSAndroid Build Coastguard Worker                     #[$front:meta]
534*e1997b9aSAndroid Build Coastguard Worker                     $(#[$($mtail:tt)+])*
535*e1997b9aSAndroid Build Coastguard Worker                 ]
536*e1997b9aSAndroid Build Coastguard Worker                 $vname:ident$( = $vval:expr)?,
537*e1997b9aSAndroid Build Coastguard Worker                 $($tail:tt)*
538*e1997b9aSAndroid Build Coastguard Worker             ]
539*e1997b9aSAndroid Build Coastguard Worker         }
540*e1997b9aSAndroid Build Coastguard Worker     ) => {
541*e1997b9aSAndroid Build Coastguard Worker         implement_class!{
542*e1997b9aSAndroid Build Coastguard Worker             @extract_perm_name
543*e1997b9aSAndroid Build Coastguard Worker             $class_name
544*e1997b9aSAndroid Build Coastguard Worker             $(#[$enum_meta])*
545*e1997b9aSAndroid Build Coastguard Worker             $enum_vis enum $enum_name {
546*e1997b9aSAndroid Build Coastguard Worker                 $next_val;
547*e1997b9aSAndroid Build Coastguard Worker                 [$($out)*]
548*e1997b9aSAndroid Build Coastguard Worker                 [
549*e1997b9aSAndroid Build Coastguard Worker                     [
550*e1997b9aSAndroid Build Coastguard Worker                         $(#[$mout])*
551*e1997b9aSAndroid Build Coastguard Worker                         #[$front]
552*e1997b9aSAndroid Build Coastguard Worker                     ]
553*e1997b9aSAndroid Build Coastguard Worker                     [$(#[$($mtail)+])*]
554*e1997b9aSAndroid Build Coastguard Worker                     $vname$( = $vval)?,
555*e1997b9aSAndroid Build Coastguard Worker                     $($tail)*
556*e1997b9aSAndroid Build Coastguard Worker                 ]
557*e1997b9aSAndroid Build Coastguard Worker             }
558*e1997b9aSAndroid Build Coastguard Worker         }
559*e1997b9aSAndroid Build Coastguard Worker     };
560*e1997b9aSAndroid Build Coastguard Worker 
561*e1997b9aSAndroid Build Coastguard Worker     // The fourth rule terminates the outer recursion and transitions to the
562*e1997b9aSAndroid Build Coastguard Worker     // implementation phase @spill.
563*e1997b9aSAndroid Build Coastguard Worker     (
564*e1997b9aSAndroid Build Coastguard Worker         @extract_perm_name
565*e1997b9aSAndroid Build Coastguard Worker         $class_name:ident
566*e1997b9aSAndroid Build Coastguard Worker         $(#[$enum_meta:meta])*
567*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident {
568*e1997b9aSAndroid Build Coastguard Worker             $next_val:expr;
569*e1997b9aSAndroid Build Coastguard Worker             [$($out:tt)*]
570*e1997b9aSAndroid Build Coastguard Worker             []
571*e1997b9aSAndroid Build Coastguard Worker         }
572*e1997b9aSAndroid Build Coastguard Worker     ) => {
573*e1997b9aSAndroid Build Coastguard Worker         implement_class!{
574*e1997b9aSAndroid Build Coastguard Worker             @spill
575*e1997b9aSAndroid Build Coastguard Worker             $class_name
576*e1997b9aSAndroid Build Coastguard Worker             $(#[$enum_meta])*
577*e1997b9aSAndroid Build Coastguard Worker             $enum_vis enum $enum_name {
578*e1997b9aSAndroid Build Coastguard Worker                 $($out)*
579*e1997b9aSAndroid Build Coastguard Worker             }
580*e1997b9aSAndroid Build Coastguard Worker         }
581*e1997b9aSAndroid Build Coastguard Worker     };
582*e1997b9aSAndroid Build Coastguard Worker 
583*e1997b9aSAndroid Build Coastguard Worker     (
584*e1997b9aSAndroid Build Coastguard Worker         @spill
585*e1997b9aSAndroid Build Coastguard Worker         $class_name:ident
586*e1997b9aSAndroid Build Coastguard Worker         $(#[$enum_meta:meta])*
587*e1997b9aSAndroid Build Coastguard Worker         $enum_vis:vis enum $enum_name:ident {
588*e1997b9aSAndroid Build Coastguard Worker             $(
589*e1997b9aSAndroid Build Coastguard Worker                 $(#[$emeta:meta])*
590*e1997b9aSAndroid Build Coastguard Worker                 $selinux_name:ident $vname:ident = $vval:expr,
591*e1997b9aSAndroid Build Coastguard Worker             )*
592*e1997b9aSAndroid Build Coastguard Worker         }
593*e1997b9aSAndroid Build Coastguard Worker     ) => {
594*e1997b9aSAndroid Build Coastguard Worker         $(#[$enum_meta])*
595*e1997b9aSAndroid Build Coastguard Worker         $enum_vis enum $enum_name {
596*e1997b9aSAndroid Build Coastguard Worker             /// The default variant of the enum.
597*e1997b9aSAndroid Build Coastguard Worker             None = 0,
598*e1997b9aSAndroid Build Coastguard Worker             $(
599*e1997b9aSAndroid Build Coastguard Worker                 $(#[$emeta])*
600*e1997b9aSAndroid Build Coastguard Worker                 $vname = $vval,
601*e1997b9aSAndroid Build Coastguard Worker             )*
602*e1997b9aSAndroid Build Coastguard Worker         }
603*e1997b9aSAndroid Build Coastguard Worker 
604*e1997b9aSAndroid Build Coastguard Worker         impl From<i32> for $enum_name {
605*e1997b9aSAndroid Build Coastguard Worker             #[allow(non_upper_case_globals)]
606*e1997b9aSAndroid Build Coastguard Worker             fn from (p: i32) -> Self {
607*e1997b9aSAndroid Build Coastguard Worker                 // Creating constants forces the compiler to evaluate the value expressions
608*e1997b9aSAndroid Build Coastguard Worker                 // so that they can be used in the match statement below.
609*e1997b9aSAndroid Build Coastguard Worker                 $(const $vname: i32 = $vval;)*
610*e1997b9aSAndroid Build Coastguard Worker                 match p {
611*e1997b9aSAndroid Build Coastguard Worker                     0 => Self::None,
612*e1997b9aSAndroid Build Coastguard Worker                     $($vname => Self::$vname,)*
613*e1997b9aSAndroid Build Coastguard Worker                     _ => Self::None,
614*e1997b9aSAndroid Build Coastguard Worker                 }
615*e1997b9aSAndroid Build Coastguard Worker             }
616*e1997b9aSAndroid Build Coastguard Worker         }
617*e1997b9aSAndroid Build Coastguard Worker 
618*e1997b9aSAndroid Build Coastguard Worker         impl From<$enum_name> for i32 {
619*e1997b9aSAndroid Build Coastguard Worker             fn from(p: $enum_name) -> i32 {
620*e1997b9aSAndroid Build Coastguard Worker                 p as i32
621*e1997b9aSAndroid Build Coastguard Worker             }
622*e1997b9aSAndroid Build Coastguard Worker         }
623*e1997b9aSAndroid Build Coastguard Worker 
624*e1997b9aSAndroid Build Coastguard Worker         impl ClassPermission for $enum_name {
625*e1997b9aSAndroid Build Coastguard Worker             fn name(&self) -> &'static str {
626*e1997b9aSAndroid Build Coastguard Worker                 match self {
627*e1997b9aSAndroid Build Coastguard Worker                     Self::None => &"none",
628*e1997b9aSAndroid Build Coastguard Worker                     $(Self::$vname => stringify!($selinux_name),)*
629*e1997b9aSAndroid Build Coastguard Worker                 }
630*e1997b9aSAndroid Build Coastguard Worker             }
631*e1997b9aSAndroid Build Coastguard Worker             fn class_name(&self) -> &'static str {
632*e1997b9aSAndroid Build Coastguard Worker                 stringify!($class_name)
633*e1997b9aSAndroid Build Coastguard Worker             }
634*e1997b9aSAndroid Build Coastguard Worker         }
635*e1997b9aSAndroid Build Coastguard Worker     };
636*e1997b9aSAndroid Build Coastguard Worker }
637*e1997b9aSAndroid Build Coastguard Worker 
638*e1997b9aSAndroid Build Coastguard Worker /// Calls `check_access` on the given class permission.
check_permission<T: ClassPermission>(source: &CStr, target: &CStr, perm: T) -> Result<()>639*e1997b9aSAndroid Build Coastguard Worker pub fn check_permission<T: ClassPermission>(source: &CStr, target: &CStr, perm: T) -> Result<()> {
640*e1997b9aSAndroid Build Coastguard Worker     check_access(source, target, perm.class_name(), perm.name())
641*e1997b9aSAndroid Build Coastguard Worker }
642*e1997b9aSAndroid Build Coastguard Worker 
643*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)]
644*e1997b9aSAndroid Build Coastguard Worker mod tests {
645*e1997b9aSAndroid Build Coastguard Worker     use super::*;
646*e1997b9aSAndroid Build Coastguard Worker     use anyhow::Result;
647*e1997b9aSAndroid Build Coastguard Worker 
648*e1997b9aSAndroid Build Coastguard Worker     /// The su_key namespace as defined in su.te and keystore_key_contexts of the
649*e1997b9aSAndroid Build Coastguard Worker     /// SePolicy (system/sepolicy).
650*e1997b9aSAndroid Build Coastguard Worker     static SU_KEY_NAMESPACE: &str = "0";
651*e1997b9aSAndroid Build Coastguard Worker     /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
652*e1997b9aSAndroid Build Coastguard Worker     /// SePolicy (system/sepolicy).
653*e1997b9aSAndroid Build Coastguard Worker     static SHELL_KEY_NAMESPACE: &str = "1";
654*e1997b9aSAndroid Build Coastguard Worker 
check_context() -> Result<(Context, &'static str, bool)>655*e1997b9aSAndroid Build Coastguard Worker     fn check_context() -> Result<(Context, &'static str, bool)> {
656*e1997b9aSAndroid Build Coastguard Worker         let context = getcon()?;
657*e1997b9aSAndroid Build Coastguard Worker         match context.to_str().unwrap() {
658*e1997b9aSAndroid Build Coastguard Worker             "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
659*e1997b9aSAndroid Build Coastguard Worker             "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
660*e1997b9aSAndroid Build Coastguard Worker             c => Err(anyhow!(format!(
661*e1997b9aSAndroid Build Coastguard Worker                 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
662*e1997b9aSAndroid Build Coastguard Worker                 c
663*e1997b9aSAndroid Build Coastguard Worker             ))),
664*e1997b9aSAndroid Build Coastguard Worker         }
665*e1997b9aSAndroid Build Coastguard Worker     }
666*e1997b9aSAndroid Build Coastguard Worker 
667*e1997b9aSAndroid Build Coastguard Worker     #[test]
test_getcon() -> Result<()>668*e1997b9aSAndroid Build Coastguard Worker     fn test_getcon() -> Result<()> {
669*e1997b9aSAndroid Build Coastguard Worker         check_context()?;
670*e1997b9aSAndroid Build Coastguard Worker         Ok(())
671*e1997b9aSAndroid Build Coastguard Worker     }
672*e1997b9aSAndroid Build Coastguard Worker 
673*e1997b9aSAndroid Build Coastguard Worker     #[test]
test_label_lookup() -> Result<()>674*e1997b9aSAndroid Build Coastguard Worker     fn test_label_lookup() -> Result<()> {
675*e1997b9aSAndroid Build Coastguard Worker         let (_context, namespace, is_su) = check_context()?;
676*e1997b9aSAndroid Build Coastguard Worker         let backend = crate::KeystoreKeyBackend::new()?;
677*e1997b9aSAndroid Build Coastguard Worker         let context = backend.lookup(namespace)?;
678*e1997b9aSAndroid Build Coastguard Worker         if is_su {
679*e1997b9aSAndroid Build Coastguard Worker             assert_eq!(context.to_str(), Ok("u:object_r:su_key:s0"));
680*e1997b9aSAndroid Build Coastguard Worker         } else {
681*e1997b9aSAndroid Build Coastguard Worker             assert_eq!(context.to_str(), Ok("u:object_r:shell_key:s0"));
682*e1997b9aSAndroid Build Coastguard Worker         }
683*e1997b9aSAndroid Build Coastguard Worker         Ok(())
684*e1997b9aSAndroid Build Coastguard Worker     }
685*e1997b9aSAndroid Build Coastguard Worker 
686*e1997b9aSAndroid Build Coastguard Worker     #[test]
context_from_string() -> Result<()>687*e1997b9aSAndroid Build Coastguard Worker     fn context_from_string() -> Result<()> {
688*e1997b9aSAndroid Build Coastguard Worker         let tctx = Context::new("u:object_r:keystore:s0").unwrap();
689*e1997b9aSAndroid Build Coastguard Worker         let sctx = Context::new("u:r:system_server:s0").unwrap();
690*e1997b9aSAndroid Build Coastguard Worker         check_access(&sctx, &tctx, "keystore2_key", "use")?;
691*e1997b9aSAndroid Build Coastguard Worker         Ok(())
692*e1997b9aSAndroid Build Coastguard Worker     }
693*e1997b9aSAndroid Build Coastguard Worker 
694*e1997b9aSAndroid Build Coastguard Worker     mod perm {
695*e1997b9aSAndroid Build Coastguard Worker         use super::super::*;
696*e1997b9aSAndroid Build Coastguard Worker         use super::*;
697*e1997b9aSAndroid Build Coastguard Worker         use anyhow::Result;
698*e1997b9aSAndroid Build Coastguard Worker 
699*e1997b9aSAndroid Build Coastguard Worker         /// check_key_perm(perm, privileged, priv_domain)
700*e1997b9aSAndroid Build Coastguard Worker         /// `perm` is a permission of the keystore2_key class and `privileged` is a boolean
701*e1997b9aSAndroid Build Coastguard Worker         /// indicating whether the permission is considered privileged.
702*e1997b9aSAndroid Build Coastguard Worker         /// Privileged permissions are expected to be denied to `shell` users but granted
703*e1997b9aSAndroid Build Coastguard Worker         /// to the given priv_domain.
704*e1997b9aSAndroid Build Coastguard Worker         macro_rules! check_key_perm {
705*e1997b9aSAndroid Build Coastguard Worker             // "use" is a keyword and cannot be used as an identifier, but we must keep
706*e1997b9aSAndroid Build Coastguard Worker             // the permission string intact. So we map the identifier name on use_ while using
707*e1997b9aSAndroid Build Coastguard Worker             // the permission string "use". In all other cases we can simply use the stringified
708*e1997b9aSAndroid Build Coastguard Worker             // identifier as permission string.
709*e1997b9aSAndroid Build Coastguard Worker             (use, $privileged:expr) => {
710*e1997b9aSAndroid Build Coastguard Worker                 check_key_perm!(use_, $privileged, "use");
711*e1997b9aSAndroid Build Coastguard Worker             };
712*e1997b9aSAndroid Build Coastguard Worker             ($perm:ident, $privileged:expr) => {
713*e1997b9aSAndroid Build Coastguard Worker                 check_key_perm!($perm, $privileged, stringify!($perm));
714*e1997b9aSAndroid Build Coastguard Worker             };
715*e1997b9aSAndroid Build Coastguard Worker             ($perm:ident, $privileged:expr, $p_str:expr) => {
716*e1997b9aSAndroid Build Coastguard Worker                 #[test]
717*e1997b9aSAndroid Build Coastguard Worker                 fn $perm() -> Result<()> {
718*e1997b9aSAndroid Build Coastguard Worker                     android_logger::init_once(
719*e1997b9aSAndroid Build Coastguard Worker                         android_logger::Config::default()
720*e1997b9aSAndroid Build Coastguard Worker                             .with_tag("keystore_selinux_tests")
721*e1997b9aSAndroid Build Coastguard Worker                             .with_max_level(log::LevelFilter::Debug),
722*e1997b9aSAndroid Build Coastguard Worker                     );
723*e1997b9aSAndroid Build Coastguard Worker                     let scontext = Context::new("u:r:shell:s0")?;
724*e1997b9aSAndroid Build Coastguard Worker                     let backend = KeystoreKeyBackend::new()?;
725*e1997b9aSAndroid Build Coastguard Worker                     let tcontext = backend.lookup(SHELL_KEY_NAMESPACE)?;
726*e1997b9aSAndroid Build Coastguard Worker 
727*e1997b9aSAndroid Build Coastguard Worker                     if $privileged {
728*e1997b9aSAndroid Build Coastguard Worker                         assert_eq!(
729*e1997b9aSAndroid Build Coastguard Worker                             Some(&Error::perm()),
730*e1997b9aSAndroid Build Coastguard Worker                             check_access(
731*e1997b9aSAndroid Build Coastguard Worker                                 &scontext,
732*e1997b9aSAndroid Build Coastguard Worker                                 &tcontext,
733*e1997b9aSAndroid Build Coastguard Worker                                 "keystore2_key",
734*e1997b9aSAndroid Build Coastguard Worker                                 $p_str
735*e1997b9aSAndroid Build Coastguard Worker                             )
736*e1997b9aSAndroid Build Coastguard Worker                             .err()
737*e1997b9aSAndroid Build Coastguard Worker                             .unwrap()
738*e1997b9aSAndroid Build Coastguard Worker                             .root_cause()
739*e1997b9aSAndroid Build Coastguard Worker                             .downcast_ref::<Error>()
740*e1997b9aSAndroid Build Coastguard Worker                         );
741*e1997b9aSAndroid Build Coastguard Worker                     } else {
742*e1997b9aSAndroid Build Coastguard Worker                         assert!(check_access(
743*e1997b9aSAndroid Build Coastguard Worker                             &scontext,
744*e1997b9aSAndroid Build Coastguard Worker                             &tcontext,
745*e1997b9aSAndroid Build Coastguard Worker                             "keystore2_key",
746*e1997b9aSAndroid Build Coastguard Worker                             $p_str
747*e1997b9aSAndroid Build Coastguard Worker                         )
748*e1997b9aSAndroid Build Coastguard Worker                         .is_ok());
749*e1997b9aSAndroid Build Coastguard Worker                     }
750*e1997b9aSAndroid Build Coastguard Worker                     Ok(())
751*e1997b9aSAndroid Build Coastguard Worker                 }
752*e1997b9aSAndroid Build Coastguard Worker             };
753*e1997b9aSAndroid Build Coastguard Worker         }
754*e1997b9aSAndroid Build Coastguard Worker 
755*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(manage_blob, true);
756*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(delete, false);
757*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(use_dev_id, true);
758*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(req_forced_op, true);
759*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(gen_unique_id, true);
760*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(grant, true);
761*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(get_info, false);
762*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(rebind, false);
763*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(update, false);
764*e1997b9aSAndroid Build Coastguard Worker         check_key_perm!(use, false);
765*e1997b9aSAndroid Build Coastguard Worker 
766*e1997b9aSAndroid Build Coastguard Worker         macro_rules! check_keystore_perm {
767*e1997b9aSAndroid Build Coastguard Worker             ($perm:ident) => {
768*e1997b9aSAndroid Build Coastguard Worker                 #[test]
769*e1997b9aSAndroid Build Coastguard Worker                 fn $perm() -> Result<()> {
770*e1997b9aSAndroid Build Coastguard Worker                     let ks_context = Context::new("u:object_r:keystore:s0")?;
771*e1997b9aSAndroid Build Coastguard Worker                     let priv_context = Context::new("u:r:system_server:s0")?;
772*e1997b9aSAndroid Build Coastguard Worker                     let unpriv_context = Context::new("u:r:shell:s0")?;
773*e1997b9aSAndroid Build Coastguard Worker                     assert!(check_access(
774*e1997b9aSAndroid Build Coastguard Worker                         &priv_context,
775*e1997b9aSAndroid Build Coastguard Worker                         &ks_context,
776*e1997b9aSAndroid Build Coastguard Worker                         "keystore2",
777*e1997b9aSAndroid Build Coastguard Worker                         stringify!($perm)
778*e1997b9aSAndroid Build Coastguard Worker                     )
779*e1997b9aSAndroid Build Coastguard Worker                     .is_ok());
780*e1997b9aSAndroid Build Coastguard Worker                     assert_eq!(
781*e1997b9aSAndroid Build Coastguard Worker                         Some(&Error::perm()),
782*e1997b9aSAndroid Build Coastguard Worker                         check_access(&unpriv_context, &ks_context, "keystore2", stringify!($perm))
783*e1997b9aSAndroid Build Coastguard Worker                             .err()
784*e1997b9aSAndroid Build Coastguard Worker                             .unwrap()
785*e1997b9aSAndroid Build Coastguard Worker                             .root_cause()
786*e1997b9aSAndroid Build Coastguard Worker                             .downcast_ref::<Error>()
787*e1997b9aSAndroid Build Coastguard Worker                     );
788*e1997b9aSAndroid Build Coastguard Worker                     Ok(())
789*e1997b9aSAndroid Build Coastguard Worker                 }
790*e1997b9aSAndroid Build Coastguard Worker             };
791*e1997b9aSAndroid Build Coastguard Worker         }
792*e1997b9aSAndroid Build Coastguard Worker 
793*e1997b9aSAndroid Build Coastguard Worker         check_keystore_perm!(add_auth);
794*e1997b9aSAndroid Build Coastguard Worker         check_keystore_perm!(clear_ns);
795*e1997b9aSAndroid Build Coastguard Worker         check_keystore_perm!(lock);
796*e1997b9aSAndroid Build Coastguard Worker         check_keystore_perm!(reset);
797*e1997b9aSAndroid Build Coastguard Worker         check_keystore_perm!(unlock);
798*e1997b9aSAndroid Build Coastguard Worker     }
799*e1997b9aSAndroid Build Coastguard Worker 
800*e1997b9aSAndroid Build Coastguard Worker     #[test]
test_getpidcon()801*e1997b9aSAndroid Build Coastguard Worker     fn test_getpidcon() {
802*e1997b9aSAndroid Build Coastguard Worker         // Check that `getpidcon` of our pid is equal to what `getcon` returns.
803*e1997b9aSAndroid Build Coastguard Worker         // And by using `unwrap` we make sure that both also have to return successfully
804*e1997b9aSAndroid Build Coastguard Worker         // fully to pass the test.
805*e1997b9aSAndroid Build Coastguard Worker         assert_eq!(getpidcon(std::process::id() as i32).unwrap(), getcon().unwrap());
806*e1997b9aSAndroid Build Coastguard Worker     }
807*e1997b9aSAndroid Build Coastguard Worker }
808