blob: e5939c85398a49f080be409dd79a94e6cf115502 [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 Danisevskis1b3a6e22020-08-07 12:39:56 -070021use android_security_keystore2::aidl::android::security::keystore2::KeyPermission;
22
23use android_security_keystore2::aidl::android::security::keystore2::KeyDescriptor::KeyDescriptor;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070024
25use std::cmp::PartialEq;
26use std::convert::From;
27
28use crate::error::Error as KsError;
29use keystore2_selinux as selinux;
30
31use anyhow::Context as AnyhowContext;
32
33use selinux::Backend;
34
Janis Danisevskis4ad056f2020-08-05 19:46:46 +000035use lazy_static::lazy_static;
36
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070037// Replace getcon with a mock in the test situation
38#[cfg(not(test))]
39use selinux::getcon;
40#[cfg(test)]
41use tests::test_getcon as getcon;
42
Janis Danisevskis4ad056f2020-08-05 19:46:46 +000043lazy_static! {
44 // Panicking here is allowed because keystore cannot function without this backend
45 // and it would happen early and indicate a gross misconfiguration of the device.
46 static ref KEYSTORE2_KEY_LABEL_BACKEND: selinux::KeystoreKeyBackend =
47 selinux::KeystoreKeyBackend::new().unwrap();
48}
49
50fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> {
51 KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string())
52}
53
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070054/// ## Background
55///
56/// AIDL enums are represented as constants of the form:
57/// ```
58/// mod EnumName {
59/// pub type EnumName = i32;
60/// pub const Variant1: EnumName = <value1>;
61/// pub const Variant2: EnumName = <value2>;
62/// ...
63/// }
64///```
65/// This macro wraps the enum in a new type, e.g., `MyPerm` and maps each variant to an SELinux
66/// permission while providing the following interface:
67/// * From<EnumName> and Into<EnumName> are implemented. Where the implementation of From maps
68/// any variant not specified to the default.
69/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
70/// representation.
71/// * `MyPerm.to_selinux(&self)` returns the SELinux string representation of the
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070072/// represented permission.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070073///
74/// ## Special behavior
75/// If the keyword `use` appears as an selinux name `use_` is used as identifier for the
76/// constructor function (e.g. `MePerm::use_()`) but the string returned by `to_selinux` will
77/// still be `"use"`.
78///
79/// ## Example
80/// ```
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070081///
82/// implement_permission!(
83/// /// MyPerm documentation.
84/// #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070085/// MyPerm from EnumName with default (None, none) {}
86/// Variant1, selinux name: variant1;
87/// Variant2, selinux name: variant1;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070088/// }
89/// );
90/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070091macro_rules! implement_permission_aidl {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070092 // This rule provides the public interface of the macro. And starts the preprocessing
93 // recursion (see below).
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070094 ($(#[$m:meta])* $name:ident from $aidl_name:ident with default ($($def:tt)*)
95 { $($element:tt)* })
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070096 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -070097 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*), [],
98 $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -070099 };
100
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700101 // The following three rules recurse through the elements of the form
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700102 // `<enum variant>, selinux name: <selinux_name>;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700103 // preprocessing the input.
104
105 // The first rule terminates the recursion and passes the processed arguments to the final
106 // rule that spills out the implementation.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700107 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*], ) => {
108 implement_permission_aidl!(@end $($m)*, $name, $aidl_name, ($($def)*) { $($out)* } );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700109 };
110
111 // The second rule is triggered if the selinux name of an element is literally `use`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700112 // It produces the tuple `<enum variant>, use_, use;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700113 // and appends it to the out list.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700114 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*],
115 $e_name:ident, selinux name: use; $($element:tt)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700116 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700117 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*),
118 [$($out)* $e_name, use_, use;], $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700119 };
120
121 // The third rule is the default rule which replaces every input tuple with
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700122 // `<enum variant>, <selinux_name>, <selinux_name>;`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700123 // and appends the result to the out list.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700124 (@replace_use $($m:meta)*, $name:ident, $aidl_name:ident, ($($def:tt)*), [$($out:tt)*],
125 $e_name:ident, selinux name: $e_str:ident; $($element:tt)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700126 => {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700127 implement_permission_aidl!(@replace_use $($m)*, $name, $aidl_name, ($($def)*),
128 [$($out)* $e_name, $e_str, $e_str;], $($element)*);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700129 };
130
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700131 (@end $($m:meta)*, $name:ident, $aidl_name:ident,
132 ($def_name:ident, $def_selinux_name:ident) {
133 $($element_name:ident, $element_identifier:ident,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700134 $selinux_name:ident;)*
135 })
136 =>
137 {
138 $(#[$m])*
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700139 pub struct $name(pub $aidl_name::$aidl_name);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700140
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700141 impl From<$aidl_name::$aidl_name> for $name {
142 fn from (p: $aidl_name::$aidl_name) -> Self {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700143 match p {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700144 $aidl_name::$def_name => Self($aidl_name::$def_name),
145 $($aidl_name::$element_name => Self($aidl_name::$element_name),)*
146 _ => Self($aidl_name::$def_name),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700147 }
148 }
149 }
150
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700151 impl Into<$aidl_name::$aidl_name> for $name {
152 fn into(self) -> $aidl_name::$aidl_name {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700153 self.0
154 }
155 }
156
157 impl $name {
158 /// Returns a string representation of the permission as required by
159 /// `selinux::check_access`.
160 pub fn to_selinux(&self) -> &'static str {
161 match self {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700162 Self($aidl_name::$def_name) => stringify!($def_selinux_name),
163 $(Self($aidl_name::$element_name) => stringify!($selinux_name),)*
164 _ => stringify!($def_selinux_name),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700165 }
166 }
167
168 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700169 pub const fn $def_selinux_name() -> Self { Self($aidl_name::$def_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700170 $(
171 /// Creates an instance representing a permission with the same name.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700172 pub const fn $element_identifier() -> Self { Self($aidl_name::$element_name) }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700173 )*
174 }
175 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700176}
177
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700178implement_permission_aidl!(
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700179 /// 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)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700194 KeyPerm from KeyPermission with default (None, none) {
195 Delete, selinux name: delete;
196 GenUniqueId, selinux name: gen_unique_id;
197 GetInfo, selinux name: get_info;
198 Grant, selinux name: grant;
199 List, selinux name: list;
200 ManageBlob, selinux name: manage_blob;
201 Rebind, selinux name: rebind;
202 ReqForcedOp, selinux name: req_forced_op;
203 Update, selinux name: update;
204 Use, selinux name: use;
205 UseDevId, 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 Danisevskis1b3a6e22020-08-07 12:39:56 -0700296 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700297 Lock = 8, selinux name: lock;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700298 /// Checked when Keystore 2.0 shall be reset.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700299 Reset = 0x10, selinux name: reset;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700300 /// Checked when Keystore 2.0 shall be unlocked.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700301 Unlock = 0x20, selinux name: unlock;
302 }
303);
304
305/// Represents a set of `KeyPerm` permissions.
306/// `IntoIterator` is implemented for this struct allowing the iteration through all the
307/// permissions in the set.
308/// It also implements a function `includes(self, other)` that checks if the permissions
309/// in `other` are included in `self`.
310///
311/// KeyPermSet can be created with the macro `key_perm_set![]`.
312///
313/// ## Example
314/// ```
315/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
316/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
317///
318/// assert!(perms1.includes(perms2))
319/// assert!(!perms2.includes(perms1))
320///
321/// let i = perms1.into_iter();
322/// // iteration in ascending order of the permission's numeric representation.
323/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
324/// assert_eq(Some(KeyPerm::grant()), i.next());
325/// assert_eq(Some(KeyPerm::use_()), i.next());
326/// assert_eq(None, i.next());
327/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700328#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
329pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700330
331mod perm {
332 use super::*;
333
334 pub struct IntoIter {
335 vec: KeyPermSet,
336 pos: u8,
337 }
338
339 impl IntoIter {
340 pub fn new(v: KeyPermSet) -> Self {
341 Self { vec: v, pos: 0 }
342 }
343 }
344
345 impl std::iter::Iterator for IntoIter {
346 type Item = KeyPerm;
347
348 fn next(&mut self) -> Option<Self::Item> {
349 loop {
350 if self.pos == 32 {
351 return None;
352 }
353 let p = self.vec.0 & (1 << self.pos);
354 self.pos += 1;
355 if p != 0 {
356 return Some(KeyPerm::from(p));
357 }
358 }
359 }
360 }
361}
362
363impl From<KeyPerm> for KeyPermSet {
364 fn from(p: KeyPerm) -> Self {
365 Self(p.0 as i32)
366 }
367}
368
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700369/// allow conversion from the AIDL wire type i32 to a permission set.
370impl From<i32> for KeyPermSet {
371 fn from(p: i32) -> Self {
372 Self(p)
373 }
374}
375
376impl From<KeyPermSet> for i32 {
377 fn from(p: KeyPermSet) -> i32 {
378 p.0
379 }
380}
381
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700382impl KeyPermSet {
383 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700384 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700385 let o: KeyPermSet = other.into();
386 (self.0 & o.0) == o.0
387 }
388}
389
390/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
391///
392/// ## Example
393/// ```
394/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
395/// ```
396#[macro_export]
397macro_rules! key_perm_set {
398 () => { KeyPermSet(0) };
399 ($head:expr $(, $tail:expr)* $(,)?) => {
400 KeyPermSet($head.0 as i32 $(| $tail.0 as i32)*)
401 };
402}
403
404impl IntoIterator for KeyPermSet {
405 type Item = KeyPerm;
406 type IntoIter = perm::IntoIter;
407
408 fn into_iter(self) -> Self::IntoIter {
409 Self::IntoIter::new(self)
410 }
411}
412
413/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
414/// the given permision `perm` of the `keystore2` security class.
415pub fn check_keystore_permission(
416 caller_ctx: &selinux::Context,
417 perm: KeystorePerm,
418) -> anyhow::Result<()> {
419 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
432/// * `Domain::App` in which case u:r:keystore:s0 is used as target context and
433/// * `Domain::SELinux` in which case the `key.namespace_` parameter is looked up in
434/// SELinux keystore key backend, and the result is used
435/// as target context.
436pub fn check_grant_permission(
437 caller_ctx: &selinux::Context,
438 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700439 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700440) -> anyhow::Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700441 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700442
443 let target_context = match key.domain {
444 Domain::App => getcon().context("check_grant_permission: getcon failed.")?,
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000445 Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
446 .context("check_grant_permission: Domain::SELinux: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700447 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
448 };
449
450 selinux::check_access(caller_ctx, &target_context, "keystore2_key", "grant")
451 .context("Grant permission is required when granting.")?;
452
453 if access_vec.includes(KeyPerm::grant()) {
454 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
455 }
456
457 for p in access_vec.into_iter() {
458 selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
459 .context(concat!(
460 "check_grant_permission: check_access failed. ",
461 "The caller may have tried to grant a permission that they don't possess."
462 ))?
463 }
464 Ok(())
465}
466
467/// Uses `selinux::check_access` to check if the given caller context `caller_cxt`
468/// has the permissions indicated by `perm` for the target domain indicated by the key
469/// descriptor `key` in the security class `keystore2_key`.
470///
471/// The behavior differs slightly depending on the selected target domain:
472/// * `Domain::App` u:r:keystore:s0 is used as target context.
473/// * `Domain::SELinux` `key.namespace_` parameter is looked up in the SELinux keystore key
474/// backend, and the result is used as target context.
475/// * `Domain::Blob` Same as SELinux but the "manage_blob" permission is always checked additionally
476/// to the one supplied in `perm`.
477/// * `Domain::Grant` Does not use selinux::check_access. Instead the `access_vector`
478/// parameter is queried for permission, which must be supplied in this case.
479///
480/// ## Return values.
481/// * Ok(()) If the requested permissions were granted.
482/// * Err(selinux::Error::perm()) If the requested permissions were denied.
483/// * Err(KsError::sys()) This error is produced if `Domain::Grant` is selected but no `access_vec`
484/// was supplied. It is also produced if `Domain::KeyId` was selected, and
485/// on various unexpected backend failures.
486pub fn check_key_permission(
487 caller_ctx: &selinux::Context,
488 perm: KeyPerm,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700489 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700490 access_vector: &Option<KeyPermSet>,
491) -> anyhow::Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700492 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700493
494 let target_context = match key.domain {
495 // apps get the default keystore context
496 Domain::App => getcon().context("check_key_permission: getcon failed.")?,
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000497 Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
498 .context("check_key_permission: Domain::SELinux: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700499 Domain::Grant => {
500 match access_vector {
501 Some(pv) => {
502 if pv.includes(perm) {
503 return Ok(());
504 } else {
505 return Err(selinux::Error::perm())
506 .context(format!("\"{}\" not granted", perm.to_selinux()));
507 }
508 }
509 None => {
510 // If DOMAIN_GRANT was selected an access vector must be supplied.
511 return Err(KsError::sys()).context(
512 "Cannot check permission for Domain::Grant without access vector.",
513 );
514 }
515 }
516 }
517 Domain::KeyId => {
518 // We should never be called with `Domain::KeyId. The database
519 // lookup should have converted this into one of `Domain::App`
520 // or `Domain::SELinux`.
521 return Err(KsError::sys()).context("Cannot check permission for Domain::KeyId.");
522 }
523 Domain::Blob => {
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000524 let tctx = lookup_keystore2_key_context(key.namespace_)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700525 .context("Domain::Blob: Failed to lookup namespace.")?;
526 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
527 // permission in addition to the requested permission.
528 selinux::check_access(
529 caller_ctx,
530 &tctx,
531 "keystore2_key",
532 KeyPerm::manage_blob().to_selinux(),
533 )?;
534
535 tctx
536 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700537 _ => {
538 return Err(KsError::sys())
539 .context(format!("Unknown domain value: \"{}\".", key.domain))
540 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700541 };
542
543 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
544}
545
546#[cfg(test)]
547mod tests {
548 use super::*;
549 use anyhow::anyhow;
550 use anyhow::Result;
551 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700552
553 const ALL_PERMS: KeyPermSet = key_perm_set![
554 KeyPerm::manage_blob(),
555 KeyPerm::delete(),
556 KeyPerm::use_dev_id(),
557 KeyPerm::req_forced_op(),
558 KeyPerm::gen_unique_id(),
559 KeyPerm::grant(),
560 KeyPerm::get_info(),
561 KeyPerm::list(),
562 KeyPerm::rebind(),
563 KeyPerm::update(),
564 KeyPerm::use_(),
565 ];
566
567 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
568 KeyPerm::manage_blob(),
569 KeyPerm::delete(),
570 KeyPerm::use_dev_id(),
571 KeyPerm::req_forced_op(),
572 KeyPerm::gen_unique_id(),
573 // No KeyPerm::grant()
574 KeyPerm::get_info(),
575 KeyPerm::list(),
576 KeyPerm::rebind(),
577 KeyPerm::update(),
578 KeyPerm::use_(),
579 ];
580
581 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
582 KeyPerm::delete(),
583 KeyPerm::get_info(),
584 KeyPerm::list(),
585 KeyPerm::rebind(),
586 KeyPerm::update(),
587 KeyPerm::use_(),
588 ];
589
590 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
591 /// SePolicy (system/sepolicy).
592 const SU_KEY_NAMESPACE: i32 = 0;
593 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
594 /// SePolicy (system/sepolicy).
595 const SHELL_KEY_NAMESPACE: i32 = 1;
596
597 pub fn test_getcon() -> Result<Context> {
598 Context::new("u:object_r:keystore:s0")
599 }
600
601 // This macro evaluates the given expression and checks that
602 // a) evaluated to Result::Err() and that
603 // b) the wrapped error is selinux::Error::perm() (permission denied).
604 // We use a macro here because a function would mask which invocation caused the failure.
605 //
606 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
607 macro_rules! assert_perm_failed {
608 ($test_function:expr) => {
609 let result = $test_function;
610 assert!(result.is_err(), "Permission check should have failed.");
611 assert_eq!(
612 Some(&selinux::Error::perm()),
613 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
614 );
615 };
616 }
617
618 fn check_context() -> Result<(selinux::Context, i32, bool)> {
619 // Calling the non mocked selinux::getcon here intended.
620 let context = selinux::getcon()?;
621 match context.to_str().unwrap() {
622 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
623 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
624 c => Err(anyhow!(format!(
625 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
626 c
627 ))),
628 }
629 }
630
631 #[test]
632 fn check_keystore_permission_test() -> Result<()> {
633 let system_server_ctx = Context::new("u:r:system_server:s0")?;
634 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
635 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
636 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
637 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
638 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
639 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
640 let shell_ctx = Context::new("u:r:shell:s0")?;
641 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
642 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
643 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()));
644 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
645 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
646 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
647 Ok(())
648 }
649
650 #[test]
651 fn check_grant_permission_app() -> Result<()> {
652 let system_server_ctx = Context::new("u:r:system_server:s0")?;
653 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700654 use android_security_keystore2::aidl::android::security::keystore2::Domain;
655 let key = KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700656 assert!(check_grant_permission(&system_server_ctx, NOT_GRANT_PERMS, &key).is_ok());
657 // attempts to grant the grant permission must always fail even when privileged.
658
659 assert_perm_failed!(check_grant_permission(
660 &system_server_ctx,
661 KeyPerm::grant().into(),
662 &key
663 ));
664 // unprivileged grant attempts always fail. shell does not have the grant permission.
665 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
666 Ok(())
667 }
668
669 #[test]
670 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700671 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700672 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700673 let key = KeyDescriptor {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700674 domain: Domain::SELinux,
675 namespace_: namespace as i64,
676 alias: None,
677 blob: None,
678 };
679 if is_su {
680 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
681 // attempts to grant the grant permission must always fail even when privileged.
682 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
683 } else {
684 // unprivileged grant attempts always fail. shell does not have the grant permission.
685 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
686 }
687 Ok(())
688 }
689
690 #[test]
691 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700692 use android_security_keystore2::aidl::android::security::keystore2::Domain;
693 let key = KeyDescriptor { domain: Domain::Grant, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700694
695 assert_perm_failed!(check_key_permission(
696 &selinux::Context::new("ignored").unwrap(),
697 KeyPerm::grant(),
698 &key,
699 &Some(UNPRIV_PERMS)
700 ));
701
702 check_key_permission(
703 &selinux::Context::new("ignored").unwrap(),
704 KeyPerm::use_(),
705 &key,
706 &Some(ALL_PERMS),
707 )
708 }
709
710 #[test]
711 fn check_key_permission_domain_app() -> Result<()> {
712 let system_server_ctx = Context::new("u:r:system_server:s0")?;
713 let shell_ctx = Context::new("u:r:shell:s0")?;
714 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700715 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700716
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700717 let key = KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700718
719 assert!(check_key_permission(&system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
720 assert!(check_key_permission(&system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
721 assert!(check_key_permission(&system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok());
722 assert!(check_key_permission(&system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
723 assert!(check_key_permission(&system_server_ctx, KeyPerm::list(), &key, &None).is_ok());
724 assert!(check_key_permission(&system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
725 assert!(check_key_permission(&system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
726 assert!(
727 check_key_permission(&system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
728 );
729 assert!(check_key_permission(&gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok());
730
731 assert!(check_key_permission(&shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
732 assert!(check_key_permission(&shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
733 assert!(check_key_permission(&shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
734 assert!(check_key_permission(&shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
735 assert!(check_key_permission(&shell_ctx, KeyPerm::list(), &key, &None).is_ok());
736 assert!(check_key_permission(&shell_ctx, KeyPerm::update(), &key, &None).is_ok());
737 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::grant(), &key, &None));
738 assert_perm_failed!(check_key_permission(
739 &shell_ctx,
740 KeyPerm::req_forced_op(),
741 &key,
742 &None
743 ));
744 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::manage_blob(), &key, &None));
745 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::use_dev_id(), &key, &None));
746 assert_perm_failed!(check_key_permission(
747 &shell_ctx,
748 KeyPerm::gen_unique_id(),
749 &key,
750 &None
751 ));
752
753 Ok(())
754 }
755
756 #[test]
757 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700758 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700759 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700760 let key = KeyDescriptor {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700761 domain: Domain::SELinux,
762 namespace_: namespace as i64,
763 alias: None,
764 blob: None,
765 };
766
767 if is_su {
768 assert!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None).is_ok());
769 assert!(check_key_permission(&sctx, KeyPerm::delete(), &key, &None).is_ok());
770 assert!(check_key_permission(&sctx, KeyPerm::get_info(), &key, &None).is_ok());
771 assert!(check_key_permission(&sctx, KeyPerm::rebind(), &key, &None).is_ok());
772 assert!(check_key_permission(&sctx, KeyPerm::list(), &key, &None).is_ok());
773 assert!(check_key_permission(&sctx, KeyPerm::update(), &key, &None).is_ok());
774 assert!(check_key_permission(&sctx, KeyPerm::grant(), &key, &None).is_ok());
775 assert!(check_key_permission(&sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
776 assert!(check_key_permission(&sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
777 assert!(check_key_permission(&sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
778 assert!(check_key_permission(&sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
779 } else {
780 assert!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None).is_ok());
781 assert!(check_key_permission(&sctx, KeyPerm::delete(), &key, &None).is_ok());
782 assert!(check_key_permission(&sctx, KeyPerm::get_info(), &key, &None).is_ok());
783 assert!(check_key_permission(&sctx, KeyPerm::rebind(), &key, &None).is_ok());
784 assert!(check_key_permission(&sctx, KeyPerm::list(), &key, &None).is_ok());
785 assert!(check_key_permission(&sctx, KeyPerm::update(), &key, &None).is_ok());
786 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::grant(), &key, &None));
787 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::req_forced_op(), &key, &None));
788 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::manage_blob(), &key, &None));
789 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::use_dev_id(), &key, &None));
790 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::gen_unique_id(), &key, &None));
791 }
792 Ok(())
793 }
794
795 #[test]
796 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700797 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700798 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700799 let key = KeyDescriptor {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700800 domain: Domain::Blob,
801 namespace_: namespace as i64,
802 alias: None,
803 blob: None,
804 };
805
806 if is_su {
807 check_key_permission(&sctx, KeyPerm::use_(), &key, &None)
808 } else {
809 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None));
810 Ok(())
811 }
812 }
813
814 #[test]
815 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700816 use android_security_keystore2::aidl::android::security::keystore2::Domain;
817 let key = KeyDescriptor { domain: Domain::KeyId, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700818
819 assert_eq!(
820 Some(&KsError::sys()),
821 check_key_permission(
822 &selinux::Context::new("ignored").unwrap(),
823 KeyPerm::use_(),
824 &key,
825 &None
826 )
827 .err()
828 .unwrap()
829 .root_cause()
830 .downcast_ref::<KsError>()
831 );
832 Ok(())
833 }
834
835 #[test]
836 fn key_perm_set_all_test() {
837 let v = key_perm_set![
838 KeyPerm::manage_blob(),
839 KeyPerm::delete(),
840 KeyPerm::use_dev_id(),
841 KeyPerm::req_forced_op(),
842 KeyPerm::gen_unique_id(),
843 KeyPerm::grant(),
844 KeyPerm::get_info(),
845 KeyPerm::list(),
846 KeyPerm::rebind(),
847 KeyPerm::update(),
848 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
849 ];
850 let mut i = v.into_iter();
851 assert_eq!(i.next().unwrap().to_selinux(), "delete");
852 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
853 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
854 assert_eq!(i.next().unwrap().to_selinux(), "grant");
855 assert_eq!(i.next().unwrap().to_selinux(), "list");
856 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
857 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
858 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
859 assert_eq!(i.next().unwrap().to_selinux(), "update");
860 assert_eq!(i.next().unwrap().to_selinux(), "use");
861 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
862 assert_eq!(None, i.next());
863 }
864 #[test]
865 fn key_perm_set_sparse_test() {
866 let v = key_perm_set![
867 KeyPerm::manage_blob(),
868 KeyPerm::req_forced_op(),
869 KeyPerm::gen_unique_id(),
870 KeyPerm::list(),
871 KeyPerm::update(),
872 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
873 ];
874 let mut i = v.into_iter();
875 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
876 assert_eq!(i.next().unwrap().to_selinux(), "list");
877 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
878 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
879 assert_eq!(i.next().unwrap().to_selinux(), "update");
880 assert_eq!(i.next().unwrap().to_selinux(), "use");
881 assert_eq!(None, i.next());
882 }
883 #[test]
884 fn key_perm_set_empty_test() {
885 let v = key_perm_set![];
886 let mut i = v.into_iter();
887 assert_eq!(None, i.next());
888 }
889 #[test]
890 fn key_perm_set_include_subset_test() {
891 let v1 = key_perm_set![
892 KeyPerm::manage_blob(),
893 KeyPerm::delete(),
894 KeyPerm::use_dev_id(),
895 KeyPerm::req_forced_op(),
896 KeyPerm::gen_unique_id(),
897 KeyPerm::grant(),
898 KeyPerm::get_info(),
899 KeyPerm::list(),
900 KeyPerm::rebind(),
901 KeyPerm::update(),
902 KeyPerm::use_(),
903 ];
904 let v2 = key_perm_set![
905 KeyPerm::manage_blob(),
906 KeyPerm::delete(),
907 KeyPerm::list(),
908 KeyPerm::rebind(),
909 KeyPerm::update(),
910 KeyPerm::use_(),
911 ];
912 assert!(v1.includes(v2));
913 assert!(!v2.includes(v1));
914 }
915 #[test]
916 fn key_perm_set_include_equal_test() {
917 let v1 = key_perm_set![
918 KeyPerm::manage_blob(),
919 KeyPerm::delete(),
920 KeyPerm::list(),
921 KeyPerm::rebind(),
922 KeyPerm::update(),
923 KeyPerm::use_(),
924 ];
925 let v2 = key_perm_set![
926 KeyPerm::manage_blob(),
927 KeyPerm::delete(),
928 KeyPerm::list(),
929 KeyPerm::rebind(),
930 KeyPerm::update(),
931 KeyPerm::use_(),
932 ];
933 assert!(v1.includes(v2));
934 assert!(v2.includes(v1));
935 }
936 #[test]
937 fn key_perm_set_include_overlap_test() {
938 let v1 = key_perm_set![
939 KeyPerm::manage_blob(),
940 KeyPerm::delete(),
941 KeyPerm::grant(), // only in v1
942 KeyPerm::list(),
943 KeyPerm::rebind(),
944 KeyPerm::update(),
945 KeyPerm::use_(),
946 ];
947 let v2 = key_perm_set![
948 KeyPerm::manage_blob(),
949 KeyPerm::delete(),
950 KeyPerm::req_forced_op(), // only in v2
951 KeyPerm::list(),
952 KeyPerm::rebind(),
953 KeyPerm::update(),
954 KeyPerm::use_(),
955 ];
956 assert!(!v1.includes(v2));
957 assert!(!v2.includes(v1));
958 }
959 #[test]
960 fn key_perm_set_include_no_overlap_test() {
961 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
962 let v2 = key_perm_set![
963 KeyPerm::req_forced_op(),
964 KeyPerm::list(),
965 KeyPerm::rebind(),
966 KeyPerm::update(),
967 KeyPerm::use_(),
968 ];
969 assert!(!v1.includes(v2));
970 assert!(!v2.includes(v1));
971 }
972}