blob: 97b241f00c0929f98746456b7d23cbf6feaa1b09 [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/// 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 Danisevskisc5b210b2020-09-11 13:27:37 -0700139 pub struct $name(pub $aidl_name);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700140
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700141 impl From<$aidl_name> for $name {
142 fn from (p: $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
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700151 impl From<$name> for $aidl_name {
152 fn from(p: $name) -> $aidl_name {
153 p.0
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700154 }
155 }
156
157 impl $name {
158 /// Returns a string representation of the permission as required by
159 /// `selinux::check_access`.
Chris Wailes3877f292021-07-26 19:24:18 -0700160 pub fn to_selinux(self) -> &'static str {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700161 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 Danisevskisc5b210b2020-09-11 13:27:37 -0700194 KeyPerm from KeyPermission with default (NONE, none) {
Satya Tangirala3361b612021-03-08 14:36:11 -0800195 CONVERT_STORAGE_KEY_TO_EPHEMERAL, selinux name: convert_storage_key_to_ephemeral;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700196 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.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700215/// * `MyPermission::to_selinux(&self)` returns the SELinux string representation of the
216/// corresponding permission.
217/// * An implicit default values `MyPermission::None` is created with a numeric representation
218/// of `0` and a string representation of `"none"`.
219/// * Specifying a value is optional. If the value is omitted it is set to the value of the
220/// previous variant left shifted by 1.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700221///
222/// ## Example
223/// ```
224/// implement_permission!(
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700225/// /// MyPermission documentation.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700226/// #[derive(Clone, Copy, Debug, Eq, PartialEq)]
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700227/// pub enum MyPermission {
228/// #[selinux(name = foo)]
229/// Foo = 1,
230/// #[selinux(name = bar)]
231/// Bar = 2,
232/// #[selinux(name = snafu)]
233/// Snafu, // Implicit value: MyPermission::Bar << 1 = 4
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700234/// }
235/// );
236/// ```
237macro_rules! implement_permission {
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700238 (
239 $(#[$enum_meta:meta])*
240 $enum_vis:vis enum $enum_name:ident {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700241 $(
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700242 $(#[$($emeta:tt)+])*
243 $vname:ident$( = $vval:tt)?
244 ),* $(,)?
245 }
246 ) => {
247 implement_permission!{
248 @extract_attr
249 $(#[$enum_meta])*
250 $enum_vis enum $enum_name {
251 1
252 []
253 [$(
254 [] [$(#[$($emeta)+])*]
255 $vname$( = $vval)?,
256 )*]
257 }
258 }
259 };
260
261 (
262 @extract_attr
263 $(#[$enum_meta:meta])*
264 $enum_vis:vis enum $enum_name:ident {
265 $next_val:tt
266 [$($out:tt)*]
267 [
268 [$(#[$mout:meta])*]
269 [
270 #[selinux(name = $selinux_name:ident)]
271 $(#[$($mtail:tt)+])*
272 ]
273 $vname:ident = $vval:tt,
274 $($tail:tt)*
275 ]
276 }
277 ) => {
278 implement_permission!{
279 @extract_attr
280 $(#[$enum_meta])*
281 $enum_vis enum $enum_name {
282 ($vval << 1)
283 [
284 $($out)*
285 $(#[$mout])*
286 $(#[$($mtail)+])*
287 $selinux_name $vname = $vval,
288 ]
289 [$($tail)*]
290 }
291 }
292 };
293
294 (
295 @extract_attr
296 $(#[$enum_meta:meta])*
297 $enum_vis:vis enum $enum_name:ident {
298 $next_val:tt
299 [$($out:tt)*]
300 [
301 [$(#[$mout:meta])*]
302 [
303 #[selinux(name = $selinux_name:ident)]
304 $(#[$($mtail:tt)+])*
305 ]
306 $vname:ident,
307 $($tail:tt)*
308 ]
309 }
310 ) => {
311 implement_permission!{
312 @extract_attr
313 $(#[$enum_meta])*
314 $enum_vis enum $enum_name {
315 ($next_val << 1)
316 [
317 $($out)*
318 $(#[$mout])*
319 $(#[$($mtail)+])*
320 $selinux_name $vname = $next_val,
321 ]
322 [$($tail)*]
323 }
324 }
325 };
326
327
328 (
329 @extract_attr
330 $(#[$enum_meta:meta])*
331 $enum_vis:vis enum $enum_name:ident {
332 $next_val:tt
333 [$($out:tt)*]
334 [
335 [$(#[$mout:meta])*]
336 [
337 #[$front:meta]
338 $(#[$($mtail:tt)+])*
339 ]
340 $vname:ident$( = $vval:tt)?,
341 $($tail:tt)*
342 ]
343 }
344 ) => {
345 implement_permission!{
346 @extract_attr
347 $(#[$enum_meta])*
348 $enum_vis enum $enum_name {
349 $next_val
350 [$($out)*]
351 [
352 [
353 $(#[$mout])*
354 #[$front]
355 ]
356 [$(#[$($mtail)+])*]
357 $vname$( = $vval)?,
358 $($tail)*
359 ]
360 }
361 }
362 };
363
364 (
365 @extract_attr
366 $(#[$enum_meta:meta])*
367 $enum_vis:vis enum $enum_name:ident {
368 $next_val:tt
369 [$($out:tt)*]
370 []
371 }
372 ) => {
373 implement_permission!{
374 @spill
375 $(#[$enum_meta])*
376 $enum_vis enum $enum_name {
377 $($out)*
378 }
379 }
380 };
381
382 (
383 @spill
384 $(#[$enum_meta:meta])*
385 $enum_vis:vis enum $enum_name:ident {
386 $(
387 $(#[$emeta:meta])*
388 $selinux_name:ident $vname:ident = $vval:tt,
389 )*
390 }
391 ) => {
392 $(#[$enum_meta])*
393 $enum_vis enum $enum_name {
394 /// The default variant of an enum.
395 None = 0,
396 $(
397 $(#[$emeta])*
398 $vname = $vval,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700399 )*
400 }
401
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700402 impl From<i32> for $enum_name {
403 #[allow(non_upper_case_globals)]
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700404 fn from (p: i32) -> Self {
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700405 // Creating constants forces the compiler to evaluate the value expressions
406 // so that they can be used in the match statement below.
407 $(const $vname: i32 = $vval;)*
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700408 match p {
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700409 0 => Self::None,
410 $($vname => Self::$vname,)*
411 _ => Self::None,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700412 }
413 }
414 }
415
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700416 impl From<$enum_name> for i32 {
417 fn from(p: $enum_name) -> i32 {
Matthew Maurerb77a28d2021-05-07 16:08:20 -0700418 p as i32
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700419 }
420 }
421
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700422 impl $enum_name {
423
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700424 /// Returns a string representation of the permission as required by
425 /// `selinux::check_access`.
Chris Wailes3877f292021-07-26 19:24:18 -0700426 pub fn to_selinux(self) -> &'static str {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700427 match self {
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700428 Self::None => &"none",
429 $(Self::$vname => stringify!($selinux_name),)*
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700430 }
431 }
432
433 /// Creates an instance representing a permission with the same name.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700434 pub const fn none() -> Self { Self::None }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700435 $(
436 /// Creates an instance representing a permission with the same name.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700437 pub const fn $selinux_name() -> Self { Self::$vname }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700438 )*
439 }
440 };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700441}
442
443implement_permission!(
444 /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
445 /// Using the implement_permission macro we get the same features as `KeyPerm`.
446 #[derive(Clone, Copy, Debug, PartialEq)]
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700447 pub enum KeystorePerm {
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700448 /// Checked when a new auth token is installed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700449 #[selinux(name = add_auth)]
450 AddAuth,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700451 /// Checked when an app is uninstalled or wiped.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700452 #[selinux(name = clear_ns)]
453 ClearNs,
Hasini Gunasinghe9ee18412021-03-11 20:12:44 +0000454 /// Checked when the user state is queried from Keystore 2.0.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700455 #[selinux(name = get_state)]
456 GetState,
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700457 /// Checked when Keystore 2.0 is asked to list a namespace that the caller
458 /// does not have the get_info permission for.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700459 #[selinux(name = list)]
460 List,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700461 /// Checked when Keystore 2.0 gets locked.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700462 #[selinux(name = lock)]
463 Lock,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700464 /// Checked when Keystore 2.0 shall be reset.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700465 #[selinux(name = reset)]
466 Reset,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700467 /// Checked when Keystore 2.0 shall be unlocked.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700468 #[selinux(name = unlock)]
469 Unlock,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000470 /// Checked when user is added or removed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700471 #[selinux(name = change_user)]
472 ChangeUser,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000473 /// Checked when password of the user is changed.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700474 #[selinux(name = change_password)]
475 ChangePassword,
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000476 /// Checked when a UID is cleared.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700477 #[selinux(name = clear_uid)]
478 ClearUID,
Hasini Gunasinghe5fc95252020-12-04 00:35:08 +0000479 /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700480 #[selinux(name = get_auth_token)]
481 GetAuthToken,
Satya Tangirala5b9e5b12021-03-09 12:54:21 -0800482 /// Checked when earlyBootEnded() is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700483 #[selinux(name = early_boot_ended)]
484 EarlyBootEnded,
Janis Danisevskis333b7c02021-03-23 18:57:41 -0700485 /// Checked when IKeystoreMaintenance::onDeviceOffBody is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700486 #[selinux(name = report_off_body)]
487 ReportOffBody,
488 /// Checked when IkeystoreMetrics::pullMetrics is called.
489 #[selinux(name = pull_metrics)]
490 PullMetrics,
Paul Crowley46c703e2021-08-06 15:13:53 -0700491 /// Checked when IKeystoreMaintenance::deleteAllKeys is called.
Janis Danisevskis751d2c82021-10-18 15:37:09 -0700492 #[selinux(name = delete_all_keys)]
493 DeleteAllKeys,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700494 }
495);
496
497/// Represents a set of `KeyPerm` permissions.
498/// `IntoIterator` is implemented for this struct allowing the iteration through all the
499/// permissions in the set.
500/// It also implements a function `includes(self, other)` that checks if the permissions
501/// in `other` are included in `self`.
502///
503/// KeyPermSet can be created with the macro `key_perm_set![]`.
504///
505/// ## Example
506/// ```
507/// let perms1 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob(), KeyPerm::grant()];
508/// let perms2 = key_perm_set![KeyPerm::use_(), KeyPerm::manage_blob()];
509///
510/// assert!(perms1.includes(perms2))
511/// assert!(!perms2.includes(perms1))
512///
513/// let i = perms1.into_iter();
514/// // iteration in ascending order of the permission's numeric representation.
515/// assert_eq(Some(KeyPerm::manage_blob()), i.next());
516/// assert_eq(Some(KeyPerm::grant()), i.next());
517/// assert_eq(Some(KeyPerm::use_()), i.next());
518/// assert_eq(None, i.next());
519/// ```
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700520#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
521pub struct KeyPermSet(pub i32);
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700522
523mod perm {
524 use super::*;
525
526 pub struct IntoIter {
527 vec: KeyPermSet,
528 pos: u8,
529 }
530
531 impl IntoIter {
532 pub fn new(v: KeyPermSet) -> Self {
533 Self { vec: v, pos: 0 }
534 }
535 }
536
537 impl std::iter::Iterator for IntoIter {
538 type Item = KeyPerm;
539
540 fn next(&mut self) -> Option<Self::Item> {
541 loop {
542 if self.pos == 32 {
543 return None;
544 }
545 let p = self.vec.0 & (1 << self.pos);
546 self.pos += 1;
547 if p != 0 {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700548 return Some(KeyPerm::from(KeyPermission(p)));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700549 }
550 }
551 }
552 }
553}
554
555impl From<KeyPerm> for KeyPermSet {
556 fn from(p: KeyPerm) -> Self {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700557 Self((p.0).0 as i32)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700558 }
559}
560
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700561/// allow conversion from the AIDL wire type i32 to a permission set.
562impl From<i32> for KeyPermSet {
563 fn from(p: i32) -> Self {
564 Self(p)
565 }
566}
567
568impl From<KeyPermSet> for i32 {
569 fn from(p: KeyPermSet) -> i32 {
570 p.0
571 }
572}
573
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700574impl KeyPermSet {
575 /// Returns true iff this permission set has all of the permissions that are in `other`.
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700576 pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700577 let o: KeyPermSet = other.into();
578 (self.0 & o.0) == o.0
579 }
580}
581
582/// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
583///
584/// ## Example
585/// ```
586/// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
587/// ```
588#[macro_export]
589macro_rules! key_perm_set {
590 () => { KeyPermSet(0) };
591 ($head:expr $(, $tail:expr)* $(,)?) => {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700592 KeyPermSet(($head.0).0 $(| ($tail.0).0)*)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700593 };
594}
595
596impl IntoIterator for KeyPermSet {
597 type Item = KeyPerm;
598 type IntoIter = perm::IntoIter;
599
600 fn into_iter(self) -> Self::IntoIter {
601 Self::IntoIter::new(self)
602 }
603}
604
605/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` may access
606/// the given permision `perm` of the `keystore2` security class.
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700607pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700608 let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
609 selinux::check_access(caller_ctx, &target_context, "keystore2", perm.to_selinux())
610}
611
612/// Uses `selinux::check_access` to check if the given caller context `caller_cxt` has
613/// all the permissions indicated in `access_vec` for the target domain indicated by the key
614/// descriptor `key` in the security class `keystore2_key`.
615///
616/// Also checks if the caller has the grant permission for the given target domain.
617///
618/// Attempts to grant the grant permission are always denied.
619///
620/// The only viable target domains are
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700621/// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
622/// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700623/// SELinux keystore key backend, and the result is used
624/// as target context.
625pub fn check_grant_permission(
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700626 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700627 access_vec: KeyPermSet,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700628 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700629) -> anyhow::Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700630 let target_context = match key.domain {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700631 Domain::APP => getcon().context("check_grant_permission: getcon failed.")?,
632 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
633 .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700634 _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
635 };
636
637 selinux::check_access(caller_ctx, &target_context, "keystore2_key", "grant")
638 .context("Grant permission is required when granting.")?;
639
640 if access_vec.includes(KeyPerm::grant()) {
641 return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
642 }
643
644 for p in access_vec.into_iter() {
645 selinux::check_access(caller_ctx, &target_context, "keystore2_key", p.to_selinux())
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800646 .context(format!(
647 concat!(
648 "check_grant_permission: check_access failed. ",
649 "The caller may have tried to grant a permission that they don't possess. {:?}"
650 ),
651 p
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700652 ))?
653 }
654 Ok(())
655}
656
657/// Uses `selinux::check_access` to check if the given caller context `caller_cxt`
658/// has the permissions indicated by `perm` for the target domain indicated by the key
659/// descriptor `key` in the security class `keystore2_key`.
660///
661/// The behavior differs slightly depending on the selected target domain:
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700662/// * `Domain::APP` u:r:keystore:s0 is used as target context.
663/// * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700664/// backend, and the result is used as target context.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700665/// * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700666/// to the one supplied in `perm`.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700667/// * `Domain::GRANT` Does not use selinux::check_access. Instead the `access_vector`
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700668/// parameter is queried for permission, which must be supplied in this case.
669///
670/// ## Return values.
671/// * Ok(()) If the requested permissions were granted.
672/// * Err(selinux::Error::perm()) If the requested permissions were denied.
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700673/// * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
674/// was supplied. It is also produced if `Domain::KEY_ID` was selected, and
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700675/// on various unexpected backend failures.
676pub fn check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800677 caller_uid: u32,
Janis Danisevskis935e6c62020-08-18 12:52:27 -0700678 caller_ctx: &CStr,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700679 perm: KeyPerm,
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700680 key: &KeyDescriptor,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700681 access_vector: &Option<KeyPermSet>,
682) -> anyhow::Result<()> {
Janis Danisevskis45760022021-01-19 16:34:10 -0800683 // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID.
684 // In the former case, key.domain was set to GRANT and we check the failure cases
685 // further below. If the access is requested by KEY_ID, key.domain would have been
686 // resolved to APP or SELINUX depending on where the key actually resides.
687 // Either way we can return here immediately if the access vector covers the requested
688 // permission. If it does not, we can still check if the caller has access by means of
689 // ownership.
690 if let Some(access_vector) = access_vector {
691 if access_vector.includes(perm) {
692 return Ok(());
693 }
694 }
695
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700696 let target_context = match key.domain {
697 // apps get the default keystore context
Janis Danisevskis45760022021-01-19 16:34:10 -0800698 Domain::APP => {
699 if caller_uid as i64 != key.nspace {
700 return Err(selinux::Error::perm())
701 .context("Trying to access key without ownership.");
702 }
703 getcon().context("check_key_permission: getcon failed.")?
704 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700705 Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
706 .context("check_key_permission: Domain::SELINUX: Failed to lookup namespace.")?,
707 Domain::GRANT => {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700708 match access_vector {
Janis Danisevskis45760022021-01-19 16:34:10 -0800709 Some(_) => {
710 return Err(selinux::Error::perm())
711 .context(format!("\"{}\" not granted", perm.to_selinux()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700712 }
713 None => {
714 // If DOMAIN_GRANT was selected an access vector must be supplied.
715 return Err(KsError::sys()).context(
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700716 "Cannot check permission for Domain::GRANT without access vector.",
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700717 );
718 }
719 }
720 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700721 Domain::KEY_ID => {
722 // We should never be called with `Domain::KEY_ID. The database
723 // lookup should have converted this into one of `Domain::APP`
724 // or `Domain::SELINUX`.
725 return Err(KsError::sys()).context("Cannot check permission for Domain::KEY_ID.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700726 }
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700727 Domain::BLOB => {
728 let tctx = lookup_keystore2_key_context(key.nspace)
729 .context("Domain::BLOB: Failed to lookup namespace.")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700730 // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
731 // permission in addition to the requested permission.
732 selinux::check_access(
733 caller_ctx,
734 &tctx,
735 "keystore2_key",
736 KeyPerm::manage_blob().to_selinux(),
737 )?;
738
739 tctx
740 }
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700741 _ => {
742 return Err(KsError::sys())
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700743 .context(format!("Unknown domain value: \"{:?}\".", key.domain))
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700744 }
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700745 };
746
747 selinux::check_access(caller_ctx, &target_context, "keystore2_key", perm.to_selinux())
748}
749
750#[cfg(test)]
751mod tests {
752 use super::*;
753 use anyhow::anyhow;
754 use anyhow::Result;
755 use keystore2_selinux::*;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700756
757 const ALL_PERMS: KeyPermSet = key_perm_set![
758 KeyPerm::manage_blob(),
759 KeyPerm::delete(),
760 KeyPerm::use_dev_id(),
761 KeyPerm::req_forced_op(),
762 KeyPerm::gen_unique_id(),
763 KeyPerm::grant(),
764 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700765 KeyPerm::rebind(),
766 KeyPerm::update(),
767 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800768 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700769 ];
770
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800771 const SYSTEM_SERVER_PERMISSIONS_NO_GRANT: KeyPermSet = key_perm_set![
772 KeyPerm::delete(),
773 KeyPerm::use_dev_id(),
774 // No KeyPerm::grant()
775 KeyPerm::get_info(),
776 KeyPerm::rebind(),
777 KeyPerm::update(),
778 KeyPerm::use_(),
779 ];
780
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700781 const NOT_GRANT_PERMS: KeyPermSet = key_perm_set![
782 KeyPerm::manage_blob(),
783 KeyPerm::delete(),
784 KeyPerm::use_dev_id(),
785 KeyPerm::req_forced_op(),
786 KeyPerm::gen_unique_id(),
787 // No KeyPerm::grant()
788 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700789 KeyPerm::rebind(),
790 KeyPerm::update(),
791 KeyPerm::use_(),
Satya Tangirala3361b612021-03-08 14:36:11 -0800792 KeyPerm::convert_storage_key_to_ephemeral(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700793 ];
794
795 const UNPRIV_PERMS: KeyPermSet = key_perm_set![
796 KeyPerm::delete(),
797 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700798 KeyPerm::rebind(),
799 KeyPerm::update(),
800 KeyPerm::use_(),
801 ];
802
803 /// The su_key namespace as defined in su.te and keystore_key_contexts of the
804 /// SePolicy (system/sepolicy).
805 const SU_KEY_NAMESPACE: i32 = 0;
806 /// The shell_key namespace as defined in shell.te and keystore_key_contexts of the
807 /// SePolicy (system/sepolicy).
808 const SHELL_KEY_NAMESPACE: i32 = 1;
809
810 pub fn test_getcon() -> Result<Context> {
811 Context::new("u:object_r:keystore:s0")
812 }
813
814 // This macro evaluates the given expression and checks that
815 // a) evaluated to Result::Err() and that
816 // b) the wrapped error is selinux::Error::perm() (permission denied).
817 // We use a macro here because a function would mask which invocation caused the failure.
818 //
819 // TODO b/164121720 Replace this macro with a function when `track_caller` is available.
820 macro_rules! assert_perm_failed {
821 ($test_function:expr) => {
822 let result = $test_function;
823 assert!(result.is_err(), "Permission check should have failed.");
824 assert_eq!(
825 Some(&selinux::Error::perm()),
826 result.err().unwrap().root_cause().downcast_ref::<selinux::Error>()
827 );
828 };
829 }
830
831 fn check_context() -> Result<(selinux::Context, i32, bool)> {
832 // Calling the non mocked selinux::getcon here intended.
833 let context = selinux::getcon()?;
834 match context.to_str().unwrap() {
835 "u:r:su:s0" => Ok((context, SU_KEY_NAMESPACE, true)),
836 "u:r:shell:s0" => Ok((context, SHELL_KEY_NAMESPACE, false)),
837 c => Err(anyhow!(format!(
838 "This test must be run as \"su\" or \"shell\". Current context: \"{}\"",
839 c
840 ))),
841 }
842 }
843
844 #[test]
845 fn check_keystore_permission_test() -> Result<()> {
846 let system_server_ctx = Context::new("u:r:system_server:s0")?;
847 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::add_auth()).is_ok());
848 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_ns()).is_ok());
849 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::get_state()).is_ok());
850 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::lock()).is_ok());
851 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::reset()).is_ok());
852 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::unlock()).is_ok());
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000853 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::change_user()).is_ok());
854 assert!(
855 check_keystore_permission(&system_server_ctx, KeystorePerm::change_password()).is_ok()
856 );
857 assert!(check_keystore_permission(&system_server_ctx, KeystorePerm::clear_uid()).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700858 let shell_ctx = Context::new("u:r:shell:s0")?;
859 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::add_auth()));
860 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_ns()));
Janis Danisevskis1bb595e2021-03-16 10:09:08 -0700861 assert!(check_keystore_permission(&shell_ctx, KeystorePerm::get_state()).is_ok());
Janis Danisevskisee10b5f2020-09-22 16:42:35 -0700862 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::list()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700863 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::lock()));
864 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::reset()));
865 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::unlock()));
Hasini Gunasinghe803c2d42021-01-27 00:48:40 +0000866 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_user()));
867 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::change_password()));
868 assert_perm_failed!(check_keystore_permission(&shell_ctx, KeystorePerm::clear_uid()));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700869 Ok(())
870 }
871
872 #[test]
873 fn check_grant_permission_app() -> Result<()> {
874 let system_server_ctx = Context::new("u:r:system_server:s0")?;
875 let shell_ctx = Context::new("u:r:shell:s0")?;
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700876 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800877 check_grant_permission(&system_server_ctx, SYSTEM_SERVER_PERMISSIONS_NO_GRANT, &key)
878 .expect("Grant permission check failed.");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700879
Janis Danisevskisa31dd9e2021-01-30 00:13:17 -0800880 // attempts to grant the grant permission must always fail even when privileged.
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700881 assert_perm_failed!(check_grant_permission(
882 &system_server_ctx,
883 KeyPerm::grant().into(),
884 &key
885 ));
886 // unprivileged grant attempts always fail. shell does not have the grant permission.
887 assert_perm_failed!(check_grant_permission(&shell_ctx, UNPRIV_PERMS, &key));
888 Ok(())
889 }
890
891 #[test]
892 fn check_grant_permission_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700893 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -0700894 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700895 domain: Domain::SELINUX,
896 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700897 alias: None,
898 blob: None,
899 };
900 if is_su {
901 assert!(check_grant_permission(&sctx, NOT_GRANT_PERMS, &key).is_ok());
902 // attempts to grant the grant permission must always fail even when privileged.
903 assert_perm_failed!(check_grant_permission(&sctx, KeyPerm::grant().into(), &key));
904 } else {
905 // unprivileged grant attempts always fail. shell does not have the grant permission.
906 assert_perm_failed!(check_grant_permission(&sctx, UNPRIV_PERMS, &key));
907 }
908 Ok(())
909 }
910
911 #[test]
912 fn check_key_permission_domain_grant() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700913 let key = KeyDescriptor { domain: Domain::GRANT, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700914
915 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800916 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700917 &selinux::Context::new("ignored").unwrap(),
918 KeyPerm::grant(),
919 &key,
920 &Some(UNPRIV_PERMS)
921 ));
922
923 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800924 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700925 &selinux::Context::new("ignored").unwrap(),
926 KeyPerm::use_(),
927 &key,
928 &Some(ALL_PERMS),
929 )
930 }
931
932 #[test]
933 fn check_key_permission_domain_app() -> Result<()> {
934 let system_server_ctx = Context::new("u:r:system_server:s0")?;
935 let shell_ctx = Context::new("u:r:shell:s0")?;
936 let gmscore_app = Context::new("u:r:gmscore_app:s0")?;
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700937
Janis Danisevskisc5b210b2020-09-11 13:27:37 -0700938 let key = KeyDescriptor { domain: Domain::APP, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700939
Janis Danisevskis45760022021-01-19 16:34:10 -0800940 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::use_(), &key, &None).is_ok());
941 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::delete(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700942 assert!(
Janis Danisevskis45760022021-01-19 16:34:10 -0800943 check_key_permission(0, &system_server_ctx, KeyPerm::get_info(), &key, &None).is_ok()
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700944 );
Janis Danisevskis45760022021-01-19 16:34:10 -0800945 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::rebind(), &key, &None).is_ok());
946 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::update(), &key, &None).is_ok());
947 assert!(check_key_permission(0, &system_server_ctx, KeyPerm::grant(), &key, &None).is_ok());
948 assert!(
949 check_key_permission(0, &system_server_ctx, KeyPerm::use_dev_id(), &key, &None).is_ok()
950 );
951 assert!(
952 check_key_permission(0, &gmscore_app, KeyPerm::gen_unique_id(), &key, &None).is_ok()
953 );
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700954
Janis Danisevskis45760022021-01-19 16:34:10 -0800955 assert!(check_key_permission(0, &shell_ctx, KeyPerm::use_(), &key, &None).is_ok());
956 assert!(check_key_permission(0, &shell_ctx, KeyPerm::delete(), &key, &None).is_ok());
957 assert!(check_key_permission(0, &shell_ctx, KeyPerm::get_info(), &key, &None).is_ok());
958 assert!(check_key_permission(0, &shell_ctx, KeyPerm::rebind(), &key, &None).is_ok());
959 assert!(check_key_permission(0, &shell_ctx, KeyPerm::update(), &key, &None).is_ok());
960 assert_perm_failed!(check_key_permission(0, &shell_ctx, KeyPerm::grant(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700961 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800962 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700963 &shell_ctx,
964 KeyPerm::req_forced_op(),
965 &key,
966 &None
967 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700968 assert_perm_failed!(check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -0800969 0,
970 &shell_ctx,
971 KeyPerm::manage_blob(),
972 &key,
973 &None
974 ));
975 assert_perm_failed!(check_key_permission(
976 0,
977 &shell_ctx,
978 KeyPerm::use_dev_id(),
979 &key,
980 &None
981 ));
982 assert_perm_failed!(check_key_permission(
983 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -0700984 &shell_ctx,
985 KeyPerm::gen_unique_id(),
986 &key,
987 &None
988 ));
989
Janis Danisevskis45760022021-01-19 16:34:10 -0800990 // Also make sure that the permission fails if the caller is not the owner.
991 assert_perm_failed!(check_key_permission(
992 1, // the owner is 0
993 &system_server_ctx,
994 KeyPerm::use_(),
995 &key,
996 &None
997 ));
998 // Unless there was a grant.
999 assert!(check_key_permission(
1000 1,
1001 &system_server_ctx,
1002 KeyPerm::use_(),
1003 &key,
1004 &Some(key_perm_set![KeyPerm::use_()])
1005 )
1006 .is_ok());
1007 // But fail if the grant did not cover the requested permission.
1008 assert_perm_failed!(check_key_permission(
1009 1,
1010 &system_server_ctx,
1011 KeyPerm::use_(),
1012 &key,
1013 &Some(key_perm_set![KeyPerm::get_info()])
1014 ));
1015
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001016 Ok(())
1017 }
1018
1019 #[test]
1020 fn check_key_permission_domain_selinux() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001021 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -07001022 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001023 domain: Domain::SELINUX,
1024 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001025 alias: None,
1026 blob: None,
1027 };
1028
Chris Wailes3877f292021-07-26 19:24:18 -07001029 assert!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None).is_ok());
1030 assert!(check_key_permission(0, &sctx, KeyPerm::delete(), &key, &None).is_ok());
1031 assert!(check_key_permission(0, &sctx, KeyPerm::get_info(), &key, &None).is_ok());
1032 assert!(check_key_permission(0, &sctx, KeyPerm::rebind(), &key, &None).is_ok());
1033 assert!(check_key_permission(0, &sctx, KeyPerm::update(), &key, &None).is_ok());
1034
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001035 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -08001036 assert!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None).is_ok());
1037 assert!(check_key_permission(0, &sctx, KeyPerm::manage_blob(), &key, &None).is_ok());
1038 assert!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None).is_ok());
1039 assert!(check_key_permission(0, &sctx, KeyPerm::gen_unique_id(), &key, &None).is_ok());
1040 assert!(check_key_permission(0, &sctx, KeyPerm::req_forced_op(), &key, &None).is_ok());
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001041 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -08001042 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::grant(), &key, &None));
1043 assert_perm_failed!(check_key_permission(
1044 0,
1045 &sctx,
1046 KeyPerm::req_forced_op(),
1047 &key,
1048 &None
1049 ));
1050 assert_perm_failed!(check_key_permission(
1051 0,
1052 &sctx,
1053 KeyPerm::manage_blob(),
1054 &key,
1055 &None
1056 ));
1057 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_dev_id(), &key, &None));
1058 assert_perm_failed!(check_key_permission(
1059 0,
1060 &sctx,
1061 KeyPerm::gen_unique_id(),
1062 &key,
1063 &None
1064 ));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001065 }
1066 Ok(())
1067 }
1068
1069 #[test]
1070 fn check_key_permission_domain_blob() -> Result<()> {
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001071 let (sctx, namespace, is_su) = check_context()?;
Janis Danisevskis1b3a6e22020-08-07 12:39:56 -07001072 let key = KeyDescriptor {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001073 domain: Domain::BLOB,
1074 nspace: namespace as i64,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001075 alias: None,
1076 blob: None,
1077 };
1078
1079 if is_su {
Janis Danisevskis45760022021-01-19 16:34:10 -08001080 check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None)
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001081 } else {
Janis Danisevskis45760022021-01-19 16:34:10 -08001082 assert_perm_failed!(check_key_permission(0, &sctx, KeyPerm::use_(), &key, &None));
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001083 Ok(())
1084 }
1085 }
1086
1087 #[test]
1088 fn check_key_permission_domain_key_id() -> Result<()> {
Janis Danisevskisc5b210b2020-09-11 13:27:37 -07001089 let key = KeyDescriptor { domain: Domain::KEY_ID, nspace: 0, alias: None, blob: None };
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001090
1091 assert_eq!(
1092 Some(&KsError::sys()),
1093 check_key_permission(
Janis Danisevskis45760022021-01-19 16:34:10 -08001094 0,
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001095 &selinux::Context::new("ignored").unwrap(),
1096 KeyPerm::use_(),
1097 &key,
1098 &None
1099 )
1100 .err()
1101 .unwrap()
1102 .root_cause()
1103 .downcast_ref::<KsError>()
1104 );
1105 Ok(())
1106 }
1107
1108 #[test]
1109 fn key_perm_set_all_test() {
1110 let v = key_perm_set![
1111 KeyPerm::manage_blob(),
1112 KeyPerm::delete(),
1113 KeyPerm::use_dev_id(),
1114 KeyPerm::req_forced_op(),
1115 KeyPerm::gen_unique_id(),
1116 KeyPerm::grant(),
1117 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001118 KeyPerm::rebind(),
1119 KeyPerm::update(),
1120 KeyPerm::use_() // Test if the macro accepts missing comma at the end of the list.
1121 ];
1122 let mut i = v.into_iter();
1123 assert_eq!(i.next().unwrap().to_selinux(), "delete");
1124 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
1125 assert_eq!(i.next().unwrap().to_selinux(), "get_info");
1126 assert_eq!(i.next().unwrap().to_selinux(), "grant");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001127 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
1128 assert_eq!(i.next().unwrap().to_selinux(), "rebind");
1129 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
1130 assert_eq!(i.next().unwrap().to_selinux(), "update");
1131 assert_eq!(i.next().unwrap().to_selinux(), "use");
1132 assert_eq!(i.next().unwrap().to_selinux(), "use_dev_id");
1133 assert_eq!(None, i.next());
1134 }
1135 #[test]
1136 fn key_perm_set_sparse_test() {
1137 let v = key_perm_set![
1138 KeyPerm::manage_blob(),
1139 KeyPerm::req_forced_op(),
1140 KeyPerm::gen_unique_id(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001141 KeyPerm::update(),
1142 KeyPerm::use_(), // Test if macro accepts the comma at the end of the list.
1143 ];
1144 let mut i = v.into_iter();
1145 assert_eq!(i.next().unwrap().to_selinux(), "gen_unique_id");
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001146 assert_eq!(i.next().unwrap().to_selinux(), "manage_blob");
1147 assert_eq!(i.next().unwrap().to_selinux(), "req_forced_op");
1148 assert_eq!(i.next().unwrap().to_selinux(), "update");
1149 assert_eq!(i.next().unwrap().to_selinux(), "use");
1150 assert_eq!(None, i.next());
1151 }
1152 #[test]
1153 fn key_perm_set_empty_test() {
1154 let v = key_perm_set![];
1155 let mut i = v.into_iter();
1156 assert_eq!(None, i.next());
1157 }
1158 #[test]
1159 fn key_perm_set_include_subset_test() {
1160 let v1 = key_perm_set![
1161 KeyPerm::manage_blob(),
1162 KeyPerm::delete(),
1163 KeyPerm::use_dev_id(),
1164 KeyPerm::req_forced_op(),
1165 KeyPerm::gen_unique_id(),
1166 KeyPerm::grant(),
1167 KeyPerm::get_info(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001168 KeyPerm::rebind(),
1169 KeyPerm::update(),
1170 KeyPerm::use_(),
1171 ];
1172 let v2 = key_perm_set![
1173 KeyPerm::manage_blob(),
1174 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001175 KeyPerm::rebind(),
1176 KeyPerm::update(),
1177 KeyPerm::use_(),
1178 ];
1179 assert!(v1.includes(v2));
1180 assert!(!v2.includes(v1));
1181 }
1182 #[test]
1183 fn key_perm_set_include_equal_test() {
1184 let v1 = key_perm_set![
1185 KeyPerm::manage_blob(),
1186 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001187 KeyPerm::rebind(),
1188 KeyPerm::update(),
1189 KeyPerm::use_(),
1190 ];
1191 let v2 = key_perm_set![
1192 KeyPerm::manage_blob(),
1193 KeyPerm::delete(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001194 KeyPerm::rebind(),
1195 KeyPerm::update(),
1196 KeyPerm::use_(),
1197 ];
1198 assert!(v1.includes(v2));
1199 assert!(v2.includes(v1));
1200 }
1201 #[test]
1202 fn key_perm_set_include_overlap_test() {
1203 let v1 = key_perm_set![
1204 KeyPerm::manage_blob(),
1205 KeyPerm::delete(),
1206 KeyPerm::grant(), // only in v1
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001207 KeyPerm::rebind(),
1208 KeyPerm::update(),
1209 KeyPerm::use_(),
1210 ];
1211 let v2 = key_perm_set![
1212 KeyPerm::manage_blob(),
1213 KeyPerm::delete(),
1214 KeyPerm::req_forced_op(), // only in v2
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001215 KeyPerm::rebind(),
1216 KeyPerm::update(),
1217 KeyPerm::use_(),
1218 ];
1219 assert!(!v1.includes(v2));
1220 assert!(!v2.includes(v1));
1221 }
1222 #[test]
1223 fn key_perm_set_include_no_overlap_test() {
1224 let v1 = key_perm_set![KeyPerm::manage_blob(), KeyPerm::delete(), KeyPerm::grant(),];
1225 let v2 = key_perm_set![
1226 KeyPerm::req_forced_op(),
Janis Danisevskis78bd48c2020-07-21 12:27:13 -07001227 KeyPerm::rebind(),
1228 KeyPerm::update(),
1229 KeyPerm::use_(),
1230 ];
1231 assert!(!v1.includes(v2));
1232 assert!(!v2.includes(v1));
1233 }
1234}