blob: 0a8eec75bbb5108f8b3a788552a5db2d65661f5b [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;
Janis Danisevskis56af0312021-10-18 16:11:41 -070028use selinux::{implement_class, Backend, ClassPermission};
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.
Janis Danisevskis56af0312021-10-18 16:11:41 -070067/// * `MyPerm.name()(&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
Janis Danisevskis56af0312021-10-18 16:11:41 -070072/// constructor function (e.g. `MePerm::use_()`) but the string returned by `name()` will
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070073/// 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
Janis Danisevskis56af0312021-10-18 16:11:41 -0700152 impl ClassPermission for $name {
153 fn name(&self) -> &'static str {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700154 match self {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700155 Self($aidl_name::$def_name) => stringify!($def_selinux_name),
156 $(Self($aidl_name::$element_name) => stringify!($selinux_name),)*
157 _ => stringify!($def_selinux_name),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700158 }
159 }
Janis Danisevskis56af0312021-10-18 16:11:41 -0700160 fn class_name(&self) -> &'static str {
161 "keystore2_key"
162 }
163 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700164
Janis Danisevskis56af0312021-10-18 16:11:41 -0700165 impl $name {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700166 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700167 pub const fn $def_selinux_name() -> Self { Self($aidl_name::$def_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700168 $(
169 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700170 pub const fn $element_identifier() -> Self { Self($aidl_name::$element_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700171 )*
172 }
173 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700174}
175
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700176implement_permission_aidl!(
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700177 /// KeyPerm provides a convenient abstraction from the SELinux class `keystore2_key`.
178 /// At the same time it maps `KeyPermissions` from the Keystore 2.0 AIDL Grant interface to
179 /// the SELinux permissions. With the implement_permission macro, we conveniently
180 /// provide mappings between the wire type bit field values, the rust enum and the SELinux
181 /// string representation.
182 ///
183 /// ## Example
184 ///
185 /// In this access check `KeyPerm::get_info().to_selinux()` would return the SELinux representation
186 /// "info".
187 /// ```
Janis Danisevskis56af0312021-10-18 16:11:41 -0700188 /// selinux::check_permission(source_context, target_context, KeyPerm::get_info());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700189 /// ```
190 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700191 KeyPerm from KeyPermission with default (NONE, none) {
Satya Tangirala3361b612021-03-08 14:36:11 -0800192 CONVERT_STORAGE_KEY_TO_EPHEMERAL, selinux name: convert_storage_key_to_ephemeral;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700193 DELETE, selinux name: delete;
194 GEN_UNIQUE_ID, selinux name: gen_unique_id;
195 GET_INFO, selinux name: get_info;
196 GRANT, selinux name: grant;
197 MANAGE_BLOB, selinux name: manage_blob;
198 REBIND, selinux name: rebind;
199 REQ_FORCED_OP, selinux name: req_forced_op;
200 UPDATE, selinux name: update;
201 USE, selinux name: use;
202 USE_DEV_ID, selinux name: use_dev_id;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700203 }
204);
205
Janis Danisevskis56af0312021-10-18 16:11:41 -0700206implement_class!(
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700207 /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
208 /// Using the implement_permission macro we get the same features as `KeyPerm`.
Janis Danisevskis56af0312021-10-18 16:11:41 -0700209 #[selinux(class_name = keystore2)]
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700210 #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700211 pub enum KeystorePerm {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700212 /// Checked when a new auth token is installed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700213 #[selinux(name = add_auth)]
214 AddAuth,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700215 /// Checked when an app is uninstalled or wiped.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700216 #[selinux(name = clear_ns)]
217 ClearNs,
Hasini Gunasinghe9ee18412021-03-11 20:12:44 +0000218 /// Checked when the user state is queried from Keystore 2.0.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700219 #[selinux(name = get_state)]
220 GetState,
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700221 /// Checked when Keystore 2.0 is asked to list a namespace that the caller
222 /// does not have the get_info permission for.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700223 #[selinux(name = list)]
224 List,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700225 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700226 #[selinux(name = lock)]
227 Lock,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700228 /// Checked when Keystore 2.0 shall be reset.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700229 #[selinux(name = reset)]
230 Reset,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700231 /// Checked when Keystore 2.0 shall be unlocked.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700232 #[selinux(name = unlock)]
233 Unlock,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000234 /// Checked when user is added or removed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700235 #[selinux(name = change_user)]
236 ChangeUser,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000237 /// Checked when password of the user is changed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700238 #[selinux(name = change_password)]
239 ChangePassword,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000240 /// Checked when a UID is cleared.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700241 #[selinux(name = clear_uid)]
242 ClearUID,
Hasini Gunasinghe5fc95252020-12-04 00:35:08 +0000243 /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700244 #[selinux(name = get_auth_token)]
245 GetAuthToken,
Satya Tangirala5b9e5b12021-03-09 12:54:21 -0800246 /// Checked when earlyBootEnded() is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700247 #[selinux(name = early_boot_ended)]
248 EarlyBootEnded,
Janis Danisevskis333b7c02021-03-23 18:57:41 -0700249 /// Checked when IKeystoreMaintenance::onDeviceOffBody is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700250 #[selinux(name = report_off_body)]
251 ReportOffBody,
252 /// Checked when IkeystoreMetrics::pullMetrics is called.
253 #[selinux(name = pull_metrics)]
254 PullMetrics,
Paul Crowley46c703e2021-08-06 15:13:53 -0700255 /// Checked when IKeystoreMaintenance::deleteAllKeys is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700256 #[selinux(name = delete_all_keys)]
257 DeleteAllKeys,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700258 }
259);
260
261/// Represents a set of `KeyPerm` permissions.
262/// `IntoIterator` is implemented for this struct allowing the iteration through all the
263/// permissions in the set.
264/// It also implements a function `includes(self, other)` that checks if the permissions
265/// in `other` are included in `self`.
266///
267/// KeyPermSet can be created with the macro `key_perm_set![]`.
268///
269/// ## Example
270/// ```
271/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
272/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
273///
274/// assert!(perms1.includes(perms2))
275/// assert!(!perms2.includes(perms1))
276///
277/// let i = perms1.into_iter();
278/// // iteration in ascending order of the permission's numeric representation.
279/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
280/// assert_eq(Some(KeyPerm::grant()), i.next());
281/// assert_eq(Some(KeyPerm::use_()), i.next());
282/// assert_eq(None, i.next());
283/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700284#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
285pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700286
287mod perm {
288 use super::*;
289
290 pub struct IntoIter {
291 vec: KeyPermSet,
292 pos: u8,
293 }
294
295 impl IntoIter {
296 pub fn new(v: KeyPermSet) -> Self {
297 Self { vec: v, pos: 0 }
298 }
299 }
300
301 impl std::iter::Iterator for IntoIter {
302 type Item = KeyPerm;
303
304 fn next(&mut self) -> Option<Self::Item> {
305 loop {
306 if self.pos == 32 {
307 return None;
308 }
309 let p = self.vec.0 & (1 << self.pos);
310 self.pos += 1;
311 if p != 0 {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700312 return Some(KeyPerm::from(KeyPermission(p)));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700313 }
314 }
315 }
316 }
317}
318
319impl From<KeyPerm> for KeyPermSet {
320 fn from(p: KeyPerm) -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700321 Self((p.0).0 as i32)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700322 }
323}
324
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700325/// allow conversion from the AIDL wire type i32 to a permission set.
326impl From<i32> for KeyPermSet {
327 fn from(p: i32) -> Self {
328 Self(p)
329 }
330}
331
332impl From<KeyPermSet> for i32 {
333 fn from(p: KeyPermSet) -> i32 {
334 p.0
335 }
336}
337
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700338impl KeyPermSet {
339 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700340 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700341 let o: KeyPermSet = other.into();
342 (self.0 & o.0) == o.0
343 }
344}
345
346/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
347///
348/// ## Example
349/// ```
350/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
351/// ```
352#[macro_export]
353macro_rules! key_perm_set {
354 () => { KeyPermSet(0) };
355 ($head:expr $(, $tail:expr)* $(,)?) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700356 KeyPermSet(($head.0).0 $(| ($tail.0).0)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700357 };
358}
359
360impl IntoIterator for KeyPermSet {
361 type Item = KeyPerm;
362 type IntoIter = perm::IntoIter;
363
364 fn into_iter(self) -> Self::IntoIter {
365 Self::IntoIter::new(self)
366 }
367}
368
Janis Danisevskis56af0312021-10-18 16:11:41 -0700369/// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` may access
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700370/// the given permision `perm` of the `keystore2` security class.
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700371pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700372 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
Janis Danisevskis56af0312021-10-18 16:11:41 -0700373 selinux::check_permission(caller_ctx, &target_context, perm)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700374}
375
Janis Danisevskis56af0312021-10-18 16:11:41 -0700376/// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` has
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700377/// all the permissions indicated in `access_vec` for the target domain indicated by the key
378/// descriptor `key` in the security class `keystore2_key`.
379///
380/// Also checks if the caller has the grant permission for the given target domain.
381///
382/// Attempts to grant the grant permission are always denied.
383///
384/// The only viable target domains are
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700385/// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
386/// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700387/// SELinux keystore key backend, and the result is used
388/// as target context.
389pub fn check_grant_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700390 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700391 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700392 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700393) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700394 let target_context = match key.domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700395 Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
396 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
397 .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700398 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
399 };
400
Janis Danisevskis56af0312021-10-18 16:11:41 -0700401 selinux::check_permission(caller_ctx, &target_context, KeyPerm::grant())
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700402 .context("Grant permission is required when granting.")?;
403
404 if access_vec.includes(KeyPerm::grant()) {
405 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
406 }
407
408 for p in access_vec.into_iter() {
Janis Danisevskis56af0312021-10-18 16:11:41 -0700409 selinux::check_permission(caller_ctx, &target_context, p).context(format!(
410 "check_grant_permission: check_permission failed. \
411 The caller may have tried to grant a permission that they don't possess. {:?}",
412 p
413 ))?
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700414 }
415 Ok(())
416}
417
Janis Danisevskis56af0312021-10-18 16:11:41 -0700418/// Uses `selinux::check_permission` to check if the given caller context `caller_cxt`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700419/// 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 Danisevskis56af0312021-10-18 16:11:41 -0700428/// * `Domain::GRANT` Does not use selinux::check_permission. 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())
Janis Danisevskis56af0312021-10-18 16:11:41 -0700472 .context(format!("\"{}\" not granted", perm.name()));
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.
Janis Danisevskis56af0312021-10-18 16:11:41 -0700493 selinux::check_permission(caller_ctx, &tctx, KeyPerm::manage_blob())?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700494
495 tctx
496 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700497 _ => {
498 return Err(KsError::sys())
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700499 .context(format!("Unknown domain value: \"{:?}\".", key.domain))
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700500 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700501 };
502
Janis Danisevskis56af0312021-10-18 16:11:41 -0700503 selinux::check_permission(caller_ctx, &target_context, perm)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700504}
505
506#[cfg(test)]
507mod tests {
508 use super::*;
509 use anyhow::anyhow;
510 use anyhow::Result;
511 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700512
513 const ALL_PERMS: KeyPermSet = key_perm_set![
514 KeyPerm::manage_blob(),
515 KeyPerm::delete(),
516 KeyPerm::use_dev_id(),
517 KeyPerm::req_forced_op(),
518 KeyPerm::gen_unique_id(),
519 KeyPerm::grant(),
520 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700521 KeyPerm::rebind(),
522 KeyPerm::update(),
523 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800524 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700525 ];
526
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800527 const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
528 KeyPerm::delete(),
529 KeyPerm::use_dev_id(),
530 // No KeyPerm::grant()
531 KeyPerm::get_info(),
532 KeyPerm::rebind(),
533 KeyPerm::update(),
534 KeyPerm::use_(),
535 ];
536
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700537 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
538 KeyPerm::manage_blob(),
539 KeyPerm::delete(),
540 KeyPerm::use_dev_id(),
541 KeyPerm::req_forced_op(),
542 KeyPerm::gen_unique_id(),
543 // No KeyPerm::grant()
544 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700545 KeyPerm::rebind(),
546 KeyPerm::update(),
547 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800548 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700549 ];
550
551 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
552 KeyPerm::delete(),
553 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700554 KeyPerm::rebind(),
555 KeyPerm::update(),
556 KeyPerm::use_(),
557 ];
558
559 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
560 /// SePolicy (system/sepolicy).
561 const SU_KEY_NAMESPACE: i32 = 0;
562 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
563 /// SePolicy (system/sepolicy).
564 const SHELL_KEY_NAMESPACE: i32 = 1;
565
566 pub fn test_getcon() -> Result<Context> {
567 Context::new("u:object_r:keystore:s0")
568 }
569
570 // This macro evaluates the given expression and checks that
571 // a) evaluated to Result::Err() and that
572 // b) the wrapped error is selinux::Error::perm() (permission denied).
573 // We use a macro here because a function would mask which invocation caused the failure.
574 //
575 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
576 macro_rules! assert_perm_failed {
577 ($test_function:expr) => {
578 let result = $test_function;
579 assert!(result.is_err(), "Permission check should have failed.");
580 assert_eq!(
581 Some(&selinux::Error::perm()),
582 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
583 );
584 };
585 }
586
587 fn check_context() -> Result<(selinux::Context, i32, bool)> {
588 // Calling the non mocked selinux::getcon here intended.
589 let context = selinux::getcon()?;
590 match context.to_str().unwrap() {
591 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
592 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
593 c => Err(anyhow!(format!(
594 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
595 c
596 ))),
597 }
598 }
599
600 #[test]
601 fn check_keystore_permission_test() -> Result<()> {
602 let system_server_ctx = Context::new("u:r:system_server:s0")?;
Janis Danisevskisa916d992021-10-19 15:46:09 -0700603 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::AddAuth).is_ok());
604 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearNs).is_ok());
605 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::GetState).is_ok());
606 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Lock).is_ok());
607 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Reset).is_ok());
608 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::Unlock).is_ok());
609 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangeUser).is_ok());
610 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ChangePassword).is_ok());
611 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::ClearUID).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700612 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskisa916d992021-10-19 15:46:09 -0700613 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::AddAuth));
614 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearNs));
615 assert!(check_keystore_permission(&shell_ctx, KeystorePerm::GetState).is_ok());
616 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::List));
617 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Lock));
618 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Reset));
619 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::Unlock));
620 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangeUser));
621 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ChangePassword));
622 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::ClearUID));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700623 Ok(())
624 }
625
626 #[test]
627 fn check_grant_permission_app() -> Result<()> {
628 let system_server_ctx = Context::new("u:r:system_server:s0")?;
629 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700630 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800631 check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
632 .expect("Grant permission check failed.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700633
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800634 // attempts to grant the grant permission must always fail even when privileged.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700635 assert_perm_failed!(check_grant_permission(
636 &system_server_ctx,
637 KeyPerm::grant().into(),
638 &key
639 ));
640 // unprivileged grant attempts always fail. shell does not have the grant permission.
641 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
642 Ok(())
643 }
644
645 #[test]
646 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700647 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700648 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700649 domain: Domain::SELINUX,
650 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700651 alias: None,
652 blob: None,
653 };
654 if is_su {
655 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
656 // attempts to grant the grant permission must always fail even when privileged.
657 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
658 } else {
659 // unprivileged grant attempts always fail. shell does not have the grant permission.
660 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
661 }
662 Ok(())
663 }
664
665 #[test]
666 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700667 let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700668
669 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800670 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700671 &selinux::Context::new("ignored").unwrap(),
672 KeyPerm::grant(),
673 &key,
674 &Some(UNPRIV_PERMS)
675 ));
676
677 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800678 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700679 &selinux::Context::new("ignored").unwrap(),
680 KeyPerm::use_(),
681 &key,
682 &Some(ALL_PERMS),
683 )
684 }
685
686 #[test]
687 fn check_key_permission_domain_app() -> Result<()> {
688 let system_server_ctx = Context::new("u:r:system_server:s0")?;
689 let shell_ctx = Context::new("u:r:shell:s0")?;
690 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700691
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700692 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700693
Janis Danisevskis45760022021-01-19 16:34:10 -0800694 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
695 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700696 assert!(
Janis Danisevskis45760022021-01-19 16:34:10 -0800697 check_key_permission(0, &system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok()
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700698 );
Janis Danisevskis45760022021-01-19 16:34:10 -0800699 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
700 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
701 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
702 assert!(
703 check_key_permission(0, &system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
704 );
705 assert!(
706 check_key_permission(0, &gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok()
707 );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700708
Janis Danisevskis45760022021-01-19 16:34:10 -0800709 assert!(check_key_permission(0, &shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
710 assert!(check_key_permission(0, &shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
711 assert!(check_key_permission(0, &shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
712 assert!(check_key_permission(0, &shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
713 assert!(check_key_permission(0, &shell_ctx, KeyPerm::update(), &key, &None).is_ok());
714 assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::grant(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700715 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800716 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700717 &shell_ctx,
718 KeyPerm::req_forced_op(),
719 &key,
720 &None
721 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700722 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800723 0,
724 &shell_ctx,
725 KeyPerm::manage_blob(),
726 &key,
727 &None
728 ));
729 assert_perm_failed!(check_key_permission(
730 0,
731 &shell_ctx,
732 KeyPerm::use_dev_id(),
733 &key,
734 &None
735 ));
736 assert_perm_failed!(check_key_permission(
737 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700738 &shell_ctx,
739 KeyPerm::gen_unique_id(),
740 &key,
741 &None
742 ));
743
Janis Danisevskis45760022021-01-19 16:34:10 -0800744 // Also make sure that the permission fails if the caller is not the owner.
745 assert_perm_failed!(check_key_permission(
746 1, // the owner is 0
747 &system_server_ctx,
748 KeyPerm::use_(),
749 &key,
750 &None
751 ));
752 // Unless there was a grant.
753 assert!(check_key_permission(
754 1,
755 &system_server_ctx,
756 KeyPerm::use_(),
757 &key,
758 &Some(key_perm_set![KeyPerm::use_()])
759 )
760 .is_ok());
761 // But fail if the grant did not cover the requested permission.
762 assert_perm_failed!(check_key_permission(
763 1,
764 &system_server_ctx,
765 KeyPerm::use_(),
766 &key,
767 &Some(key_perm_set![KeyPerm::get_info()])
768 ));
769
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700770 Ok(())
771 }
772
773 #[test]
774 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700775 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700776 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700777 domain: Domain::SELINUX,
778 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700779 alias: None,
780 blob: None,
781 };
782
Chris Wailes3877f292021-07-26 19:24:18 -0700783 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
784 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
785 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
786 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
787 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
788
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700789 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800790 assert!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None).is_ok());
791 assert!(check_key_permission(0, &sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
792 assert!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
793 assert!(check_key_permission(0, &sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
794 assert!(check_key_permission(0, &sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700795 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800796 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None));
797 assert_perm_failed!(check_key_permission(
798 0,
799 &sctx,
800 KeyPerm::req_forced_op(),
801 &key,
802 &None
803 ));
804 assert_perm_failed!(check_key_permission(
805 0,
806 &sctx,
807 KeyPerm::manage_blob(),
808 &key,
809 &None
810 ));
811 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None));
812 assert_perm_failed!(check_key_permission(
813 0,
814 &sctx,
815 KeyPerm::gen_unique_id(),
816 &key,
817 &None
818 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700819 }
820 Ok(())
821 }
822
823 #[test]
824 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700825 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700826 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700827 domain: Domain::BLOB,
828 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700829 alias: None,
830 blob: None,
831 };
832
833 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800834 check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700835 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800836 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700837 Ok(())
838 }
839 }
840
841 #[test]
842 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700843 let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700844
845 assert_eq!(
846 Some(&KsError::sys()),
847 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800848 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700849 &selinux::Context::new("ignored").unwrap(),
850 KeyPerm::use_(),
851 &key,
852 &None
853 )
854 .err()
855 .unwrap()
856 .root_cause()
857 .downcast_ref::<KsError>()
858 );
859 Ok(())
860 }
861
862 #[test]
863 fn key_perm_set_all_test() {
864 let v = key_perm_set![
865 KeyPerm::manage_blob(),
866 KeyPerm::delete(),
867 KeyPerm::use_dev_id(),
868 KeyPerm::req_forced_op(),
869 KeyPerm::gen_unique_id(),
870 KeyPerm::grant(),
871 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700872 KeyPerm::rebind(),
873 KeyPerm::update(),
874 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
875 ];
876 let mut i = v.into_iter();
Janis Danisevskis56af0312021-10-18 16:11:41 -0700877 assert_eq!(i.next().unwrap().name(), "delete");
878 assert_eq!(i.next().unwrap().name(), "gen_unique_id");
879 assert_eq!(i.next().unwrap().name(), "get_info");
880 assert_eq!(i.next().unwrap().name(), "grant");
881 assert_eq!(i.next().unwrap().name(), "manage_blob");
882 assert_eq!(i.next().unwrap().name(), "rebind");
883 assert_eq!(i.next().unwrap().name(), "req_forced_op");
884 assert_eq!(i.next().unwrap().name(), "update");
885 assert_eq!(i.next().unwrap().name(), "use");
886 assert_eq!(i.next().unwrap().name(), "use_dev_id");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700887 assert_eq!(None, i.next());
888 }
889 #[test]
890 fn key_perm_set_sparse_test() {
891 let v = key_perm_set![
892 KeyPerm::manage_blob(),
893 KeyPerm::req_forced_op(),
894 KeyPerm::gen_unique_id(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700895 KeyPerm::update(),
896 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
897 ];
898 let mut i = v.into_iter();
Janis Danisevskis56af0312021-10-18 16:11:41 -0700899 assert_eq!(i.next().unwrap().name(), "gen_unique_id");
900 assert_eq!(i.next().unwrap().name(), "manage_blob");
901 assert_eq!(i.next().unwrap().name(), "req_forced_op");
902 assert_eq!(i.next().unwrap().name(), "update");
903 assert_eq!(i.next().unwrap().name(), "use");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700904 assert_eq!(None, i.next());
905 }
906 #[test]
907 fn key_perm_set_empty_test() {
908 let v = key_perm_set![];
909 let mut i = v.into_iter();
910 assert_eq!(None, i.next());
911 }
912 #[test]
913 fn key_perm_set_include_subset_test() {
914 let v1 = key_perm_set![
915 KeyPerm::manage_blob(),
916 KeyPerm::delete(),
917 KeyPerm::use_dev_id(),
918 KeyPerm::req_forced_op(),
919 KeyPerm::gen_unique_id(),
920 KeyPerm::grant(),
921 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700922 KeyPerm::rebind(),
923 KeyPerm::update(),
924 KeyPerm::use_(),
925 ];
926 let v2 = key_perm_set![
927 KeyPerm::manage_blob(),
928 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700929 KeyPerm::rebind(),
930 KeyPerm::update(),
931 KeyPerm::use_(),
932 ];
933 assert!(v1.includes(v2));
934 assert!(!v2.includes(v1));
935 }
936 #[test]
937 fn key_perm_set_include_equal_test() {
938 let v1 = key_perm_set![
939 KeyPerm::manage_blob(),
940 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700941 KeyPerm::rebind(),
942 KeyPerm::update(),
943 KeyPerm::use_(),
944 ];
945 let v2 = 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 assert!(v1.includes(v2));
953 assert!(v2.includes(v1));
954 }
955 #[test]
956 fn key_perm_set_include_overlap_test() {
957 let v1 = key_perm_set![
958 KeyPerm::manage_blob(),
959 KeyPerm::delete(),
960 KeyPerm::grant(), // only in v1
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700961 KeyPerm::rebind(),
962 KeyPerm::update(),
963 KeyPerm::use_(),
964 ];
965 let v2 = key_perm_set![
966 KeyPerm::manage_blob(),
967 KeyPerm::delete(),
968 KeyPerm::req_forced_op(), // only in v2
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700969 KeyPerm::rebind(),
970 KeyPerm::update(),
971 KeyPerm::use_(),
972 ];
973 assert!(!v1.includes(v2));
974 assert!(!v2.includes(v1));
975 }
976 #[test]
977 fn key_perm_set_include_no_overlap_test() {
978 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
979 let v2 = key_perm_set![
980 KeyPerm::req_forced_op(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700981 KeyPerm::rebind(),
982 KeyPerm::update(),
983 KeyPerm::use_(),
984 ];
985 assert!(!v1.includes(v2));
986 assert!(!v2.includes(v1));
987 }
988}