1*e1997b9aSAndroid Build Coastguard Worker // Copyright 2020, The Android Open Source Project
2*e1997b9aSAndroid Build Coastguard Worker //
3*e1997b9aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*e1997b9aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*e1997b9aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*e1997b9aSAndroid Build Coastguard Worker //
7*e1997b9aSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*e1997b9aSAndroid Build Coastguard Worker //
9*e1997b9aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*e1997b9aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*e1997b9aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*e1997b9aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*e1997b9aSAndroid Build Coastguard Worker // limitations under the License.
14*e1997b9aSAndroid Build Coastguard Worker
15*e1997b9aSAndroid Build Coastguard Worker //! This crate provides access control primitives for Keystore 2.0.
16*e1997b9aSAndroid Build Coastguard Worker //! It provides high level functions for checking permissions in the keystore2 and keystore2_key
17*e1997b9aSAndroid Build Coastguard Worker //! SELinux classes based on the keystore2_selinux backend.
18*e1997b9aSAndroid Build Coastguard Worker //! It also provides KeystorePerm and KeyPerm as convenience wrappers for the SELinux permission
19*e1997b9aSAndroid Build Coastguard Worker //! defined by keystore2 and keystore2_key respectively.
20*e1997b9aSAndroid Build Coastguard Worker
21*e1997b9aSAndroid Build Coastguard Worker use crate::error::Error as KsError;
22*e1997b9aSAndroid Build Coastguard Worker use crate::error::ResponseCode;
23*e1997b9aSAndroid Build Coastguard Worker use crate::ks_err;
24*e1997b9aSAndroid Build Coastguard Worker use android_system_keystore2::aidl::android::system::keystore2::{
25*e1997b9aSAndroid Build Coastguard Worker Domain::Domain, KeyDescriptor::KeyDescriptor, KeyPermission::KeyPermission,
26*e1997b9aSAndroid Build Coastguard Worker };
27*e1997b9aSAndroid Build Coastguard Worker use anyhow::Context as AnyhowContext;
28*e1997b9aSAndroid Build Coastguard Worker use keystore2_selinux as selinux;
29*e1997b9aSAndroid Build Coastguard Worker use selinux::{implement_class, Backend, ClassPermission};
30*e1997b9aSAndroid Build Coastguard Worker use std::cmp::PartialEq;
31*e1997b9aSAndroid Build Coastguard Worker use std::convert::From;
32*e1997b9aSAndroid Build Coastguard Worker use std::ffi::CStr;
33*e1997b9aSAndroid Build Coastguard Worker use std::sync::LazyLock;
34*e1997b9aSAndroid Build Coastguard Worker
35*e1997b9aSAndroid Build Coastguard Worker // Replace getcon with a mock in the test situation
36*e1997b9aSAndroid Build Coastguard Worker #[cfg(not(test))]
37*e1997b9aSAndroid Build Coastguard Worker use selinux::getcon;
38*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)]
39*e1997b9aSAndroid Build Coastguard Worker use tests::test_getcon as getcon;
40*e1997b9aSAndroid Build Coastguard Worker
41*e1997b9aSAndroid Build Coastguard Worker #[cfg(test)]
42*e1997b9aSAndroid Build Coastguard Worker mod tests;
43*e1997b9aSAndroid Build Coastguard Worker
44*e1997b9aSAndroid Build Coastguard Worker // Panicking here is allowed because keystore cannot function without this backend
45*e1997b9aSAndroid Build Coastguard Worker // and it would happen early and indicate a gross misconfiguration of the device.
46*e1997b9aSAndroid Build Coastguard Worker static KEYSTORE2_KEY_LABEL_BACKEND: LazyLock<selinux::KeystoreKeyBackend> =
47*e1997b9aSAndroid Build Coastguard Worker LazyLock::new(|| selinux::KeystoreKeyBackend::new().unwrap());
48*e1997b9aSAndroid Build Coastguard Worker
lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context>49*e1997b9aSAndroid Build Coastguard Worker fn lookup_keystore2_key_context(namespace: i64) -> anyhow::Result<selinux::Context> {
50*e1997b9aSAndroid Build Coastguard Worker KEYSTORE2_KEY_LABEL_BACKEND.lookup(&namespace.to_string())
51*e1997b9aSAndroid Build Coastguard Worker }
52*e1997b9aSAndroid Build Coastguard Worker
53*e1997b9aSAndroid Build Coastguard Worker implement_class!(
54*e1997b9aSAndroid Build Coastguard Worker /// KeyPerm provides a convenient abstraction from the SELinux class `keystore2_key`.
55*e1997b9aSAndroid Build Coastguard Worker /// At the same time it maps `KeyPermissions` from the Keystore 2.0 AIDL Grant interface to
56*e1997b9aSAndroid Build Coastguard Worker /// the SELinux permissions.
57*e1997b9aSAndroid Build Coastguard Worker #[repr(i32)]
58*e1997b9aSAndroid Build Coastguard Worker #[selinux(class_name = keystore2_key)]
59*e1997b9aSAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialEq, Eq)]
60*e1997b9aSAndroid Build Coastguard Worker pub enum KeyPerm {
61*e1997b9aSAndroid Build Coastguard Worker /// Checked when convert_storage_key_to_ephemeral is called.
62*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = convert_storage_key_to_ephemeral)]
63*e1997b9aSAndroid Build Coastguard Worker ConvertStorageKeyToEphemeral = KeyPermission::CONVERT_STORAGE_KEY_TO_EPHEMERAL.0,
64*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller tries do delete a key.
65*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = delete)]
66*e1997b9aSAndroid Build Coastguard Worker Delete = KeyPermission::DELETE.0,
67*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller tries to use a unique id.
68*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = gen_unique_id)]
69*e1997b9aSAndroid Build Coastguard Worker GenUniqueId = KeyPermission::GEN_UNIQUE_ID.0,
70*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller tries to load a key.
71*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = get_info)]
72*e1997b9aSAndroid Build Coastguard Worker GetInfo = KeyPermission::GET_INFO.0,
73*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller attempts to grant a key to another uid.
74*e1997b9aSAndroid Build Coastguard Worker /// Also used for gating key migration attempts.
75*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = grant)]
76*e1997b9aSAndroid Build Coastguard Worker Grant = KeyPermission::GRANT.0,
77*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller attempts to use Domain::BLOB.
78*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = manage_blob)]
79*e1997b9aSAndroid Build Coastguard Worker ManageBlob = KeyPermission::MANAGE_BLOB.0,
80*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller tries to create a key which implies rebinding
81*e1997b9aSAndroid Build Coastguard Worker /// an alias to the new key.
82*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = rebind)]
83*e1997b9aSAndroid Build Coastguard Worker Rebind = KeyPermission::REBIND.0,
84*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller attempts to create a forced operation.
85*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = req_forced_op)]
86*e1997b9aSAndroid Build Coastguard Worker ReqForcedOp = KeyPermission::REQ_FORCED_OP.0,
87*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller attempts to update public key artifacts.
88*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = update)]
89*e1997b9aSAndroid Build Coastguard Worker Update = KeyPermission::UPDATE.0,
90*e1997b9aSAndroid Build Coastguard Worker /// Checked when the caller attempts to use a private or public key.
91*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = use)]
92*e1997b9aSAndroid Build Coastguard Worker Use = KeyPermission::USE.0,
93*e1997b9aSAndroid Build Coastguard Worker /// Does nothing, and is not checked. For use of device identifiers,
94*e1997b9aSAndroid Build Coastguard Worker /// the caller must hold the READ_PRIVILEGED_PHONE_STATE Android
95*e1997b9aSAndroid Build Coastguard Worker /// permission.
96*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = use_dev_id)]
97*e1997b9aSAndroid Build Coastguard Worker UseDevId = KeyPermission::USE_DEV_ID.0,
98*e1997b9aSAndroid Build Coastguard Worker }
99*e1997b9aSAndroid Build Coastguard Worker );
100*e1997b9aSAndroid Build Coastguard Worker
101*e1997b9aSAndroid Build Coastguard Worker implement_class!(
102*e1997b9aSAndroid Build Coastguard Worker /// KeystorePerm provides a convenient abstraction from the SELinux class `keystore2`.
103*e1997b9aSAndroid Build Coastguard Worker /// Using the implement_permission macro we get the same features as `KeyPerm`.
104*e1997b9aSAndroid Build Coastguard Worker #[selinux(class_name = keystore2)]
105*e1997b9aSAndroid Build Coastguard Worker #[derive(Clone, Copy, Debug, PartialEq, Eq)]
106*e1997b9aSAndroid Build Coastguard Worker pub enum KeystorePerm {
107*e1997b9aSAndroid Build Coastguard Worker /// Checked when a new auth token is installed.
108*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = add_auth)]
109*e1997b9aSAndroid Build Coastguard Worker AddAuth,
110*e1997b9aSAndroid Build Coastguard Worker /// Checked when an app is uninstalled or wiped.
111*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = clear_ns)]
112*e1997b9aSAndroid Build Coastguard Worker ClearNs,
113*e1997b9aSAndroid Build Coastguard Worker /// Checked when Keystore 2.0 is asked to list a namespace that the caller
114*e1997b9aSAndroid Build Coastguard Worker /// does not have the get_info permission for.
115*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = list)]
116*e1997b9aSAndroid Build Coastguard Worker List,
117*e1997b9aSAndroid Build Coastguard Worker /// Checked when Keystore 2.0 gets locked.
118*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = lock)]
119*e1997b9aSAndroid Build Coastguard Worker Lock,
120*e1997b9aSAndroid Build Coastguard Worker /// Checked when Keystore 2.0 shall be reset.
121*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = reset)]
122*e1997b9aSAndroid Build Coastguard Worker Reset,
123*e1997b9aSAndroid Build Coastguard Worker /// Checked when Keystore 2.0 shall be unlocked.
124*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = unlock)]
125*e1997b9aSAndroid Build Coastguard Worker Unlock,
126*e1997b9aSAndroid Build Coastguard Worker /// Checked when user is added or removed.
127*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = change_user)]
128*e1997b9aSAndroid Build Coastguard Worker ChangeUser,
129*e1997b9aSAndroid Build Coastguard Worker /// Checked when password of the user is changed.
130*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = change_password)]
131*e1997b9aSAndroid Build Coastguard Worker ChangePassword,
132*e1997b9aSAndroid Build Coastguard Worker /// Checked when a UID is cleared.
133*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = clear_uid)]
134*e1997b9aSAndroid Build Coastguard Worker ClearUID,
135*e1997b9aSAndroid Build Coastguard Worker /// Checked when Credstore calls IKeystoreAuthorization to obtain auth tokens.
136*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = get_auth_token)]
137*e1997b9aSAndroid Build Coastguard Worker GetAuthToken,
138*e1997b9aSAndroid Build Coastguard Worker /// Checked when earlyBootEnded() is called.
139*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = early_boot_ended)]
140*e1997b9aSAndroid Build Coastguard Worker EarlyBootEnded,
141*e1997b9aSAndroid Build Coastguard Worker /// Checked when IKeystoreMetrics::pullMetrics is called.
142*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = pull_metrics)]
143*e1997b9aSAndroid Build Coastguard Worker PullMetrics,
144*e1997b9aSAndroid Build Coastguard Worker /// Checked when IKeystoreMaintenance::deleteAllKeys is called.
145*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = delete_all_keys)]
146*e1997b9aSAndroid Build Coastguard Worker DeleteAllKeys,
147*e1997b9aSAndroid Build Coastguard Worker /// Checked on calls to IRemotelyProvisionedKeyPool::getAttestationKey
148*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = get_attestation_key)]
149*e1997b9aSAndroid Build Coastguard Worker GetAttestationKey,
150*e1997b9aSAndroid Build Coastguard Worker /// Checked on IKeystoreAuthorization::getLastAuthTime() is called.
151*e1997b9aSAndroid Build Coastguard Worker #[selinux(name = get_last_auth_time)]
152*e1997b9aSAndroid Build Coastguard Worker GetLastAuthTime,
153*e1997b9aSAndroid Build Coastguard Worker }
154*e1997b9aSAndroid Build Coastguard Worker );
155*e1997b9aSAndroid Build Coastguard Worker
156*e1997b9aSAndroid Build Coastguard Worker /// Represents a set of `KeyPerm` permissions.
157*e1997b9aSAndroid Build Coastguard Worker /// `IntoIterator` is implemented for this struct allowing the iteration through all the
158*e1997b9aSAndroid Build Coastguard Worker /// permissions in the set.
159*e1997b9aSAndroid Build Coastguard Worker /// It also implements a function `includes(self, other)` that checks if the permissions
160*e1997b9aSAndroid Build Coastguard Worker /// in `other` are included in `self`.
161*e1997b9aSAndroid Build Coastguard Worker ///
162*e1997b9aSAndroid Build Coastguard Worker /// KeyPermSet can be created with the macro `key_perm_set![]`.
163*e1997b9aSAndroid Build Coastguard Worker ///
164*e1997b9aSAndroid Build Coastguard Worker /// ## Example
165*e1997b9aSAndroid Build Coastguard Worker /// ```
166*e1997b9aSAndroid Build Coastguard Worker /// let perms1 = key_perm_set![KeyPerm::Use, KeyPerm::ManageBlob, KeyPerm::Grant];
167*e1997b9aSAndroid Build Coastguard Worker /// let perms2 = key_perm_set![KeyPerm::Use, KeyPerm::ManageBlob];
168*e1997b9aSAndroid Build Coastguard Worker ///
169*e1997b9aSAndroid Build Coastguard Worker /// assert!(perms1.includes(perms2))
170*e1997b9aSAndroid Build Coastguard Worker /// assert!(!perms2.includes(perms1))
171*e1997b9aSAndroid Build Coastguard Worker ///
172*e1997b9aSAndroid Build Coastguard Worker /// let i = perms1.into_iter();
173*e1997b9aSAndroid Build Coastguard Worker /// // iteration in ascending order of the permission's numeric representation.
174*e1997b9aSAndroid Build Coastguard Worker /// assert_eq(Some(KeyPerm::ManageBlob), i.next());
175*e1997b9aSAndroid Build Coastguard Worker /// assert_eq(Some(KeyPerm::Grant), i.next());
176*e1997b9aSAndroid Build Coastguard Worker /// assert_eq(Some(KeyPerm::Use), i.next());
177*e1997b9aSAndroid Build Coastguard Worker /// assert_eq(None, i.next());
178*e1997b9aSAndroid Build Coastguard Worker /// ```
179*e1997b9aSAndroid Build Coastguard Worker #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)]
180*e1997b9aSAndroid Build Coastguard Worker pub struct KeyPermSet(pub i32);
181*e1997b9aSAndroid Build Coastguard Worker
182*e1997b9aSAndroid Build Coastguard Worker mod perm {
183*e1997b9aSAndroid Build Coastguard Worker use super::*;
184*e1997b9aSAndroid Build Coastguard Worker
185*e1997b9aSAndroid Build Coastguard Worker pub struct IntoIter {
186*e1997b9aSAndroid Build Coastguard Worker vec: KeyPermSet,
187*e1997b9aSAndroid Build Coastguard Worker pos: u8,
188*e1997b9aSAndroid Build Coastguard Worker }
189*e1997b9aSAndroid Build Coastguard Worker
190*e1997b9aSAndroid Build Coastguard Worker impl IntoIter {
new(v: KeyPermSet) -> Self191*e1997b9aSAndroid Build Coastguard Worker pub fn new(v: KeyPermSet) -> Self {
192*e1997b9aSAndroid Build Coastguard Worker Self { vec: v, pos: 0 }
193*e1997b9aSAndroid Build Coastguard Worker }
194*e1997b9aSAndroid Build Coastguard Worker }
195*e1997b9aSAndroid Build Coastguard Worker
196*e1997b9aSAndroid Build Coastguard Worker impl std::iter::Iterator for IntoIter {
197*e1997b9aSAndroid Build Coastguard Worker type Item = KeyPerm;
198*e1997b9aSAndroid Build Coastguard Worker
next(&mut self) -> Option<Self::Item>199*e1997b9aSAndroid Build Coastguard Worker fn next(&mut self) -> Option<Self::Item> {
200*e1997b9aSAndroid Build Coastguard Worker loop {
201*e1997b9aSAndroid Build Coastguard Worker if self.pos == 32 {
202*e1997b9aSAndroid Build Coastguard Worker return None;
203*e1997b9aSAndroid Build Coastguard Worker }
204*e1997b9aSAndroid Build Coastguard Worker let p = self.vec.0 & (1 << self.pos);
205*e1997b9aSAndroid Build Coastguard Worker self.pos += 1;
206*e1997b9aSAndroid Build Coastguard Worker if p != 0 {
207*e1997b9aSAndroid Build Coastguard Worker return Some(KeyPerm::from(p));
208*e1997b9aSAndroid Build Coastguard Worker }
209*e1997b9aSAndroid Build Coastguard Worker }
210*e1997b9aSAndroid Build Coastguard Worker }
211*e1997b9aSAndroid Build Coastguard Worker }
212*e1997b9aSAndroid Build Coastguard Worker }
213*e1997b9aSAndroid Build Coastguard Worker
214*e1997b9aSAndroid Build Coastguard Worker impl From<KeyPerm> for KeyPermSet {
from(p: KeyPerm) -> Self215*e1997b9aSAndroid Build Coastguard Worker fn from(p: KeyPerm) -> Self {
216*e1997b9aSAndroid Build Coastguard Worker Self(p as i32)
217*e1997b9aSAndroid Build Coastguard Worker }
218*e1997b9aSAndroid Build Coastguard Worker }
219*e1997b9aSAndroid Build Coastguard Worker
220*e1997b9aSAndroid Build Coastguard Worker /// allow conversion from the AIDL wire type i32 to a permission set.
221*e1997b9aSAndroid Build Coastguard Worker impl From<i32> for KeyPermSet {
from(p: i32) -> Self222*e1997b9aSAndroid Build Coastguard Worker fn from(p: i32) -> Self {
223*e1997b9aSAndroid Build Coastguard Worker Self(p)
224*e1997b9aSAndroid Build Coastguard Worker }
225*e1997b9aSAndroid Build Coastguard Worker }
226*e1997b9aSAndroid Build Coastguard Worker
227*e1997b9aSAndroid Build Coastguard Worker impl From<KeyPermSet> for i32 {
from(p: KeyPermSet) -> i32228*e1997b9aSAndroid Build Coastguard Worker fn from(p: KeyPermSet) -> i32 {
229*e1997b9aSAndroid Build Coastguard Worker p.0
230*e1997b9aSAndroid Build Coastguard Worker }
231*e1997b9aSAndroid Build Coastguard Worker }
232*e1997b9aSAndroid Build Coastguard Worker
233*e1997b9aSAndroid Build Coastguard Worker impl KeyPermSet {
234*e1997b9aSAndroid Build Coastguard Worker /// Returns true iff this permission set has all of the permissions that are in `other`.
includes<T: Into<KeyPermSet>>(&self, other: T) -> bool235*e1997b9aSAndroid Build Coastguard Worker pub fn includes<T: Into<KeyPermSet>>(&self, other: T) -> bool {
236*e1997b9aSAndroid Build Coastguard Worker let o: KeyPermSet = other.into();
237*e1997b9aSAndroid Build Coastguard Worker (self.0 & o.0) == o.0
238*e1997b9aSAndroid Build Coastguard Worker }
239*e1997b9aSAndroid Build Coastguard Worker }
240*e1997b9aSAndroid Build Coastguard Worker
241*e1997b9aSAndroid Build Coastguard Worker /// This macro can be used to create a `KeyPermSet` from a list of `KeyPerm` values.
242*e1997b9aSAndroid Build Coastguard Worker ///
243*e1997b9aSAndroid Build Coastguard Worker /// ## Example
244*e1997b9aSAndroid Build Coastguard Worker /// ```
245*e1997b9aSAndroid Build Coastguard Worker /// let v = key_perm_set![Perm::delete(), Perm::manage_blob()];
246*e1997b9aSAndroid Build Coastguard Worker /// ```
247*e1997b9aSAndroid Build Coastguard Worker #[macro_export]
248*e1997b9aSAndroid Build Coastguard Worker macro_rules! key_perm_set {
249*e1997b9aSAndroid Build Coastguard Worker () => { KeyPermSet(0) };
250*e1997b9aSAndroid Build Coastguard Worker ($head:expr $(, $tail:expr)* $(,)?) => {
251*e1997b9aSAndroid Build Coastguard Worker KeyPermSet($head as i32 $(| $tail as i32)*)
252*e1997b9aSAndroid Build Coastguard Worker };
253*e1997b9aSAndroid Build Coastguard Worker }
254*e1997b9aSAndroid Build Coastguard Worker
255*e1997b9aSAndroid Build Coastguard Worker impl IntoIterator for KeyPermSet {
256*e1997b9aSAndroid Build Coastguard Worker type Item = KeyPerm;
257*e1997b9aSAndroid Build Coastguard Worker type IntoIter = perm::IntoIter;
258*e1997b9aSAndroid Build Coastguard Worker
into_iter(self) -> Self::IntoIter259*e1997b9aSAndroid Build Coastguard Worker fn into_iter(self) -> Self::IntoIter {
260*e1997b9aSAndroid Build Coastguard Worker Self::IntoIter::new(self)
261*e1997b9aSAndroid Build Coastguard Worker }
262*e1997b9aSAndroid Build Coastguard Worker }
263*e1997b9aSAndroid Build Coastguard Worker
264*e1997b9aSAndroid Build Coastguard Worker /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` may access
265*e1997b9aSAndroid Build Coastguard Worker /// the given permision `perm` of the `keystore2` security class.
check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()>266*e1997b9aSAndroid Build Coastguard Worker pub fn check_keystore_permission(caller_ctx: &CStr, perm: KeystorePerm) -> anyhow::Result<()> {
267*e1997b9aSAndroid Build Coastguard Worker let target_context = getcon().context("check_keystore_permission: getcon failed.")?;
268*e1997b9aSAndroid Build Coastguard Worker selinux::check_permission(caller_ctx, &target_context, perm)
269*e1997b9aSAndroid Build Coastguard Worker }
270*e1997b9aSAndroid Build Coastguard Worker
271*e1997b9aSAndroid Build Coastguard Worker /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt` has
272*e1997b9aSAndroid Build Coastguard Worker /// all the permissions indicated in `access_vec` for the target domain indicated by the key
273*e1997b9aSAndroid Build Coastguard Worker /// descriptor `key` in the security class `keystore2_key`.
274*e1997b9aSAndroid Build Coastguard Worker ///
275*e1997b9aSAndroid Build Coastguard Worker /// Also checks if the caller has the grant permission for the given target domain.
276*e1997b9aSAndroid Build Coastguard Worker ///
277*e1997b9aSAndroid Build Coastguard Worker /// Attempts to grant the grant permission are always denied.
278*e1997b9aSAndroid Build Coastguard Worker ///
279*e1997b9aSAndroid Build Coastguard Worker /// The only viable target domains are
280*e1997b9aSAndroid Build Coastguard Worker /// * `Domain::APP` in which case u:r:keystore:s0 is used as target context and
281*e1997b9aSAndroid Build Coastguard Worker /// * `Domain::SELINUX` in which case the `key.nspace` parameter is looked up in
282*e1997b9aSAndroid Build Coastguard Worker /// SELinux keystore key backend, and the result is used
283*e1997b9aSAndroid Build Coastguard Worker /// as target context.
check_grant_permission( caller_uid: u32, caller_ctx: &CStr, access_vec: KeyPermSet, key: &KeyDescriptor, ) -> anyhow::Result<()>284*e1997b9aSAndroid Build Coastguard Worker pub fn check_grant_permission(
285*e1997b9aSAndroid Build Coastguard Worker caller_uid: u32,
286*e1997b9aSAndroid Build Coastguard Worker caller_ctx: &CStr,
287*e1997b9aSAndroid Build Coastguard Worker access_vec: KeyPermSet,
288*e1997b9aSAndroid Build Coastguard Worker key: &KeyDescriptor,
289*e1997b9aSAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
290*e1997b9aSAndroid Build Coastguard Worker let target_context = match key.domain {
291*e1997b9aSAndroid Build Coastguard Worker Domain::APP => {
292*e1997b9aSAndroid Build Coastguard Worker if caller_uid as i64 != key.nspace {
293*e1997b9aSAndroid Build Coastguard Worker return Err(selinux::Error::perm())
294*e1997b9aSAndroid Build Coastguard Worker .context("Trying to access key without ownership.");
295*e1997b9aSAndroid Build Coastguard Worker }
296*e1997b9aSAndroid Build Coastguard Worker getcon().context("check_grant_permission: getcon failed.")?
297*e1997b9aSAndroid Build Coastguard Worker }
298*e1997b9aSAndroid Build Coastguard Worker Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
299*e1997b9aSAndroid Build Coastguard Worker .context("check_grant_permission: Domain::SELINUX: Failed to lookup namespace.")?,
300*e1997b9aSAndroid Build Coastguard Worker _ => return Err(KsError::sys()).context(format!("Cannot grant {:?}.", key.domain)),
301*e1997b9aSAndroid Build Coastguard Worker };
302*e1997b9aSAndroid Build Coastguard Worker
303*e1997b9aSAndroid Build Coastguard Worker selinux::check_permission(caller_ctx, &target_context, KeyPerm::Grant)
304*e1997b9aSAndroid Build Coastguard Worker .context("Grant permission is required when granting.")?;
305*e1997b9aSAndroid Build Coastguard Worker
306*e1997b9aSAndroid Build Coastguard Worker if access_vec.includes(KeyPerm::Grant) {
307*e1997b9aSAndroid Build Coastguard Worker return Err(selinux::Error::perm()).context("Grant permission cannot be granted.");
308*e1997b9aSAndroid Build Coastguard Worker }
309*e1997b9aSAndroid Build Coastguard Worker
310*e1997b9aSAndroid Build Coastguard Worker for p in access_vec.into_iter() {
311*e1997b9aSAndroid Build Coastguard Worker selinux::check_permission(caller_ctx, &target_context, p).context(ks_err!(
312*e1997b9aSAndroid Build Coastguard Worker "check_permission failed. \
313*e1997b9aSAndroid Build Coastguard Worker The caller may have tried to grant a permission that they don't possess. {:?}",
314*e1997b9aSAndroid Build Coastguard Worker p
315*e1997b9aSAndroid Build Coastguard Worker ))?
316*e1997b9aSAndroid Build Coastguard Worker }
317*e1997b9aSAndroid Build Coastguard Worker Ok(())
318*e1997b9aSAndroid Build Coastguard Worker }
319*e1997b9aSAndroid Build Coastguard Worker
320*e1997b9aSAndroid Build Coastguard Worker /// Uses `selinux::check_permission` to check if the given caller context `caller_cxt`
321*e1997b9aSAndroid Build Coastguard Worker /// has the permissions indicated by `perm` for the target domain indicated by the key
322*e1997b9aSAndroid Build Coastguard Worker /// descriptor `key` in the security class `keystore2_key`.
323*e1997b9aSAndroid Build Coastguard Worker ///
324*e1997b9aSAndroid Build Coastguard Worker /// The behavior differs slightly depending on the selected target domain:
325*e1997b9aSAndroid Build Coastguard Worker /// * `Domain::APP` u:r:keystore:s0 is used as target context.
326*e1997b9aSAndroid Build Coastguard Worker /// * `Domain::SELINUX` `key.nspace` parameter is looked up in the SELinux keystore key
327*e1997b9aSAndroid Build Coastguard Worker /// backend, and the result is used as target context.
328*e1997b9aSAndroid Build Coastguard Worker /// * `Domain::BLOB` Same as SELinux but the "manage_blob" permission is always checked additionally
329*e1997b9aSAndroid Build Coastguard Worker /// to the one supplied in `perm`.
330*e1997b9aSAndroid Build Coastguard Worker /// * `Domain::GRANT` Does not use selinux::check_permission. Instead the `access_vector`
331*e1997b9aSAndroid Build Coastguard Worker /// parameter is queried for permission, which must be supplied in this case.
332*e1997b9aSAndroid Build Coastguard Worker ///
333*e1997b9aSAndroid Build Coastguard Worker /// ## Return values.
334*e1997b9aSAndroid Build Coastguard Worker /// * Ok(()) If the requested permissions were granted.
335*e1997b9aSAndroid Build Coastguard Worker /// * Err(selinux::Error::perm()) If the requested permissions were denied.
336*e1997b9aSAndroid Build Coastguard Worker /// * Err(KsError::sys()) This error is produced if `Domain::GRANT` is selected but no `access_vec`
337*e1997b9aSAndroid Build Coastguard Worker /// was supplied. It is also produced if `Domain::KEY_ID` was selected, and
338*e1997b9aSAndroid Build Coastguard Worker /// on various unexpected backend failures.
check_key_permission( caller_uid: u32, caller_ctx: &CStr, perm: KeyPerm, key: &KeyDescriptor, access_vector: &Option<KeyPermSet>, ) -> anyhow::Result<()>339*e1997b9aSAndroid Build Coastguard Worker pub fn check_key_permission(
340*e1997b9aSAndroid Build Coastguard Worker caller_uid: u32,
341*e1997b9aSAndroid Build Coastguard Worker caller_ctx: &CStr,
342*e1997b9aSAndroid Build Coastguard Worker perm: KeyPerm,
343*e1997b9aSAndroid Build Coastguard Worker key: &KeyDescriptor,
344*e1997b9aSAndroid Build Coastguard Worker access_vector: &Option<KeyPermSet>,
345*e1997b9aSAndroid Build Coastguard Worker ) -> anyhow::Result<()> {
346*e1997b9aSAndroid Build Coastguard Worker // If an access vector was supplied, the key is either accessed by GRANT or by KEY_ID.
347*e1997b9aSAndroid Build Coastguard Worker // In the former case, key.domain was set to GRANT and we check the failure cases
348*e1997b9aSAndroid Build Coastguard Worker // further below. If the access is requested by KEY_ID, key.domain would have been
349*e1997b9aSAndroid Build Coastguard Worker // resolved to APP or SELINUX depending on where the key actually resides.
350*e1997b9aSAndroid Build Coastguard Worker // Either way we can return here immediately if the access vector covers the requested
351*e1997b9aSAndroid Build Coastguard Worker // permission. If it does not, we can still check if the caller has access by means of
352*e1997b9aSAndroid Build Coastguard Worker // ownership.
353*e1997b9aSAndroid Build Coastguard Worker if let Some(access_vector) = access_vector {
354*e1997b9aSAndroid Build Coastguard Worker if access_vector.includes(perm) {
355*e1997b9aSAndroid Build Coastguard Worker return Ok(());
356*e1997b9aSAndroid Build Coastguard Worker }
357*e1997b9aSAndroid Build Coastguard Worker }
358*e1997b9aSAndroid Build Coastguard Worker
359*e1997b9aSAndroid Build Coastguard Worker let target_context = match key.domain {
360*e1997b9aSAndroid Build Coastguard Worker // apps get the default keystore context
361*e1997b9aSAndroid Build Coastguard Worker Domain::APP => {
362*e1997b9aSAndroid Build Coastguard Worker if caller_uid as i64 != key.nspace {
363*e1997b9aSAndroid Build Coastguard Worker return Err(selinux::Error::perm())
364*e1997b9aSAndroid Build Coastguard Worker .context("Trying to access key without ownership.");
365*e1997b9aSAndroid Build Coastguard Worker }
366*e1997b9aSAndroid Build Coastguard Worker getcon().context(ks_err!("getcon failed."))?
367*e1997b9aSAndroid Build Coastguard Worker }
368*e1997b9aSAndroid Build Coastguard Worker Domain::SELINUX => lookup_keystore2_key_context(key.nspace)
369*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Domain::SELINUX: Failed to lookup namespace."))?,
370*e1997b9aSAndroid Build Coastguard Worker Domain::GRANT => {
371*e1997b9aSAndroid Build Coastguard Worker match access_vector {
372*e1997b9aSAndroid Build Coastguard Worker Some(_) => {
373*e1997b9aSAndroid Build Coastguard Worker return Err(selinux::Error::perm())
374*e1997b9aSAndroid Build Coastguard Worker .context(format!("\"{}\" not granted", perm.name()));
375*e1997b9aSAndroid Build Coastguard Worker }
376*e1997b9aSAndroid Build Coastguard Worker None => {
377*e1997b9aSAndroid Build Coastguard Worker // If DOMAIN_GRANT was selected an access vector must be supplied.
378*e1997b9aSAndroid Build Coastguard Worker return Err(KsError::sys()).context(ks_err!(
379*e1997b9aSAndroid Build Coastguard Worker "Cannot check permission for Domain::GRANT without access vector.",
380*e1997b9aSAndroid Build Coastguard Worker ));
381*e1997b9aSAndroid Build Coastguard Worker }
382*e1997b9aSAndroid Build Coastguard Worker }
383*e1997b9aSAndroid Build Coastguard Worker }
384*e1997b9aSAndroid Build Coastguard Worker Domain::KEY_ID => {
385*e1997b9aSAndroid Build Coastguard Worker // We should never be called with `Domain::KEY_ID. The database
386*e1997b9aSAndroid Build Coastguard Worker // lookup should have converted this into one of `Domain::APP`
387*e1997b9aSAndroid Build Coastguard Worker // or `Domain::SELINUX`.
388*e1997b9aSAndroid Build Coastguard Worker return Err(KsError::sys())
389*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Cannot check permission for Domain::KEY_ID.",));
390*e1997b9aSAndroid Build Coastguard Worker }
391*e1997b9aSAndroid Build Coastguard Worker Domain::BLOB => {
392*e1997b9aSAndroid Build Coastguard Worker let tctx = lookup_keystore2_key_context(key.nspace)
393*e1997b9aSAndroid Build Coastguard Worker .context(ks_err!("Domain::BLOB: Failed to lookup namespace."))?;
394*e1997b9aSAndroid Build Coastguard Worker // If DOMAIN_KEY_BLOB was specified, we check for the "manage_blob"
395*e1997b9aSAndroid Build Coastguard Worker // permission in addition to the requested permission.
396*e1997b9aSAndroid Build Coastguard Worker selinux::check_permission(caller_ctx, &tctx, KeyPerm::ManageBlob)?;
397*e1997b9aSAndroid Build Coastguard Worker
398*e1997b9aSAndroid Build Coastguard Worker tctx
399*e1997b9aSAndroid Build Coastguard Worker }
400*e1997b9aSAndroid Build Coastguard Worker _ => {
401*e1997b9aSAndroid Build Coastguard Worker return Err(KsError::Rc(ResponseCode::INVALID_ARGUMENT))
402*e1997b9aSAndroid Build Coastguard Worker .context(format!("Unknown domain value: \"{:?}\".", key.domain))
403*e1997b9aSAndroid Build Coastguard Worker }
404*e1997b9aSAndroid Build Coastguard Worker };
405*e1997b9aSAndroid Build Coastguard Worker
406*e1997b9aSAndroid Build Coastguard Worker selinux::check_permission(caller_ctx, &target_context, perm)
407*e1997b9aSAndroid Build Coastguard Worker }
408