blob: e7999bcb381baf2236198e6e26043a1e34230d85 [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 Danisevskisc5b210b2020-09-11 13:27:37 -070021use android_system_keystore2::aidl::android::system::keystore2::{
22 Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
23};
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070024
25use std::cmp::PartialEq;
26use std::convert::From;
Janis Danisevskis935e6c62020-08-18 12:52:27 -070027use std::ffi::CStr;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070028
29use crate::error::Error as KsError;
30use keystore2_selinux as selinux;
31
32use anyhow::Context as AnyhowContext;
33
34use selinux::Backend;
35
Janis Danisevskis4ad056f2020-08-05 19:46:46 +000036use lazy_static::lazy_static;
37
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070038// Replace getcon with a mock in the test situation
39#[cfg(not(test))]
40use selinux::getcon;
41#[cfg(test)]
42use tests::test_getcon as getcon;
43
Janis Danisevskis4ad056f2020-08-05 19:46:46 +000044lazy_static! {
45 // Panicking here is allowed because keystore cannot function without this backend
46 // and it would happen early and indicate a gross misconfiguration of the device.
47 static ref KEYSTORE2_KEY_LABEL_BACKEND: selinux::KeystoreKeyBackend =
48 selinux::KeystoreKeyBackend::new().unwrap();
49}
50
51fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> {
52 KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string())
53}
54
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070055/// ## Background
56///
57/// AIDL enums are represented as constants of the form:
58/// ```
59/// mod EnumName {
60/// pub type EnumName = i32;
61/// pub const Variant1: EnumName = <value1>;
62/// pub const Variant2: EnumName = <value2>;
63/// ...
64/// }
65///```
66/// This macro wraps the enum in a new type, e.g., `MyPerm` and maps each variant to an SELinux
67/// permission while providing the following interface:
68/// * From<EnumName> and Into<EnumName> are implemented. Where the implementation of From maps
69/// any variant not specified to the default.
70/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
71/// representation.
72/// * `MyPerm.to_selinux(&self)` returns the SELinux string representation of the
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070073/// represented permission.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070074///
75/// ## Special behavior
76/// If the keyword `use` appears as an selinux name `use_` is used as identifier for the
77/// constructor function (e.g. `MePerm::use_()`) but the string returned by `to_selinux` will
78/// still be `"use"`.
79///
80/// ## Example
81/// ```
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070082///
83/// implement_permission!(
84/// /// MyPerm documentation.
85/// #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070086/// MyPerm from EnumName with default (None, none) {}
87/// Variant1, selinux name: variant1;
88/// Variant2, selinux name: variant1;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070089/// }
90/// );
91/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070092macro_rules! implement_permission_aidl {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070093 // This rule provides the public interface of the macro. And starts the preprocessing
94 // recursion (see below).
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070095 ($(#[$m:meta])* $name:ident from $aidl_name:ident with default ($($def:tt)*)
96 { $($element:tt)* })
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070097 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070098 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*), [],
99 $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700100 };
101
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700102 // The following three rules recurse through the elements of the form
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700103 // `<enum variant>, selinux name: <selinux_name>;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700104 // preprocessing the input.
105
106 // The first rule terminates the recursion and passes the processed arguments to the final
107 // rule that spills out the implementation.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700108 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*], ) => {
109 implement_permission_aidl!(@end $($m)*, $name, $aidl_name, ($($def)*) { $($out)* } );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700110 };
111
112 // The second rule is triggered if the selinux name of an element is literally `use`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700113 // It produces the tuple `<enum variant>, use_, use;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700114 // and appends it to the out list.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700115 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*],
116 $e_name:ident, selinux name: use; $($element:tt)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700117 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700118 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*),
119 [$($out)* $e_name, use_, use;], $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700120 };
121
122 // The third rule is the default rule which replaces every input tuple with
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700123 // `<enum variant>, <selinux_name>, <selinux_name>;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700124 // and appends the result to the out list.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700125 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*],
126 $e_name:ident, selinux name: $e_str:ident; $($element:tt)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700127 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700128 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*),
129 [$($out)* $e_name, $e_str, $e_str;], $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700130 };
131
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700132 (@end $($m:meta)*, $name:ident, $aidl_name:ident,
133 ($def_name:ident, $def_selinux_name:ident) {
134 $($element_name:ident, $element_identifier:ident,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700135 $selinux_name:ident;)*
136 })
137 =>
138 {
139 $(#[$m])*
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700140 pub struct $name(pub $aidl_name);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700141
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700142 impl From<$aidl_name> for $name {
143 fn from (p: $aidl_name) -> Self {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700144 match p {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700145 $aidl_name::$def_name => Self($aidl_name::$def_name),
146 $($aidl_name::$element_name => Self($aidl_name::$element_name),)*
147 _ => Self($aidl_name::$def_name),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700148 }
149 }
150 }
151
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700152 impl From<$name> for $aidl_name {
153 fn from(p: $name) -> $aidl_name {
154 p.0
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700155 }
156 }
157
158 impl $name {
159 /// Returns a string representation of the permission as required by
160 /// `selinux::check_access`.
161 pub fn to_selinux(&self) -> &'static str {
162 match self {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700163 Self($aidl_name::$def_name) => stringify!($def_selinux_name),
164 $(Self($aidl_name::$element_name) => stringify!($selinux_name),)*
165 _ => stringify!($def_selinux_name),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700166 }
167 }
168
169 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700170 pub const fn $def_selinux_name() -> Self { Self($aidl_name::$def_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700171 $(
172 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700173 pub const fn $element_identifier() -> Self { Self($aidl_name::$element_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700174 )*
175 }
176 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700177}
178
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700179implement_permission_aidl!(
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700180 /// KeyPerm provides a convenient abstraction from the SELinux class `keystore2_key`.
181 /// At the same time it maps `KeyPermissions` from the Keystore 2.0 AIDL Grant interface to
182 /// the SELinux permissions. With the implement_permission macro, we conveniently
183 /// provide mappings between the wire type bit field values, the rust enum and the SELinux
184 /// string representation.
185 ///
186 /// ## Example
187 ///
188 /// In this access check `KeyPerm::get_info().to_selinux()` would return the SELinux representation
189 /// "info".
190 /// ```
191 /// selinux::check_access(source_context, target_context, "keystore2_key",
192 /// KeyPerm::get_info().to_selinux());
193 /// ```
194 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700195 KeyPerm from KeyPermission with default (NONE, none) {
Satya Tangirala3361b612021-03-08 14:36:11 -0800196 CONVERT_STORAGE_KEY_TO_EPHEMERAL, selinux name: convert_storage_key_to_ephemeral;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700197 DELETE, selinux name: delete;
198 GEN_UNIQUE_ID, selinux name: gen_unique_id;
199 GET_INFO, selinux name: get_info;
200 GRANT, selinux name: grant;
201 MANAGE_BLOB, selinux name: manage_blob;
202 REBIND, selinux name: rebind;
203 REQ_FORCED_OP, selinux name: req_forced_op;
204 UPDATE, selinux name: update;
205 USE, selinux name: use;
206 USE_DEV_ID, selinux name: use_dev_id;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700207 }
208);
209
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700210/// This macro implements an enum with values mapped to SELinux permission names.
211/// The below example wraps the enum MyPermission in the tuple struct `MyPerm` and implements
212/// * From<i32> and Into<i32> are implemented. Where the implementation of From maps
213/// any variant not specified to the default.
214/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
215/// representation.
216/// * `MyPerm.to_selinux(&self)` returns the SELinux string representation of the
217/// represented permission.
218///
219/// ## Example
220/// ```
221/// implement_permission!(
222/// /// MyPerm documentation.
223/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
224/// MyPerm with default (None = 0, none) {
225/// Foo = 1, selinux name: foo;
226/// Bar = 2, selinux name: bar;
227/// }
228/// );
229/// ```
230macro_rules! implement_permission {
231 // This rule provides the public interface of the macro. And starts the preprocessing
232 // recursion (see below).
233 ($(#[$m:meta])* $name:ident with default
234 ($def_name:ident = $def_val:expr, $def_selinux_name:ident)
235 {
236 $($(#[$element_meta:meta])*
237 $element_name:ident = $element_val:expr, selinux name: $selinux_name:ident;)*
238 })
239 => {
240 $(#[$m])*
241 pub enum $name {
242 /// The default variant of an enum.
243 $def_name = $def_val,
244 $(
245 $(#[$element_meta])*
246 $element_name = $element_val,
247 )*
248 }
249
250 impl From<i32> for $name {
251 fn from (p: i32) -> Self {
252 match p {
253 $def_val => Self::$def_name,
254 $($element_val => Self::$element_name,)*
255 _ => Self::$def_name,
256 }
257 }
258 }
259
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700260 impl From<$name> for i32 {
261 fn from(p: $name) -> i32 {
262 p as i32
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700263 }
264 }
265
266 impl $name {
267 /// Returns a string representation of the permission as required by
268 /// `selinux::check_access`.
269 pub fn to_selinux(&self) -> &'static str {
270 match self {
271 Self::$def_name => stringify!($def_selinux_name),
272 $(Self::$element_name => stringify!($selinux_name),)*
273 }
274 }
275
276 /// Creates an instance representing a permission with the same name.
277 pub const fn $def_selinux_name() -> Self { Self::$def_name }
278 $(
279 /// Creates an instance representing a permission with the same name.
280 pub const fn $selinux_name() -> Self { Self::$element_name }
281 )*
282 }
283 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700284}
285
286implement_permission!(
287 /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
288 /// Using the implement_permission macro we get the same features as `KeyPerm`.
289 #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700290 KeystorePerm with default (None = 0, none) {
291 /// Checked when a new auth token is installed.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700292 AddAuth = 1, selinux name: add_auth;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700293 /// Checked when an app is uninstalled or wiped.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700294 ClearNs = 2, selinux name: clear_ns;
Hasini Gunasinghe9ee18412021-03-11 20:12:44 +0000295 /// Checked when the user state is queried from Keystore 2.0.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700296 GetState = 4, selinux name: get_state;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700297 /// Checked when Keystore 2.0 is asked to list a namespace that the caller
298 /// does not have the get_info permission for.
299 List = 8, selinux name: list;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700300 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700301 Lock = 0x10, selinux name: lock;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700302 /// Checked when Keystore 2.0 shall be reset.
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000303 Reset = 0x20, selinux name: reset;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700304 /// Checked when Keystore 2.0 shall be unlocked.
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000305 Unlock = 0x40, selinux name: unlock;
306 /// Checked when user is added or removed.
307 ChangeUser = 0x80, selinux name: change_user;
308 /// Checked when password of the user is changed.
309 ChangePassword = 0x100, selinux name: change_password;
310 /// Checked when a UID is cleared.
311 ClearUID = 0x200, selinux name: clear_uid;
Hasini Gunasinghe5fc95252020-12-04 00:35:08 +0000312 /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens.
313 GetAuthToken = 0x400, selinux name: get_auth_token;
Satya Tangirala5b9e5b12021-03-09 12:54:21 -0800314 /// Checked when earlyBootEnded() is called.
315 EarlyBootEnded = 0x800, selinux name: early_boot_ended;
Janis Danisevskis333b7c02021-03-23 18:57:41 -0700316 /// Checked when IKeystoreMaintenance::onDeviceOffBody is called.
317 ReportOffBody = 0x1000, selinux name: report_off_body;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700318 }
319);
320
321/// Represents a set of `KeyPerm` permissions.
322/// `IntoIterator` is implemented for this struct allowing the iteration through all the
323/// permissions in the set.
324/// It also implements a function `includes(self, other)` that checks if the permissions
325/// in `other` are included in `self`.
326///
327/// KeyPermSet can be created with the macro `key_perm_set![]`.
328///
329/// ## Example
330/// ```
331/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
332/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
333///
334/// assert!(perms1.includes(perms2))
335/// assert!(!perms2.includes(perms1))
336///
337/// let i = perms1.into_iter();
338/// // iteration in ascending order of the permission's numeric representation.
339/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
340/// assert_eq(Some(KeyPerm::grant()), i.next());
341/// assert_eq(Some(KeyPerm::use_()), i.next());
342/// assert_eq(None, i.next());
343/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700344#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
345pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700346
347mod perm {
348 use super::*;
349
350 pub struct IntoIter {
351 vec: KeyPermSet,
352 pos: u8,
353 }
354
355 impl IntoIter {
356 pub fn new(v: KeyPermSet) -> Self {
357 Self { vec: v, pos: 0 }
358 }
359 }
360
361 impl std::iter::Iterator for IntoIter {
362 type Item = KeyPerm;
363
364 fn next(&mut self) -> Option<Self::Item> {
365 loop {
366 if self.pos == 32 {
367 return None;
368 }
369 let p = self.vec.0 & (1 << self.pos);
370 self.pos += 1;
371 if p != 0 {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700372 return Some(KeyPerm::from(KeyPermission(p)));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700373 }
374 }
375 }
376 }
377}
378
379impl From<KeyPerm> for KeyPermSet {
380 fn from(p: KeyPerm) -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700381 Self((p.0).0 as i32)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700382 }
383}
384
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700385/// allow conversion from the AIDL wire type i32 to a permission set.
386impl From<i32> for KeyPermSet {
387 fn from(p: i32) -> Self {
388 Self(p)
389 }
390}
391
392impl From<KeyPermSet> for i32 {
393 fn from(p: KeyPermSet) -> i32 {
394 p.0
395 }
396}
397
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700398impl KeyPermSet {
399 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700400 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700401 let o: KeyPermSet = other.into();
402 (self.0 & o.0) == o.0
403 }
404}
405
406/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
407///
408/// ## Example
409/// ```
410/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
411/// ```
412#[macro_export]
413macro_rules! key_perm_set {
414 () => { KeyPermSet(0) };
415 ($head:expr $(, $tail:expr)* $(,)?) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700416 KeyPermSet(($head.0).0 $(| ($tail.0).0)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700417 };
418}
419
420impl IntoIterator for KeyPermSet {
421 type Item = KeyPerm;
422 type IntoIter = perm::IntoIter;
423
424 fn into_iter(self) -> Self::IntoIter {
425 Self::IntoIter::new(self)
426 }
427}
428
429/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
430/// the given permision `perm` of the `keystore2` security class.
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700431pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700432 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
433 selinux::check_access(caller_ctx, &target_context, "keystore2", perm.to_selinux())
434}
435
436/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` has
437/// all the permissions indicated in `access_vec` for the target domain indicated by the key
438/// descriptor `key` in the security class `keystore2_key`.
439///
440/// Also checks if the caller has the grant permission for the given target domain.
441///
442/// Attempts to grant the grant permission are always denied.
443///
444/// The only viable target domains are
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700445/// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
446/// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700447/// SELinux keystore key backend, and the result is used
448/// as target context.
449pub fn check_grant_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700450 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700451 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700452 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700453) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700454 let target_context = match key.domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700455 Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
456 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
457 .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700458 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
459 };
460
461 selinux::check_access(caller_ctx, &target_context, "keystore2_key", "grant")
462 .context("Grant permission is required when granting.")?;
463
464 if access_vec.includes(KeyPerm::grant()) {
465 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
466 }
467
468 for p in access_vec.into_iter() {
469 selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800470 .context(format!(
471 concat!(
472 "check_grant_permission: check_access failed. ",
473 "The caller may have tried to grant a permission that they don't possess. {:?}"
474 ),
475 p
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700476 ))?
477 }
478 Ok(())
479}
480
481/// Uses `selinux::check_access` to check if the given caller context `caller_cxt`
482/// has the permissions indicated by `perm` for the target domain indicated by the key
483/// descriptor `key` in the security class `keystore2_key`.
484///
485/// The behavior differs slightly depending on the selected target domain:
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700486/// * `Domain::APP` u:r:keystore:s0 is used as target context.
487/// * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700488/// backend, and the result is used as target context.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700489/// * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700490/// to the one supplied in `perm`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700491/// * `Domain::GRANT` Does not use selinux::check_access. Instead the `access_vector`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700492/// parameter is queried for permission, which must be supplied in this case.
493///
494/// ## Return values.
495/// * Ok(()) If the requested permissions were granted.
496/// * Err(selinux::Error::perm()) If the requested permissions were denied.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700497/// * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
498/// was supplied. It is also produced if `Domain::KEY_ID` was selected, and
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700499/// on various unexpected backend failures.
500pub fn check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800501 caller_uid: u32,
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700502 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700503 perm: KeyPerm,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700504 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700505 access_vector: &Option<KeyPermSet>,
506) -> anyhow::Result<()> {
Janis Danisevskis45760022021-01-19 16:34:10 -0800507 // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID.
508 // In the former case, key.domain was set to GRANT and we check the failure cases
509 // further below. If the access is requested by KEY_ID, key.domain would have been
510 // resolved to APP or SELINUX depending on where the key actually resides.
511 // Either way we can return here immediately if the access vector covers the requested
512 // permission. If it does not, we can still check if the caller has access by means of
513 // ownership.
514 if let Some(access_vector) = access_vector {
515 if access_vector.includes(perm) {
516 return Ok(());
517 }
518 }
519
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700520 let target_context = match key.domain {
521 // apps get the default keystore context
Janis Danisevskis45760022021-01-19 16:34:10 -0800522 Domain::APP => {
523 if caller_uid as i64 != key.nspace {
524 return Err(selinux::Error::perm())
525 .context("Trying to access key without ownership.");
526 }
527 getcon().context("check_key_permission: getcon failed.")?
528 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700529 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
530 .context("check_key_permission: Domain::SELINUX: Failed to lookup namespace.")?,
531 Domain::GRANT => {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700532 match access_vector {
Janis Danisevskis45760022021-01-19 16:34:10 -0800533 Some(_) => {
534 return Err(selinux::Error::perm())
535 .context(format!("\"{}\" not granted", perm.to_selinux()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700536 }
537 None => {
538 // If DOMAIN_GRANT was selected an access vector must be supplied.
539 return Err(KsError::sys()).context(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700540 "Cannot check permission for Domain::GRANT without access vector.",
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700541 );
542 }
543 }
544 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700545 Domain::KEY_ID => {
546 // We should never be called with `Domain::KEY_ID. The database
547 // lookup should have converted this into one of `Domain::APP`
548 // or `Domain::SELINUX`.
549 return Err(KsError::sys()).context("Cannot check permission for Domain::KEY_ID.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700550 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700551 Domain::BLOB => {
552 let tctx = lookup_keystore2_key_context(key.nspace)
553 .context("Domain::BLOB: Failed to lookup namespace.")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700554 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
555 // permission in addition to the requested permission.
556 selinux::check_access(
557 caller_ctx,
558 &tctx,
559 "keystore2_key",
560 KeyPerm::manage_blob().to_selinux(),
561 )?;
562
563 tctx
564 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700565 _ => {
566 return Err(KsError::sys())
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700567 .context(format!("Unknown domain value: \"{:?}\".", key.domain))
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700568 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700569 };
570
571 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
572}
573
574#[cfg(test)]
575mod tests {
576 use super::*;
577 use anyhow::anyhow;
578 use anyhow::Result;
579 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700580
581 const ALL_PERMS: KeyPermSet = key_perm_set![
582 KeyPerm::manage_blob(),
583 KeyPerm::delete(),
584 KeyPerm::use_dev_id(),
585 KeyPerm::req_forced_op(),
586 KeyPerm::gen_unique_id(),
587 KeyPerm::grant(),
588 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700589 KeyPerm::rebind(),
590 KeyPerm::update(),
591 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800592 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700593 ];
594
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800595 const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
596 KeyPerm::delete(),
597 KeyPerm::use_dev_id(),
598 // No KeyPerm::grant()
599 KeyPerm::get_info(),
600 KeyPerm::rebind(),
601 KeyPerm::update(),
602 KeyPerm::use_(),
603 ];
604
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700605 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
606 KeyPerm::manage_blob(),
607 KeyPerm::delete(),
608 KeyPerm::use_dev_id(),
609 KeyPerm::req_forced_op(),
610 KeyPerm::gen_unique_id(),
611 // No KeyPerm::grant()
612 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700613 KeyPerm::rebind(),
614 KeyPerm::update(),
615 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800616 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700617 ];
618
619 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
620 KeyPerm::delete(),
621 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700622 KeyPerm::rebind(),
623 KeyPerm::update(),
624 KeyPerm::use_(),
625 ];
626
627 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
628 /// SePolicy (system/sepolicy).
629 const SU_KEY_NAMESPACE: i32 = 0;
630 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
631 /// SePolicy (system/sepolicy).
632 const SHELL_KEY_NAMESPACE: i32 = 1;
633
634 pub fn test_getcon() -> Result<Context> {
635 Context::new("u:object_r:keystore:s0")
636 }
637
638 // This macro evaluates the given expression and checks that
639 // a) evaluated to Result::Err() and that
640 // b) the wrapped error is selinux::Error::perm() (permission denied).
641 // We use a macro here because a function would mask which invocation caused the failure.
642 //
643 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
644 macro_rules! assert_perm_failed {
645 ($test_function:expr) => {
646 let result = $test_function;
647 assert!(result.is_err(), "Permission check should have failed.");
648 assert_eq!(
649 Some(&selinux::Error::perm()),
650 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
651 );
652 };
653 }
654
655 fn check_context() -> Result<(selinux::Context, i32, bool)> {
656 // Calling the non mocked selinux::getcon here intended.
657 let context = selinux::getcon()?;
658 match context.to_str().unwrap() {
659 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
660 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
661 c => Err(anyhow!(format!(
662 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
663 c
664 ))),
665 }
666 }
667
668 #[test]
669 fn check_keystore_permission_test() -> Result<()> {
670 let system_server_ctx = Context::new("u:r:system_server:s0")?;
671 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
672 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
673 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
674 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
675 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
676 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000677 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::change_user()).is_ok());
678 assert!(
679 check_keystore_permission(&system_server_ctx, KeystorePerm::change_password()).is_ok()
680 );
681 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_uid()).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700682 let shell_ctx = Context::new("u:r:shell:s0")?;
683 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
684 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
Janis Danisevskis1bb595e2021-03-16 10:09:08 -0700685 assert!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()).is_ok());
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700686 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::list()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700687 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
688 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
689 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000690 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_user()));
691 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_password()));
692 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_uid()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700693 Ok(())
694 }
695
696 #[test]
697 fn check_grant_permission_app() -> Result<()> {
698 let system_server_ctx = Context::new("u:r:system_server:s0")?;
699 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700700 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800701 check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
702 .expect("Grant permission check failed.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700703
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800704 // attempts to grant the grant permission must always fail even when privileged.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700705 assert_perm_failed!(check_grant_permission(
706 &system_server_ctx,
707 KeyPerm::grant().into(),
708 &key
709 ));
710 // unprivileged grant attempts always fail. shell does not have the grant permission.
711 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
712 Ok(())
713 }
714
715 #[test]
716 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700717 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700718 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700719 domain: Domain::SELINUX,
720 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700721 alias: None,
722 blob: None,
723 };
724 if is_su {
725 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
726 // attempts to grant the grant permission must always fail even when privileged.
727 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
728 } else {
729 // unprivileged grant attempts always fail. shell does not have the grant permission.
730 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
731 }
732 Ok(())
733 }
734
735 #[test]
736 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700737 let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700738
739 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800740 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700741 &selinux::Context::new("ignored").unwrap(),
742 KeyPerm::grant(),
743 &key,
744 &Some(UNPRIV_PERMS)
745 ));
746
747 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800748 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700749 &selinux::Context::new("ignored").unwrap(),
750 KeyPerm::use_(),
751 &key,
752 &Some(ALL_PERMS),
753 )
754 }
755
756 #[test]
757 fn check_key_permission_domain_app() -> Result<()> {
758 let system_server_ctx = Context::new("u:r:system_server:s0")?;
759 let shell_ctx = Context::new("u:r:shell:s0")?;
760 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700761
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700762 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700763
Janis Danisevskis45760022021-01-19 16:34:10 -0800764 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
765 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700766 assert!(
Janis Danisevskis45760022021-01-19 16:34:10 -0800767 check_key_permission(0, &system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok()
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700768 );
Janis Danisevskis45760022021-01-19 16:34:10 -0800769 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
770 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
771 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
772 assert!(
773 check_key_permission(0, &system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
774 );
775 assert!(
776 check_key_permission(0, &gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok()
777 );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700778
Janis Danisevskis45760022021-01-19 16:34:10 -0800779 assert!(check_key_permission(0, &shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
780 assert!(check_key_permission(0, &shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
781 assert!(check_key_permission(0, &shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
782 assert!(check_key_permission(0, &shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
783 assert!(check_key_permission(0, &shell_ctx, KeyPerm::update(), &key, &None).is_ok());
784 assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::grant(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700785 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800786 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700787 &shell_ctx,
788 KeyPerm::req_forced_op(),
789 &key,
790 &None
791 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700792 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800793 0,
794 &shell_ctx,
795 KeyPerm::manage_blob(),
796 &key,
797 &None
798 ));
799 assert_perm_failed!(check_key_permission(
800 0,
801 &shell_ctx,
802 KeyPerm::use_dev_id(),
803 &key,
804 &None
805 ));
806 assert_perm_failed!(check_key_permission(
807 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700808 &shell_ctx,
809 KeyPerm::gen_unique_id(),
810 &key,
811 &None
812 ));
813
Janis Danisevskis45760022021-01-19 16:34:10 -0800814 // Also make sure that the permission fails if the caller is not the owner.
815 assert_perm_failed!(check_key_permission(
816 1, // the owner is 0
817 &system_server_ctx,
818 KeyPerm::use_(),
819 &key,
820 &None
821 ));
822 // Unless there was a grant.
823 assert!(check_key_permission(
824 1,
825 &system_server_ctx,
826 KeyPerm::use_(),
827 &key,
828 &Some(key_perm_set![KeyPerm::use_()])
829 )
830 .is_ok());
831 // But fail if the grant did not cover the requested permission.
832 assert_perm_failed!(check_key_permission(
833 1,
834 &system_server_ctx,
835 KeyPerm::use_(),
836 &key,
837 &Some(key_perm_set![KeyPerm::get_info()])
838 ));
839
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700840 Ok(())
841 }
842
843 #[test]
844 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700845 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700846 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700847 domain: Domain::SELINUX,
848 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700849 alias: None,
850 blob: None,
851 };
852
853 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800854 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
855 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
856 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
857 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
858 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
859 assert!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None).is_ok());
860 assert!(check_key_permission(0, &sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
861 assert!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
862 assert!(check_key_permission(0, &sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
863 assert!(check_key_permission(0, &sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700864 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800865 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
866 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
867 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
868 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
869 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
870 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None));
871 assert_perm_failed!(check_key_permission(
872 0,
873 &sctx,
874 KeyPerm::req_forced_op(),
875 &key,
876 &None
877 ));
878 assert_perm_failed!(check_key_permission(
879 0,
880 &sctx,
881 KeyPerm::manage_blob(),
882 &key,
883 &None
884 ));
885 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None));
886 assert_perm_failed!(check_key_permission(
887 0,
888 &sctx,
889 KeyPerm::gen_unique_id(),
890 &key,
891 &None
892 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700893 }
894 Ok(())
895 }
896
897 #[test]
898 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700899 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700900 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700901 domain: Domain::BLOB,
902 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700903 alias: None,
904 blob: None,
905 };
906
907 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800908 check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700909 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800910 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700911 Ok(())
912 }
913 }
914
915 #[test]
916 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700917 let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700918
919 assert_eq!(
920 Some(&KsError::sys()),
921 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800922 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700923 &selinux::Context::new("ignored").unwrap(),
924 KeyPerm::use_(),
925 &key,
926 &None
927 )
928 .err()
929 .unwrap()
930 .root_cause()
931 .downcast_ref::<KsError>()
932 );
933 Ok(())
934 }
935
936 #[test]
937 fn key_perm_set_all_test() {
938 let v = key_perm_set![
939 KeyPerm::manage_blob(),
940 KeyPerm::delete(),
941 KeyPerm::use_dev_id(),
942 KeyPerm::req_forced_op(),
943 KeyPerm::gen_unique_id(),
944 KeyPerm::grant(),
945 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700946 KeyPerm::rebind(),
947 KeyPerm::update(),
948 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
949 ];
950 let mut i = v.into_iter();
951 assert_eq!(i.next().unwrap().to_selinux(), "delete");
952 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
953 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
954 assert_eq!(i.next().unwrap().to_selinux(), "grant");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700955 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
956 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
957 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
958 assert_eq!(i.next().unwrap().to_selinux(), "update");
959 assert_eq!(i.next().unwrap().to_selinux(), "use");
960 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
961 assert_eq!(None, i.next());
962 }
963 #[test]
964 fn key_perm_set_sparse_test() {
965 let v = key_perm_set![
966 KeyPerm::manage_blob(),
967 KeyPerm::req_forced_op(),
968 KeyPerm::gen_unique_id(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700969 KeyPerm::update(),
970 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
971 ];
972 let mut i = v.into_iter();
973 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700974 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
975 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
976 assert_eq!(i.next().unwrap().to_selinux(), "update");
977 assert_eq!(i.next().unwrap().to_selinux(), "use");
978 assert_eq!(None, i.next());
979 }
980 #[test]
981 fn key_perm_set_empty_test() {
982 let v = key_perm_set![];
983 let mut i = v.into_iter();
984 assert_eq!(None, i.next());
985 }
986 #[test]
987 fn key_perm_set_include_subset_test() {
988 let v1 = key_perm_set![
989 KeyPerm::manage_blob(),
990 KeyPerm::delete(),
991 KeyPerm::use_dev_id(),
992 KeyPerm::req_forced_op(),
993 KeyPerm::gen_unique_id(),
994 KeyPerm::grant(),
995 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700996 KeyPerm::rebind(),
997 KeyPerm::update(),
998 KeyPerm::use_(),
999 ];
1000 let v2 = key_perm_set![
1001 KeyPerm::manage_blob(),
1002 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001003 KeyPerm::rebind(),
1004 KeyPerm::update(),
1005 KeyPerm::use_(),
1006 ];
1007 assert!(v1.includes(v2));
1008 assert!(!v2.includes(v1));
1009 }
1010 #[test]
1011 fn key_perm_set_include_equal_test() {
1012 let v1 = key_perm_set![
1013 KeyPerm::manage_blob(),
1014 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001015 KeyPerm::rebind(),
1016 KeyPerm::update(),
1017 KeyPerm::use_(),
1018 ];
1019 let v2 = key_perm_set![
1020 KeyPerm::manage_blob(),
1021 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001022 KeyPerm::rebind(),
1023 KeyPerm::update(),
1024 KeyPerm::use_(),
1025 ];
1026 assert!(v1.includes(v2));
1027 assert!(v2.includes(v1));
1028 }
1029 #[test]
1030 fn key_perm_set_include_overlap_test() {
1031 let v1 = key_perm_set![
1032 KeyPerm::manage_blob(),
1033 KeyPerm::delete(),
1034 KeyPerm::grant(), // only in v1
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001035 KeyPerm::rebind(),
1036 KeyPerm::update(),
1037 KeyPerm::use_(),
1038 ];
1039 let v2 = key_perm_set![
1040 KeyPerm::manage_blob(),
1041 KeyPerm::delete(),
1042 KeyPerm::req_forced_op(), // only in v2
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001043 KeyPerm::rebind(),
1044 KeyPerm::update(),
1045 KeyPerm::use_(),
1046 ];
1047 assert!(!v1.includes(v2));
1048 assert!(!v2.includes(v1));
1049 }
1050 #[test]
1051 fn key_perm_set_include_no_overlap_test() {
1052 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
1053 let v2 = key_perm_set![
1054 KeyPerm::req_forced_op(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001055 KeyPerm::rebind(),
1056 KeyPerm::update(),
1057 KeyPerm::use_(),
1058 ];
1059 assert!(!v1.includes(v2));
1060 assert!(!v2.includes(v1));
1061 }
1062}