Diced: Add selinux permission checks.

Add permission checks to IDiceNode entry points.

Test: N/A
Bug: 198197213
Change-Id: I3118515f42c160e2c52a478ee4adefa81e2fe80c
diff --git a/diced/src/lib.rs b/diced/src/lib.rs
index ac9484a..462d2aa 100644
--- a/diced/src/lib.rs
+++ b/diced/src/lib.rs
@@ -15,6 +15,7 @@
 //! Implement the android.security.dice.IDiceNode service.
 
 mod error;
+mod permission;
 mod resident_node;
 
 pub use crate::resident_node::ResidentNode;
@@ -29,7 +30,9 @@
 use binder::{public_api::Result as BinderResult, BinderFeatures, Strong, ThreadState};
 pub use diced_open_dice_cbor as dice;
 use error::{map_or_log_err, Error};
+use keystore2_selinux as selinux;
 use libc::uid_t;
+use permission::Permission;
 use std::sync::Arc;
 
 /// A DiceNode backend implementation.
@@ -72,6 +75,24 @@
     node_impl: Arc<dyn DiceNodeImpl + Sync + Send>,
 }
 
+/// This function uses its namesake in the permission module and in
+/// combination with with_calling_sid from the binder crate to check
+/// if the caller has the given keystore permission.
+pub fn check_caller_permission<T: selinux::ClassPermission>(perm: T) -> Result<()> {
+    ThreadState::with_calling_sid(|calling_sid| {
+        let target_context =
+            selinux::getcon().context("In check_caller_permission: getcon failed.")?;
+
+        selinux::check_permission(
+            calling_sid.ok_or(Error::Rc(ResponseCode::SYSTEM_ERROR)).context(
+                "In check_keystore_permission: Cannot check permission without calling_sid.",
+            )?,
+            &target_context,
+            perm,
+        )
+    })
+}
+
 fn client_input_values(uid: uid_t) -> Result<BinderInputValues> {
     Ok(BinderInputValues {
         codeHash: vec![0; dice::HASH_SIZE],
@@ -101,21 +122,26 @@
     }
 
     fn sign(&self, input_values: &[BinderInputValues], message: &[u8]) -> Result<Signature> {
+        check_caller_permission(Permission::UseSign).context("In DiceNode::sign:")?;
         let client =
             client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::sign:")?;
         self.node_impl.sign(client, input_values, message)
     }
     fn get_attestation_chain(&self, input_values: &[BinderInputValues]) -> Result<Bcc> {
+        check_caller_permission(Permission::GetAttestationChain)
+            .context("In DiceNode::get_attestation_chain:")?;
         let client = client_input_values(ThreadState::get_calling_uid())
             .context("In DiceNode::get_attestation_chain:")?;
         self.node_impl.get_attestation_chain(client, input_values)
     }
     fn derive(&self, input_values: &[BinderInputValues]) -> Result<BccHandover> {
+        check_caller_permission(Permission::Derive).context("In DiceNode::derive:")?;
         let client =
             client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::extend:")?;
         self.node_impl.derive(client, input_values)
     }
     fn demote(&self, input_values: &[BinderInputValues]) -> Result<()> {
+        check_caller_permission(Permission::Demote).context("In DiceNode::demote:")?;
         let client =
             client_input_values(ThreadState::get_calling_uid()).context("In DiceNode::demote:")?;
         self.node_impl.demote(client, input_values)
diff --git a/diced/src/permission.rs b/diced/src/permission.rs
new file mode 100644
index 0000000..116df1b
--- /dev/null
+++ b/diced/src/permission.rs
@@ -0,0 +1,46 @@
+// Copyright 2021, The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//     http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+//! This crate provides convenience wrappers for the SELinux permission
+//! defined in the diced SELinux access class.
+
+use keystore2_selinux as selinux;
+use selinux::{implement_class, ClassPermission};
+
+implement_class!(
+    /// Permission provides a convenient abstraction from the SELinux class `diced`.
+    #[selinux(class_name = diced)]
+    #[derive(Clone, Copy, Debug, PartialEq)]
+    pub enum Permission {
+        /// Checked when a client attempts to call seal or unseal.
+        #[selinux(name = use_seal)]
+        UseSeal,
+        /// Checked when a client attempts to call IDiceNode::sign.
+        #[selinux(name = use_sign)]
+        UseSign,
+        /// Checked when a client attempts to call IDiceNode::getAttestationChain.
+        #[selinux(name = get_attestation_chain)]
+        GetAttestationChain,
+        /// Checked when a client attempts to call IDiceNode::derive.
+        #[selinux(name = derive)]
+        Derive,
+        /// Checked when a client wants to demote itself by calling IDiceNode::demote.
+        #[selinux(name = demote)]
+        Demote,
+        /// Checked when a client calls IDiceMaintenance::demote in an attempt to
+        /// demote this dice node.
+        #[selinux(name = demote_self)]
+        DemoteSelf,
+    }
+);