blob: a81954fe28aa1bff01ce0d0acf1e270a8bef3617 [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
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700152 impl Into<$aidl_name> for $name {
153 fn into(self) -> $aidl_name {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700154 self.0
155 }
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) {
196 DELETE, selinux name: delete;
197 GEN_UNIQUE_ID, selinux name: gen_unique_id;
198 GET_INFO, selinux name: get_info;
199 GRANT, selinux name: grant;
200 MANAGE_BLOB, selinux name: manage_blob;
201 REBIND, selinux name: rebind;
202 REQ_FORCED_OP, selinux name: req_forced_op;
203 UPDATE, selinux name: update;
204 USE, selinux name: use;
205 USE_DEV_ID, selinux name: use_dev_id;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700206 }
207);
208
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700209/// This macro implements an enum with values mapped to SELinux permission names.
210/// The below example wraps the enum MyPermission in the tuple struct `MyPerm` and implements
211/// * From<i32> and Into<i32> are implemented. Where the implementation of From maps
212/// any variant not specified to the default.
213/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
214/// representation.
215/// * `MyPerm.to_selinux(&self)` returns the SELinux string representation of the
216/// represented permission.
217///
218/// ## Example
219/// ```
220/// implement_permission!(
221/// /// MyPerm documentation.
222/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
223/// MyPerm with default (None = 0, none) {
224/// Foo = 1, selinux name: foo;
225/// Bar = 2, selinux name: bar;
226/// }
227/// );
228/// ```
229macro_rules! implement_permission {
230 // This rule provides the public interface of the macro. And starts the preprocessing
231 // recursion (see below).
232 ($(#[$m:meta])* $name:ident with default
233 ($def_name:ident = $def_val:expr, $def_selinux_name:ident)
234 {
235 $($(#[$element_meta:meta])*
236 $element_name:ident = $element_val:expr, selinux name: $selinux_name:ident;)*
237 })
238 => {
239 $(#[$m])*
240 pub enum $name {
241 /// The default variant of an enum.
242 $def_name = $def_val,
243 $(
244 $(#[$element_meta])*
245 $element_name = $element_val,
246 )*
247 }
248
249 impl From<i32> for $name {
250 fn from (p: i32) -> Self {
251 match p {
252 $def_val => Self::$def_name,
253 $($element_val => Self::$element_name,)*
254 _ => Self::$def_name,
255 }
256 }
257 }
258
259 impl Into<i32> for $name {
260 fn into(self) -> i32 {
261 self as i32
262 }
263 }
264
265 impl $name {
266 /// Returns a string representation of the permission as required by
267 /// `selinux::check_access`.
268 pub fn to_selinux(&self) -> &'static str {
269 match self {
270 Self::$def_name => stringify!($def_selinux_name),
271 $(Self::$element_name => stringify!($selinux_name),)*
272 }
273 }
274
275 /// Creates an instance representing a permission with the same name.
276 pub const fn $def_selinux_name() -> Self { Self::$def_name }
277 $(
278 /// Creates an instance representing a permission with the same name.
279 pub const fn $selinux_name() -> Self { Self::$element_name }
280 )*
281 }
282 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700283}
284
285implement_permission!(
286 /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
287 /// Using the implement_permission macro we get the same features as `KeyPerm`.
288 #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700289 KeystorePerm with default (None = 0, none) {
290 /// Checked when a new auth token is installed.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700291 AddAuth = 1, selinux name: add_auth;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700292 /// Checked when an app is uninstalled or wiped.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700293 ClearNs = 2, selinux name: clear_ns;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700294 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700295 GetState = 4, selinux name: get_state;
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700296 /// Checked when Keystore 2.0 is asked to list a namespace that the caller
297 /// does not have the get_info permission for.
298 List = 8, selinux name: list;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700299 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700300 Lock = 0x10, selinux name: lock;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700301 /// Checked when Keystore 2.0 shall be reset.
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700302 Reset = 0x20, selinux name: reset;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700303 /// Checked when Keystore 2.0 shall be unlocked.
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700304 Unlock = 0x40, selinux name: unlock;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700305 }
306);
307
308/// Represents a set of `KeyPerm` permissions.
309/// `IntoIterator` is implemented for this struct allowing the iteration through all the
310/// permissions in the set.
311/// It also implements a function `includes(self, other)` that checks if the permissions
312/// in `other` are included in `self`.
313///
314/// KeyPermSet can be created with the macro `key_perm_set![]`.
315///
316/// ## Example
317/// ```
318/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
319/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
320///
321/// assert!(perms1.includes(perms2))
322/// assert!(!perms2.includes(perms1))
323///
324/// let i = perms1.into_iter();
325/// // iteration in ascending order of the permission's numeric representation.
326/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
327/// assert_eq(Some(KeyPerm::grant()), i.next());
328/// assert_eq(Some(KeyPerm::use_()), i.next());
329/// assert_eq(None, i.next());
330/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700331#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
332pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700333
334mod perm {
335 use super::*;
336
337 pub struct IntoIter {
338 vec: KeyPermSet,
339 pos: u8,
340 }
341
342 impl IntoIter {
343 pub fn new(v: KeyPermSet) -> Self {
344 Self { vec: v, pos: 0 }
345 }
346 }
347
348 impl std::iter::Iterator for IntoIter {
349 type Item = KeyPerm;
350
351 fn next(&mut self) -> Option<Self::Item> {
352 loop {
353 if self.pos == 32 {
354 return None;
355 }
356 let p = self.vec.0 & (1 << self.pos);
357 self.pos += 1;
358 if p != 0 {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700359 return Some(KeyPerm::from(KeyPermission(p)));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700360 }
361 }
362 }
363 }
364}
365
366impl From<KeyPerm> for KeyPermSet {
367 fn from(p: KeyPerm) -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700368 Self((p.0).0 as i32)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700369 }
370}
371
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700372/// allow conversion from the AIDL wire type i32 to a permission set.
373impl From<i32> for KeyPermSet {
374 fn from(p: i32) -> Self {
375 Self(p)
376 }
377}
378
379impl From<KeyPermSet> for i32 {
380 fn from(p: KeyPermSet) -> i32 {
381 p.0
382 }
383}
384
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700385impl KeyPermSet {
386 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700387 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700388 let o: KeyPermSet = other.into();
389 (self.0 & o.0) == o.0
390 }
391}
392
393/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
394///
395/// ## Example
396/// ```
397/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
398/// ```
399#[macro_export]
400macro_rules! key_perm_set {
401 () => { KeyPermSet(0) };
402 ($head:expr $(, $tail:expr)* $(,)?) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700403 KeyPermSet(($head.0).0 $(| ($tail.0).0)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700404 };
405}
406
407impl IntoIterator for KeyPermSet {
408 type Item = KeyPerm;
409 type IntoIter = perm::IntoIter;
410
411 fn into_iter(self) -> Self::IntoIter {
412 Self::IntoIter::new(self)
413 }
414}
415
416/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
417/// the given permision `perm` of the `keystore2` security class.
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700418pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700419 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
420 selinux::check_access(caller_ctx, &target_context, "keystore2", perm.to_selinux())
421}
422
423/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` has
424/// all the permissions indicated in `access_vec` for the target domain indicated by the key
425/// descriptor `key` in the security class `keystore2_key`.
426///
427/// Also checks if the caller has the grant permission for the given target domain.
428///
429/// Attempts to grant the grant permission are always denied.
430///
431/// The only viable target domains are
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700432/// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
433/// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700434/// SELinux keystore key backend, and the result is used
435/// as target context.
436pub fn check_grant_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700437 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700438 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700439 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700440) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700441 let target_context = match key.domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700442 Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
443 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
444 .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700445 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
446 };
447
448 selinux::check_access(caller_ctx, &target_context, "keystore2_key", "grant")
449 .context("Grant permission is required when granting.")?;
450
451 if access_vec.includes(KeyPerm::grant()) {
452 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
453 }
454
455 for p in access_vec.into_iter() {
456 selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
457 .context(concat!(
458 "check_grant_permission: check_access failed. ",
459 "The caller may have tried to grant a permission that they don't possess."
460 ))?
461 }
462 Ok(())
463}
464
465/// Uses `selinux::check_access` to check if the given caller context `caller_cxt`
466/// has the permissions indicated by `perm` for the target domain indicated by the key
467/// descriptor `key` in the security class `keystore2_key`.
468///
469/// The behavior differs slightly depending on the selected target domain:
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700470/// * `Domain::APP` u:r:keystore:s0 is used as target context.
471/// * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700472/// backend, and the result is used as target context.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700473/// * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700474/// to the one supplied in `perm`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700475/// * `Domain::GRANT` Does not use selinux::check_access. Instead the `access_vector`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700476/// parameter is queried for permission, which must be supplied in this case.
477///
478/// ## Return values.
479/// * Ok(()) If the requested permissions were granted.
480/// * Err(selinux::Error::perm()) If the requested permissions were denied.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700481/// * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
482/// was supplied. It is also produced if `Domain::KEY_ID` was selected, and
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700483/// on various unexpected backend failures.
484pub fn check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800485 caller_uid: u32,
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700486 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700487 perm: KeyPerm,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700488 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700489 access_vector: &Option<KeyPermSet>,
490) -> anyhow::Result<()> {
Janis Danisevskis45760022021-01-19 16:34:10 -0800491 // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID.
492 // In the former case, key.domain was set to GRANT and we check the failure cases
493 // further below. If the access is requested by KEY_ID, key.domain would have been
494 // resolved to APP or SELINUX depending on where the key actually resides.
495 // Either way we can return here immediately if the access vector covers the requested
496 // permission. If it does not, we can still check if the caller has access by means of
497 // ownership.
498 if let Some(access_vector) = access_vector {
499 if access_vector.includes(perm) {
500 return Ok(());
501 }
502 }
503
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700504 let target_context = match key.domain {
505 // apps get the default keystore context
Janis Danisevskis45760022021-01-19 16:34:10 -0800506 Domain::APP => {
507 if caller_uid as i64 != key.nspace {
508 return Err(selinux::Error::perm())
509 .context("Trying to access key without ownership.");
510 }
511 getcon().context("check_key_permission: getcon failed.")?
512 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700513 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
514 .context("check_key_permission: Domain::SELINUX: Failed to lookup namespace.")?,
515 Domain::GRANT => {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700516 match access_vector {
Janis Danisevskis45760022021-01-19 16:34:10 -0800517 Some(_) => {
518 return Err(selinux::Error::perm())
519 .context(format!("\"{}\" not granted", perm.to_selinux()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700520 }
521 None => {
522 // If DOMAIN_GRANT was selected an access vector must be supplied.
523 return Err(KsError::sys()).context(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700524 "Cannot check permission for Domain::GRANT without access vector.",
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700525 );
526 }
527 }
528 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700529 Domain::KEY_ID => {
530 // We should never be called with `Domain::KEY_ID. The database
531 // lookup should have converted this into one of `Domain::APP`
532 // or `Domain::SELINUX`.
533 return Err(KsError::sys()).context("Cannot check permission for Domain::KEY_ID.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700534 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700535 Domain::BLOB => {
536 let tctx = lookup_keystore2_key_context(key.nspace)
537 .context("Domain::BLOB: Failed to lookup namespace.")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700538 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
539 // permission in addition to the requested permission.
540 selinux::check_access(
541 caller_ctx,
542 &tctx,
543 "keystore2_key",
544 KeyPerm::manage_blob().to_selinux(),
545 )?;
546
547 tctx
548 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700549 _ => {
550 return Err(KsError::sys())
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700551 .context(format!("Unknown domain value: \"{:?}\".", key.domain))
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700552 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700553 };
554
555 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
556}
557
558#[cfg(test)]
559mod tests {
560 use super::*;
561 use anyhow::anyhow;
562 use anyhow::Result;
563 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700564
565 const ALL_PERMS: KeyPermSet = key_perm_set![
566 KeyPerm::manage_blob(),
567 KeyPerm::delete(),
568 KeyPerm::use_dev_id(),
569 KeyPerm::req_forced_op(),
570 KeyPerm::gen_unique_id(),
571 KeyPerm::grant(),
572 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700573 KeyPerm::rebind(),
574 KeyPerm::update(),
575 KeyPerm::use_(),
576 ];
577
578 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
579 KeyPerm::manage_blob(),
580 KeyPerm::delete(),
581 KeyPerm::use_dev_id(),
582 KeyPerm::req_forced_op(),
583 KeyPerm::gen_unique_id(),
584 // No KeyPerm::grant()
585 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700586 KeyPerm::rebind(),
587 KeyPerm::update(),
588 KeyPerm::use_(),
589 ];
590
591 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
592 KeyPerm::delete(),
593 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700594 KeyPerm::rebind(),
595 KeyPerm::update(),
596 KeyPerm::use_(),
597 ];
598
599 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
600 /// SePolicy (system/sepolicy).
601 const SU_KEY_NAMESPACE: i32 = 0;
602 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
603 /// SePolicy (system/sepolicy).
604 const SHELL_KEY_NAMESPACE: i32 = 1;
605
606 pub fn test_getcon() -> Result<Context> {
607 Context::new("u:object_r:keystore:s0")
608 }
609
610 // This macro evaluates the given expression and checks that
611 // a) evaluated to Result::Err() and that
612 // b) the wrapped error is selinux::Error::perm() (permission denied).
613 // We use a macro here because a function would mask which invocation caused the failure.
614 //
615 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
616 macro_rules! assert_perm_failed {
617 ($test_function:expr) => {
618 let result = $test_function;
619 assert!(result.is_err(), "Permission check should have failed.");
620 assert_eq!(
621 Some(&selinux::Error::perm()),
622 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
623 );
624 };
625 }
626
627 fn check_context() -> Result<(selinux::Context, i32, bool)> {
628 // Calling the non mocked selinux::getcon here intended.
629 let context = selinux::getcon()?;
630 match context.to_str().unwrap() {
631 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
632 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
633 c => Err(anyhow!(format!(
634 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
635 c
636 ))),
637 }
638 }
639
640 #[test]
641 fn check_keystore_permission_test() -> Result<()> {
642 let system_server_ctx = Context::new("u:r:system_server:s0")?;
643 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
644 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
645 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700646 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::list()).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700647 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
648 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
649 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
650 let shell_ctx = Context::new("u:r:shell:s0")?;
651 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
652 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
653 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()));
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700654 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::list()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700655 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
656 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
657 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
658 Ok(())
659 }
660
661 #[test]
662 fn check_grant_permission_app() -> Result<()> {
663 let system_server_ctx = Context::new("u:r:system_server:s0")?;
664 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700665 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700666 assert!(check_grant_permission(&system_server_ctx, NOT_GRANT_PERMS, &key).is_ok());
667 // attempts to grant the grant permission must always fail even when privileged.
668
669 assert_perm_failed!(check_grant_permission(
670 &system_server_ctx,
671 KeyPerm::grant().into(),
672 &key
673 ));
674 // unprivileged grant attempts always fail. shell does not have the grant permission.
675 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
676 Ok(())
677 }
678
679 #[test]
680 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700681 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700682 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700683 domain: Domain::SELINUX,
684 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700685 alias: None,
686 blob: None,
687 };
688 if is_su {
689 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
690 // attempts to grant the grant permission must always fail even when privileged.
691 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
692 } else {
693 // unprivileged grant attempts always fail. shell does not have the grant permission.
694 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
695 }
696 Ok(())
697 }
698
699 #[test]
700 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700701 let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700702
703 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800704 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700705 &selinux::Context::new("ignored").unwrap(),
706 KeyPerm::grant(),
707 &key,
708 &Some(UNPRIV_PERMS)
709 ));
710
711 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800712 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700713 &selinux::Context::new("ignored").unwrap(),
714 KeyPerm::use_(),
715 &key,
716 &Some(ALL_PERMS),
717 )
718 }
719
720 #[test]
721 fn check_key_permission_domain_app() -> Result<()> {
722 let system_server_ctx = Context::new("u:r:system_server:s0")?;
723 let shell_ctx = Context::new("u:r:shell:s0")?;
724 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700725
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700726 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700727
Janis Danisevskis45760022021-01-19 16:34:10 -0800728 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
729 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700730 assert!(
Janis Danisevskis45760022021-01-19 16:34:10 -0800731 check_key_permission(0, &system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok()
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700732 );
Janis Danisevskis45760022021-01-19 16:34:10 -0800733 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
734 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
735 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
736 assert!(
737 check_key_permission(0, &system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
738 );
739 assert!(
740 check_key_permission(0, &gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok()
741 );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700742
Janis Danisevskis45760022021-01-19 16:34:10 -0800743 assert!(check_key_permission(0, &shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
744 assert!(check_key_permission(0, &shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
745 assert!(check_key_permission(0, &shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
746 assert!(check_key_permission(0, &shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
747 assert!(check_key_permission(0, &shell_ctx, KeyPerm::update(), &key, &None).is_ok());
748 assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::grant(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700749 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800750 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700751 &shell_ctx,
752 KeyPerm::req_forced_op(),
753 &key,
754 &None
755 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700756 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800757 0,
758 &shell_ctx,
759 KeyPerm::manage_blob(),
760 &key,
761 &None
762 ));
763 assert_perm_failed!(check_key_permission(
764 0,
765 &shell_ctx,
766 KeyPerm::use_dev_id(),
767 &key,
768 &None
769 ));
770 assert_perm_failed!(check_key_permission(
771 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700772 &shell_ctx,
773 KeyPerm::gen_unique_id(),
774 &key,
775 &None
776 ));
777
Janis Danisevskis45760022021-01-19 16:34:10 -0800778 // Also make sure that the permission fails if the caller is not the owner.
779 assert_perm_failed!(check_key_permission(
780 1, // the owner is 0
781 &system_server_ctx,
782 KeyPerm::use_(),
783 &key,
784 &None
785 ));
786 // Unless there was a grant.
787 assert!(check_key_permission(
788 1,
789 &system_server_ctx,
790 KeyPerm::use_(),
791 &key,
792 &Some(key_perm_set![KeyPerm::use_()])
793 )
794 .is_ok());
795 // But fail if the grant did not cover the requested permission.
796 assert_perm_failed!(check_key_permission(
797 1,
798 &system_server_ctx,
799 KeyPerm::use_(),
800 &key,
801 &Some(key_perm_set![KeyPerm::get_info()])
802 ));
803
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700804 Ok(())
805 }
806
807 #[test]
808 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700809 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700810 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700811 domain: Domain::SELINUX,
812 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700813 alias: None,
814 blob: None,
815 };
816
817 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800818 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
819 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
820 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
821 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
822 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
823 assert!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None).is_ok());
824 assert!(check_key_permission(0, &sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
825 assert!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
826 assert!(check_key_permission(0, &sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
827 assert!(check_key_permission(0, &sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700828 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800829 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
830 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
831 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
832 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
833 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
834 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None));
835 assert_perm_failed!(check_key_permission(
836 0,
837 &sctx,
838 KeyPerm::req_forced_op(),
839 &key,
840 &None
841 ));
842 assert_perm_failed!(check_key_permission(
843 0,
844 &sctx,
845 KeyPerm::manage_blob(),
846 &key,
847 &None
848 ));
849 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None));
850 assert_perm_failed!(check_key_permission(
851 0,
852 &sctx,
853 KeyPerm::gen_unique_id(),
854 &key,
855 &None
856 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700857 }
858 Ok(())
859 }
860
861 #[test]
862 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700863 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700864 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700865 domain: Domain::BLOB,
866 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700867 alias: None,
868 blob: None,
869 };
870
871 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -0800872 check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700873 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -0800874 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700875 Ok(())
876 }
877 }
878
879 #[test]
880 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700881 let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700882
883 assert_eq!(
884 Some(&KsError::sys()),
885 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800886 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700887 &selinux::Context::new("ignored").unwrap(),
888 KeyPerm::use_(),
889 &key,
890 &None
891 )
892 .err()
893 .unwrap()
894 .root_cause()
895 .downcast_ref::<KsError>()
896 );
897 Ok(())
898 }
899
900 #[test]
901 fn key_perm_set_all_test() {
902 let v = key_perm_set![
903 KeyPerm::manage_blob(),
904 KeyPerm::delete(),
905 KeyPerm::use_dev_id(),
906 KeyPerm::req_forced_op(),
907 KeyPerm::gen_unique_id(),
908 KeyPerm::grant(),
909 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700910 KeyPerm::rebind(),
911 KeyPerm::update(),
912 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
913 ];
914 let mut i = v.into_iter();
915 assert_eq!(i.next().unwrap().to_selinux(), "delete");
916 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
917 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
918 assert_eq!(i.next().unwrap().to_selinux(), "grant");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700919 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
920 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
921 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
922 assert_eq!(i.next().unwrap().to_selinux(), "update");
923 assert_eq!(i.next().unwrap().to_selinux(), "use");
924 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
925 assert_eq!(None, i.next());
926 }
927 #[test]
928 fn key_perm_set_sparse_test() {
929 let v = key_perm_set![
930 KeyPerm::manage_blob(),
931 KeyPerm::req_forced_op(),
932 KeyPerm::gen_unique_id(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700933 KeyPerm::update(),
934 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
935 ];
936 let mut i = v.into_iter();
937 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700938 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
939 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
940 assert_eq!(i.next().unwrap().to_selinux(), "update");
941 assert_eq!(i.next().unwrap().to_selinux(), "use");
942 assert_eq!(None, i.next());
943 }
944 #[test]
945 fn key_perm_set_empty_test() {
946 let v = key_perm_set![];
947 let mut i = v.into_iter();
948 assert_eq!(None, i.next());
949 }
950 #[test]
951 fn key_perm_set_include_subset_test() {
952 let v1 = key_perm_set![
953 KeyPerm::manage_blob(),
954 KeyPerm::delete(),
955 KeyPerm::use_dev_id(),
956 KeyPerm::req_forced_op(),
957 KeyPerm::gen_unique_id(),
958 KeyPerm::grant(),
959 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700960 KeyPerm::rebind(),
961 KeyPerm::update(),
962 KeyPerm::use_(),
963 ];
964 let v2 = key_perm_set![
965 KeyPerm::manage_blob(),
966 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700967 KeyPerm::rebind(),
968 KeyPerm::update(),
969 KeyPerm::use_(),
970 ];
971 assert!(v1.includes(v2));
972 assert!(!v2.includes(v1));
973 }
974 #[test]
975 fn key_perm_set_include_equal_test() {
976 let v1 = key_perm_set![
977 KeyPerm::manage_blob(),
978 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700979 KeyPerm::rebind(),
980 KeyPerm::update(),
981 KeyPerm::use_(),
982 ];
983 let v2 = key_perm_set![
984 KeyPerm::manage_blob(),
985 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700986 KeyPerm::rebind(),
987 KeyPerm::update(),
988 KeyPerm::use_(),
989 ];
990 assert!(v1.includes(v2));
991 assert!(v2.includes(v1));
992 }
993 #[test]
994 fn key_perm_set_include_overlap_test() {
995 let v1 = key_perm_set![
996 KeyPerm::manage_blob(),
997 KeyPerm::delete(),
998 KeyPerm::grant(), // only in v1
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700999 KeyPerm::rebind(),
1000 KeyPerm::update(),
1001 KeyPerm::use_(),
1002 ];
1003 let v2 = key_perm_set![
1004 KeyPerm::manage_blob(),
1005 KeyPerm::delete(),
1006 KeyPerm::req_forced_op(), // only in v2
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001007 KeyPerm::rebind(),
1008 KeyPerm::update(),
1009 KeyPerm::use_(),
1010 ];
1011 assert!(!v1.includes(v2));
1012 assert!(!v2.includes(v1));
1013 }
1014 #[test]
1015 fn key_perm_set_include_no_overlap_test() {
1016 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
1017 let v2 = key_perm_set![
1018 KeyPerm::req_forced_op(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001019 KeyPerm::rebind(),
1020 KeyPerm::update(),
1021 KeyPerm::use_(),
1022 ];
1023 assert!(!v1.includes(v2));
1024 assert!(!v2.includes(v1));
1025 }
1026}