xref: /aosp_15_r20/system/security/keystore2/src/permission.rs (revision e1997b9af69e3155ead6e072d106a0077849ffba)
1 // Copyright 2020, The Android Open Source Project
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 //! This crate provides access control primitives for Keystore 2.0.
16 //! It provides high level functions for checking permissions in the keystore2 and keystore2_key
17 //! SELinux classes based on the keystore2_selinux backend.
18 //! It also provides KeystorePerm and KeyPerm as convenience wrappers for the SELinux permission
19 //! defined by keystore2 and keystore2_key respectively.
20 
21 use crate::error::Error as KsError;
22 use crate::error::ResponseCode;
23 use crate::ks_err;
24 use android_system_keystore2::aidl::android::system::keystore2::{
25     Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
26 };
27 use anyhow::Context as AnyhowContext;
28 use keystore2_selinux as selinux;
29 use selinux::{implement_class, Backend, ClassPermission};
30 use std::cmp::PartialEq;
31 use std::convert::From;
32 use std::ffi::CStr;
33 use std::sync::LazyLock;
34 
35 // Replace getcon with a mock in the test situation
36 #[cfg(not(test))]
37 use selinux::getcon;
38 #[cfg(test)]
39 use tests::test_getcon as getcon;
40 
41 #[cfg(test)]
42 mod tests;
43 
44 // Panicking here is allowed because keystore cannot function without this backend
45 // and it would happen early and indicate a gross misconfiguration of the device.
46 static KEYSTORE2_KEY_LABEL_BACKEND: LazyLock<selinux::KeystoreKeyBackend> =
47     LazyLock::new(|| selinux::KeystoreKeyBackend::new().unwrap());
48 
lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context>49 fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> {
50     KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string())
51 }
52 
53 implement_class!(
54     /// KeyPerm provides a convenient abstraction from the SELinux class `keystore2_key`.
55     /// At the same time it maps `KeyPermissions` from the Keystore 2.0 AIDL Grant interface to
56     /// the SELinux permissions.
57     #[repr(i32)]
58     #[selinux(class_name = keystore2_key)]
59     #[derive(Clone, Copy, Debug, PartialEq, Eq)]
60     pub enum KeyPerm {
61         /// Checked when convert_storage_key_to_ephemeral is called.
62         #[selinux(name = convert_storage_key_to_ephemeral)]
63         ConvertStorageKeyToEphemeral = KeyPermission::CONVERT_STORAGE_KEY_TO_EPHEMERAL.0,
64         /// Checked when the caller tries do delete a key.
65         #[selinux(name = delete)]
66         Delete = KeyPermission::DELETE.0,
67         /// Checked when the caller tries to use a unique id.
68         #[selinux(name = gen_unique_id)]
69         GenUniqueId = KeyPermission::GEN_UNIQUE_ID.0,
70         /// Checked when the caller tries to load a key.
71         #[selinux(name = get_info)]
72         GetInfo = KeyPermission::GET_INFO.0,
73         /// Checked when the caller attempts to grant a key to another uid.
74         /// Also used for gating key migration attempts.
75         #[selinux(name = grant)]
76         Grant = KeyPermission::GRANT.0,
77         /// Checked when the caller attempts to use Domain::BLOB.
78         #[selinux(name = manage_blob)]
79         ManageBlob = KeyPermission::MANAGE_BLOB.0,
80         /// Checked when the caller tries to create a key which implies rebinding
81         /// an alias to the new key.
82         #[selinux(name = rebind)]
83         Rebind = KeyPermission::REBIND.0,
84         /// Checked when the caller attempts to create a forced operation.
85         #[selinux(name = req_forced_op)]
86         ReqForcedOp = KeyPermission::REQ_FORCED_OP.0,
87         /// Checked when the caller attempts to update public key artifacts.
88         #[selinux(name = update)]
89         Update = KeyPermission::UPDATE.0,
90         /// Checked when the caller attempts to use a private or public key.
91         #[selinux(name = use)]
92         Use = KeyPermission::USE.0,
93         /// Does nothing, and is not checked. For use of device identifiers,
94         /// the caller must hold the READ_PRIVILEGED_PHONE_STATE Android
95         /// permission.
96         #[selinux(name = use_dev_id)]
97         UseDevId = KeyPermission::USE_DEV_ID.0,
98     }
99 );
100 
101 implement_class!(
102     /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
103     /// Using the implement_permission macro we get the same features as `KeyPerm`.
104     #[selinux(class_name = keystore2)]
105     #[derive(Clone, Copy, Debug, PartialEq, Eq)]
106     pub enum KeystorePerm {
107         /// Checked when a new auth token is installed.
108         #[selinux(name = add_auth)]
109         AddAuth,
110         /// Checked when an app is uninstalled or wiped.
111         #[selinux(name = clear_ns)]
112         ClearNs,
113         /// Checked when Keystore 2.0 is asked to list a namespace that the caller
114         /// does not have the get_info permission for.
115         #[selinux(name = list)]
116         List,
117         /// Checked when Keystore 2.0 gets locked.
118         #[selinux(name = lock)]
119         Lock,
120         /// Checked when Keystore 2.0 shall be reset.
121         #[selinux(name = reset)]
122         Reset,
123         /// Checked when Keystore 2.0 shall be unlocked.
124         #[selinux(name = unlock)]
125         Unlock,
126         /// Checked when user is added or removed.
127         #[selinux(name = change_user)]
128         ChangeUser,
129         /// Checked when password of the user is changed.
130         #[selinux(name = change_password)]
131         ChangePassword,
132         /// Checked when a UID is cleared.
133         #[selinux(name = clear_uid)]
134         ClearUID,
135         /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens.
136         #[selinux(name = get_auth_token)]
137         GetAuthToken,
138         /// Checked when earlyBootEnded() is called.
139         #[selinux(name = early_boot_ended)]
140         EarlyBootEnded,
141         /// Checked when IKeystoreMetrics::pullMetrics is called.
142         #[selinux(name = pull_metrics)]
143         PullMetrics,
144         /// Checked when IKeystoreMaintenance::deleteAllKeys is called.
145         #[selinux(name = delete_all_keys)]
146         DeleteAllKeys,
147         /// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey
148         #[selinux(name = get_attestation_key)]
149         GetAttestationKey,
150         /// Checked on IKeystoreAuthorization::getLastAuthTime() is called.
151         #[selinux(name = get_last_auth_time)]
152         GetLastAuthTime,
153     }
154 );
155 
156 /// Represents a set of `KeyPerm` permissions.
157 /// `IntoIterator` is implemented for this struct allowing the iteration through all the
158 /// permissions in the set.
159 /// It also implements a function `includes(self, other)` that checks if the permissions
160 /// in `other` are included in `self`.
161 ///
162 /// KeyPermSet can be created with the macro `key_perm_set![]`.
163 ///
164 /// ## Example
165 /// ```
166 /// let perms1 = key_perm_set![KeyPerm::Use, KeyPerm::ManageBlob, KeyPerm::Grant];
167 /// let perms2 = key_perm_set![KeyPerm::Use, KeyPerm::ManageBlob];
168 ///
169 /// assert!(perms1.includes(perms2))
170 /// assert!(!perms2.includes(perms1))
171 ///
172 /// let i = perms1.into_iter();
173 /// // iteration in ascending order of the permission's numeric representation.
174 /// assert_eq(Some(KeyPerm::ManageBlob), i.next());
175 /// assert_eq(Some(KeyPerm::Grant), i.next());
176 /// assert_eq(Some(KeyPerm::Use), i.next());
177 /// assert_eq(None, i.next());
178 /// ```
179 #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
180 pub struct KeyPermSet(pub i32);
181 
182 mod perm {
183     use super::*;
184 
185     pub struct IntoIter {
186         vec: KeyPermSet,
187         pos: u8,
188     }
189 
190     impl IntoIter {
new(v: KeyPermSet) -> Self191         pub fn new(v: KeyPermSet) -> Self {
192             Self { vec: v, pos: 0 }
193         }
194     }
195 
196     impl std::iter::Iterator for IntoIter {
197         type Item = KeyPerm;
198 
next(&mut self) -> Option<Self::Item>199         fn next(&mut self) -> Option<Self::Item> {
200             loop {
201                 if self.pos == 32 {
202                     return None;
203                 }
204                 let p = self.vec.0 & (1 << self.pos);
205                 self.pos += 1;
206                 if p != 0 {
207                     return Some(KeyPerm::from(p));
208                 }
209             }
210         }
211     }
212 }
213 
214 impl From<KeyPerm> for KeyPermSet {
from(p: KeyPerm) -> Self215     fn from(p: KeyPerm) -> Self {
216         Self(p as i32)
217     }
218 }
219 
220 /// allow conversion from the AIDL wire type i32 to a permission set.
221 impl From<i32> for KeyPermSet {
from(p: i32) -> Self222     fn from(p: i32) -> Self {
223         Self(p)
224     }
225 }
226 
227 impl From<KeyPermSet> for i32 {
from(p: KeyPermSet) -> i32228     fn from(p: KeyPermSet) -> i32 {
229         p.0
230     }
231 }
232 
233 impl KeyPermSet {
234     /// Returns true iff this permission set has all of the permissions that are in `other`.
includes<T: Into<KeyPermSet>>(&self, other: T) -> bool235     pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
236         let o: KeyPermSet = other.into();
237         (self.0 & o.0) == o.0
238     }
239 }
240 
241 /// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
242 ///
243 /// ## Example
244 /// ```
245 /// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
246 /// ```
247 #[macro_export]
248 macro_rules! key_perm_set {
249     () => { KeyPermSet(0) };
250     ($head:expr $(, $tail:expr)* $(,)?) => {
251         KeyPermSet($head as i32 $(| $tail as i32)*)
252     };
253 }
254 
255 impl IntoIterator for KeyPermSet {
256     type Item = KeyPerm;
257     type IntoIter = perm::IntoIter;
258 
into_iter(self) -> Self::IntoIter259     fn into_iter(self) -> Self::IntoIter {
260         Self::IntoIter::new(self)
261     }
262 }
263 
264 /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` may access
265 /// the given permision `perm` of the `keystore2` security class.
check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()>266 pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
267     let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
268     selinux::check_permission(caller_ctx, &target_context, perm)
269 }
270 
271 /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` has
272 /// all the permissions indicated in `access_vec` for the target domain indicated by the key
273 /// descriptor `key` in the security class `keystore2_key`.
274 ///
275 /// Also checks if the caller has the grant permission for the given target domain.
276 ///
277 /// Attempts to grant the grant permission are always denied.
278 ///
279 /// The only viable target domains are
280 ///  * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
281 ///  * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
282 ///                      SELinux keystore key backend, and the result is used
283 ///                      as target context.
check_grant_permission( caller_uid: u32, caller_ctx: &CStr, access_vec: KeyPermSet, key: &KeyDescriptor, ) -> anyhow::Result<()>284 pub fn check_grant_permission(
285     caller_uid: u32,
286     caller_ctx: &CStr,
287     access_vec: KeyPermSet,
288     key: &KeyDescriptor,
289 ) -> anyhow::Result<()> {
290     let target_context = match key.domain {
291         Domain::APP => {
292             if caller_uid as i64 != key.nspace {
293                 return Err(selinux::Error::perm())
294                     .context("Trying to access key without ownership.");
295             }
296             getcon().context("check_grant_permission: getcon failed.")?
297         }
298         Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
299             .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
300         _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
301     };
302 
303     selinux::check_permission(caller_ctx, &target_context, KeyPerm::Grant)
304         .context("Grant permission is required when granting.")?;
305 
306     if access_vec.includes(KeyPerm::Grant) {
307         return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
308     }
309 
310     for p in access_vec.into_iter() {
311         selinux::check_permission(caller_ctx, &target_context, p).context(ks_err!(
312             "check_permission failed. \
313             The caller may have tried to grant a permission that they don't possess. {:?}",
314             p
315         ))?
316     }
317     Ok(())
318 }
319 
320 /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt`
321 /// has the permissions indicated by `perm` for the target domain indicated by the key
322 /// descriptor `key` in the security class `keystore2_key`.
323 ///
324 /// The behavior differs slightly depending on the selected target domain:
325 ///  * `Domain::APP` u:r:keystore:s0 is used as target context.
326 ///  * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
327 ///                      backend, and the result is used as target context.
328 ///  * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
329 ///                   to the one supplied in `perm`.
330 ///  * `Domain::GRANT` Does not use selinux::check_permission. Instead the `access_vector`
331 ///                    parameter is queried for permission, which must be supplied in this case.
332 ///
333 /// ## Return values.
334 ///  * Ok(()) If the requested permissions were granted.
335 ///  * Err(selinux::Error::perm()) If the requested permissions were denied.
336 ///  * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
337 ///                      was supplied. It is also produced if `Domain::KEY_ID` was selected, and
338 ///                      on various unexpected backend failures.
check_key_permission( caller_uid: u32, caller_ctx: &CStr, perm: KeyPerm, key: &KeyDescriptor, access_vector: &Option<KeyPermSet>, ) -> anyhow::Result<()>339 pub fn check_key_permission(
340     caller_uid: u32,
341     caller_ctx: &CStr,
342     perm: KeyPerm,
343     key: &KeyDescriptor,
344     access_vector: &Option<KeyPermSet>,
345 ) -> anyhow::Result<()> {
346     // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID.
347     // In the former case, key.domain was set to GRANT and we check the failure cases
348     // further below. If the access is requested by KEY_ID, key.domain would have been
349     // resolved to APP or SELINUX depending on where the key actually resides.
350     // Either way we can return here immediately if the access vector covers the requested
351     // permission. If it does not, we can still check if the caller has access by means of
352     // ownership.
353     if let Some(access_vector) = access_vector {
354         if access_vector.includes(perm) {
355             return Ok(());
356         }
357     }
358 
359     let target_context = match key.domain {
360         // apps get the default keystore context
361         Domain::APP => {
362             if caller_uid as i64 != key.nspace {
363                 return Err(selinux::Error::perm())
364                     .context("Trying to access key without ownership.");
365             }
366             getcon().context(ks_err!("getcon failed."))?
367         }
368         Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
369             .context(ks_err!("Domain::SELINUX: Failed to lookup namespace."))?,
370         Domain::GRANT => {
371             match access_vector {
372                 Some(_) => {
373                     return Err(selinux::Error::perm())
374                         .context(format!("\"{}\" not granted", perm.name()));
375                 }
376                 None => {
377                     // If DOMAIN_GRANT was selected an access vector must be supplied.
378                     return Err(KsError::sys()).context(ks_err!(
379                         "Cannot check permission for Domain::GRANT without access vector.",
380                     ));
381                 }
382             }
383         }
384         Domain::KEY_ID => {
385             // We should never be called with `Domain::KEY_ID. The database
386             // lookup should have converted this into one of `Domain::APP`
387             // or `Domain::SELINUX`.
388             return Err(KsError::sys())
389                 .context(ks_err!("Cannot check permission for Domain::KEY_ID.",));
390         }
391         Domain::BLOB => {
392             let tctx = lookup_keystore2_key_context(key.nspace)
393                 .context(ks_err!("Domain::BLOB: Failed to lookup namespace."))?;
394             // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
395             // permission in addition to the requested permission.
396             selinux::check_permission(caller_ctx, &tctx, KeyPerm::ManageBlob)?;
397 
398             tctx
399         }
400         _ => {
401             return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
402                 .context(format!("Unknown domain value: \"{:?}\".", key.domain))
403         }
404     };
405 
406     selinux::check_permission(caller_ctx, &target_context, perm)
407 }
408