Remove the DICE service from microdroid
The DICE logic is provided by microdroid_maanger so remove the legacy DICE service from microdroid. Bug: 243133253 Test: atest MicrodroidTests Test: atest ComposHostTestCases Change-Id: Ibc1a074b4c6f26b56e8723d135f7e862c6fd5203
This commit is contained in:
parent
e4b0285491
commit
3b80c9b14b
|
@ -70,7 +70,6 @@ android_system_image {
|
||||||
"apexd",
|
"apexd",
|
||||||
"atrace",
|
"atrace",
|
||||||
"debuggerd",
|
"debuggerd",
|
||||||
"dice-service.microdroid",
|
|
||||||
"linker",
|
"linker",
|
||||||
"linkerconfig",
|
"linkerconfig",
|
||||||
"servicemanager.microdroid",
|
"servicemanager.microdroid",
|
||||||
|
@ -80,7 +79,6 @@ android_system_image {
|
||||||
"task_profiles.json",
|
"task_profiles.json",
|
||||||
"public.libraries.android.txt",
|
"public.libraries.android.txt",
|
||||||
|
|
||||||
"microdroid_compatibility_matrix",
|
|
||||||
"microdroid_event-log-tags",
|
"microdroid_event-log-tags",
|
||||||
"microdroid_file_contexts",
|
"microdroid_file_contexts",
|
||||||
"microdroid_manifest",
|
"microdroid_manifest",
|
||||||
|
@ -532,14 +530,6 @@ prebuilt_etc {
|
||||||
installable: false,
|
installable: false,
|
||||||
}
|
}
|
||||||
|
|
||||||
prebuilt_etc {
|
|
||||||
name: "microdroid_compatibility_matrix",
|
|
||||||
src: "microdroid_compatibility_matrix.xml",
|
|
||||||
filename: "compatibility_matrix.current.xml",
|
|
||||||
relative_install_path: "vintf",
|
|
||||||
installable: false,
|
|
||||||
}
|
|
||||||
|
|
||||||
prebuilt_etc {
|
prebuilt_etc {
|
||||||
name: "microdroid_manifest",
|
name: "microdroid_manifest",
|
||||||
src: "microdroid_manifest.xml",
|
src: "microdroid_manifest.xml",
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
package {
|
|
||||||
default_applicable_licenses: ["Android-Apache-2.0"],
|
|
||||||
}
|
|
||||||
|
|
||||||
rust_binary {
|
|
||||||
name: "dice-service.microdroid",
|
|
||||||
srcs: ["service.rs"],
|
|
||||||
prefer_rlib: true,
|
|
||||||
rustlibs: [
|
|
||||||
"android.hardware.security.dice-V1-rust",
|
|
||||||
"android.security.dice-rust",
|
|
||||||
"libandroid_logger",
|
|
||||||
"libanyhow",
|
|
||||||
"libbinder_rs",
|
|
||||||
"libbyteorder",
|
|
||||||
"libdiced",
|
|
||||||
"libdiced_open_dice_cbor",
|
|
||||||
"libdiced_sample_inputs",
|
|
||||||
"libdiced_utils",
|
|
||||||
"liblibc",
|
|
||||||
"liblog_rust",
|
|
||||||
"libserde",
|
|
||||||
],
|
|
||||||
init_rc: ["dice-service.microdroid.rc"],
|
|
||||||
bootstrap: true,
|
|
||||||
}
|
|
|
@ -1,3 +0,0 @@
|
||||||
service dice-microdroid /system/bin/dice-service.microdroid
|
|
||||||
user diced
|
|
||||||
group diced
|
|
|
@ -1,303 +0,0 @@
|
||||||
// Copyright 2022, 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.
|
|
||||||
|
|
||||||
//! Main entry point for the microdroid DICE service implementation.
|
|
||||||
|
|
||||||
use android_hardware_security_dice::aidl::android::hardware::security::dice::{
|
|
||||||
Bcc::Bcc, BccHandover::BccHandover, InputValues::InputValues as BinderInputValues,
|
|
||||||
Signature::Signature,
|
|
||||||
};
|
|
||||||
use anyhow::{bail, ensure, Context, Error, Result};
|
|
||||||
use byteorder::{NativeEndian, ReadBytesExt};
|
|
||||||
use dice::{ContextImpl, OpenDiceCborContext};
|
|
||||||
use diced::{dice, DiceMaintenance, DiceNode, DiceNodeImpl};
|
|
||||||
use diced_utils::make_bcc_handover;
|
|
||||||
use libc::{c_void, mmap, munmap, MAP_FAILED, MAP_PRIVATE, PROT_READ};
|
|
||||||
use serde::{Deserialize, Serialize};
|
|
||||||
use std::fs;
|
|
||||||
use std::os::unix::io::AsRawFd;
|
|
||||||
use std::panic;
|
|
||||||
use std::path::{Path, PathBuf};
|
|
||||||
use std::ptr::null_mut;
|
|
||||||
use std::slice;
|
|
||||||
use std::sync::{Arc, RwLock};
|
|
||||||
|
|
||||||
const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
|
|
||||||
const DICE_NODE_SERVICE_NAME: &str = "android.security.dice.IDiceNode";
|
|
||||||
const DICE_MAINTENANCE_SERVICE_NAME: &str = "android.security.dice.IDiceMaintenance";
|
|
||||||
|
|
||||||
/// Artifacts that are mapped into the process address space from the driver.
|
|
||||||
struct MappedDriverArtifacts<'a> {
|
|
||||||
mmap_addr: *mut c_void,
|
|
||||||
mmap_size: usize,
|
|
||||||
cdi_attest: &'a [u8; dice::CDI_SIZE],
|
|
||||||
cdi_seal: &'a [u8; dice::CDI_SIZE],
|
|
||||||
bcc: &'a [u8],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MappedDriverArtifacts<'_> {
|
|
||||||
fn new(driver_path: &Path) -> Result<Self> {
|
|
||||||
let mut file = fs::File::open(driver_path)
|
|
||||||
.map_err(|error| Error::new(error).context("Opening driver"))?;
|
|
||||||
let mmap_size =
|
|
||||||
file.read_u64::<NativeEndian>()
|
|
||||||
.map_err(|error| Error::new(error).context("Reading driver"))? as usize;
|
|
||||||
// It's safe to map the driver as the service will only create a single
|
|
||||||
// mapping per process.
|
|
||||||
let mmap_addr = unsafe {
|
|
||||||
let fd = file.as_raw_fd();
|
|
||||||
mmap(null_mut(), mmap_size, PROT_READ, MAP_PRIVATE, fd, 0)
|
|
||||||
};
|
|
||||||
if mmap_addr == MAP_FAILED {
|
|
||||||
bail!("Failed to mmap {:?}", driver_path);
|
|
||||||
}
|
|
||||||
// The slice is created for the region of memory that was just
|
|
||||||
// successfully mapped into the process address space so it will be
|
|
||||||
// accessible and not referenced from anywhere else.
|
|
||||||
let mmap_buf =
|
|
||||||
unsafe { slice::from_raw_parts((mmap_addr as *const u8).as_ref().unwrap(), mmap_size) };
|
|
||||||
// Very inflexible parsing / validation of the BccHandover data. Assumes deterministically
|
|
||||||
// encoded CBOR.
|
|
||||||
//
|
|
||||||
// BccHandover = {
|
|
||||||
// 1 : bstr .size 32, ; CDI_Attest
|
|
||||||
// 2 : bstr .size 32, ; CDI_Seal
|
|
||||||
// 3 : Bcc, ; Certificate chain
|
|
||||||
// }
|
|
||||||
if mmap_buf[0..4] != [0xa3, 0x01, 0x58, 0x20]
|
|
||||||
|| mmap_buf[36..39] != [0x02, 0x58, 0x20]
|
|
||||||
|| mmap_buf[71] != 0x03
|
|
||||||
{
|
|
||||||
bail!("BccHandover format mismatch");
|
|
||||||
}
|
|
||||||
Ok(Self {
|
|
||||||
mmap_addr,
|
|
||||||
mmap_size,
|
|
||||||
cdi_attest: mmap_buf[4..36].try_into().unwrap(),
|
|
||||||
cdi_seal: mmap_buf[39..71].try_into().unwrap(),
|
|
||||||
bcc: &mmap_buf[72..],
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Drop for MappedDriverArtifacts<'_> {
|
|
||||||
fn drop(&mut self) {
|
|
||||||
// All references to the mapped region have the same lifetime as self.
|
|
||||||
// Since self is being dropped, so are all the references to the mapped
|
|
||||||
// region meaning its safe to unmap.
|
|
||||||
let ret = unsafe { munmap(self.mmap_addr, self.mmap_size) };
|
|
||||||
if ret != 0 {
|
|
||||||
log::warn!("Failed to munmap ({})", ret);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Artifacts that are kept in the process address space after the artifacts
|
|
||||||
/// from the driver have been consumed.
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
struct RawArtifacts {
|
|
||||||
cdi_attest: [u8; dice::CDI_SIZE],
|
|
||||||
cdi_seal: [u8; dice::CDI_SIZE],
|
|
||||||
bcc: Vec<u8>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Clone, Serialize, Deserialize)]
|
|
||||||
enum UpdatableArtifacts {
|
|
||||||
Invalid,
|
|
||||||
Driver(PathBuf),
|
|
||||||
Updated(RawArtifacts),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl UpdatableArtifacts {
|
|
||||||
fn get(
|
|
||||||
&self,
|
|
||||||
input_values: &BinderInputValues,
|
|
||||||
) -> Result<(dice::CdiAttest, dice::CdiSeal, Vec<u8>)> {
|
|
||||||
let input_values: diced_utils::InputValues = input_values.into();
|
|
||||||
match self {
|
|
||||||
Self::Invalid => bail!("No DICE artifacts available."),
|
|
||||||
Self::Driver(driver_path) => {
|
|
||||||
let artifacts = MappedDriverArtifacts::new(driver_path.as_path())?;
|
|
||||||
dice::OpenDiceCborContext::new().bcc_main_flow(
|
|
||||||
artifacts.cdi_attest,
|
|
||||||
artifacts.cdi_seal,
|
|
||||||
artifacts.bcc,
|
|
||||||
&input_values,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
Self::Updated(artifacts) => dice::OpenDiceCborContext::new().bcc_main_flow(
|
|
||||||
&artifacts.cdi_attest,
|
|
||||||
&artifacts.cdi_seal,
|
|
||||||
&artifacts.bcc,
|
|
||||||
&input_values,
|
|
||||||
),
|
|
||||||
}
|
|
||||||
.context("Deriving artifacts")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn update(self, inputs: &BinderInputValues) -> Result<Self> {
|
|
||||||
if let Self::Invalid = self {
|
|
||||||
bail!("Cannot update invalid DICE artifacts.");
|
|
||||||
}
|
|
||||||
let (cdi_attest, cdi_seal, bcc) =
|
|
||||||
self.get(inputs).context("Failed to get update artifacts.")?;
|
|
||||||
if let Self::Driver(ref driver_path) = self {
|
|
||||||
// Writing to the device wipes the artifacts. The string is ignored
|
|
||||||
// by the driver but included for documentation.
|
|
||||||
fs::write(driver_path, "wipe")
|
|
||||||
.map_err(|error| Error::new(error).context("Wiping driver"))?;
|
|
||||||
}
|
|
||||||
Ok(Self::Updated(RawArtifacts {
|
|
||||||
cdi_attest: cdi_attest[..].try_into().unwrap(),
|
|
||||||
cdi_seal: cdi_seal[..].try_into().unwrap(),
|
|
||||||
bcc,
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct ArtifactManager {
|
|
||||||
artifacts: RwLock<UpdatableArtifacts>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ArtifactManager {
|
|
||||||
fn new(driver_path: &Path) -> Self {
|
|
||||||
Self {
|
|
||||||
artifacts: RwLock::new(if driver_path.exists() {
|
|
||||||
log::info!("Using DICE values from driver");
|
|
||||||
UpdatableArtifacts::Driver(driver_path.to_path_buf())
|
|
||||||
} else if Path::new(AVF_STRICT_BOOT).exists() {
|
|
||||||
log::error!("Strict boot requires DICE value from driver but none were found");
|
|
||||||
UpdatableArtifacts::Invalid
|
|
||||||
} else {
|
|
||||||
log::warn!("Using sample DICE values");
|
|
||||||
let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
|
|
||||||
.expect("Failed to create sample dice artifacts.");
|
|
||||||
UpdatableArtifacts::Updated(RawArtifacts {
|
|
||||||
cdi_attest: cdi_attest[..].try_into().unwrap(),
|
|
||||||
cdi_seal: cdi_seal[..].try_into().unwrap(),
|
|
||||||
bcc,
|
|
||||||
})
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DiceNodeImpl for ArtifactManager {
|
|
||||||
fn sign(
|
|
||||||
&self,
|
|
||||||
client: BinderInputValues,
|
|
||||||
input_values: &[BinderInputValues],
|
|
||||||
message: &[u8],
|
|
||||||
) -> Result<Signature> {
|
|
||||||
ensure!(input_values.is_empty(), "Extra input values not supported");
|
|
||||||
let artifacts = self.artifacts.read().unwrap().clone();
|
|
||||||
let (cdi_attest, _, _) =
|
|
||||||
artifacts.get(&client).context("Failed to get signing artifacts.")?;
|
|
||||||
let mut dice = OpenDiceCborContext::new();
|
|
||||||
let seed = dice
|
|
||||||
.derive_cdi_private_key_seed(
|
|
||||||
cdi_attest[..].try_into().context("Failed to convert cdi_attest.")?,
|
|
||||||
)
|
|
||||||
.context("Failed to derive seed from cdi_attest.")?;
|
|
||||||
let (_public_key, private_key) = dice
|
|
||||||
.keypair_from_seed(seed[..].try_into().context("Failed to convert seed.")?)
|
|
||||||
.context("Failed to derive keypair from seed.")?;
|
|
||||||
let signature = dice
|
|
||||||
.sign(message, private_key[..].try_into().context("Failed to convert private_key.")?)
|
|
||||||
.context("Failed to sign.")?;
|
|
||||||
Ok(Signature { data: signature })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_attestation_chain(
|
|
||||||
&self,
|
|
||||||
client: BinderInputValues,
|
|
||||||
input_values: &[BinderInputValues],
|
|
||||||
) -> Result<Bcc> {
|
|
||||||
ensure!(input_values.is_empty(), "Extra input values not supported");
|
|
||||||
let artifacts = self.artifacts.read().unwrap().clone();
|
|
||||||
let (_, _, bcc) =
|
|
||||||
artifacts.get(&client).context("Failed to get attestation chain artifacts.")?;
|
|
||||||
Ok(Bcc { data: bcc })
|
|
||||||
}
|
|
||||||
|
|
||||||
fn derive(
|
|
||||||
&self,
|
|
||||||
client: BinderInputValues,
|
|
||||||
input_values: &[BinderInputValues],
|
|
||||||
) -> Result<BccHandover> {
|
|
||||||
ensure!(input_values.is_empty(), "Extra input values not supported");
|
|
||||||
let artifacts = self.artifacts.read().unwrap().clone();
|
|
||||||
let (cdi_attest, cdi_seal, bcc) =
|
|
||||||
artifacts.get(&client).context("Failed to get attestation chain artifacts.")?;
|
|
||||||
make_bcc_handover(
|
|
||||||
&cdi_attest
|
|
||||||
.to_vec()
|
|
||||||
.as_slice()
|
|
||||||
.try_into()
|
|
||||||
.context("Trying to convert cdi_attest to sized array.")?,
|
|
||||||
&cdi_seal
|
|
||||||
.to_vec()
|
|
||||||
.as_slice()
|
|
||||||
.try_into()
|
|
||||||
.context("Trying to convert cdi_seal to sized array.")?,
|
|
||||||
&bcc,
|
|
||||||
)
|
|
||||||
.context("Trying to construct BccHandover.")
|
|
||||||
}
|
|
||||||
|
|
||||||
fn demote(
|
|
||||||
&self,
|
|
||||||
_client: BinderInputValues,
|
|
||||||
_input_values: &[BinderInputValues],
|
|
||||||
) -> Result<()> {
|
|
||||||
bail!("Demote not supported.");
|
|
||||||
}
|
|
||||||
|
|
||||||
fn demote_self(&self, input_values: &[BinderInputValues]) -> Result<()> {
|
|
||||||
ensure!(input_values.len() == 1, "Can only demote_self one level.");
|
|
||||||
let mut artifacts = self.artifacts.write().unwrap();
|
|
||||||
*artifacts = (*artifacts).clone().update(&input_values[0])?;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn main() {
|
|
||||||
android_logger::init_once(
|
|
||||||
android_logger::Config::default().with_tag("dice").with_min_level(log::Level::Debug),
|
|
||||||
);
|
|
||||||
// Redirect panic messages to logcat.
|
|
||||||
panic::set_hook(Box::new(|panic_info| {
|
|
||||||
log::error!("{}", panic_info);
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Saying hi.
|
|
||||||
log::info!("DICE service is starting.");
|
|
||||||
|
|
||||||
let node_impl = Arc::new(ArtifactManager::new(Path::new("/dev/open-dice0")));
|
|
||||||
|
|
||||||
let node = DiceNode::new_as_binder(node_impl.clone())
|
|
||||||
.expect("Failed to create IDiceNode service instance.");
|
|
||||||
|
|
||||||
let maintenance = DiceMaintenance::new_as_binder(node_impl)
|
|
||||||
.expect("Failed to create IDiceMaintenance service instance.");
|
|
||||||
|
|
||||||
binder::add_service(DICE_NODE_SERVICE_NAME, node.as_binder())
|
|
||||||
.expect("Failed to register IDiceNode Service");
|
|
||||||
|
|
||||||
binder::add_service(DICE_MAINTENANCE_SERVICE_NAME, maintenance.as_binder())
|
|
||||||
.expect("Failed to register IDiceMaintenance Service");
|
|
||||||
|
|
||||||
log::info!("Joining thread pool now.");
|
|
||||||
binder::ProcessState::join_thread_pool();
|
|
||||||
}
|
|
|
@ -67,8 +67,6 @@ on init
|
||||||
|
|
||||||
start servicemanager
|
start servicemanager
|
||||||
|
|
||||||
start dice-microdroid
|
|
||||||
|
|
||||||
on init
|
on init
|
||||||
mkdir /mnt/apk 0755 system system
|
mkdir /mnt/apk 0755 system system
|
||||||
mkdir /mnt/extra-apk 0755 root root
|
mkdir /mnt/extra-apk 0755 root root
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<compatibility-matrix version="1.0" type="framework">
|
|
||||||
<hal format="aidl" optional="true">
|
|
||||||
<name>android.hardware.security.dice</name>
|
|
||||||
<version>1</version>
|
|
||||||
<interface>
|
|
||||||
<name>IDiceDevice</name>
|
|
||||||
<instance>default</instance>
|
|
||||||
</interface>
|
|
||||||
</hal>
|
|
||||||
</compatibility-matrix>
|
|
Loading…
Reference in New Issue