| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 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 |  | 
| Janis Danisevskis | a2f4850 | 2021-10-18 16:07:09 -0700 | [diff] [blame] | 21 | use crate::error::Error as KsError; | 
| Rajesh Nyamagoud | caee93e | 2022-05-26 00:20:38 +0000 | [diff] [blame] | 22 | use crate::error::ResponseCode; | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 23 | use crate::ks_err; | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 24 | use android_system_keystore2::aidl::android::system::keystore2::{ | 
|  | 25 | Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission, | 
|  | 26 | }; | 
| Janis Danisevskis | a2f4850 | 2021-10-18 16:07:09 -0700 | [diff] [blame] | 27 | use anyhow::Context as AnyhowContext; | 
|  | 28 | use keystore2_selinux as selinux; | 
|  | 29 | use lazy_static::lazy_static; | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 30 | use selinux::{implement_class, Backend, ClassPermission}; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 31 | use std::cmp::PartialEq; | 
|  | 32 | use std::convert::From; | 
| Janis Danisevskis | 935e6c6 | 2020-08-18 12:52:27 -0700 | [diff] [blame] | 33 | use std::ffi::CStr; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 34 |  | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 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 |  | 
| Janis Danisevskis | 4ad056f | 2020-08-05 19:46:46 +0000 | [diff] [blame] | 41 | lazy_static! { | 
|  | 42 | // Panicking here is allowed because keystore cannot function without this backend | 
|  | 43 | // and it would happen early and indicate a gross misconfiguration of the device. | 
|  | 44 | static ref KEYSTORE2_KEY_LABEL_BACKEND: selinux::KeystoreKeyBackend = | 
|  | 45 | selinux::KeystoreKeyBackend::new().unwrap(); | 
|  | 46 | } | 
|  | 47 |  | 
|  | 48 | fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> { | 
|  | 49 | KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string()) | 
|  | 50 | } | 
|  | 51 |  | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 52 | implement_class!( | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 53 | /// KeyPerm provides a convenient abstraction from the SELinux class `keystore2_key`. | 
|  | 54 | /// At the same time it maps `KeyPermissions` from the Keystore 2.0 AIDL Grant interface to | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 55 | /// the SELinux permissions. | 
|  | 56 | #[repr(i32)] | 
|  | 57 | #[selinux(class_name = keystore2_key)] | 
| Chris Wailes | 263de9f | 2022-08-11 15:00:51 -0700 | [diff] [blame] | 58 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 59 | pub enum KeyPerm { | 
|  | 60 | /// Checked when convert_storage_key_to_ephemeral is called. | 
|  | 61 | #[selinux(name = convert_storage_key_to_ephemeral)] | 
|  | 62 | ConvertStorageKeyToEphemeral = KeyPermission::CONVERT_STORAGE_KEY_TO_EPHEMERAL.0, | 
|  | 63 | /// Checked when the caller tries do delete a key. | 
|  | 64 | #[selinux(name = delete)] | 
|  | 65 | Delete = KeyPermission::DELETE.0, | 
|  | 66 | /// Checked when the caller tries to use a unique id. | 
|  | 67 | #[selinux(name = gen_unique_id)] | 
|  | 68 | GenUniqueId = KeyPermission::GEN_UNIQUE_ID.0, | 
|  | 69 | /// Checked when the caller tries to load a key. | 
|  | 70 | #[selinux(name = get_info)] | 
|  | 71 | GetInfo = KeyPermission::GET_INFO.0, | 
|  | 72 | /// Checked when the caller attempts to grant a key to another uid. | 
|  | 73 | /// Also used for gating key migration attempts. | 
|  | 74 | #[selinux(name = grant)] | 
|  | 75 | Grant = KeyPermission::GRANT.0, | 
|  | 76 | /// Checked when the caller attempts to use Domain::BLOB. | 
|  | 77 | #[selinux(name = manage_blob)] | 
|  | 78 | ManageBlob = KeyPermission::MANAGE_BLOB.0, | 
|  | 79 | /// Checked when the caller tries to create a key which implies rebinding | 
|  | 80 | /// an alias to the new key. | 
|  | 81 | #[selinux(name = rebind)] | 
|  | 82 | Rebind = KeyPermission::REBIND.0, | 
|  | 83 | /// Checked when the caller attempts to create a forced operation. | 
|  | 84 | #[selinux(name = req_forced_op)] | 
|  | 85 | ReqForcedOp = KeyPermission::REQ_FORCED_OP.0, | 
|  | 86 | /// Checked when the caller attempts to update public key artifacts. | 
|  | 87 | #[selinux(name = update)] | 
|  | 88 | Update = KeyPermission::UPDATE.0, | 
|  | 89 | /// Checked when the caller attempts to use a private or public key. | 
|  | 90 | #[selinux(name = use)] | 
|  | 91 | Use = KeyPermission::USE.0, | 
| Eran Messeri | 653932e | 2022-06-14 17:04:10 +0100 | [diff] [blame] | 92 | /// Does nothing, and is not checked. For use of device identifiers, | 
|  | 93 | /// the caller must hold the READ_PRIVILEGED_PHONE_STATE Android | 
|  | 94 | /// permission. | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 95 | #[selinux(name = use_dev_id)] | 
|  | 96 | UseDevId = KeyPermission::USE_DEV_ID.0, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 97 | } | 
|  | 98 | ); | 
|  | 99 |  | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 100 | implement_class!( | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 101 | /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`. | 
|  | 102 | /// Using the implement_permission macro we get the same features as `KeyPerm`. | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 103 | #[selinux(class_name = keystore2)] | 
| Chris Wailes | 263de9f | 2022-08-11 15:00:51 -0700 | [diff] [blame] | 104 | #[derive(Clone, Copy, Debug, PartialEq, Eq)] | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 105 | pub enum KeystorePerm { | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 106 | /// Checked when a new auth token is installed. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 107 | #[selinux(name = add_auth)] | 
|  | 108 | AddAuth, | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 109 | /// Checked when an app is uninstalled or wiped. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 110 | #[selinux(name = clear_ns)] | 
|  | 111 | ClearNs, | 
| Hasini Gunasinghe | 9ee1841 | 2021-03-11 20:12:44 +0000 | [diff] [blame] | 112 | /// Checked when the user state is queried from Keystore 2.0. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 113 | #[selinux(name = get_state)] | 
|  | 114 | GetState, | 
| Janis Danisevskis | ee10b5f | 2020-09-22 16:42:35 -0700 | [diff] [blame] | 115 | /// Checked when Keystore 2.0 is asked to list a namespace that the caller | 
|  | 116 | /// does not have the get_info permission for. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 117 | #[selinux(name = list)] | 
|  | 118 | List, | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 119 | /// Checked when Keystore 2.0 gets locked. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 120 | #[selinux(name = lock)] | 
|  | 121 | Lock, | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 122 | /// Checked when Keystore 2.0 shall be reset. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 123 | #[selinux(name = reset)] | 
|  | 124 | Reset, | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 125 | /// Checked when Keystore 2.0 shall be unlocked. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 126 | #[selinux(name = unlock)] | 
|  | 127 | Unlock, | 
| Hasini Gunasinghe | 803c2d4 | 2021-01-27 00:48:40 +0000 | [diff] [blame] | 128 | /// Checked when user is added or removed. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 129 | #[selinux(name = change_user)] | 
|  | 130 | ChangeUser, | 
| Hasini Gunasinghe | 803c2d4 | 2021-01-27 00:48:40 +0000 | [diff] [blame] | 131 | /// Checked when password of the user is changed. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 132 | #[selinux(name = change_password)] | 
|  | 133 | ChangePassword, | 
| Hasini Gunasinghe | 803c2d4 | 2021-01-27 00:48:40 +0000 | [diff] [blame] | 134 | /// Checked when a UID is cleared. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 135 | #[selinux(name = clear_uid)] | 
|  | 136 | ClearUID, | 
| Hasini Gunasinghe | 5fc9525 | 2020-12-04 00:35:08 +0000 | [diff] [blame] | 137 | /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 138 | #[selinux(name = get_auth_token)] | 
|  | 139 | GetAuthToken, | 
| Satya Tangirala | 5b9e5b1 | 2021-03-09 12:54:21 -0800 | [diff] [blame] | 140 | /// Checked when earlyBootEnded() is called. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 141 | #[selinux(name = early_boot_ended)] | 
|  | 142 | EarlyBootEnded, | 
| Janis Danisevskis | 333b7c0 | 2021-03-23 18:57:41 -0700 | [diff] [blame] | 143 | /// Checked when IKeystoreMaintenance::onDeviceOffBody is called. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 144 | #[selinux(name = report_off_body)] | 
|  | 145 | ReportOffBody, | 
|  | 146 | /// Checked when IkeystoreMetrics::pullMetrics is called. | 
|  | 147 | #[selinux(name = pull_metrics)] | 
|  | 148 | PullMetrics, | 
| Paul Crowley | 46c703e | 2021-08-06 15:13:53 -0700 | [diff] [blame] | 149 | /// Checked when IKeystoreMaintenance::deleteAllKeys is called. | 
| Janis Danisevskis | 751d2c8 | 2021-10-18 15:37:09 -0700 | [diff] [blame] | 150 | #[selinux(name = delete_all_keys)] | 
|  | 151 | DeleteAllKeys, | 
| Seth Moore | 7ee79f9 | 2021-12-07 11:42:49 -0800 | [diff] [blame] | 152 | /// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey | 
|  | 153 | #[selinux(name = get_attestation_key)] | 
|  | 154 | GetAttestationKey, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 155 | } | 
|  | 156 | ); | 
|  | 157 |  | 
|  | 158 | /// Represents a set of `KeyPerm` permissions. | 
|  | 159 | /// `IntoIterator` is implemented for this struct allowing the iteration through all the | 
|  | 160 | /// permissions in the set. | 
|  | 161 | /// It also implements a function `includes(self, other)` that checks if the permissions | 
|  | 162 | /// in `other` are included in `self`. | 
|  | 163 | /// | 
|  | 164 | /// KeyPermSet can be created with the macro `key_perm_set![]`. | 
|  | 165 | /// | 
|  | 166 | /// ## Example | 
|  | 167 | /// ``` | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 168 | /// let perms1 = key_perm_set![KeyPerm::Use, KeyPerm::ManageBlob, KeyPerm::Grant]; | 
|  | 169 | /// let perms2 = key_perm_set![KeyPerm::Use, KeyPerm::ManageBlob]; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 170 | /// | 
|  | 171 | /// assert!(perms1.includes(perms2)) | 
|  | 172 | /// assert!(!perms2.includes(perms1)) | 
|  | 173 | /// | 
|  | 174 | /// let i = perms1.into_iter(); | 
|  | 175 | /// // iteration in ascending order of the permission's numeric representation. | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 176 | /// assert_eq(Some(KeyPerm::ManageBlob), i.next()); | 
|  | 177 | /// assert_eq(Some(KeyPerm::Grant), i.next()); | 
|  | 178 | /// assert_eq(Some(KeyPerm::Use), i.next()); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 179 | /// assert_eq(None, i.next()); | 
|  | 180 | /// ``` | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 181 | #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] | 
|  | 182 | pub struct KeyPermSet(pub i32); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 183 |  | 
|  | 184 | mod perm { | 
|  | 185 | use super::*; | 
|  | 186 |  | 
|  | 187 | pub struct IntoIter { | 
|  | 188 | vec: KeyPermSet, | 
|  | 189 | pos: u8, | 
|  | 190 | } | 
|  | 191 |  | 
|  | 192 | impl IntoIter { | 
|  | 193 | pub fn new(v: KeyPermSet) -> Self { | 
|  | 194 | Self { vec: v, pos: 0 } | 
|  | 195 | } | 
|  | 196 | } | 
|  | 197 |  | 
|  | 198 | impl std::iter::Iterator for IntoIter { | 
|  | 199 | type Item = KeyPerm; | 
|  | 200 |  | 
|  | 201 | fn next(&mut self) -> Option<Self::Item> { | 
|  | 202 | loop { | 
|  | 203 | if self.pos == 32 { | 
|  | 204 | return None; | 
|  | 205 | } | 
|  | 206 | let p = self.vec.0 & (1 << self.pos); | 
|  | 207 | self.pos += 1; | 
|  | 208 | if p != 0 { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 209 | return Some(KeyPerm::from(p)); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 210 | } | 
|  | 211 | } | 
|  | 212 | } | 
|  | 213 | } | 
|  | 214 | } | 
|  | 215 |  | 
|  | 216 | impl From<KeyPerm> for KeyPermSet { | 
|  | 217 | fn from(p: KeyPerm) -> Self { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 218 | Self(p as i32) | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 219 | } | 
|  | 220 | } | 
|  | 221 |  | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 222 | /// allow conversion from the AIDL wire type i32 to a permission set. | 
|  | 223 | impl From<i32> for KeyPermSet { | 
|  | 224 | fn from(p: i32) -> Self { | 
|  | 225 | Self(p) | 
|  | 226 | } | 
|  | 227 | } | 
|  | 228 |  | 
|  | 229 | impl From<KeyPermSet> for i32 { | 
|  | 230 | fn from(p: KeyPermSet) -> i32 { | 
|  | 231 | p.0 | 
|  | 232 | } | 
|  | 233 | } | 
|  | 234 |  | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 235 | impl KeyPermSet { | 
|  | 236 | /// Returns true iff this permission set has all of the permissions that are in `other`. | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 237 | pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 238 | let o: KeyPermSet = other.into(); | 
|  | 239 | (self.0 & o.0) == o.0 | 
|  | 240 | } | 
|  | 241 | } | 
|  | 242 |  | 
|  | 243 | /// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values. | 
|  | 244 | /// | 
|  | 245 | /// ## Example | 
|  | 246 | /// ``` | 
|  | 247 | /// let v = key_perm_set![Perm::delete(), Perm::manage_blob()]; | 
|  | 248 | /// ``` | 
|  | 249 | #[macro_export] | 
|  | 250 | macro_rules! key_perm_set { | 
|  | 251 | () => { KeyPermSet(0) }; | 
|  | 252 | ($head:expr $(, $tail:expr)* $(,)?) => { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 253 | KeyPermSet($head as i32 $(| $tail as i32)*) | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 254 | }; | 
|  | 255 | } | 
|  | 256 |  | 
|  | 257 | impl IntoIterator for KeyPermSet { | 
|  | 258 | type Item = KeyPerm; | 
|  | 259 | type IntoIter = perm::IntoIter; | 
|  | 260 |  | 
|  | 261 | fn into_iter(self) -> Self::IntoIter { | 
|  | 262 | Self::IntoIter::new(self) | 
|  | 263 | } | 
|  | 264 | } | 
|  | 265 |  | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 266 | /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` may access | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 267 | /// the given permision `perm` of the `keystore2` security class. | 
| Janis Danisevskis | 935e6c6 | 2020-08-18 12:52:27 -0700 | [diff] [blame] | 268 | pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 269 | let target_context = getcon().context("check_keystore_permission: getcon failed.")?; | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 270 | selinux::check_permission(caller_ctx, &target_context, perm) | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 271 | } | 
|  | 272 |  | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 273 | /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` has | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 274 | /// all the permissions indicated in `access_vec` for the target domain indicated by the key | 
|  | 275 | /// descriptor `key` in the security class `keystore2_key`. | 
|  | 276 | /// | 
|  | 277 | /// Also checks if the caller has the grant permission for the given target domain. | 
|  | 278 | /// | 
|  | 279 | /// Attempts to grant the grant permission are always denied. | 
|  | 280 | /// | 
|  | 281 | /// The only viable target domains are | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 282 | ///  * `Domain::APP` in which case u:r:keystore:s0 is used as target context and | 
|  | 283 | ///  * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 284 | ///                      SELinux keystore key backend, and the result is used | 
|  | 285 | ///                      as target context. | 
|  | 286 | pub fn check_grant_permission( | 
| Janis Danisevskis | 935e6c6 | 2020-08-18 12:52:27 -0700 | [diff] [blame] | 287 | caller_ctx: &CStr, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 288 | access_vec: KeyPermSet, | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 289 | key: &KeyDescriptor, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 290 | ) -> anyhow::Result<()> { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 291 | let target_context = match key.domain { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 292 | Domain::APP => getcon().context("check_grant_permission: getcon failed.")?, | 
|  | 293 | Domain::SELINUX => lookup_keystore2_key_context(key.nspace) | 
|  | 294 | .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 295 | _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)), | 
|  | 296 | }; | 
|  | 297 |  | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 298 | selinux::check_permission(caller_ctx, &target_context, KeyPerm::Grant) | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 299 | .context("Grant permission is required when granting.")?; | 
|  | 300 |  | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 301 | if access_vec.includes(KeyPerm::Grant) { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 302 | return Err(selinux::Error::perm()).context("Grant permission cannot be granted."); | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | for p in access_vec.into_iter() { | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 306 | selinux::check_permission(caller_ctx, &target_context, p).context(ks_err!( | 
|  | 307 | "check_permission failed. \ | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 308 | The caller may have tried to grant a permission that they don't possess. {:?}", | 
|  | 309 | p | 
|  | 310 | ))? | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 311 | } | 
|  | 312 | Ok(()) | 
|  | 313 | } | 
|  | 314 |  | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 315 | /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 316 | /// has the permissions indicated by `perm` for the target domain indicated by the key | 
|  | 317 | /// descriptor `key` in the security class `keystore2_key`. | 
|  | 318 | /// | 
|  | 319 | /// The behavior differs slightly depending on the selected target domain: | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 320 | ///  * `Domain::APP` u:r:keystore:s0 is used as target context. | 
|  | 321 | ///  * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 322 | ///                      backend, and the result is used as target context. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 323 | ///  * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 324 | ///                   to the one supplied in `perm`. | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 325 | ///  * `Domain::GRANT` Does not use selinux::check_permission. Instead the `access_vector` | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 326 | ///                    parameter is queried for permission, which must be supplied in this case. | 
|  | 327 | /// | 
|  | 328 | /// ## Return values. | 
|  | 329 | ///  * Ok(()) If the requested permissions were granted. | 
|  | 330 | ///  * Err(selinux::Error::perm()) If the requested permissions were denied. | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 331 | ///  * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec` | 
|  | 332 | ///                      was supplied. It is also produced if `Domain::KEY_ID` was selected, and | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 333 | ///                      on various unexpected backend failures. | 
|  | 334 | pub fn check_key_permission( | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 335 | caller_uid: u32, | 
| Janis Danisevskis | 935e6c6 | 2020-08-18 12:52:27 -0700 | [diff] [blame] | 336 | caller_ctx: &CStr, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 337 | perm: KeyPerm, | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 338 | key: &KeyDescriptor, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 339 | access_vector: &Option<KeyPermSet>, | 
|  | 340 | ) -> anyhow::Result<()> { | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 341 | // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID. | 
|  | 342 | // In the former case, key.domain was set to GRANT and we check the failure cases | 
|  | 343 | // further below. If the access is requested by KEY_ID, key.domain would have been | 
|  | 344 | // resolved to APP or SELINUX depending on where the key actually resides. | 
|  | 345 | // Either way we can return here immediately if the access vector covers the requested | 
|  | 346 | // permission. If it does not, we can still check if the caller has access by means of | 
|  | 347 | // ownership. | 
|  | 348 | if let Some(access_vector) = access_vector { | 
|  | 349 | if access_vector.includes(perm) { | 
|  | 350 | return Ok(()); | 
|  | 351 | } | 
|  | 352 | } | 
|  | 353 |  | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 354 | let target_context = match key.domain { | 
|  | 355 | // apps get the default keystore context | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 356 | Domain::APP => { | 
|  | 357 | if caller_uid as i64 != key.nspace { | 
|  | 358 | return Err(selinux::Error::perm()) | 
|  | 359 | .context("Trying to access key without ownership."); | 
|  | 360 | } | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 361 | getcon().context(ks_err!("getcon failed."))? | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 362 | } | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 363 | Domain::SELINUX => lookup_keystore2_key_context(key.nspace) | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 364 | .context(ks_err!("Domain::SELINUX: Failed to lookup namespace."))?, | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 365 | Domain::GRANT => { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 366 | match access_vector { | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 367 | Some(_) => { | 
|  | 368 | return Err(selinux::Error::perm()) | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 369 | .context(format!("\"{}\" not granted", perm.name())); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 370 | } | 
|  | 371 | None => { | 
|  | 372 | // If DOMAIN_GRANT was selected an access vector must be supplied. | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 373 | return Err(KsError::sys()).context(ks_err!( | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 374 | "Cannot check permission for Domain::GRANT without access vector.", | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 375 | )); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 376 | } | 
|  | 377 | } | 
|  | 378 | } | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 379 | Domain::KEY_ID => { | 
|  | 380 | // We should never be called with `Domain::KEY_ID. The database | 
|  | 381 | // lookup should have converted this into one of `Domain::APP` | 
|  | 382 | // or `Domain::SELINUX`. | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 383 | return Err(KsError::sys()) | 
|  | 384 | .context(ks_err!("Cannot check permission for Domain::KEY_ID.",)); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 385 | } | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 386 | Domain::BLOB => { | 
|  | 387 | let tctx = lookup_keystore2_key_context(key.nspace) | 
| Shaquille Johnson | 9da2e1c | 2022-09-19 12:39:01 +0000 | [diff] [blame] | 388 | .context(ks_err!("Domain::BLOB: Failed to lookup namespace."))?; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 389 | // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob" | 
|  | 390 | // permission in addition to the requested permission. | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 391 | selinux::check_permission(caller_ctx, &tctx, KeyPerm::ManageBlob)?; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 392 |  | 
|  | 393 | tctx | 
|  | 394 | } | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 395 | _ => { | 
| Rajesh Nyamagoud | caee93e | 2022-05-26 00:20:38 +0000 | [diff] [blame] | 396 | return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT)) | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 397 | .context(format!("Unknown domain value: \"{:?}\".", key.domain)) | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 398 | } | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 399 | }; | 
|  | 400 |  | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 401 | selinux::check_permission(caller_ctx, &target_context, perm) | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 402 | } | 
|  | 403 |  | 
|  | 404 | #[cfg(test)] | 
|  | 405 | mod tests { | 
|  | 406 | use super::*; | 
|  | 407 | use anyhow::anyhow; | 
|  | 408 | use anyhow::Result; | 
|  | 409 | use keystore2_selinux::*; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 410 |  | 
|  | 411 | const ALL_PERMS: KeyPermSet = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 412 | KeyPerm::ManageBlob, | 
|  | 413 | KeyPerm::Delete, | 
|  | 414 | KeyPerm::UseDevId, | 
|  | 415 | KeyPerm::ReqForcedOp, | 
|  | 416 | KeyPerm::GenUniqueId, | 
|  | 417 | KeyPerm::Grant, | 
|  | 418 | KeyPerm::GetInfo, | 
|  | 419 | KeyPerm::Rebind, | 
|  | 420 | KeyPerm::Update, | 
|  | 421 | KeyPerm::Use, | 
|  | 422 | KeyPerm::ConvertStorageKeyToEphemeral, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 423 | ]; | 
|  | 424 |  | 
| Janis Danisevskis | a31dd9e | 2021-01-30 00:13:17 -0800 | [diff] [blame] | 425 | const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 426 | KeyPerm::Delete, | 
|  | 427 | KeyPerm::UseDevId, | 
|  | 428 | // No KeyPerm::Grant | 
|  | 429 | KeyPerm::GetInfo, | 
|  | 430 | KeyPerm::Rebind, | 
|  | 431 | KeyPerm::Update, | 
|  | 432 | KeyPerm::Use, | 
| Janis Danisevskis | a31dd9e | 2021-01-30 00:13:17 -0800 | [diff] [blame] | 433 | ]; | 
|  | 434 |  | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 435 | const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 436 | KeyPerm::ManageBlob, | 
|  | 437 | KeyPerm::Delete, | 
|  | 438 | KeyPerm::UseDevId, | 
|  | 439 | KeyPerm::ReqForcedOp, | 
|  | 440 | KeyPerm::GenUniqueId, | 
|  | 441 | // No KeyPerm::Grant | 
|  | 442 | KeyPerm::GetInfo, | 
|  | 443 | KeyPerm::Rebind, | 
|  | 444 | KeyPerm::Update, | 
|  | 445 | KeyPerm::Use, | 
|  | 446 | KeyPerm::ConvertStorageKeyToEphemeral, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 447 | ]; | 
|  | 448 |  | 
|  | 449 | const UNPRIV_PERMS: KeyPermSet = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 450 | KeyPerm::Delete, | 
|  | 451 | KeyPerm::GetInfo, | 
|  | 452 | KeyPerm::Rebind, | 
|  | 453 | KeyPerm::Update, | 
|  | 454 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 455 | ]; | 
|  | 456 |  | 
|  | 457 | /// The su_key namespace as defined in su.te and keystore_key_contexts of the | 
|  | 458 | /// SePolicy (system/sepolicy). | 
|  | 459 | const SU_KEY_NAMESPACE: i32 = 0; | 
|  | 460 | /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the | 
|  | 461 | /// SePolicy (system/sepolicy). | 
|  | 462 | const SHELL_KEY_NAMESPACE: i32 = 1; | 
|  | 463 |  | 
|  | 464 | pub fn test_getcon() -> Result<Context> { | 
|  | 465 | Context::new("u:object_r:keystore:s0") | 
|  | 466 | } | 
|  | 467 |  | 
|  | 468 | // This macro evaluates the given expression and checks that | 
|  | 469 | // a) evaluated to Result::Err() and that | 
|  | 470 | // b) the wrapped error is selinux::Error::perm() (permission denied). | 
|  | 471 | // We use a macro here because a function would mask which invocation caused the failure. | 
|  | 472 | // | 
|  | 473 | // TODO b/164121720 Replace this macro with a function when `track_caller` is available. | 
|  | 474 | macro_rules! assert_perm_failed { | 
|  | 475 | ($test_function:expr) => { | 
|  | 476 | let result = $test_function; | 
|  | 477 | assert!(result.is_err(), "Permission check should have failed."); | 
|  | 478 | assert_eq!( | 
|  | 479 | Some(&selinux::Error::perm()), | 
|  | 480 | result.err().unwrap().root_cause().downcast_ref::<selinux::Error>() | 
|  | 481 | ); | 
|  | 482 | }; | 
|  | 483 | } | 
|  | 484 |  | 
|  | 485 | fn check_context() -> Result<(selinux::Context, i32, bool)> { | 
|  | 486 | // Calling the non mocked selinux::getcon here intended. | 
|  | 487 | let context = selinux::getcon()?; | 
|  | 488 | match context.to_str().unwrap() { | 
|  | 489 | "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)), | 
|  | 490 | "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)), | 
|  | 491 | c => Err(anyhow!(format!( | 
|  | 492 | "This test must be run as \"su\" or \"shell\". Current context: \"{}\"", | 
|  | 493 | c | 
|  | 494 | ))), | 
|  | 495 | } | 
|  | 496 | } | 
|  | 497 |  | 
|  | 498 | #[test] | 
|  | 499 | fn check_keystore_permission_test() -> Result<()> { | 
|  | 500 | let system_server_ctx = Context::new("u:r:system_server:s0")?; | 
| Janis Danisevskis | a916d99 | 2021-10-19 15:46:09 -0700 | [diff] [blame] | 501 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::AddAuth).is_ok()); | 
|  | 502 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearNs).is_ok()); | 
|  | 503 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::GetState).is_ok()); | 
|  | 504 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Lock).is_ok()); | 
|  | 505 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Reset).is_ok()); | 
|  | 506 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Unlock).is_ok()); | 
|  | 507 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangeUser).is_ok()); | 
|  | 508 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangePassword).is_ok()); | 
|  | 509 | assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearUID).is_ok()); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 510 | let shell_ctx = Context::new("u:r:shell:s0")?; | 
| Janis Danisevskis | a916d99 | 2021-10-19 15:46:09 -0700 | [diff] [blame] | 511 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::AddAuth)); | 
|  | 512 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearNs)); | 
|  | 513 | assert!(check_keystore_permission(&shell_ctx, KeystorePerm::GetState).is_ok()); | 
|  | 514 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::List)); | 
|  | 515 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Lock)); | 
|  | 516 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Reset)); | 
|  | 517 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Unlock)); | 
|  | 518 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangeUser)); | 
|  | 519 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangePassword)); | 
|  | 520 | assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearUID)); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 521 | Ok(()) | 
|  | 522 | } | 
|  | 523 |  | 
|  | 524 | #[test] | 
|  | 525 | fn check_grant_permission_app() -> Result<()> { | 
|  | 526 | let system_server_ctx = Context::new("u:r:system_server:s0")?; | 
|  | 527 | let shell_ctx = Context::new("u:r:shell:s0")?; | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 528 | let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None }; | 
| Janis Danisevskis | a31dd9e | 2021-01-30 00:13:17 -0800 | [diff] [blame] | 529 | check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key) | 
|  | 530 | .expect("Grant permission check failed."); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 531 |  | 
| Janis Danisevskis | a31dd9e | 2021-01-30 00:13:17 -0800 | [diff] [blame] | 532 | // attempts to grant the grant permission must always fail even when privileged. | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 533 | assert_perm_failed!(check_grant_permission( | 
|  | 534 | &system_server_ctx, | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 535 | KeyPerm::Grant.into(), | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 536 | &key | 
|  | 537 | )); | 
|  | 538 | // unprivileged grant attempts always fail. shell does not have the grant permission. | 
|  | 539 | assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key)); | 
|  | 540 | Ok(()) | 
|  | 541 | } | 
|  | 542 |  | 
|  | 543 | #[test] | 
|  | 544 | fn check_grant_permission_selinux() -> Result<()> { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 545 | let (sctx, namespace, is_su) = check_context()?; | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 546 | let key = KeyDescriptor { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 547 | domain: Domain::SELINUX, | 
|  | 548 | nspace: namespace as i64, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 549 | alias: None, | 
|  | 550 | blob: None, | 
|  | 551 | }; | 
|  | 552 | if is_su { | 
|  | 553 | assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok()); | 
|  | 554 | // attempts to grant the grant permission must always fail even when privileged. | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 555 | assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::Grant.into(), &key)); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 556 | } else { | 
|  | 557 | // unprivileged grant attempts always fail. shell does not have the grant permission. | 
|  | 558 | assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key)); | 
|  | 559 | } | 
|  | 560 | Ok(()) | 
|  | 561 | } | 
|  | 562 |  | 
|  | 563 | #[test] | 
|  | 564 | fn check_key_permission_domain_grant() -> Result<()> { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 565 | let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None }; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 566 |  | 
|  | 567 | assert_perm_failed!(check_key_permission( | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 568 | 0, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 569 | &selinux::Context::new("ignored").unwrap(), | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 570 | KeyPerm::Grant, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 571 | &key, | 
|  | 572 | &Some(UNPRIV_PERMS) | 
|  | 573 | )); | 
|  | 574 |  | 
|  | 575 | check_key_permission( | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 576 | 0, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 577 | &selinux::Context::new("ignored").unwrap(), | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 578 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 579 | &key, | 
|  | 580 | &Some(ALL_PERMS), | 
|  | 581 | ) | 
|  | 582 | } | 
|  | 583 |  | 
|  | 584 | #[test] | 
|  | 585 | fn check_key_permission_domain_app() -> Result<()> { | 
|  | 586 | let system_server_ctx = Context::new("u:r:system_server:s0")?; | 
|  | 587 | let shell_ctx = Context::new("u:r:shell:s0")?; | 
|  | 588 | let gmscore_app = Context::new("u:r:gmscore_app:s0")?; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 589 |  | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 590 | let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None }; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 591 |  | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 592 | assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Use, &key, &None).is_ok()); | 
|  | 593 | assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Delete, &key, &None).is_ok()); | 
|  | 594 | assert!(check_key_permission(0, &system_server_ctx, KeyPerm::GetInfo, &key, &None).is_ok()); | 
|  | 595 | assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Rebind, &key, &None).is_ok()); | 
|  | 596 | assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Update, &key, &None).is_ok()); | 
|  | 597 | assert!(check_key_permission(0, &system_server_ctx, KeyPerm::Grant, &key, &None).is_ok()); | 
|  | 598 | assert!(check_key_permission(0, &system_server_ctx, KeyPerm::UseDevId, &key, &None).is_ok()); | 
|  | 599 | assert!(check_key_permission(0, &gmscore_app, KeyPerm::GenUniqueId, &key, &None).is_ok()); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 600 |  | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 601 | assert!(check_key_permission(0, &shell_ctx, KeyPerm::Use, &key, &None).is_ok()); | 
|  | 602 | assert!(check_key_permission(0, &shell_ctx, KeyPerm::Delete, &key, &None).is_ok()); | 
|  | 603 | assert!(check_key_permission(0, &shell_ctx, KeyPerm::GetInfo, &key, &None).is_ok()); | 
|  | 604 | assert!(check_key_permission(0, &shell_ctx, KeyPerm::Rebind, &key, &None).is_ok()); | 
|  | 605 | assert!(check_key_permission(0, &shell_ctx, KeyPerm::Update, &key, &None).is_ok()); | 
|  | 606 | assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::Grant, &key, &None)); | 
|  | 607 | assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::ReqForcedOp, &key, &None)); | 
|  | 608 | assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::ManageBlob, &key, &None)); | 
|  | 609 | assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::UseDevId, &key, &None)); | 
|  | 610 | assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::GenUniqueId, &key, &None)); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 611 |  | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 612 | // Also make sure that the permission fails if the caller is not the owner. | 
|  | 613 | assert_perm_failed!(check_key_permission( | 
|  | 614 | 1, // the owner is 0 | 
|  | 615 | &system_server_ctx, | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 616 | KeyPerm::Use, | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 617 | &key, | 
|  | 618 | &None | 
|  | 619 | )); | 
|  | 620 | // Unless there was a grant. | 
|  | 621 | assert!(check_key_permission( | 
|  | 622 | 1, | 
|  | 623 | &system_server_ctx, | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 624 | KeyPerm::Use, | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 625 | &key, | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 626 | &Some(key_perm_set![KeyPerm::Use]) | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 627 | ) | 
|  | 628 | .is_ok()); | 
|  | 629 | // But fail if the grant did not cover the requested permission. | 
|  | 630 | assert_perm_failed!(check_key_permission( | 
|  | 631 | 1, | 
|  | 632 | &system_server_ctx, | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 633 | KeyPerm::Use, | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 634 | &key, | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 635 | &Some(key_perm_set![KeyPerm::GetInfo]) | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 636 | )); | 
|  | 637 |  | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 638 | Ok(()) | 
|  | 639 | } | 
|  | 640 |  | 
|  | 641 | #[test] | 
|  | 642 | fn check_key_permission_domain_selinux() -> Result<()> { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 643 | let (sctx, namespace, is_su) = check_context()?; | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 644 | let key = KeyDescriptor { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 645 | domain: Domain::SELINUX, | 
|  | 646 | nspace: namespace as i64, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 647 | alias: None, | 
|  | 648 | blob: None, | 
|  | 649 | }; | 
|  | 650 |  | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 651 | assert!(check_key_permission(0, &sctx, KeyPerm::Use, &key, &None).is_ok()); | 
|  | 652 | assert!(check_key_permission(0, &sctx, KeyPerm::Delete, &key, &None).is_ok()); | 
|  | 653 | assert!(check_key_permission(0, &sctx, KeyPerm::GetInfo, &key, &None).is_ok()); | 
|  | 654 | assert!(check_key_permission(0, &sctx, KeyPerm::Rebind, &key, &None).is_ok()); | 
|  | 655 | assert!(check_key_permission(0, &sctx, KeyPerm::Update, &key, &None).is_ok()); | 
| Chris Wailes | 3877f29 | 2021-07-26 19:24:18 -0700 | [diff] [blame] | 656 |  | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 657 | if is_su { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 658 | assert!(check_key_permission(0, &sctx, KeyPerm::Grant, &key, &None).is_ok()); | 
|  | 659 | assert!(check_key_permission(0, &sctx, KeyPerm::ManageBlob, &key, &None).is_ok()); | 
|  | 660 | assert!(check_key_permission(0, &sctx, KeyPerm::UseDevId, &key, &None).is_ok()); | 
|  | 661 | assert!(check_key_permission(0, &sctx, KeyPerm::GenUniqueId, &key, &None).is_ok()); | 
|  | 662 | assert!(check_key_permission(0, &sctx, KeyPerm::ReqForcedOp, &key, &None).is_ok()); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 663 | } else { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 664 | assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::Grant, &key, &None)); | 
|  | 665 | assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::ReqForcedOp, &key, &None)); | 
|  | 666 | assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::ManageBlob, &key, &None)); | 
|  | 667 | assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::UseDevId, &key, &None)); | 
|  | 668 | assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::GenUniqueId, &key, &None)); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 669 | } | 
|  | 670 | Ok(()) | 
|  | 671 | } | 
|  | 672 |  | 
|  | 673 | #[test] | 
|  | 674 | fn check_key_permission_domain_blob() -> Result<()> { | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 675 | let (sctx, namespace, is_su) = check_context()?; | 
| Janis Danisevskis | 1b3a6e2 | 2020-08-07 12:39:56 -0700 | [diff] [blame] | 676 | let key = KeyDescriptor { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 677 | domain: Domain::BLOB, | 
|  | 678 | nspace: namespace as i64, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 679 | alias: None, | 
|  | 680 | blob: None, | 
|  | 681 | }; | 
|  | 682 |  | 
|  | 683 | if is_su { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 684 | check_key_permission(0, &sctx, KeyPerm::Use, &key, &None) | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 685 | } else { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 686 | assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::Use, &key, &None)); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 687 | Ok(()) | 
|  | 688 | } | 
|  | 689 | } | 
|  | 690 |  | 
|  | 691 | #[test] | 
|  | 692 | fn check_key_permission_domain_key_id() -> Result<()> { | 
| Janis Danisevskis | c5b210b | 2020-09-11 13:27:37 -0700 | [diff] [blame] | 693 | let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None }; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 694 |  | 
|  | 695 | assert_eq!( | 
|  | 696 | Some(&KsError::sys()), | 
|  | 697 | check_key_permission( | 
| Janis Danisevskis | 4576002 | 2021-01-19 16:34:10 -0800 | [diff] [blame] | 698 | 0, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 699 | &selinux::Context::new("ignored").unwrap(), | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 700 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 701 | &key, | 
|  | 702 | &None | 
|  | 703 | ) | 
|  | 704 | .err() | 
|  | 705 | .unwrap() | 
|  | 706 | .root_cause() | 
|  | 707 | .downcast_ref::<KsError>() | 
|  | 708 | ); | 
|  | 709 | Ok(()) | 
|  | 710 | } | 
|  | 711 |  | 
|  | 712 | #[test] | 
|  | 713 | fn key_perm_set_all_test() { | 
|  | 714 | let v = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 715 | KeyPerm::ManageBlob, | 
|  | 716 | KeyPerm::Delete, | 
|  | 717 | KeyPerm::UseDevId, | 
|  | 718 | KeyPerm::ReqForcedOp, | 
|  | 719 | KeyPerm::GenUniqueId, | 
|  | 720 | KeyPerm::Grant, | 
|  | 721 | KeyPerm::GetInfo, | 
|  | 722 | KeyPerm::Rebind, | 
|  | 723 | KeyPerm::Update, | 
|  | 724 | KeyPerm::Use // Test if the macro accepts missing comma at the end of the list. | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 725 | ]; | 
|  | 726 | let mut i = v.into_iter(); | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 727 | assert_eq!(i.next().unwrap().name(), "delete"); | 
|  | 728 | assert_eq!(i.next().unwrap().name(), "gen_unique_id"); | 
|  | 729 | assert_eq!(i.next().unwrap().name(), "get_info"); | 
|  | 730 | assert_eq!(i.next().unwrap().name(), "grant"); | 
|  | 731 | assert_eq!(i.next().unwrap().name(), "manage_blob"); | 
|  | 732 | assert_eq!(i.next().unwrap().name(), "rebind"); | 
|  | 733 | assert_eq!(i.next().unwrap().name(), "req_forced_op"); | 
|  | 734 | assert_eq!(i.next().unwrap().name(), "update"); | 
|  | 735 | assert_eq!(i.next().unwrap().name(), "use"); | 
|  | 736 | assert_eq!(i.next().unwrap().name(), "use_dev_id"); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 737 | assert_eq!(None, i.next()); | 
|  | 738 | } | 
|  | 739 | #[test] | 
|  | 740 | fn key_perm_set_sparse_test() { | 
|  | 741 | let v = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 742 | KeyPerm::ManageBlob, | 
|  | 743 | KeyPerm::ReqForcedOp, | 
|  | 744 | KeyPerm::GenUniqueId, | 
|  | 745 | KeyPerm::Update, | 
|  | 746 | KeyPerm::Use, // Test if macro accepts the comma at the end of the list. | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 747 | ]; | 
|  | 748 | let mut i = v.into_iter(); | 
| Janis Danisevskis | 56af031 | 2021-10-18 16:11:41 -0700 | [diff] [blame] | 749 | assert_eq!(i.next().unwrap().name(), "gen_unique_id"); | 
|  | 750 | assert_eq!(i.next().unwrap().name(), "manage_blob"); | 
|  | 751 | assert_eq!(i.next().unwrap().name(), "req_forced_op"); | 
|  | 752 | assert_eq!(i.next().unwrap().name(), "update"); | 
|  | 753 | assert_eq!(i.next().unwrap().name(), "use"); | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 754 | assert_eq!(None, i.next()); | 
|  | 755 | } | 
|  | 756 | #[test] | 
|  | 757 | fn key_perm_set_empty_test() { | 
|  | 758 | let v = key_perm_set![]; | 
|  | 759 | let mut i = v.into_iter(); | 
|  | 760 | assert_eq!(None, i.next()); | 
|  | 761 | } | 
|  | 762 | #[test] | 
|  | 763 | fn key_perm_set_include_subset_test() { | 
|  | 764 | let v1 = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 765 | KeyPerm::ManageBlob, | 
|  | 766 | KeyPerm::Delete, | 
|  | 767 | KeyPerm::UseDevId, | 
|  | 768 | KeyPerm::ReqForcedOp, | 
|  | 769 | KeyPerm::GenUniqueId, | 
|  | 770 | KeyPerm::Grant, | 
|  | 771 | KeyPerm::GetInfo, | 
|  | 772 | KeyPerm::Rebind, | 
|  | 773 | KeyPerm::Update, | 
|  | 774 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 775 | ]; | 
|  | 776 | let v2 = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 777 | KeyPerm::ManageBlob, | 
|  | 778 | KeyPerm::Delete, | 
|  | 779 | KeyPerm::Rebind, | 
|  | 780 | KeyPerm::Update, | 
|  | 781 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 782 | ]; | 
|  | 783 | assert!(v1.includes(v2)); | 
|  | 784 | assert!(!v2.includes(v1)); | 
|  | 785 | } | 
|  | 786 | #[test] | 
|  | 787 | fn key_perm_set_include_equal_test() { | 
|  | 788 | let v1 = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 789 | KeyPerm::ManageBlob, | 
|  | 790 | KeyPerm::Delete, | 
|  | 791 | KeyPerm::Rebind, | 
|  | 792 | KeyPerm::Update, | 
|  | 793 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 794 | ]; | 
|  | 795 | let v2 = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 796 | KeyPerm::ManageBlob, | 
|  | 797 | KeyPerm::Delete, | 
|  | 798 | KeyPerm::Rebind, | 
|  | 799 | KeyPerm::Update, | 
|  | 800 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 801 | ]; | 
|  | 802 | assert!(v1.includes(v2)); | 
|  | 803 | assert!(v2.includes(v1)); | 
|  | 804 | } | 
|  | 805 | #[test] | 
|  | 806 | fn key_perm_set_include_overlap_test() { | 
|  | 807 | let v1 = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 808 | KeyPerm::ManageBlob, | 
|  | 809 | KeyPerm::Delete, | 
|  | 810 | KeyPerm::Grant, // only in v1 | 
|  | 811 | KeyPerm::Rebind, | 
|  | 812 | KeyPerm::Update, | 
|  | 813 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 814 | ]; | 
|  | 815 | let v2 = key_perm_set![ | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 816 | KeyPerm::ManageBlob, | 
|  | 817 | KeyPerm::Delete, | 
|  | 818 | KeyPerm::ReqForcedOp, // only in v2 | 
|  | 819 | KeyPerm::Rebind, | 
|  | 820 | KeyPerm::Update, | 
|  | 821 | KeyPerm::Use, | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 822 | ]; | 
|  | 823 | assert!(!v1.includes(v2)); | 
|  | 824 | assert!(!v2.includes(v1)); | 
|  | 825 | } | 
|  | 826 | #[test] | 
|  | 827 | fn key_perm_set_include_no_overlap_test() { | 
| Janis Danisevskis | 39d57e7 | 2021-10-19 16:56:20 -0700 | [diff] [blame] | 828 | let v1 = key_perm_set![KeyPerm::ManageBlob, KeyPerm::Delete, KeyPerm::Grant,]; | 
|  | 829 | let v2 = | 
|  | 830 | key_perm_set![KeyPerm::ReqForcedOp, KeyPerm::Rebind, KeyPerm::Update, KeyPerm::Use,]; | 
| Janis Danisevskis | 78bd48c | 2020-07-21 12:27:13 -0700 | [diff] [blame] | 831 | assert!(!v1.includes(v2)); | 
|  | 832 | assert!(!v2.includes(v1)); | 
|  | 833 | } | 
|  | 834 | } |