blob: 8343a2997a7f539f87e2feb9f30163e6eb50735c [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;
Hasini Gunasinghe15891e62021-06-10 16:23:27 +0000318 /// Checked when IkeystoreMetrics::pullMetris is called.
319 PullMetrics = 0x2000, selinux name: pull_metrics;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700320 }
321);
322
323/// Represents a set of `KeyPerm` permissions.
324/// `IntoIterator` is implemented for this struct allowing the iteration through all the
325/// permissions in the set.
326/// It also implements a function `includes(self, other)` that checks if the permissions
327/// in `other` are included in `self`.
328///
329/// KeyPermSet can be created with the macro `key_perm_set![]`.
330///
331/// ## Example
332/// ```
333/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
334/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
335///
336/// assert!(perms1.includes(perms2))
337/// assert!(!perms2.includes(perms1))
338///
339/// let i = perms1.into_iter();
340/// // iteration in ascending order of the permission's numeric representation.
341/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
342/// assert_eq(Some(KeyPerm::grant()), i.next());
343/// assert_eq(Some(KeyPerm::use_()), i.next());
344/// assert_eq(None, i.next());
345/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700346#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
347pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700348
349mod perm {
350 use super::*;
351
352 pub struct IntoIter {
353 vec: KeyPermSet,
354 pos: u8,
355 }
356
357 impl IntoIter {
358 pub fn new(v: KeyPermSet) -> Self {
359 Self { vec: v, pos: 0 }
360 }
361 }
362
363 impl std::iter::Iterator for IntoIter {
364 type Item = KeyPerm;
365
366 fn next(&mut self) -> Option<Self::Item> {
367 loop {
368 if self.pos == 32 {
369 return None;
370 }
371 let p = self.vec.0 & (1 << self.pos);
372 self.pos += 1;
373 if p != 0 {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700374 return Some(KeyPerm::from(KeyPermission(p)));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700375 }
376 }
377 }
378 }
379}
380
381impl From<KeyPerm> for KeyPermSet {
382 fn from(p: KeyPerm) -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700383 Self((p.0).0 as i32)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700384 }
385}
386
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700387/// allow conversion from the AIDL wire type i32 to a permission set.
388impl From<i32> for KeyPermSet {
389 fn from(p: i32) -> Self {
390 Self(p)
391 }
392}
393
394impl From<KeyPermSet> for i32 {
395 fn from(p: KeyPermSet) -> i32 {
396 p.0
397 }
398}
399
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700400impl KeyPermSet {
401 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700402 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700403 let o: KeyPermSet = other.into();
404 (self.0 & o.0) == o.0
405 }
406}
407
408/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
409///
410/// ## Example
411/// ```
412/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
413/// ```
414#[macro_export]
415macro_rules! key_perm_set {
416 () => { KeyPermSet(0) };
417 ($head:expr $(, $tail:expr)* $(,)?) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700418 KeyPermSet(($head.0).0 $(| ($tail.0).0)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700419 };
420}
421
422impl IntoIterator for KeyPermSet {
423 type Item = KeyPerm;
424 type IntoIter = perm::IntoIter;
425
426 fn into_iter(self) -> Self::IntoIter {
427 Self::IntoIter::new(self)
428 }
429}
430
431/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
432/// the given permision `perm` of the `keystore2` security class.
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700433pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700434 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
435 selinux::check_access(caller_ctx, &target_context, "keystore2", perm.to_selinux())
436}
437
438/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` has
439/// all the permissions indicated in `access_vec` for the target domain indicated by the key
440/// descriptor `key` in the security class `keystore2_key`.
441///
442/// Also checks if the caller has the grant permission for the given target domain.
443///
444/// Attempts to grant the grant permission are always denied.
445///
446/// The only viable target domains are
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700447/// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
448/// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700449/// SELinux keystore key backend, and the result is used
450/// as target context.
451pub fn check_grant_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700452 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700453 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700454 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700455) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700456 let target_context = match key.domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700457 Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
458 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
459 .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700460 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
461 };
462
463 selinux::check_access(caller_ctx, &target_context, "keystore2_key", "grant")
464 .context("Grant permission is required when granting.")?;
465
466 if access_vec.includes(KeyPerm::grant()) {
467 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
468 }
469
470 for p in access_vec.into_iter() {
471 selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800472 .context(format!(
473 concat!(
474 "check_grant_permission: check_access failed. ",
475 "The caller may have tried to grant a permission that they don't possess. {:?}"
476 ),
477 p
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700478 ))?
479 }
480 Ok(())
481}
482
483/// Uses `selinux::check_access` to check if the given caller context `caller_cxt`
484/// has the permissions indicated by `perm` for the target domain indicated by the key
485/// descriptor `key` in the security class `keystore2_key`.
486///
487/// The behavior differs slightly depending on the selected target domain:
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700488/// * `Domain::APP` u:r:keystore:s0 is used as target context.
489/// * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700490/// backend, and the result is used as target context.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700491/// * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700492/// to the one supplied in `perm`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700493/// * `Domain::GRANT` Does not use selinux::check_access. Instead the `access_vector`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700494/// parameter is queried for permission, which must be supplied in this case.
495///
496/// ## Return values.
497/// * Ok(()) If the requested permissions were granted.
498/// * Err(selinux::Error::perm()) If the requested permissions were denied.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700499/// * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
500/// was supplied. It is also produced if `Domain::KEY_ID` was selected, and
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700501/// on various unexpected backend failures.
502pub fn check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800503 caller_uid: u32,
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700504 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700505 perm: KeyPerm,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700506 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700507 access_vector: &Option<KeyPermSet>,
508) -> anyhow::Result<()> {
Janis Danisevskis45760022021-01-19 16:34:10 -0800509 // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID.
510 // In the former case, key.domain was set to GRANT and we check the failure cases
511 // further below. If the access is requested by KEY_ID, key.domain would have been
512 // resolved to APP or SELINUX depending on where the key actually resides.
513 // Either way we can return here immediately if the access vector covers the requested
514 // permission. If it does not, we can still check if the caller has access by means of
515 // ownership.
516 if let Some(access_vector) = access_vector {
517 if access_vector.includes(perm) {
518 return Ok(());
519 }
520 }
521
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700522 let target_context = match key.domain {
523 // apps get the default keystore context
Janis Danisevskis45760022021-01-19 16:34:10 -0800524 Domain::APP => {
525 if caller_uid as i64 != key.nspace {
526 return Err(selinux::Error::perm())
527 .context("Trying to access key without ownership.");
528 }
529 getcon().context("check_key_permission: getcon failed.")?
530 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700531 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
532 .context("check_key_permission: Domain::SELINUX: Failed to lookup namespace.")?,
533 Domain::GRANT => {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700534 match access_vector {
Janis Danisevskis45760022021-01-19 16:34:10 -0800535 Some(_) => {
536 return Err(selinux::Error::perm())
537 .context(format!("\"{}\" not granted", perm.to_selinux()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700538 }
539 None => {
540 // If DOMAIN_GRANT was selected an access vector must be supplied.
541 return Err(KsError::sys()).context(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700542 "Cannot check permission for Domain::GRANT without access vector.",
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700543 );
544 }
545 }
546 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700547 Domain::KEY_ID => {
548 // We should never be called with `Domain::KEY_ID. The database
549 // lookup should have converted this into one of `Domain::APP`
550 // or `Domain::SELINUX`.
551 return Err(KsError::sys()).context("Cannot check permission for Domain::KEY_ID.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700552 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700553 Domain::BLOB => {
554 let tctx = lookup_keystore2_key_context(key.nspace)
555 .context("Domain::BLOB: Failed to lookup namespace.")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700556 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
557 // permission in addition to the requested permission.
558 selinux::check_access(
559 caller_ctx,
560 &tctx,
561 "keystore2_key",
562 KeyPerm::manage_blob().to_selinux(),
563 )?;
564
565 tctx
566 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700567 _ => {
568 return Err(KsError::sys())
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700569 .context(format!("Unknown domain value: \"{:?}\".", key.domain))
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700570 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700571 };
572
573 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
574}
575
576#[cfg(test)]
577mod tests {
578 use super::*;
579 use anyhow::anyhow;
580 use anyhow::Result;
581 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700582
583 const ALL_PERMS: KeyPermSet = key_perm_set![
584 KeyPerm::manage_blob(),
585 KeyPerm::delete(),
586 KeyPerm::use_dev_id(),
587 KeyPerm::req_forced_op(),
588 KeyPerm::gen_unique_id(),
589 KeyPerm::grant(),
590 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700591 KeyPerm::rebind(),
592 KeyPerm::update(),
593 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800594 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700595 ];
596
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800597 const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
598 KeyPerm::delete(),
599 KeyPerm::use_dev_id(),
600 // No KeyPerm::grant()
601 KeyPerm::get_info(),
602 KeyPerm::rebind(),
603 KeyPerm::update(),
604 KeyPerm::use_(),
605 ];
606
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700607 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
608 KeyPerm::manage_blob(),
609 KeyPerm::delete(),
610 KeyPerm::use_dev_id(),
611 KeyPerm::req_forced_op(),
612 KeyPerm::gen_unique_id(),
613 // No KeyPerm::grant()
614 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700615 KeyPerm::rebind(),
616 KeyPerm::update(),
617 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800618 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700619 ];
620
621 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
622 KeyPerm::delete(),
623 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700624 KeyPerm::rebind(),
625 KeyPerm::update(),
626 KeyPerm::use_(),
627 ];
628
629 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
630 /// SePolicy (system/sepolicy).
631 const SU_KEY_NAMESPACE: i32 = 0;
632 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
633 /// SePolicy (system/sepolicy).
634 const SHELL_KEY_NAMESPACE: i32 = 1;
635
636 pub fn test_getcon() -> Result<Context> {
637 Context::new("u:object_r:keystore:s0")
638 }
639
640 // This macro evaluates the given expression and checks that
641 // a) evaluated to Result::Err() and that
642 // b) the wrapped error is selinux::Error::perm() (permission denied).
643 // We use a macro here because a function would mask which invocation caused the failure.
644 //
645 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
646 macro_rules! assert_perm_failed {
647 ($test_function:expr) => {
648 let result = $test_function;
649 assert!(result.is_err(), "Permission check should have failed.");
650 assert_eq!(
651 Some(&selinux::Error::perm()),
652 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
653 );
654 };
655 }
656
657 fn check_context() -> Result<(selinux::Context, i32, bool)> {
658 // Calling the non mocked selinux::getcon here intended.
659 let context = selinux::getcon()?;
660 match context.to_str().unwrap() {
661 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
662 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
663 c => Err(anyhow!(format!(
664 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
665 c
666 ))),
667 }
668 }
669
670 #[test]
671 fn check_keystore_permission_test() -> Result<()> {
672 let system_server_ctx = Context::new("u:r:system_server:s0")?;
673 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
674 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
675 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
676 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
677 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
678 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000679 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::change_user()).is_ok());
680 assert!(
681 check_keystore_permission(&system_server_ctx, KeystorePerm::change_password()).is_ok()
682 );
683 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_uid()).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700684 let shell_ctx = Context::new("u:r:shell:s0")?;
685 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
686 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
Janis Danisevskis1bb595e2021-03-16 10:09:08 -0700687 assert!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()).is_ok());
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700688 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::list()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700689 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
690 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
691 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000692 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_user()));
693 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_password()));
694 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_uid()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700695 Ok(())
696 }
697
698 #[test]
699 fn check_grant_permission_app() -> Result<()> {
700 let system_server_ctx = Context::new("u:r:system_server:s0")?;
701 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700702 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800703 check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
704 .expect("Grant permission check failed.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700705
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800706 // attempts to grant the grant permission must always fail even when privileged.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700707 assert_perm_failed!(check_grant_permission(
708 &system_server_ctx,
709 KeyPerm::grant().into(),
710 &key
711 ));
712 // unprivileged grant attempts always fail. shell does not have the grant permission.
713 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
714 Ok(())
715 }
716
717 #[test]
718 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700719 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700720 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700721 domain: Domain::SELINUX,
722 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700723 alias: None,
724 blob: None,
725 };
726 if is_su {
727 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
728 // attempts to grant the grant permission must always fail even when privileged.
729 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
730 } else {
731 // unprivileged grant attempts always fail. shell does not have the grant permission.
732 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
733 }
734 Ok(())
735 }
736
737 #[test]
738 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700739 let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700740
741 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800742 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700743 &selinux::Context::new("ignored").unwrap(),
744 KeyPerm::grant(),
745 &key,
746 &Some(UNPRIV_PERMS)
747 ));
748
749 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800750 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700751 &selinux::Context::new("ignored").unwrap(),
752 KeyPerm::use_(),
753 &key,
754 &Some(ALL_PERMS),
755 )
756 }
757
758 #[test]
759 fn check_key_permission_domain_app() -> Result<()> {
760 let system_server_ctx = Context::new("u:r:system_server:s0")?;
761 let shell_ctx = Context::new("u:r:shell:s0")?;
762 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700763
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700764 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700765
Janis Danisevskis45760022021-01-19 16:34:10 -0800766 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
767 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700768 assert!(
Janis Danisevskis45760022021-01-19 16:34:10 -0800769 check_key_permission(0, &system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok()
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700770 );
Janis Danisevskis45760022021-01-19 16:34:10 -0800771 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
772 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
773 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
774 assert!(
775 check_key_permission(0, &system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
776 );
777 assert!(
778 check_key_permission(0, &gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok()
779 );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700780
Janis Danisevskis45760022021-01-19 16:34:10 -0800781 assert!(check_key_permission(0, &shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
782 assert!(check_key_permission(0, &shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
783 assert!(check_key_permission(0, &shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
784 assert!(check_key_permission(0, &shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
785 assert!(check_key_permission(0, &shell_ctx, KeyPerm::update(), &key, &None).is_ok());
786 assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::grant(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700787 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800788 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700789 &shell_ctx,
790 KeyPerm::req_forced_op(),
791 &key,
792 &None
793 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700794 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800795 0,
796 &shell_ctx,
797 KeyPerm::manage_blob(),
798 &key,
799 &None
800 ));
801 assert_perm_failed!(check_key_permission(
802 0,
803 &shell_ctx,
804 KeyPerm::use_dev_id(),
805 &key,
806 &None
807 ));
808 assert_perm_failed!(check_key_permission(
809 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700810 &shell_ctx,
811 KeyPerm::gen_unique_id(),
812 &key,
813 &None
814 ));
815
Janis Danisevskis45760022021-01-19 16:34:10 -0800816 // Also make sure that the permission fails if the caller is not the owner.
817 assert_perm_failed!(check_key_permission(
818 1, // the owner is 0
819 &system_server_ctx,
820 KeyPerm::use_(),
821 &key,
822 &None
823 ));
824 // Unless there was a grant.
825 assert!(check_key_permission(
826 1,
827 &system_server_ctx,
828 KeyPerm::use_(),
829 &key,
830 &Some(key_perm_set![KeyPerm::use_()])
831 )
832 .is_ok());
833 // But fail if the grant did not cover the requested permission.
834 assert_perm_failed!(check_key_permission(
835 1,
836 &system_server_ctx,
837 KeyPerm::use_(),
838 &key,
839 &Some(key_perm_set![KeyPerm::get_info()])
840 ));
841
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700842 Ok(())
843 }
844
845 #[test]
846 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700847 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700848 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700849 domain: Domain::SELINUX,
850 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700851 alias: None,
852 blob: None,
853 };
854
855 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800856 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
857 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
858 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
859 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
860 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
861 assert!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None).is_ok());
862 assert!(check_key_permission(0, &sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
863 assert!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
864 assert!(check_key_permission(0, &sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
865 assert!(check_key_permission(0, &sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700866 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800867 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
868 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
869 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
870 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
871 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
872 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None));
873 assert_perm_failed!(check_key_permission(
874 0,
875 &sctx,
876 KeyPerm::req_forced_op(),
877 &key,
878 &None
879 ));
880 assert_perm_failed!(check_key_permission(
881 0,
882 &sctx,
883 KeyPerm::manage_blob(),
884 &key,
885 &None
886 ));
887 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None));
888 assert_perm_failed!(check_key_permission(
889 0,
890 &sctx,
891 KeyPerm::gen_unique_id(),
892 &key,
893 &None
894 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700895 }
896 Ok(())
897 }
898
899 #[test]
900 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700901 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700902 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700903 domain: Domain::BLOB,
904 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700905 alias: None,
906 blob: None,
907 };
908
909 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800910 check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700911 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800912 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700913 Ok(())
914 }
915 }
916
917 #[test]
918 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700919 let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700920
921 assert_eq!(
922 Some(&KsError::sys()),
923 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800924 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700925 &selinux::Context::new("ignored").unwrap(),
926 KeyPerm::use_(),
927 &key,
928 &None
929 )
930 .err()
931 .unwrap()
932 .root_cause()
933 .downcast_ref::<KsError>()
934 );
935 Ok(())
936 }
937
938 #[test]
939 fn key_perm_set_all_test() {
940 let v = key_perm_set![
941 KeyPerm::manage_blob(),
942 KeyPerm::delete(),
943 KeyPerm::use_dev_id(),
944 KeyPerm::req_forced_op(),
945 KeyPerm::gen_unique_id(),
946 KeyPerm::grant(),
947 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700948 KeyPerm::rebind(),
949 KeyPerm::update(),
950 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
951 ];
952 let mut i = v.into_iter();
953 assert_eq!(i.next().unwrap().to_selinux(), "delete");
954 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
955 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
956 assert_eq!(i.next().unwrap().to_selinux(), "grant");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700957 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
958 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
959 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
960 assert_eq!(i.next().unwrap().to_selinux(), "update");
961 assert_eq!(i.next().unwrap().to_selinux(), "use");
962 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
963 assert_eq!(None, i.next());
964 }
965 #[test]
966 fn key_perm_set_sparse_test() {
967 let v = key_perm_set![
968 KeyPerm::manage_blob(),
969 KeyPerm::req_forced_op(),
970 KeyPerm::gen_unique_id(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700971 KeyPerm::update(),
972 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
973 ];
974 let mut i = v.into_iter();
975 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700976 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
977 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
978 assert_eq!(i.next().unwrap().to_selinux(), "update");
979 assert_eq!(i.next().unwrap().to_selinux(), "use");
980 assert_eq!(None, i.next());
981 }
982 #[test]
983 fn key_perm_set_empty_test() {
984 let v = key_perm_set![];
985 let mut i = v.into_iter();
986 assert_eq!(None, i.next());
987 }
988 #[test]
989 fn key_perm_set_include_subset_test() {
990 let v1 = key_perm_set![
991 KeyPerm::manage_blob(),
992 KeyPerm::delete(),
993 KeyPerm::use_dev_id(),
994 KeyPerm::req_forced_op(),
995 KeyPerm::gen_unique_id(),
996 KeyPerm::grant(),
997 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700998 KeyPerm::rebind(),
999 KeyPerm::update(),
1000 KeyPerm::use_(),
1001 ];
1002 let v2 = key_perm_set![
1003 KeyPerm::manage_blob(),
1004 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001005 KeyPerm::rebind(),
1006 KeyPerm::update(),
1007 KeyPerm::use_(),
1008 ];
1009 assert!(v1.includes(v2));
1010 assert!(!v2.includes(v1));
1011 }
1012 #[test]
1013 fn key_perm_set_include_equal_test() {
1014 let v1 = key_perm_set![
1015 KeyPerm::manage_blob(),
1016 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001017 KeyPerm::rebind(),
1018 KeyPerm::update(),
1019 KeyPerm::use_(),
1020 ];
1021 let v2 = key_perm_set![
1022 KeyPerm::manage_blob(),
1023 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001024 KeyPerm::rebind(),
1025 KeyPerm::update(),
1026 KeyPerm::use_(),
1027 ];
1028 assert!(v1.includes(v2));
1029 assert!(v2.includes(v1));
1030 }
1031 #[test]
1032 fn key_perm_set_include_overlap_test() {
1033 let v1 = key_perm_set![
1034 KeyPerm::manage_blob(),
1035 KeyPerm::delete(),
1036 KeyPerm::grant(), // only in v1
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001037 KeyPerm::rebind(),
1038 KeyPerm::update(),
1039 KeyPerm::use_(),
1040 ];
1041 let v2 = key_perm_set![
1042 KeyPerm::manage_blob(),
1043 KeyPerm::delete(),
1044 KeyPerm::req_forced_op(), // only in v2
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001045 KeyPerm::rebind(),
1046 KeyPerm::update(),
1047 KeyPerm::use_(),
1048 ];
1049 assert!(!v1.includes(v2));
1050 assert!(!v2.includes(v1));
1051 }
1052 #[test]
1053 fn key_perm_set_include_no_overlap_test() {
1054 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
1055 let v2 = key_perm_set![
1056 KeyPerm::req_forced_op(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001057 KeyPerm::rebind(),
1058 KeyPerm::update(),
1059 KeyPerm::use_(),
1060 ];
1061 assert!(!v1.includes(v2));
1062 assert!(!v2.includes(v1));
1063 }
1064}