blob: df594845b0e4c7fbb3deda0ef8ba391b9c039423 [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;
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 Danisevskis1b3a6e22020-08-07 12:39:56 -0700140 pub struct $name(pub $aidl_name::$aidl_name);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700141
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700142 impl From<$aidl_name::$aidl_name> for $name {
143 fn from (p: $aidl_name::$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 Danisevskis1b3a6e22020-08-07 12:39:56 -0700152 impl Into<$aidl_name::$aidl_name> for $name {
153 fn into(self) -> $aidl_name::$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 Danisevskis1b3a6e22020-08-07 12:39:56 -0700195 KeyPerm from KeyPermission with default (None, none) {
196 Delete, selinux name: delete;
197 GenUniqueId, selinux name: gen_unique_id;
198 GetInfo, selinux name: get_info;
199 Grant, selinux name: grant;
200 List, selinux name: list;
201 ManageBlob, selinux name: manage_blob;
202 Rebind, selinux name: rebind;
203 ReqForcedOp, selinux name: req_forced_op;
204 Update, selinux name: update;
205 Use, selinux name: use;
206 UseDevId, selinux name: use_dev_id;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700207 }
208);
209
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700210/// This macro implements an enum with values mapped to SELinux permission names.
211/// The below example wraps the enum MyPermission in the tuple struct `MyPerm` and implements
212/// * From<i32> and Into<i32> are implemented. Where the implementation of From maps
213/// any variant not specified to the default.
214/// * Every variant has a constructor with a name corresponding to its lower case SELinux string
215/// representation.
216/// * `MyPerm.to_selinux(&self)` returns the SELinux string representation of the
217/// represented permission.
218///
219/// ## Example
220/// ```
221/// implement_permission!(
222/// /// MyPerm documentation.
223/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
224/// MyPerm with default (None = 0, none) {
225/// Foo = 1, selinux name: foo;
226/// Bar = 2, selinux name: bar;
227/// }
228/// );
229/// ```
230macro_rules! implement_permission {
231 // This rule provides the public interface of the macro. And starts the preprocessing
232 // recursion (see below).
233 ($(#[$m:meta])* $name:ident with default
234 ($def_name:ident = $def_val:expr, $def_selinux_name:ident)
235 {
236 $($(#[$element_meta:meta])*
237 $element_name:ident = $element_val:expr, selinux name: $selinux_name:ident;)*
238 })
239 => {
240 $(#[$m])*
241 pub enum $name {
242 /// The default variant of an enum.
243 $def_name = $def_val,
244 $(
245 $(#[$element_meta])*
246 $element_name = $element_val,
247 )*
248 }
249
250 impl From<i32> for $name {
251 fn from (p: i32) -> Self {
252 match p {
253 $def_val => Self::$def_name,
254 $($element_val => Self::$element_name,)*
255 _ => Self::$def_name,
256 }
257 }
258 }
259
260 impl Into<i32> for $name {
261 fn into(self) -> i32 {
262 self as i32
263 }
264 }
265
266 impl $name {
267 /// Returns a string representation of the permission as required by
268 /// `selinux::check_access`.
269 pub fn to_selinux(&self) -> &'static str {
270 match self {
271 Self::$def_name => stringify!($def_selinux_name),
272 $(Self::$element_name => stringify!($selinux_name),)*
273 }
274 }
275
276 /// Creates an instance representing a permission with the same name.
277 pub const fn $def_selinux_name() -> Self { Self::$def_name }
278 $(
279 /// Creates an instance representing a permission with the same name.
280 pub const fn $selinux_name() -> Self { Self::$element_name }
281 )*
282 }
283 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700284}
285
286implement_permission!(
287 /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
288 /// Using the implement_permission macro we get the same features as `KeyPerm`.
289 #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700290 KeystorePerm with default (None = 0, none) {
291 /// Checked when a new auth token is installed.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700292 AddAuth = 1, selinux name: add_auth;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700293 /// Checked when an app is uninstalled or wiped.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700294 ClearNs = 2, selinux name: clear_ns;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700295 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700296 GetState = 4, selinux name: get_state;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700297 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700298 Lock = 8, selinux name: lock;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700299 /// Checked when Keystore 2.0 shall be reset.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700300 Reset = 0x10, selinux name: reset;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700301 /// Checked when Keystore 2.0 shall be unlocked.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700302 Unlock = 0x20, selinux name: unlock;
303 }
304);
305
306/// Represents a set of `KeyPerm` permissions.
307/// `IntoIterator` is implemented for this struct allowing the iteration through all the
308/// permissions in the set.
309/// It also implements a function `includes(self, other)` that checks if the permissions
310/// in `other` are included in `self`.
311///
312/// KeyPermSet can be created with the macro `key_perm_set![]`.
313///
314/// ## Example
315/// ```
316/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
317/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
318///
319/// assert!(perms1.includes(perms2))
320/// assert!(!perms2.includes(perms1))
321///
322/// let i = perms1.into_iter();
323/// // iteration in ascending order of the permission's numeric representation.
324/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
325/// assert_eq(Some(KeyPerm::grant()), i.next());
326/// assert_eq(Some(KeyPerm::use_()), i.next());
327/// assert_eq(None, i.next());
328/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700329#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
330pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700331
332mod perm {
333 use super::*;
334
335 pub struct IntoIter {
336 vec: KeyPermSet,
337 pos: u8,
338 }
339
340 impl IntoIter {
341 pub fn new(v: KeyPermSet) -> Self {
342 Self { vec: v, pos: 0 }
343 }
344 }
345
346 impl std::iter::Iterator for IntoIter {
347 type Item = KeyPerm;
348
349 fn next(&mut self) -> Option<Self::Item> {
350 loop {
351 if self.pos == 32 {
352 return None;
353 }
354 let p = self.vec.0 & (1 << self.pos);
355 self.pos += 1;
356 if p != 0 {
357 return Some(KeyPerm::from(p));
358 }
359 }
360 }
361 }
362}
363
364impl From<KeyPerm> for KeyPermSet {
365 fn from(p: KeyPerm) -> Self {
366 Self(p.0 as i32)
367 }
368}
369
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700370/// allow conversion from the AIDL wire type i32 to a permission set.
371impl From<i32> for KeyPermSet {
372 fn from(p: i32) -> Self {
373 Self(p)
374 }
375}
376
377impl From<KeyPermSet> for i32 {
378 fn from(p: KeyPermSet) -> i32 {
379 p.0
380 }
381}
382
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700383impl KeyPermSet {
384 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700385 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700386 let o: KeyPermSet = other.into();
387 (self.0 & o.0) == o.0
388 }
389}
390
391/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
392///
393/// ## Example
394/// ```
395/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
396/// ```
397#[macro_export]
398macro_rules! key_perm_set {
399 () => { KeyPermSet(0) };
400 ($head:expr $(, $tail:expr)* $(,)?) => {
401 KeyPermSet($head.0 as i32 $(| $tail.0 as i32)*)
402 };
403}
404
405impl IntoIterator for KeyPermSet {
406 type Item = KeyPerm;
407 type IntoIter = perm::IntoIter;
408
409 fn into_iter(self) -> Self::IntoIter {
410 Self::IntoIter::new(self)
411 }
412}
413
414/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
415/// the given permision `perm` of the `keystore2` security class.
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700416pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700417 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
418 selinux::check_access(caller_ctx, &target_context, "keystore2", perm.to_selinux())
419}
420
421/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` has
422/// all the permissions indicated in `access_vec` for the target domain indicated by the key
423/// descriptor `key` in the security class `keystore2_key`.
424///
425/// Also checks if the caller has the grant permission for the given target domain.
426///
427/// Attempts to grant the grant permission are always denied.
428///
429/// The only viable target domains are
430/// * `Domain::App` in which case u:r:keystore:s0 is used as target context and
431/// * `Domain::SELinux` in which case the `key.namespace_` parameter is looked up in
432/// SELinux keystore key backend, and the result is used
433/// as target context.
434pub fn check_grant_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700435 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700436 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700437 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700438) -> anyhow::Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700439 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700440
441 let target_context = match key.domain {
442 Domain::App => getcon().context("check_grant_permission: getcon failed.")?,
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000443 Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
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:
470/// * `Domain::App` u:r:keystore:s0 is used as target context.
471/// * `Domain::SELinux` `key.namespace_` parameter is looked up in the SELinux keystore key
472/// backend, and the result is used as target context.
473/// * `Domain::Blob` Same as SELinux but the "manage_blob" permission is always checked additionally
474/// to the one supplied in `perm`.
475/// * `Domain::Grant` Does not use selinux::check_access. Instead the `access_vector`
476/// 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.
481/// * 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::KeyId` was selected, and
483/// on various unexpected backend failures.
484pub fn check_key_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700485 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700486 perm: KeyPerm,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700487 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700488 access_vector: &Option<KeyPermSet>,
489) -> anyhow::Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700490 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700491
492 let target_context = match key.domain {
493 // apps get the default keystore context
494 Domain::App => getcon().context("check_key_permission: getcon failed.")?,
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000495 Domain::SELinux => lookup_keystore2_key_context(key.namespace_)
496 .context("check_key_permission: Domain::SELinux: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700497 Domain::Grant => {
498 match access_vector {
499 Some(pv) => {
500 if pv.includes(perm) {
501 return Ok(());
502 } else {
503 return Err(selinux::Error::perm())
504 .context(format!("\"{}\" not granted", perm.to_selinux()));
505 }
506 }
507 None => {
508 // If DOMAIN_GRANT was selected an access vector must be supplied.
509 return Err(KsError::sys()).context(
510 "Cannot check permission for Domain::Grant without access vector.",
511 );
512 }
513 }
514 }
515 Domain::KeyId => {
516 // We should never be called with `Domain::KeyId. The database
517 // lookup should have converted this into one of `Domain::App`
518 // or `Domain::SELinux`.
519 return Err(KsError::sys()).context("Cannot check permission for Domain::KeyId.");
520 }
521 Domain::Blob => {
Janis Danisevskis4ad056f2020-08-05 19:46:46 +0000522 let tctx = lookup_keystore2_key_context(key.namespace_)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700523 .context("Domain::Blob: Failed to lookup namespace.")?;
524 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
525 // permission in addition to the requested permission.
526 selinux::check_access(
527 caller_ctx,
528 &tctx,
529 "keystore2_key",
530 KeyPerm::manage_blob().to_selinux(),
531 )?;
532
533 tctx
534 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700535 _ => {
536 return Err(KsError::sys())
537 .context(format!("Unknown domain value: \"{}\".", key.domain))
538 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700539 };
540
541 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
542}
543
544#[cfg(test)]
545mod tests {
546 use super::*;
547 use anyhow::anyhow;
548 use anyhow::Result;
549 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700550
551 const ALL_PERMS: KeyPermSet = key_perm_set![
552 KeyPerm::manage_blob(),
553 KeyPerm::delete(),
554 KeyPerm::use_dev_id(),
555 KeyPerm::req_forced_op(),
556 KeyPerm::gen_unique_id(),
557 KeyPerm::grant(),
558 KeyPerm::get_info(),
559 KeyPerm::list(),
560 KeyPerm::rebind(),
561 KeyPerm::update(),
562 KeyPerm::use_(),
563 ];
564
565 const NOT_GRANT_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 // No KeyPerm::grant()
572 KeyPerm::get_info(),
573 KeyPerm::list(),
574 KeyPerm::rebind(),
575 KeyPerm::update(),
576 KeyPerm::use_(),
577 ];
578
579 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
580 KeyPerm::delete(),
581 KeyPerm::get_info(),
582 KeyPerm::list(),
583 KeyPerm::rebind(),
584 KeyPerm::update(),
585 KeyPerm::use_(),
586 ];
587
588 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
589 /// SePolicy (system/sepolicy).
590 const SU_KEY_NAMESPACE: i32 = 0;
591 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
592 /// SePolicy (system/sepolicy).
593 const SHELL_KEY_NAMESPACE: i32 = 1;
594
595 pub fn test_getcon() -> Result<Context> {
596 Context::new("u:object_r:keystore:s0")
597 }
598
599 // This macro evaluates the given expression and checks that
600 // a) evaluated to Result::Err() and that
601 // b) the wrapped error is selinux::Error::perm() (permission denied).
602 // We use a macro here because a function would mask which invocation caused the failure.
603 //
604 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
605 macro_rules! assert_perm_failed {
606 ($test_function:expr) => {
607 let result = $test_function;
608 assert!(result.is_err(), "Permission check should have failed.");
609 assert_eq!(
610 Some(&selinux::Error::perm()),
611 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
612 );
613 };
614 }
615
616 fn check_context() -> Result<(selinux::Context, i32, bool)> {
617 // Calling the non mocked selinux::getcon here intended.
618 let context = selinux::getcon()?;
619 match context.to_str().unwrap() {
620 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
621 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
622 c => Err(anyhow!(format!(
623 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
624 c
625 ))),
626 }
627 }
628
629 #[test]
630 fn check_keystore_permission_test() -> Result<()> {
631 let system_server_ctx = Context::new("u:r:system_server:s0")?;
632 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
633 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
634 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
635 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
636 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
637 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
638 let shell_ctx = Context::new("u:r:shell:s0")?;
639 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
640 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
641 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()));
642 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
643 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
644 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
645 Ok(())
646 }
647
648 #[test]
649 fn check_grant_permission_app() -> Result<()> {
650 let system_server_ctx = Context::new("u:r:system_server:s0")?;
651 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700652 use android_security_keystore2::aidl::android::security::keystore2::Domain;
653 let key = KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700654 assert!(check_grant_permission(&system_server_ctx, NOT_GRANT_PERMS, &key).is_ok());
655 // attempts to grant the grant permission must always fail even when privileged.
656
657 assert_perm_failed!(check_grant_permission(
658 &system_server_ctx,
659 KeyPerm::grant().into(),
660 &key
661 ));
662 // unprivileged grant attempts always fail. shell does not have the grant permission.
663 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
664 Ok(())
665 }
666
667 #[test]
668 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700669 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700670 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700671 let key = KeyDescriptor {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700672 domain: Domain::SELinux,
673 namespace_: namespace as i64,
674 alias: None,
675 blob: None,
676 };
677 if is_su {
678 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
679 // attempts to grant the grant permission must always fail even when privileged.
680 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
681 } else {
682 // unprivileged grant attempts always fail. shell does not have the grant permission.
683 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
684 }
685 Ok(())
686 }
687
688 #[test]
689 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700690 use android_security_keystore2::aidl::android::security::keystore2::Domain;
691 let key = KeyDescriptor { domain: Domain::Grant, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700692
693 assert_perm_failed!(check_key_permission(
694 &selinux::Context::new("ignored").unwrap(),
695 KeyPerm::grant(),
696 &key,
697 &Some(UNPRIV_PERMS)
698 ));
699
700 check_key_permission(
701 &selinux::Context::new("ignored").unwrap(),
702 KeyPerm::use_(),
703 &key,
704 &Some(ALL_PERMS),
705 )
706 }
707
708 #[test]
709 fn check_key_permission_domain_app() -> Result<()> {
710 let system_server_ctx = Context::new("u:r:system_server:s0")?;
711 let shell_ctx = Context::new("u:r:shell:s0")?;
712 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700713 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700714
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700715 let key = KeyDescriptor { domain: Domain::App, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700716
717 assert!(check_key_permission(&system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
718 assert!(check_key_permission(&system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
719 assert!(check_key_permission(&system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok());
720 assert!(check_key_permission(&system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
721 assert!(check_key_permission(&system_server_ctx, KeyPerm::list(), &key, &None).is_ok());
722 assert!(check_key_permission(&system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
723 assert!(check_key_permission(&system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
724 assert!(
725 check_key_permission(&system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
726 );
727 assert!(check_key_permission(&gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok());
728
729 assert!(check_key_permission(&shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
730 assert!(check_key_permission(&shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
731 assert!(check_key_permission(&shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
732 assert!(check_key_permission(&shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
733 assert!(check_key_permission(&shell_ctx, KeyPerm::list(), &key, &None).is_ok());
734 assert!(check_key_permission(&shell_ctx, KeyPerm::update(), &key, &None).is_ok());
735 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::grant(), &key, &None));
736 assert_perm_failed!(check_key_permission(
737 &shell_ctx,
738 KeyPerm::req_forced_op(),
739 &key,
740 &None
741 ));
742 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::manage_blob(), &key, &None));
743 assert_perm_failed!(check_key_permission(&shell_ctx, KeyPerm::use_dev_id(), &key, &None));
744 assert_perm_failed!(check_key_permission(
745 &shell_ctx,
746 KeyPerm::gen_unique_id(),
747 &key,
748 &None
749 ));
750
751 Ok(())
752 }
753
754 #[test]
755 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700756 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700757 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700758 let key = KeyDescriptor {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700759 domain: Domain::SELinux,
760 namespace_: namespace as i64,
761 alias: None,
762 blob: None,
763 };
764
765 if is_su {
766 assert!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None).is_ok());
767 assert!(check_key_permission(&sctx, KeyPerm::delete(), &key, &None).is_ok());
768 assert!(check_key_permission(&sctx, KeyPerm::get_info(), &key, &None).is_ok());
769 assert!(check_key_permission(&sctx, KeyPerm::rebind(), &key, &None).is_ok());
770 assert!(check_key_permission(&sctx, KeyPerm::list(), &key, &None).is_ok());
771 assert!(check_key_permission(&sctx, KeyPerm::update(), &key, &None).is_ok());
772 assert!(check_key_permission(&sctx, KeyPerm::grant(), &key, &None).is_ok());
773 assert!(check_key_permission(&sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
774 assert!(check_key_permission(&sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
775 assert!(check_key_permission(&sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
776 assert!(check_key_permission(&sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
777 } else {
778 assert!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None).is_ok());
779 assert!(check_key_permission(&sctx, KeyPerm::delete(), &key, &None).is_ok());
780 assert!(check_key_permission(&sctx, KeyPerm::get_info(), &key, &None).is_ok());
781 assert!(check_key_permission(&sctx, KeyPerm::rebind(), &key, &None).is_ok());
782 assert!(check_key_permission(&sctx, KeyPerm::list(), &key, &None).is_ok());
783 assert!(check_key_permission(&sctx, KeyPerm::update(), &key, &None).is_ok());
784 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::grant(), &key, &None));
785 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::req_forced_op(), &key, &None));
786 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::manage_blob(), &key, &None));
787 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::use_dev_id(), &key, &None));
788 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::gen_unique_id(), &key, &None));
789 }
790 Ok(())
791 }
792
793 #[test]
794 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700795 use android_security_keystore2::aidl::android::security::keystore2::Domain;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700796 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700797 let key = KeyDescriptor {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700798 domain: Domain::Blob,
799 namespace_: namespace as i64,
800 alias: None,
801 blob: None,
802 };
803
804 if is_su {
805 check_key_permission(&sctx, KeyPerm::use_(), &key, &None)
806 } else {
807 assert_perm_failed!(check_key_permission(&sctx, KeyPerm::use_(), &key, &None));
808 Ok(())
809 }
810 }
811
812 #[test]
813 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700814 use android_security_keystore2::aidl::android::security::keystore2::Domain;
815 let key = KeyDescriptor { domain: Domain::KeyId, namespace_: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700816
817 assert_eq!(
818 Some(&KsError::sys()),
819 check_key_permission(
820 &selinux::Context::new("ignored").unwrap(),
821 KeyPerm::use_(),
822 &key,
823 &None
824 )
825 .err()
826 .unwrap()
827 .root_cause()
828 .downcast_ref::<KsError>()
829 );
830 Ok(())
831 }
832
833 #[test]
834 fn key_perm_set_all_test() {
835 let v = key_perm_set![
836 KeyPerm::manage_blob(),
837 KeyPerm::delete(),
838 KeyPerm::use_dev_id(),
839 KeyPerm::req_forced_op(),
840 KeyPerm::gen_unique_id(),
841 KeyPerm::grant(),
842 KeyPerm::get_info(),
843 KeyPerm::list(),
844 KeyPerm::rebind(),
845 KeyPerm::update(),
846 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
847 ];
848 let mut i = v.into_iter();
849 assert_eq!(i.next().unwrap().to_selinux(), "delete");
850 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
851 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
852 assert_eq!(i.next().unwrap().to_selinux(), "grant");
853 assert_eq!(i.next().unwrap().to_selinux(), "list");
854 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
855 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
856 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
857 assert_eq!(i.next().unwrap().to_selinux(), "update");
858 assert_eq!(i.next().unwrap().to_selinux(), "use");
859 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
860 assert_eq!(None, i.next());
861 }
862 #[test]
863 fn key_perm_set_sparse_test() {
864 let v = key_perm_set![
865 KeyPerm::manage_blob(),
866 KeyPerm::req_forced_op(),
867 KeyPerm::gen_unique_id(),
868 KeyPerm::list(),
869 KeyPerm::update(),
870 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
871 ];
872 let mut i = v.into_iter();
873 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
874 assert_eq!(i.next().unwrap().to_selinux(), "list");
875 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
876 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
877 assert_eq!(i.next().unwrap().to_selinux(), "update");
878 assert_eq!(i.next().unwrap().to_selinux(), "use");
879 assert_eq!(None, i.next());
880 }
881 #[test]
882 fn key_perm_set_empty_test() {
883 let v = key_perm_set![];
884 let mut i = v.into_iter();
885 assert_eq!(None, i.next());
886 }
887 #[test]
888 fn key_perm_set_include_subset_test() {
889 let v1 = key_perm_set![
890 KeyPerm::manage_blob(),
891 KeyPerm::delete(),
892 KeyPerm::use_dev_id(),
893 KeyPerm::req_forced_op(),
894 KeyPerm::gen_unique_id(),
895 KeyPerm::grant(),
896 KeyPerm::get_info(),
897 KeyPerm::list(),
898 KeyPerm::rebind(),
899 KeyPerm::update(),
900 KeyPerm::use_(),
901 ];
902 let v2 = key_perm_set![
903 KeyPerm::manage_blob(),
904 KeyPerm::delete(),
905 KeyPerm::list(),
906 KeyPerm::rebind(),
907 KeyPerm::update(),
908 KeyPerm::use_(),
909 ];
910 assert!(v1.includes(v2));
911 assert!(!v2.includes(v1));
912 }
913 #[test]
914 fn key_perm_set_include_equal_test() {
915 let v1 = key_perm_set![
916 KeyPerm::manage_blob(),
917 KeyPerm::delete(),
918 KeyPerm::list(),
919 KeyPerm::rebind(),
920 KeyPerm::update(),
921 KeyPerm::use_(),
922 ];
923 let v2 = key_perm_set![
924 KeyPerm::manage_blob(),
925 KeyPerm::delete(),
926 KeyPerm::list(),
927 KeyPerm::rebind(),
928 KeyPerm::update(),
929 KeyPerm::use_(),
930 ];
931 assert!(v1.includes(v2));
932 assert!(v2.includes(v1));
933 }
934 #[test]
935 fn key_perm_set_include_overlap_test() {
936 let v1 = key_perm_set![
937 KeyPerm::manage_blob(),
938 KeyPerm::delete(),
939 KeyPerm::grant(), // only in v1
940 KeyPerm::list(),
941 KeyPerm::rebind(),
942 KeyPerm::update(),
943 KeyPerm::use_(),
944 ];
945 let v2 = key_perm_set![
946 KeyPerm::manage_blob(),
947 KeyPerm::delete(),
948 KeyPerm::req_forced_op(), // only in v2
949 KeyPerm::list(),
950 KeyPerm::rebind(),
951 KeyPerm::update(),
952 KeyPerm::use_(),
953 ];
954 assert!(!v1.includes(v2));
955 assert!(!v2.includes(v1));
956 }
957 #[test]
958 fn key_perm_set_include_no_overlap_test() {
959 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
960 let v2 = key_perm_set![
961 KeyPerm::req_forced_op(),
962 KeyPerm::list(),
963 KeyPerm::rebind(),
964 KeyPerm::update(),
965 KeyPerm::use_(),
966 ];
967 assert!(!v1.includes(v2));
968 assert!(!v2.includes(v1));
969 }
970}