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