blob: 0db56ddadc962e5306031b8a2ab98d522de16e32 [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
21use keystore_aidl_generated as aidl;
22
23use std::cmp::PartialEq;
24use std::convert::From;
25
26use crate::error::Error as KsError;
27use keystore2_selinux as selinux;
28
29use anyhow::Context as AnyhowContext;
30
31use selinux::Backend;
32
Janis Danisevskis4ad056f2020-08-05 19:46:46 +000033use lazy_static::lazy_static;
34
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070035// Replace getcon with a mock in the test situation
36#[cfg(not(test))]
37use selinux::getcon;
38#[cfg(test)]
39use tests::test_getcon as getcon;
40
Janis Danisevskis4ad056f2020-08-05 19:46:46 +000041lazy_static! {
42 // Panicking here is allowed because keystore cannot function without this backend
43 // and it would happen early and indicate a gross misconfiguration of the device.
44 static ref KEYSTORE2_KEY_LABEL_BACKEND: selinux::KeystoreKeyBackend =
45 selinux::KeystoreKeyBackend::new().unwrap();
46}
47
48fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> {
49 KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string())
50}
51
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070052/// The below example wraps the enum MyPermission in the tuple struct `MyPerm` and implements
53/// * `From<i32> for `MyPerm`, where each unknown numeric value is mapped to the given default,
54/// here `None`
55/// * `Into<MyPermission> for `MyPerm`
56/// * `MyPerm::foo()` and `MyPerm::bar()` which construct MyPerm instances representing
57/// `MyPermission::Foo` and `MyPermission::Bar` respectively.
58/// * `MyPerm.to_selinux(&self)`, which returns the selinux string representation of the
59/// represented permission.
60/// * Tests in the given test namespace for each permision that check that the numeric
61/// representations of MyPermission and MyPerm match. (TODO replace with static assert if
62/// they become available.)
63///
64/// ## Special behavior
65/// If the keyword `use` appears as an selinux name `use_` is used as identifier for the
66/// constructor function (e.g. `MePerm::use_()`) but the string returned by `to_selinux` will
67/// still be `"use"`.
68///
69/// ## Example
70/// ```
71/// #[i32]
72/// enum MyPermission {
73/// None = 0,
74/// Foo = 1,
75/// Bar = 2,
76/// }
77///
78/// implement_permission!(
79/// /// MyPerm documentation.
80/// #[derive(Clone, Copy, Debug, PartialEq)]
81/// MyPermission as MyPerm with default (None = 0, none)
82/// and test namespace my_perm_tests {
83/// Foo = 1, selinux name: foo;
84/// Bar = 2, selinux name: bar;
85/// }
86/// );
87/// ```
88macro_rules! implement_permission {
89 // This rule provides the public interface of the macro. And starts the preprocessing
90 // recursion (see below).
91 ($(#[$m:meta])* $t:ty as $name:ident with default ($($def:tt)*)
92 and test namespace $tn:ident { $($element:tt)* })
93 => {
94 implement_permission!(@replace_use $($m)*, $t, $name, $tn, ($($def)*), [] , $($element)*);
95 };
96
97
98 // The following three rules recurse through the elements of the form
99 // `<enum variant> = <integer_literal>, selinux name: <selinux_name>;`
100 // preprocessing the input.
101
102 // The first rule terminates the recursion and passes the processed arguments to the final
103 // rule that spills out the implementation.
104 (@replace_use $($m:meta)*, $t:ty, $name:ident, $tn:ident, ($($def:tt)*), [$($out:tt)*], ) => {
105 implement_permission!(@end $($m)*, $t, $name, $tn, ($($def)*) { $($out)* } );
106 };
107
108 // The second rule is triggered if the selinux name of an element is literally `use`.
109 // It produces the tuple `<enum variant> = <integer_literal>, use_, use;`
110 // and appends it to the out list.
111 (@replace_use $($m:meta)*, $t:ty, $name:ident, $tn:ident, ($($def:tt)*), [$($out:tt)*],
112 $e_name:ident = $e_val:expr, selinux name: use; $($element:tt)*)
113 => {
114 implement_permission!(@replace_use $($m)*, $t, $name, $tn, ($($def)*),
115 [$($out)* $e_name = $e_val, use_, use;], $($element)*);
116 };
117
118 // The third rule is the default rule which replaces every input tuple with
119 // `<enum variant> = <integer_literal>, <selinux_name>, <selinux_name>;`
120 // and appends the result to the out list.
121 (@replace_use $($m:meta)*, $t:ty, $name:ident, $tn:ident, ($($def:tt)*), [$($out:tt)*],
122 $e_name:ident = $e_val:expr, selinux name: $e_str:ident; $($element:tt)*)
123 => {
124 implement_permission!(@replace_use $($m)*, $t, $name, $tn, ($($def)*),
125 [$($out)* $e_name = $e_val, $e_str, $e_str;], $($element)*);
126 };
127
128 (@end $($m:meta)*, $t:ty, $name:ident, $tn:ident,
129 ($def_name:ident = $def:expr, $def_selinux_name:ident) {
130 $($element_name:ident = $element_val:expr, $element_identifier:ident,
131 $selinux_name:ident;)*
132 })
133 =>
134 {
135 $(#[$m])*
136 pub struct $name($t);
137
138 impl From<i32> for $name {
139 fn from (p: i32) -> Self {
140 match p {
141 $def => Self(<$t>::$def_name),
142 $($element_val => Self(<$t>::$element_name),)*
143 _ => Self(<$t>::$def_name),
144 }
145 }
146 }
147
148 impl Into<$t> for $name {
149 fn into(self) -> $t {
150 self.0
151 }
152 }
153
154 impl $name {
155 /// Returns a string representation of the permission as required by
156 /// `selinux::check_access`.
157 pub fn to_selinux(&self) -> &'static str {
158 match self {
159 Self(<$t>::$def_name) => stringify!($def_selinux_name),
160 $(Self(<$t>::$element_name) => stringify!($selinux_name),)*
161 }
162 }
163
164 /// Creates an instance representing a permission with the same name.
165 pub const fn $def_selinux_name() -> Self { Self(<$t>::$def_name) }
166 $(
167 /// Creates an instance representing a permission with the same name.
168 pub const fn $element_identifier() -> Self { Self(<$t>::$element_name) }
169 )*
170 }
171 #[cfg(test)]
172 mod $tn {
173 use super::*;
174
175 #[test]
176 fn $def_selinux_name() {
177 assert_eq!($name::$def_selinux_name(), (<$t>::$def_name as i32).into());
178 }
179 $(
180 #[test]
181 fn $element_identifier() {
182 assert_eq!($name::$element_identifier(), (<$t>::$element_name as i32).into());
183 }
184 )*
185 }
186 };
187
188
189}
190
191implement_permission!(
192 /// KeyPerm provides a convenient abstraction from the SELinux class `keystore2_key`.
193 /// At the same time it maps `KeyPermissions` from the Keystore 2.0 AIDL Grant interface to
194 /// the SELinux permissions. With the implement_permission macro, we conveniently
195 /// provide mappings between the wire type bit field values, the rust enum and the SELinux
196 /// string representation.
197 ///
198 /// ## Example
199 ///
200 /// In this access check `KeyPerm::get_info().to_selinux()` would return the SELinux representation
201 /// "info".
202 /// ```
203 /// selinux::check_access(source_context, target_context, "keystore2_key",
204 /// KeyPerm::get_info().to_selinux());
205 /// ```
206 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
207 aidl::KeyPermission as KeyPerm with default (None = 0, none)
208 and test namespace key_perm_tests {
209 Delete = 1, selinux name: delete;
210 GenUniqueId = 2, selinux name: gen_unique_id;
211 GetInfo = 4, selinux name: get_info;
212 Grant = 8, selinux name: grant;
213 List = 0x10, selinux name: list;
214 ManageBlob = 0x20, selinux name: manage_blob;
215 Rebind = 0x40, selinux name: rebind;
216 ReqForcedOp = 0x80, selinux name: req_forced_op;
217 Update = 0x100, selinux name: update;
218 Use = 0x200, selinux name: use;
219 UseDevId = 0x400, selinux name: use_dev_id;
220 }
221);
222
223/// KeystorePermission defines values for the SELinux `keystore2` security class.
224/// Countrary to `KeyPermission`, this enum is not generated by AIDL and need not be
225/// wrapped by newtype pattern. But we conveniently use the implement_permission macro
226/// to provide the same feature that we did for `KeyPermission` to this set of permissions.
227#[repr(i32)]
228#[derive(Debug, Clone, Copy, Eq, PartialEq)]
229pub enum KeystorePermission {
230 /// `None` is not a permission that can ever be granted. It is not known to the SEPolicy.
231 None = 0,
232 /// Checked when a new auth token is installed.
233 AddAuth = 1,
234 /// Checked when an app is uninstalled or wiped.
235 ClearNs = 2,
236 /// Checked when the locked state of Keystore 2.0 is queried.
237 GetState = 4,
238 /// Checked when Keystore 2.0 gets locked.
239 Lock = 8,
240 /// Checked when Keystore 2.0 shall be reset.
241 Reset = 0x10,
242 /// Checked when Keystore 2.0 shall be unlocked.
243 Unlock = 0x20,
244}
245
246implement_permission!(
247 /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
248 /// Using the implement_permission macro we get the same features as `KeyPerm`.
249 #[derive(Clone, Copy, Debug, PartialEq)]
250 KeystorePermission as KeystorePerm with default (None = 0, none)
251 and test namespace keystore_perm_tests {
252 AddAuth = 1, selinux name: add_auth;
253 ClearNs = 2, selinux name: clear_ns;
254 GetState = 4, selinux name: get_state;
255 Lock = 8, selinux name: lock;
256 Reset = 0x10, selinux name: reset;
257 Unlock = 0x20, selinux name: unlock;
258 }
259);
260
261/// Represents a set of `KeyPerm` permissions.
262/// `IntoIterator` is implemented for this struct allowing the iteration through all the
263/// permissions in the set.
264/// It also implements a function `includes(self, other)` that checks if the permissions
265/// in `other` are included in `self`.
266///
267/// KeyPermSet can be created with the macro `key_perm_set![]`.
268///
269/// ## Example
270/// ```
271/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
272/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
273///
274/// assert!(perms1.includes(perms2))
275/// assert!(!perms2.includes(perms1))
276///
277/// let i = perms1.into_iter();
278/// // iteration in ascending order of the permission's numeric representation.
279/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
280/// assert_eq(Some(KeyPerm::grant()), i.next());
281/// assert_eq(Some(KeyPerm::use_()), i.next());
282/// assert_eq(None, i.next());
283/// ```
284#[derive(Copy, Clone)]
285pub struct KeyPermSet(i32);
286
287mod perm {
288 use super::*;
289
290 pub struct IntoIter {
291 vec: KeyPermSet,
292 pos: u8,
293 }
294
295 impl IntoIter {
296 pub fn new(v: KeyPermSet) -> Self {
297 Self { vec: v, pos: 0 }
298 }
299 }
300
301 impl std::iter::Iterator for IntoIter {
302 type Item = KeyPerm;
303
304 fn next(&mut self) -> Option<Self::Item> {
305 loop {
306 if self.pos == 32 {
307 return None;
308 }
309 let p = self.vec.0 & (1 << self.pos);
310 self.pos += 1;
311 if p != 0 {
312 return Some(KeyPerm::from(p));
313 }
314 }
315 }
316 }
317}
318
319impl From<KeyPerm> for KeyPermSet {
320 fn from(p: KeyPerm) -> Self {
321 Self(p.0 as i32)
322 }
323}
324
325impl KeyPermSet {
326 /// Returns true iff this permission set has all of the permissions that are in `other`.
327 fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
328 let o: KeyPermSet = other.into();
329 (self.0 & o.0) == o.0
330 }
331}
332
333/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
334///
335/// ## Example
336/// ```
337/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
338/// ```
339#[macro_export]
340macro_rules! key_perm_set {
341 () => { KeyPermSet(0) };
342 ($head:expr $(, $tail:expr)* $(,)?) => {
343 KeyPermSet($head.0 as i32 $(| $tail.0 as i32)*)
344 };
345}
346
347impl IntoIterator for KeyPermSet {
348 type Item = KeyPerm;
349 type IntoIter = perm::IntoIter;
350
351 fn into_iter(self) -> Self::IntoIter {
352 Self::IntoIter::new(self)
353 }
354}
355
356/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
357/// the given permision `perm` of the `keystore2` security class.
358pub fn check_keystore_permission(
359 caller_ctx: &selinux::Context,
360 perm: KeystorePerm,
361) -> anyhow::Result<()> {
362 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
363 selinux::check_access(caller_ctx, &target_context, "keystore2", perm.to_selinux())
364}
365
366/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` has
367/// all the permissions indicated in `access_vec` for the target domain indicated by the key
368/// descriptor `key` in the security class `keystore2_key`.
369///
370/// Also checks if the caller has the grant permission for the given target domain.
371///
372/// Attempts to grant the grant permission are always denied.
373///
374/// The only viable target domains are
375/// * `Domain::App` in which case u:r:keystore:s0 is used as target context and
376/// * `Domain::SELinux` in which case the `key.namespace_` parameter is looked up in
377/// SELinux keystore key backend, and the result is used
378/// as target context.
379pub fn check_grant_permission(
380 caller_ctx: &selinux::Context,
381 access_vec: KeyPermSet,
382 key: &aidl::KeyDescriptor,
383) -> anyhow::Result<()> {
384 use aidl::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700385
386 let target_context = match key.domain {
387 Domain::App => getcon().context("check_grant_permission: getcon failed.")?,
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000388 Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
389 .context("check_grant_permission: Domain::SELinux: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700390 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
391 };
392
393 selinux::check_access(caller_ctx, &target_context, "keystore2_key", "grant")
394 .context("Grant permission is required when granting.")?;
395
396 if access_vec.includes(KeyPerm::grant()) {
397 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
398 }
399
400 for p in access_vec.into_iter() {
401 selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
402 .context(concat!(
403 "check_grant_permission: check_access failed. ",
404 "The caller may have tried to grant a permission that they don't possess."
405 ))?
406 }
407 Ok(())
408}
409
410/// Uses `selinux::check_access` to check if the given caller context `caller_cxt`
411/// has the permissions indicated by `perm` for the target domain indicated by the key
412/// descriptor `key` in the security class `keystore2_key`.
413///
414/// The behavior differs slightly depending on the selected target domain:
415/// * `Domain::App` u:r:keystore:s0 is used as target context.
416/// * `Domain::SELinux` `key.namespace_` parameter is looked up in the SELinux keystore key
417/// backend, and the result is used as target context.
418/// * `Domain::Blob` Same as SELinux but the "manage_blob" permission is always checked additionally
419/// to the one supplied in `perm`.
420/// * `Domain::Grant` Does not use selinux::check_access. Instead the `access_vector`
421/// parameter is queried for permission, which must be supplied in this case.
422///
423/// ## Return values.
424/// * Ok(()) If the requested permissions were granted.
425/// * Err(selinux::Error::perm()) If the requested permissions were denied.
426/// * Err(KsError::sys()) This error is produced if `Domain::Grant` is selected but no `access_vec`
427/// was supplied. It is also produced if `Domain::KeyId` was selected, and
428/// on various unexpected backend failures.
429pub fn check_key_permission(
430 caller_ctx: &selinux::Context,
431 perm: KeyPerm,
432 key: &aidl::KeyDescriptor,
433 access_vector: &Option<KeyPermSet>,
434) -> anyhow::Result<()> {
435 use aidl::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700436
437 let target_context = match key.domain {
438 // apps get the default keystore context
439 Domain::App => getcon().context("check_key_permission: getcon failed.")?,
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000440 Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
441 .context("check_key_permission: Domain::SELinux: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700442 Domain::Grant => {
443 match access_vector {
444 Some(pv) => {
445 if pv.includes(perm) {
446 return Ok(());
447 } else {
448 return Err(selinux::Error::perm())
449 .context(format!("\"{}\" not granted", perm.to_selinux()));
450 }
451 }
452 None => {
453 // If DOMAIN_GRANT was selected an access vector must be supplied.
454 return Err(KsError::sys()).context(
455 "Cannot check permission for Domain::Grant without access vector.",
456 );
457 }
458 }
459 }
460 Domain::KeyId => {
461 // We should never be called with `Domain::KeyId. The database
462 // lookup should have converted this into one of `Domain::App`
463 // or `Domain::SELinux`.
464 return Err(KsError::sys()).context("Cannot check permission for Domain::KeyId.");
465 }
466 Domain::Blob => {
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000467 let tctx = lookup_keystore2_key_context(key.namespace_)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700468 .context("Domain::Blob: Failed to lookup namespace.")?;
469 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
470 // permission in addition to the requested permission.
471 selinux::check_access(
472 caller_ctx,
473 &tctx,
474 "keystore2_key",
475 KeyPerm::manage_blob().to_selinux(),
476 )?;
477
478 tctx
479 }
480 };
481
482 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
483}
484
485#[cfg(test)]
486mod tests {
487 use super::*;
488 use anyhow::anyhow;
489 use anyhow::Result;
490 use keystore2_selinux::*;
491 use keystore_aidl_generated as aidl;
492
493 const ALL_PERMS: KeyPermSet = key_perm_set![
494 KeyPerm::manage_blob(),
495 KeyPerm::delete(),
496 KeyPerm::use_dev_id(),
497 KeyPerm::req_forced_op(),
498 KeyPerm::gen_unique_id(),
499 KeyPerm::grant(),
500 KeyPerm::get_info(),
501 KeyPerm::list(),
502 KeyPerm::rebind(),
503 KeyPerm::update(),
504 KeyPerm::use_(),
505 ];
506
507 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
508 KeyPerm::manage_blob(),
509 KeyPerm::delete(),
510 KeyPerm::use_dev_id(),
511 KeyPerm::req_forced_op(),
512 KeyPerm::gen_unique_id(),
513 // No KeyPerm::grant()
514 KeyPerm::get_info(),
515 KeyPerm::list(),
516 KeyPerm::rebind(),
517 KeyPerm::update(),
518 KeyPerm::use_(),
519 ];
520
521 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
522 KeyPerm::delete(),
523 KeyPerm::get_info(),
524 KeyPerm::list(),
525 KeyPerm::rebind(),
526 KeyPerm::update(),
527 KeyPerm::use_(),
528 ];
529
530 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
531 /// SePolicy (system/sepolicy).
532 const SU_KEY_NAMESPACE: i32 = 0;
533 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
534 /// SePolicy (system/sepolicy).
535 const SHELL_KEY_NAMESPACE: i32 = 1;
536
537 pub fn test_getcon() -> Result<Context> {
538 Context::new("u:object_r:keystore:s0")
539 }
540
541 // This macro evaluates the given expression and checks that
542 // a) evaluated to Result::Err() and that
543 // b) the wrapped error is selinux::Error::perm() (permission denied).
544 // We use a macro here because a function would mask which invocation caused the failure.
545 //
546 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
547 macro_rules! assert_perm_failed {
548 ($test_function:expr) => {
549 let result = $test_function;
550 assert!(result.is_err(), "Permission check should have failed.");
551 assert_eq!(
552 Some(&selinux::Error::perm()),
553 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
554 );
555 };
556 }
557
558 fn check_context() -> Result<(selinux::Context, i32, bool)> {
559 // Calling the non mocked selinux::getcon here intended.
560 let context = selinux::getcon()?;
561 match context.to_str().unwrap() {
562 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
563 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
564 c => Err(anyhow!(format!(
565 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
566 c
567 ))),
568 }
569 }
570
571 #[test]
572 fn check_keystore_permission_test() -> Result<()> {
573 let system_server_ctx = Context::new("u:r:system_server:s0")?;
574 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
575 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
576 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
577 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
578 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
579 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
580 let shell_ctx = Context::new("u:r:shell:s0")?;
581 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
582 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
583 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()));
584 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
585 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
586 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
587 Ok(())
588 }
589
590 #[test]
591 fn check_grant_permission_app() -> Result<()> {
592 let system_server_ctx = Context::new("u:r:system_server:s0")?;
593 let shell_ctx = Context::new("u:r:shell:s0")?;
594 use aidl::Domain;
595 let key =
596 aidl::KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
597 assert!(check_grant_permission(&system_server_ctx, NOT_GRANT_PERMS, &key).is_ok());
598 // attempts to grant the grant permission must always fail even when privileged.
599
600 assert_perm_failed!(check_grant_permission(
601 &system_server_ctx,
602 KeyPerm::grant().into(),
603 &key
604 ));
605 // unprivileged grant attempts always fail. shell does not have the grant permission.
606 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
607 Ok(())
608 }
609
610 #[test]
611 fn check_grant_permission_selinux() -> Result<()> {
612 use aidl::Domain;
613 let (sctx, namespace, is_su) = check_context()?;
614 let key = aidl::KeyDescriptor {
615 domain: Domain::SELinux,
616 namespace_: namespace as i64,
617 alias: None,
618 blob: None,
619 };
620 if is_su {
621 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
622 // attempts to grant the grant permission must always fail even when privileged.
623 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
624 } else {
625 // unprivileged grant attempts always fail. shell does not have the grant permission.
626 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
627 }
628 Ok(())
629 }
630
631 #[test]
632 fn check_key_permission_domain_grant() -> Result<()> {
633 use aidl::Domain;
634 let key =
635 aidl::KeyDescriptor { domain: Domain::Grant, namespace_: 0, alias: None, blob: None };
636
637 assert_perm_failed!(check_key_permission(
638 &selinux::Context::new("ignored").unwrap(),
639 KeyPerm::grant(),
640 &key,
641 &Some(UNPRIV_PERMS)
642 ));
643
644 check_key_permission(
645 &selinux::Context::new("ignored").unwrap(),
646 KeyPerm::use_(),
647 &key,
648 &Some(ALL_PERMS),
649 )
650 }
651
652 #[test]
653 fn check_key_permission_domain_app() -> Result<()> {
654 let system_server_ctx = Context::new("u:r:system_server:s0")?;
655 let shell_ctx = Context::new("u:r:shell:s0")?;
656 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
657 use aidl::Domain;
658
659 let key =
660 aidl::KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
661
662 assert!(check_key_permission(&system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
663 assert!(check_key_permission(&system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
664 assert!(check_key_permission(&system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok());
665 assert!(check_key_permission(&system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
666 assert!(check_key_permission(&system_server_ctx, KeyPerm::list(), &key, &None).is_ok());
667 assert!(check_key_permission(&system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
668 assert!(check_key_permission(&system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
669 assert!(
670 check_key_permission(&system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
671 );
672 assert!(check_key_permission(&gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok());
673
674 assert!(check_key_permission(&shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
675 assert!(check_key_permission(&shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
676 assert!(check_key_permission(&shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
677 assert!(check_key_permission(&shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
678 assert!(check_key_permission(&shell_ctx, KeyPerm::list(), &key, &None).is_ok());
679 assert!(check_key_permission(&shell_ctx, KeyPerm::update(), &key, &None).is_ok());
680 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::grant(), &key, &None));
681 assert_perm_failed!(check_key_permission(
682 &shell_ctx,
683 KeyPerm::req_forced_op(),
684 &key,
685 &None
686 ));
687 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::manage_blob(), &key, &None));
688 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::use_dev_id(), &key, &None));
689 assert_perm_failed!(check_key_permission(
690 &shell_ctx,
691 KeyPerm::gen_unique_id(),
692 &key,
693 &None
694 ));
695
696 Ok(())
697 }
698
699 #[test]
700 fn check_key_permission_domain_selinux() -> Result<()> {
701 use aidl::Domain;
702 let (sctx, namespace, is_su) = check_context()?;
703 let key = aidl::KeyDescriptor {
704 domain: Domain::SELinux,
705 namespace_: namespace as i64,
706 alias: None,
707 blob: None,
708 };
709
710 if is_su {
711 assert!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None).is_ok());
712 assert!(check_key_permission(&sctx, KeyPerm::delete(), &key, &None).is_ok());
713 assert!(check_key_permission(&sctx, KeyPerm::get_info(), &key, &None).is_ok());
714 assert!(check_key_permission(&sctx, KeyPerm::rebind(), &key, &None).is_ok());
715 assert!(check_key_permission(&sctx, KeyPerm::list(), &key, &None).is_ok());
716 assert!(check_key_permission(&sctx, KeyPerm::update(), &key, &None).is_ok());
717 assert!(check_key_permission(&sctx, KeyPerm::grant(), &key, &None).is_ok());
718 assert!(check_key_permission(&sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
719 assert!(check_key_permission(&sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
720 assert!(check_key_permission(&sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
721 assert!(check_key_permission(&sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
722 } else {
723 assert!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None).is_ok());
724 assert!(check_key_permission(&sctx, KeyPerm::delete(), &key, &None).is_ok());
725 assert!(check_key_permission(&sctx, KeyPerm::get_info(), &key, &None).is_ok());
726 assert!(check_key_permission(&sctx, KeyPerm::rebind(), &key, &None).is_ok());
727 assert!(check_key_permission(&sctx, KeyPerm::list(), &key, &None).is_ok());
728 assert!(check_key_permission(&sctx, KeyPerm::update(), &key, &None).is_ok());
729 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::grant(), &key, &None));
730 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::req_forced_op(), &key, &None));
731 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::manage_blob(), &key, &None));
732 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::use_dev_id(), &key, &None));
733 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::gen_unique_id(), &key, &None));
734 }
735 Ok(())
736 }
737
738 #[test]
739 fn check_key_permission_domain_blob() -> Result<()> {
740 use aidl::Domain;
741 let (sctx, namespace, is_su) = check_context()?;
742 let key = aidl::KeyDescriptor {
743 domain: Domain::Blob,
744 namespace_: namespace as i64,
745 alias: None,
746 blob: None,
747 };
748
749 if is_su {
750 check_key_permission(&sctx, KeyPerm::use_(), &key, &None)
751 } else {
752 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None));
753 Ok(())
754 }
755 }
756
757 #[test]
758 fn check_key_permission_domain_key_id() -> Result<()> {
759 use aidl::Domain;
760 let key =
761 aidl::KeyDescriptor { domain: Domain::KeyId, namespace_: 0, alias: None, blob: None };
762
763 assert_eq!(
764 Some(&KsError::sys()),
765 check_key_permission(
766 &selinux::Context::new("ignored").unwrap(),
767 KeyPerm::use_(),
768 &key,
769 &None
770 )
771 .err()
772 .unwrap()
773 .root_cause()
774 .downcast_ref::<KsError>()
775 );
776 Ok(())
777 }
778
779 #[test]
780 fn key_perm_set_all_test() {
781 let v = key_perm_set![
782 KeyPerm::manage_blob(),
783 KeyPerm::delete(),
784 KeyPerm::use_dev_id(),
785 KeyPerm::req_forced_op(),
786 KeyPerm::gen_unique_id(),
787 KeyPerm::grant(),
788 KeyPerm::get_info(),
789 KeyPerm::list(),
790 KeyPerm::rebind(),
791 KeyPerm::update(),
792 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
793 ];
794 let mut i = v.into_iter();
795 assert_eq!(i.next().unwrap().to_selinux(), "delete");
796 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
797 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
798 assert_eq!(i.next().unwrap().to_selinux(), "grant");
799 assert_eq!(i.next().unwrap().to_selinux(), "list");
800 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
801 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
802 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
803 assert_eq!(i.next().unwrap().to_selinux(), "update");
804 assert_eq!(i.next().unwrap().to_selinux(), "use");
805 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
806 assert_eq!(None, i.next());
807 }
808 #[test]
809 fn key_perm_set_sparse_test() {
810 let v = key_perm_set![
811 KeyPerm::manage_blob(),
812 KeyPerm::req_forced_op(),
813 KeyPerm::gen_unique_id(),
814 KeyPerm::list(),
815 KeyPerm::update(),
816 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
817 ];
818 let mut i = v.into_iter();
819 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
820 assert_eq!(i.next().unwrap().to_selinux(), "list");
821 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
822 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
823 assert_eq!(i.next().unwrap().to_selinux(), "update");
824 assert_eq!(i.next().unwrap().to_selinux(), "use");
825 assert_eq!(None, i.next());
826 }
827 #[test]
828 fn key_perm_set_empty_test() {
829 let v = key_perm_set![];
830 let mut i = v.into_iter();
831 assert_eq!(None, i.next());
832 }
833 #[test]
834 fn key_perm_set_include_subset_test() {
835 let v1 = key_perm_set![
836 KeyPerm::manage_blob(),
837 KeyPerm::delete(),
838 KeyPerm::use_dev_id(),
839 KeyPerm::req_forced_op(),
840 KeyPerm::gen_unique_id(),
841 KeyPerm::grant(),
842 KeyPerm::get_info(),
843 KeyPerm::list(),
844 KeyPerm::rebind(),
845 KeyPerm::update(),
846 KeyPerm::use_(),
847 ];
848 let v2 = key_perm_set![
849 KeyPerm::manage_blob(),
850 KeyPerm::delete(),
851 KeyPerm::list(),
852 KeyPerm::rebind(),
853 KeyPerm::update(),
854 KeyPerm::use_(),
855 ];
856 assert!(v1.includes(v2));
857 assert!(!v2.includes(v1));
858 }
859 #[test]
860 fn key_perm_set_include_equal_test() {
861 let v1 = key_perm_set![
862 KeyPerm::manage_blob(),
863 KeyPerm::delete(),
864 KeyPerm::list(),
865 KeyPerm::rebind(),
866 KeyPerm::update(),
867 KeyPerm::use_(),
868 ];
869 let v2 = key_perm_set![
870 KeyPerm::manage_blob(),
871 KeyPerm::delete(),
872 KeyPerm::list(),
873 KeyPerm::rebind(),
874 KeyPerm::update(),
875 KeyPerm::use_(),
876 ];
877 assert!(v1.includes(v2));
878 assert!(v2.includes(v1));
879 }
880 #[test]
881 fn key_perm_set_include_overlap_test() {
882 let v1 = key_perm_set![
883 KeyPerm::manage_blob(),
884 KeyPerm::delete(),
885 KeyPerm::grant(), // only in v1
886 KeyPerm::list(),
887 KeyPerm::rebind(),
888 KeyPerm::update(),
889 KeyPerm::use_(),
890 ];
891 let v2 = key_perm_set![
892 KeyPerm::manage_blob(),
893 KeyPerm::delete(),
894 KeyPerm::req_forced_op(), // only in v2
895 KeyPerm::list(),
896 KeyPerm::rebind(),
897 KeyPerm::update(),
898 KeyPerm::use_(),
899 ];
900 assert!(!v1.includes(v2));
901 assert!(!v2.includes(v1));
902 }
903 #[test]
904 fn key_perm_set_include_no_overlap_test() {
905 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
906 let v2 = key_perm_set![
907 KeyPerm::req_forced_op(),
908 KeyPerm::list(),
909 KeyPerm::rebind(),
910 KeyPerm::update(),
911 KeyPerm::use_(),
912 ];
913 assert!(!v1.includes(v2));
914 assert!(!v2.includes(v1));
915 }
916}