blob: fad563696a97c83cbb934b20177531dc30bb90df [file] [log] [blame]
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001// 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 Danisevskisa2f48502021-10-18 16:07:09 -070021use crate::error::Error as KsError;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -070022use android_system_keystore2::aidl::android::system::keystore2::{
23 Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
24};
Janis Danisevskisa2f48502021-10-18 16:07:09 -070025use anyhow::Context as AnyhowContext;
26use keystore2_selinux as selinux;
27use lazy_static::lazy_static;
28use selinux::{implement_permission, Backend};
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070029use std::cmp::PartialEq;
30use std::convert::From;
Janis Danisevskis935e6c62020-08-18 12:52:27 -070031use std::ffi::CStr;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070032
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070033// Replace getcon with a mock in the test situation
34#[cfg(not(test))]
35use selinux::getcon;
36#[cfg(test)]
37use tests::test_getcon as getcon;
38
Janis Danisevskis4ad056f2020-08-05 19:46:46 +000039lazy_static! {
40 // Panicking here is allowed because keystore cannot function without this backend
41 // and it would happen early and indicate a gross misconfiguration of the device.
42 static ref KEYSTORE2_KEY_LABEL_BACKEND: selinux::KeystoreKeyBackend =
43 selinux::KeystoreKeyBackend::new().unwrap();
44}
45
46fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> {
47 KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string())
48}
49
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070050/// ## Background
51///
52/// AIDL enums are represented as constants of the form:
53/// ```
54/// mod EnumName {
55/// pub type EnumName = i32;
56/// pub const Variant1: EnumName = <value1>;
57/// pub const Variant2: EnumName = <value2>;
58/// ...
59/// }
60///```
61/// This macro wraps the enum in a new type, e.g., `MyPerm` and maps each variant to an SELinux
62/// permission while providing the following interface:
63/// * From<EnumName> and Into<EnumName> are implemented. Where the implementation of From maps
64/// any variant not specified to the default.
65/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
66/// representation.
67/// * `MyPerm.to_selinux(&self)` returns the SELinux string representation of the
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070068/// represented permission.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070069///
70/// ## Special behavior
71/// If the keyword `use` appears as an selinux name `use_` is used as identifier for the
72/// constructor function (e.g. `MePerm::use_()`) but the string returned by `to_selinux` will
73/// still be `"use"`.
74///
75/// ## Example
76/// ```
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070077/// implement_permission!(
78/// /// MyPerm documentation.
79/// #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070080/// MyPerm from EnumName with default (None, none) {}
81/// Variant1, selinux name: variant1;
82/// Variant2, selinux name: variant1;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070083/// }
84/// );
85/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070086macro_rules! implement_permission_aidl {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070087 // This rule provides the public interface of the macro. And starts the preprocessing
88 // recursion (see below).
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070089 ($(#[$m:meta])* $name:ident from $aidl_name:ident with default ($($def:tt)*)
90 { $($element:tt)* })
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070091 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070092 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*), [],
93 $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070094 };
95
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070096 // The following three rules recurse through the elements of the form
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070097 // `<enum variant>, selinux name: <selinux_name>;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070098 // preprocessing the input.
99
100 // The first rule terminates the recursion and passes the processed arguments to the final
101 // rule that spills out the implementation.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700102 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*], ) => {
103 implement_permission_aidl!(@end $($m)*, $name, $aidl_name, ($($def)*) { $($out)* } );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700104 };
105
106 // The second rule is triggered if the selinux name of an element is literally `use`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700107 // It produces the tuple `<enum variant>, use_, use;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700108 // and appends it to the out list.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700109 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*],
110 $e_name:ident, selinux name: use; $($element:tt)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700111 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700112 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*),
113 [$($out)* $e_name, use_, use;], $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700114 };
115
116 // The third rule is the default rule which replaces every input tuple with
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700117 // `<enum variant>, <selinux_name>, <selinux_name>;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700118 // and appends the result to the out list.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700119 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*],
120 $e_name:ident, selinux name: $e_str:ident; $($element:tt)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700121 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700122 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*),
123 [$($out)* $e_name, $e_str, $e_str;], $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700124 };
125
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700126 (@end $($m:meta)*, $name:ident, $aidl_name:ident,
127 ($def_name:ident, $def_selinux_name:ident) {
128 $($element_name:ident, $element_identifier:ident,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700129 $selinux_name:ident;)*
130 })
131 =>
132 {
133 $(#[$m])*
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700134 pub struct $name(pub $aidl_name);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700135
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700136 impl From<$aidl_name> for $name {
137 fn from (p: $aidl_name) -> Self {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700138 match p {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700139 $aidl_name::$def_name => Self($aidl_name::$def_name),
140 $($aidl_name::$element_name => Self($aidl_name::$element_name),)*
141 _ => Self($aidl_name::$def_name),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700142 }
143 }
144 }
145
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700146 impl From<$name> for $aidl_name {
147 fn from(p: $name) -> $aidl_name {
148 p.0
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700149 }
150 }
151
152 impl $name {
153 /// Returns a string representation of the permission as required by
154 /// `selinux::check_access`.
Chris Wailes3877f292021-07-26 19:24:18 -0700155 pub fn to_selinux(self) -> &'static str {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700156 match self {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700157 Self($aidl_name::$def_name) => stringify!($def_selinux_name),
158 $(Self($aidl_name::$element_name) => stringify!($selinux_name),)*
159 _ => stringify!($def_selinux_name),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700160 }
161 }
162
163 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700164 pub const fn $def_selinux_name() -> Self { Self($aidl_name::$def_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700165 $(
166 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700167 pub const fn $element_identifier() -> Self { Self($aidl_name::$element_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700168 )*
169 }
170 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700171}
172
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700173implement_permission_aidl!(
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700174 /// KeyPerm provides a convenient abstraction from the SELinux class `keystore2_key`.
175 /// At the same time it maps `KeyPermissions` from the Keystore 2.0 AIDL Grant interface to
176 /// the SELinux permissions. With the implement_permission macro, we conveniently
177 /// provide mappings between the wire type bit field values, the rust enum and the SELinux
178 /// string representation.
179 ///
180 /// ## Example
181 ///
182 /// In this access check `KeyPerm::get_info().to_selinux()` would return the SELinux representation
183 /// "info".
184 /// ```
185 /// selinux::check_access(source_context, target_context, "keystore2_key",
186 /// KeyPerm::get_info().to_selinux());
187 /// ```
188 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700189 KeyPerm from KeyPermission with default (NONE, none) {
Satya Tangirala3361b612021-03-08 14:36:11 -0800190 CONVERT_STORAGE_KEY_TO_EPHEMERAL, selinux name: convert_storage_key_to_ephemeral;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700191 DELETE, selinux name: delete;
192 GEN_UNIQUE_ID, selinux name: gen_unique_id;
193 GET_INFO, selinux name: get_info;
194 GRANT, selinux name: grant;
195 MANAGE_BLOB, selinux name: manage_blob;
196 REBIND, selinux name: rebind;
197 REQ_FORCED_OP, selinux name: req_forced_op;
198 UPDATE, selinux name: update;
199 USE, selinux name: use;
200 USE_DEV_ID, selinux name: use_dev_id;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700201 }
202);
203
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700204implement_permission!(
205 /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
206 /// Using the implement_permission macro we get the same features as `KeyPerm`.
207 #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700208 pub enum KeystorePerm {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700209 /// Checked when a new auth token is installed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700210 #[selinux(name = add_auth)]
211 AddAuth,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700212 /// Checked when an app is uninstalled or wiped.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700213 #[selinux(name = clear_ns)]
214 ClearNs,
Hasini Gunasinghe9ee18412021-03-11 20:12:44 +0000215 /// Checked when the user state is queried from Keystore 2.0.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700216 #[selinux(name = get_state)]
217 GetState,
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700218 /// Checked when Keystore 2.0 is asked to list a namespace that the caller
219 /// does not have the get_info permission for.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700220 #[selinux(name = list)]
221 List,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700222 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700223 #[selinux(name = lock)]
224 Lock,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700225 /// Checked when Keystore 2.0 shall be reset.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700226 #[selinux(name = reset)]
227 Reset,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700228 /// Checked when Keystore 2.0 shall be unlocked.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700229 #[selinux(name = unlock)]
230 Unlock,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000231 /// Checked when user is added or removed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700232 #[selinux(name = change_user)]
233 ChangeUser,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000234 /// Checked when password of the user is changed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700235 #[selinux(name = change_password)]
236 ChangePassword,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000237 /// Checked when a UID is cleared.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700238 #[selinux(name = clear_uid)]
239 ClearUID,
Hasini Gunasinghe5fc95252020-12-04 00:35:08 +0000240 /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700241 #[selinux(name = get_auth_token)]
242 GetAuthToken,
Satya Tangirala5b9e5b12021-03-09 12:54:21 -0800243 /// Checked when earlyBootEnded() is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700244 #[selinux(name = early_boot_ended)]
245 EarlyBootEnded,
Janis Danisevskis333b7c02021-03-23 18:57:41 -0700246 /// Checked when IKeystoreMaintenance::onDeviceOffBody is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700247 #[selinux(name = report_off_body)]
248 ReportOffBody,
249 /// Checked when IkeystoreMetrics::pullMetrics is called.
250 #[selinux(name = pull_metrics)]
251 PullMetrics,
Paul Crowley46c703e2021-08-06 15:13:53 -0700252 /// Checked when IKeystoreMaintenance::deleteAllKeys is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700253 #[selinux(name = delete_all_keys)]
254 DeleteAllKeys,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700255 }
256);
257
258/// Represents a set of `KeyPerm` permissions.
259/// `IntoIterator` is implemented for this struct allowing the iteration through all the
260/// permissions in the set.
261/// It also implements a function `includes(self, other)` that checks if the permissions
262/// in `other` are included in `self`.
263///
264/// KeyPermSet can be created with the macro `key_perm_set![]`.
265///
266/// ## Example
267/// ```
268/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
269/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
270///
271/// assert!(perms1.includes(perms2))
272/// assert!(!perms2.includes(perms1))
273///
274/// let i = perms1.into_iter();
275/// // iteration in ascending order of the permission's numeric representation.
276/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
277/// assert_eq(Some(KeyPerm::grant()), i.next());
278/// assert_eq(Some(KeyPerm::use_()), i.next());
279/// assert_eq(None, i.next());
280/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700281#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
282pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700283
284mod perm {
285 use super::*;
286
287 pub struct IntoIter {
288 vec: KeyPermSet,
289 pos: u8,
290 }
291
292 impl IntoIter {
293 pub fn new(v: KeyPermSet) -> Self {
294 Self { vec: v, pos: 0 }
295 }
296 }
297
298 impl std::iter::Iterator for IntoIter {
299 type Item = KeyPerm;
300
301 fn next(&mut self) -> Option<Self::Item> {
302 loop {
303 if self.pos == 32 {
304 return None;
305 }
306 let p = self.vec.0 & (1 << self.pos);
307 self.pos += 1;
308 if p != 0 {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700309 return Some(KeyPerm::from(KeyPermission(p)));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700310 }
311 }
312 }
313 }
314}
315
316impl From<KeyPerm> for KeyPermSet {
317 fn from(p: KeyPerm) -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700318 Self((p.0).0 as i32)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700319 }
320}
321
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700322/// allow conversion from the AIDL wire type i32 to a permission set.
323impl From<i32> for KeyPermSet {
324 fn from(p: i32) -> Self {
325 Self(p)
326 }
327}
328
329impl From<KeyPermSet> for i32 {
330 fn from(p: KeyPermSet) -> i32 {
331 p.0
332 }
333}
334
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700335impl KeyPermSet {
336 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700337 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700338 let o: KeyPermSet = other.into();
339 (self.0 & o.0) == o.0
340 }
341}
342
343/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
344///
345/// ## Example
346/// ```
347/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
348/// ```
349#[macro_export]
350macro_rules! key_perm_set {
351 () => { KeyPermSet(0) };
352 ($head:expr $(, $tail:expr)* $(,)?) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700353 KeyPermSet(($head.0).0 $(| ($tail.0).0)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700354 };
355}
356
357impl IntoIterator for KeyPermSet {
358 type Item = KeyPerm;
359 type IntoIter = perm::IntoIter;
360
361 fn into_iter(self) -> Self::IntoIter {
362 Self::IntoIter::new(self)
363 }
364}
365
366/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
367/// the given permision `perm` of the `keystore2` security class.
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700368pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700369 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
370 selinux::check_access(caller_ctx, &target_context, "keystore2", perm.to_selinux())
371}
372
373/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` has
374/// all the permissions indicated in `access_vec` for the target domain indicated by the key
375/// descriptor `key` in the security class `keystore2_key`.
376///
377/// Also checks if the caller has the grant permission for the given target domain.
378///
379/// Attempts to grant the grant permission are always denied.
380///
381/// The only viable target domains are
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700382/// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
383/// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700384/// SELinux keystore key backend, and the result is used
385/// as target context.
386pub fn check_grant_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700387 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700388 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700389 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700390) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700391 let target_context = match key.domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700392 Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
393 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
394 .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700395 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
396 };
397
398 selinux::check_access(caller_ctx, &target_context, "keystore2_key", "grant")
399 .context("Grant permission is required when granting.")?;
400
401 if access_vec.includes(KeyPerm::grant()) {
402 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
403 }
404
405 for p in access_vec.into_iter() {
406 selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800407 .context(format!(
408 concat!(
409 "check_grant_permission: check_access failed. ",
410 "The caller may have tried to grant a permission that they don't possess. {:?}"
411 ),
412 p
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700413 ))?
414 }
415 Ok(())
416}
417
418/// Uses `selinux::check_access` to check if the given caller context `caller_cxt`
419/// has the permissions indicated by `perm` for the target domain indicated by the key
420/// descriptor `key` in the security class `keystore2_key`.
421///
422/// The behavior differs slightly depending on the selected target domain:
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700423/// * `Domain::APP` u:r:keystore:s0 is used as target context.
424/// * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700425/// backend, and the result is used as target context.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700426/// * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700427/// to the one supplied in `perm`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700428/// * `Domain::GRANT` Does not use selinux::check_access. Instead the `access_vector`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700429/// parameter is queried for permission, which must be supplied in this case.
430///
431/// ## Return values.
432/// * Ok(()) If the requested permissions were granted.
433/// * Err(selinux::Error::perm()) If the requested permissions were denied.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700434/// * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
435/// was supplied. It is also produced if `Domain::KEY_ID` was selected, and
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700436/// on various unexpected backend failures.
437pub fn check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800438 caller_uid: u32,
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700439 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700440 perm: KeyPerm,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700441 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700442 access_vector: &Option<KeyPermSet>,
443) -> anyhow::Result<()> {
Janis Danisevskis45760022021-01-19 16:34:10 -0800444 // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID.
445 // In the former case, key.domain was set to GRANT and we check the failure cases
446 // further below. If the access is requested by KEY_ID, key.domain would have been
447 // resolved to APP or SELINUX depending on where the key actually resides.
448 // Either way we can return here immediately if the access vector covers the requested
449 // permission. If it does not, we can still check if the caller has access by means of
450 // ownership.
451 if let Some(access_vector) = access_vector {
452 if access_vector.includes(perm) {
453 return Ok(());
454 }
455 }
456
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700457 let target_context = match key.domain {
458 // apps get the default keystore context
Janis Danisevskis45760022021-01-19 16:34:10 -0800459 Domain::APP => {
460 if caller_uid as i64 != key.nspace {
461 return Err(selinux::Error::perm())
462 .context("Trying to access key without ownership.");
463 }
464 getcon().context("check_key_permission: getcon failed.")?
465 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700466 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
467 .context("check_key_permission: Domain::SELINUX: Failed to lookup namespace.")?,
468 Domain::GRANT => {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700469 match access_vector {
Janis Danisevskis45760022021-01-19 16:34:10 -0800470 Some(_) => {
471 return Err(selinux::Error::perm())
472 .context(format!("\"{}\" not granted", perm.to_selinux()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700473 }
474 None => {
475 // If DOMAIN_GRANT was selected an access vector must be supplied.
476 return Err(KsError::sys()).context(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700477 "Cannot check permission for Domain::GRANT without access vector.",
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700478 );
479 }
480 }
481 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700482 Domain::KEY_ID => {
483 // We should never be called with `Domain::KEY_ID. The database
484 // lookup should have converted this into one of `Domain::APP`
485 // or `Domain::SELINUX`.
486 return Err(KsError::sys()).context("Cannot check permission for Domain::KEY_ID.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700487 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700488 Domain::BLOB => {
489 let tctx = lookup_keystore2_key_context(key.nspace)
490 .context("Domain::BLOB: Failed to lookup namespace.")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700491 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
492 // permission in addition to the requested permission.
493 selinux::check_access(
494 caller_ctx,
495 &tctx,
496 "keystore2_key",
497 KeyPerm::manage_blob().to_selinux(),
498 )?;
499
500 tctx
501 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700502 _ => {
503 return Err(KsError::sys())
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700504 .context(format!("Unknown domain value: \"{:?}\".", key.domain))
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700505 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700506 };
507
508 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
509}
510
511#[cfg(test)]
512mod tests {
513 use super::*;
514 use anyhow::anyhow;
515 use anyhow::Result;
516 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700517
518 const ALL_PERMS: KeyPermSet = key_perm_set![
519 KeyPerm::manage_blob(),
520 KeyPerm::delete(),
521 KeyPerm::use_dev_id(),
522 KeyPerm::req_forced_op(),
523 KeyPerm::gen_unique_id(),
524 KeyPerm::grant(),
525 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700526 KeyPerm::rebind(),
527 KeyPerm::update(),
528 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800529 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700530 ];
531
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800532 const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
533 KeyPerm::delete(),
534 KeyPerm::use_dev_id(),
535 // No KeyPerm::grant()
536 KeyPerm::get_info(),
537 KeyPerm::rebind(),
538 KeyPerm::update(),
539 KeyPerm::use_(),
540 ];
541
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700542 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
543 KeyPerm::manage_blob(),
544 KeyPerm::delete(),
545 KeyPerm::use_dev_id(),
546 KeyPerm::req_forced_op(),
547 KeyPerm::gen_unique_id(),
548 // No KeyPerm::grant()
549 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700550 KeyPerm::rebind(),
551 KeyPerm::update(),
552 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800553 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700554 ];
555
556 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
557 KeyPerm::delete(),
558 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700559 KeyPerm::rebind(),
560 KeyPerm::update(),
561 KeyPerm::use_(),
562 ];
563
564 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
565 /// SePolicy (system/sepolicy).
566 const SU_KEY_NAMESPACE: i32 = 0;
567 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
568 /// SePolicy (system/sepolicy).
569 const SHELL_KEY_NAMESPACE: i32 = 1;
570
571 pub fn test_getcon() -> Result<Context> {
572 Context::new("u:object_r:keystore:s0")
573 }
574
575 // This macro evaluates the given expression and checks that
576 // a) evaluated to Result::Err() and that
577 // b) the wrapped error is selinux::Error::perm() (permission denied).
578 // We use a macro here because a function would mask which invocation caused the failure.
579 //
580 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
581 macro_rules! assert_perm_failed {
582 ($test_function:expr) => {
583 let result = $test_function;
584 assert!(result.is_err(), "Permission check should have failed.");
585 assert_eq!(
586 Some(&selinux::Error::perm()),
587 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
588 );
589 };
590 }
591
592 fn check_context() -> Result<(selinux::Context, i32, bool)> {
593 // Calling the non mocked selinux::getcon here intended.
594 let context = selinux::getcon()?;
595 match context.to_str().unwrap() {
596 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
597 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
598 c => Err(anyhow!(format!(
599 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
600 c
601 ))),
602 }
603 }
604
605 #[test]
606 fn check_keystore_permission_test() -> Result<()> {
607 let system_server_ctx = Context::new("u:r:system_server:s0")?;
608 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
609 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
610 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
611 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
612 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
613 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000614 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::change_user()).is_ok());
615 assert!(
616 check_keystore_permission(&system_server_ctx, KeystorePerm::change_password()).is_ok()
617 );
618 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_uid()).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700619 let shell_ctx = Context::new("u:r:shell:s0")?;
620 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
621 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
Janis Danisevskis1bb595e2021-03-16 10:09:08 -0700622 assert!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()).is_ok());
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700623 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::list()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700624 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
625 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
626 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000627 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_user()));
628 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_password()));
629 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_uid()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700630 Ok(())
631 }
632
633 #[test]
634 fn check_grant_permission_app() -> Result<()> {
635 let system_server_ctx = Context::new("u:r:system_server:s0")?;
636 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700637 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800638 check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
639 .expect("Grant permission check failed.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700640
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800641 // attempts to grant the grant permission must always fail even when privileged.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700642 assert_perm_failed!(check_grant_permission(
643 &system_server_ctx,
644 KeyPerm::grant().into(),
645 &key
646 ));
647 // unprivileged grant attempts always fail. shell does not have the grant permission.
648 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
649 Ok(())
650 }
651
652 #[test]
653 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700654 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700655 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700656 domain: Domain::SELINUX,
657 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700658 alias: None,
659 blob: None,
660 };
661 if is_su {
662 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
663 // attempts to grant the grant permission must always fail even when privileged.
664 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
665 } else {
666 // unprivileged grant attempts always fail. shell does not have the grant permission.
667 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
668 }
669 Ok(())
670 }
671
672 #[test]
673 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700674 let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700675
676 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800677 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700678 &selinux::Context::new("ignored").unwrap(),
679 KeyPerm::grant(),
680 &key,
681 &Some(UNPRIV_PERMS)
682 ));
683
684 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800685 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700686 &selinux::Context::new("ignored").unwrap(),
687 KeyPerm::use_(),
688 &key,
689 &Some(ALL_PERMS),
690 )
691 }
692
693 #[test]
694 fn check_key_permission_domain_app() -> Result<()> {
695 let system_server_ctx = Context::new("u:r:system_server:s0")?;
696 let shell_ctx = Context::new("u:r:shell:s0")?;
697 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700698
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700699 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700700
Janis Danisevskis45760022021-01-19 16:34:10 -0800701 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
702 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700703 assert!(
Janis Danisevskis45760022021-01-19 16:34:10 -0800704 check_key_permission(0, &system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok()
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700705 );
Janis Danisevskis45760022021-01-19 16:34:10 -0800706 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
707 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
708 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
709 assert!(
710 check_key_permission(0, &system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
711 );
712 assert!(
713 check_key_permission(0, &gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok()
714 );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700715
Janis Danisevskis45760022021-01-19 16:34:10 -0800716 assert!(check_key_permission(0, &shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
717 assert!(check_key_permission(0, &shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
718 assert!(check_key_permission(0, &shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
719 assert!(check_key_permission(0, &shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
720 assert!(check_key_permission(0, &shell_ctx, KeyPerm::update(), &key, &None).is_ok());
721 assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::grant(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700722 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800723 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700724 &shell_ctx,
725 KeyPerm::req_forced_op(),
726 &key,
727 &None
728 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700729 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800730 0,
731 &shell_ctx,
732 KeyPerm::manage_blob(),
733 &key,
734 &None
735 ));
736 assert_perm_failed!(check_key_permission(
737 0,
738 &shell_ctx,
739 KeyPerm::use_dev_id(),
740 &key,
741 &None
742 ));
743 assert_perm_failed!(check_key_permission(
744 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700745 &shell_ctx,
746 KeyPerm::gen_unique_id(),
747 &key,
748 &None
749 ));
750
Janis Danisevskis45760022021-01-19 16:34:10 -0800751 // Also make sure that the permission fails if the caller is not the owner.
752 assert_perm_failed!(check_key_permission(
753 1, // the owner is 0
754 &system_server_ctx,
755 KeyPerm::use_(),
756 &key,
757 &None
758 ));
759 // Unless there was a grant.
760 assert!(check_key_permission(
761 1,
762 &system_server_ctx,
763 KeyPerm::use_(),
764 &key,
765 &Some(key_perm_set![KeyPerm::use_()])
766 )
767 .is_ok());
768 // But fail if the grant did not cover the requested permission.
769 assert_perm_failed!(check_key_permission(
770 1,
771 &system_server_ctx,
772 KeyPerm::use_(),
773 &key,
774 &Some(key_perm_set![KeyPerm::get_info()])
775 ));
776
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700777 Ok(())
778 }
779
780 #[test]
781 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700782 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700783 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700784 domain: Domain::SELINUX,
785 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700786 alias: None,
787 blob: None,
788 };
789
Chris Wailes3877f292021-07-26 19:24:18 -0700790 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
791 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
792 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
793 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
794 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
795
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700796 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800797 assert!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None).is_ok());
798 assert!(check_key_permission(0, &sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
799 assert!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
800 assert!(check_key_permission(0, &sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
801 assert!(check_key_permission(0, &sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700802 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800803 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None));
804 assert_perm_failed!(check_key_permission(
805 0,
806 &sctx,
807 KeyPerm::req_forced_op(),
808 &key,
809 &None
810 ));
811 assert_perm_failed!(check_key_permission(
812 0,
813 &sctx,
814 KeyPerm::manage_blob(),
815 &key,
816 &None
817 ));
818 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None));
819 assert_perm_failed!(check_key_permission(
820 0,
821 &sctx,
822 KeyPerm::gen_unique_id(),
823 &key,
824 &None
825 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700826 }
827 Ok(())
828 }
829
830 #[test]
831 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700832 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700833 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700834 domain: Domain::BLOB,
835 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700836 alias: None,
837 blob: None,
838 };
839
840 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800841 check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700842 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800843 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700844 Ok(())
845 }
846 }
847
848 #[test]
849 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700850 let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700851
852 assert_eq!(
853 Some(&KsError::sys()),
854 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800855 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700856 &selinux::Context::new("ignored").unwrap(),
857 KeyPerm::use_(),
858 &key,
859 &None
860 )
861 .err()
862 .unwrap()
863 .root_cause()
864 .downcast_ref::<KsError>()
865 );
866 Ok(())
867 }
868
869 #[test]
870 fn key_perm_set_all_test() {
871 let v = key_perm_set![
872 KeyPerm::manage_blob(),
873 KeyPerm::delete(),
874 KeyPerm::use_dev_id(),
875 KeyPerm::req_forced_op(),
876 KeyPerm::gen_unique_id(),
877 KeyPerm::grant(),
878 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700879 KeyPerm::rebind(),
880 KeyPerm::update(),
881 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
882 ];
883 let mut i = v.into_iter();
884 assert_eq!(i.next().unwrap().to_selinux(), "delete");
885 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
886 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
887 assert_eq!(i.next().unwrap().to_selinux(), "grant");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700888 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
889 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
890 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
891 assert_eq!(i.next().unwrap().to_selinux(), "update");
892 assert_eq!(i.next().unwrap().to_selinux(), "use");
893 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
894 assert_eq!(None, i.next());
895 }
896 #[test]
897 fn key_perm_set_sparse_test() {
898 let v = key_perm_set![
899 KeyPerm::manage_blob(),
900 KeyPerm::req_forced_op(),
901 KeyPerm::gen_unique_id(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700902 KeyPerm::update(),
903 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
904 ];
905 let mut i = v.into_iter();
906 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700907 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
908 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
909 assert_eq!(i.next().unwrap().to_selinux(), "update");
910 assert_eq!(i.next().unwrap().to_selinux(), "use");
911 assert_eq!(None, i.next());
912 }
913 #[test]
914 fn key_perm_set_empty_test() {
915 let v = key_perm_set![];
916 let mut i = v.into_iter();
917 assert_eq!(None, i.next());
918 }
919 #[test]
920 fn key_perm_set_include_subset_test() {
921 let v1 = key_perm_set![
922 KeyPerm::manage_blob(),
923 KeyPerm::delete(),
924 KeyPerm::use_dev_id(),
925 KeyPerm::req_forced_op(),
926 KeyPerm::gen_unique_id(),
927 KeyPerm::grant(),
928 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700929 KeyPerm::rebind(),
930 KeyPerm::update(),
931 KeyPerm::use_(),
932 ];
933 let v2 = key_perm_set![
934 KeyPerm::manage_blob(),
935 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700936 KeyPerm::rebind(),
937 KeyPerm::update(),
938 KeyPerm::use_(),
939 ];
940 assert!(v1.includes(v2));
941 assert!(!v2.includes(v1));
942 }
943 #[test]
944 fn key_perm_set_include_equal_test() {
945 let v1 = key_perm_set![
946 KeyPerm::manage_blob(),
947 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700948 KeyPerm::rebind(),
949 KeyPerm::update(),
950 KeyPerm::use_(),
951 ];
952 let v2 = key_perm_set![
953 KeyPerm::manage_blob(),
954 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700955 KeyPerm::rebind(),
956 KeyPerm::update(),
957 KeyPerm::use_(),
958 ];
959 assert!(v1.includes(v2));
960 assert!(v2.includes(v1));
961 }
962 #[test]
963 fn key_perm_set_include_overlap_test() {
964 let v1 = key_perm_set![
965 KeyPerm::manage_blob(),
966 KeyPerm::delete(),
967 KeyPerm::grant(), // only in v1
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700968 KeyPerm::rebind(),
969 KeyPerm::update(),
970 KeyPerm::use_(),
971 ];
972 let v2 = key_perm_set![
973 KeyPerm::manage_blob(),
974 KeyPerm::delete(),
975 KeyPerm::req_forced_op(), // only in v2
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700976 KeyPerm::rebind(),
977 KeyPerm::update(),
978 KeyPerm::use_(),
979 ];
980 assert!(!v1.includes(v2));
981 assert!(!v2.includes(v1));
982 }
983 #[test]
984 fn key_perm_set_include_no_overlap_test() {
985 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
986 let v2 = key_perm_set![
987 KeyPerm::req_forced_op(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700988 KeyPerm::rebind(),
989 KeyPerm::update(),
990 KeyPerm::use_(),
991 ];
992 assert!(!v1.includes(v2));
993 assert!(!v2.includes(v1));
994 }
995}