Merge changes from topic "block-apex-dmverity-mount"
* changes:
Microdroid stores APEX pubkeys in instance.img
Update microdroid's built-in apexes
diff --git a/microdroid/Android.bp b/microdroid/Android.bp
index 1638f6f..e4334cb 100644
--- a/microdroid/Android.bp
+++ b/microdroid/Android.bp
@@ -101,7 +101,10 @@
multilib: {
common: {
deps: [
+ // non-updatable & mandatory apexes
+ "com.android.i18n",
"com.android.runtime",
+
"microdroid_plat_sepolicy.cil",
"microdroid_plat_mapping_file",
],
diff --git a/microdroid/init.rc b/microdroid/init.rc
index f6a7ecc..347f514 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -19,7 +19,6 @@
mkdir /mnt/apk 0755 system system
start microdroid_manager
- # TODO(b/190343842) verify apexes/apk before mounting them.
# Exec apexd in the VM mode to avoid unnecessary overhead of normal mode.
# (e.g. session management)
diff --git a/microdroid_manager/Android.bp b/microdroid_manager/Android.bp
index 104c04a..9957689 100644
--- a/microdroid_manager/Android.bp
+++ b/microdroid_manager/Android.bp
@@ -32,6 +32,7 @@
"libuuid",
"libvsock",
"librand",
+ "libzip",
],
shared_libs: [
"libbinder_rpc_unstable",
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index 51d74b0..73983a7 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -311,16 +311,22 @@
ret
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct MicrodroidData {
pub apk_data: ApkData,
- // TODO(b/197053593) add data for APEXes
+ pub apex_data: Vec<ApexData>,
}
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct ApkData {
pub root_hash: Box<RootHash>,
// TODO(b/199143508) add cert
}
pub type RootHash = [u8];
+
+#[derive(Debug, Serialize, Deserialize, PartialEq)]
+pub struct ApexData {
+ pub name: String,
+ pub pubkey: Vec<u8>,
+}
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 4f192dc..2e80b90 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -16,7 +16,7 @@
mod instance;
mod ioutil;
-mod metadata;
+mod payload;
use crate::instance::{ApkData, InstanceDisk, MicrodroidData, RootHash};
use anyhow::{anyhow, bail, Context, Result};
@@ -25,8 +25,10 @@
use binder::{FromIBinder, Strong};
use idsig::V4Signature;
use log::{error, info, warn};
+use microdroid_metadata::Metadata;
use microdroid_payload_config::{Task, TaskType, VmPayloadConfig};
use nix::ioctl_read_bad;
+use payload::{get_apex_data_from_payload, load_metadata};
use rustutils::system_properties;
use rustutils::system_properties::PropertyWatcher;
use std::fs::{self, File, OpenOptions};
@@ -90,26 +92,23 @@
kernlog::init()?;
info!("started.");
- let metadata = metadata::load()?;
+ let metadata = load_metadata()?;
let mut instance = InstanceDisk::new()?;
- let data = instance.read_microdroid_data().context("Failed to read identity data")?;
- let saved_root_hash: Option<&[u8]> =
- if let Some(data) = data.as_ref() { Some(&data.apk_data.root_hash) } else { None };
+ let saved_data = instance.read_microdroid_data().context("Failed to read identity data")?;
// Verify the payload before using it.
- let verified_root_hash =
- verify_payload(saved_root_hash).context("Payload verification failed")?;
- if let Some(saved_root_hash) = saved_root_hash {
- if saved_root_hash == verified_root_hash.as_ref() {
- info!("Saved root_hash is verified.");
+ let verified_data =
+ verify_payload(&metadata, saved_data.as_ref()).context("Payload verification failed")?;
+ if let Some(saved_data) = saved_data {
+ if saved_data == verified_data {
+ info!("Saved data is verified.");
} else {
- bail!("Detected an update of the APK which isn't supported yet.");
+ bail!("Detected an update of the payload which isn't supported yet.");
}
} else {
- info!("Saving APK root_hash: {}", to_hex_string(verified_root_hash.as_ref()));
- let data = MicrodroidData { apk_data: ApkData { root_hash: verified_root_hash } };
- instance.write_microdroid_data(&data).context("Failed to write identity data")?;
+ info!("Saving verified data.");
+ instance.write_microdroid_data(&verified_data).context("Failed to write identity data")?;
}
wait_for_apex_config_done()?;
@@ -138,12 +137,17 @@
Ok(())
}
-// Verify payload before executing it. Full verification (which is slow) is done when the root_hash
-// values from the idsig file and the instance disk are different. This function returns the
-// verified root hash that can be saved to the instance disk.
-fn verify_payload(root_hash: Option<&RootHash>) -> Result<Box<RootHash>> {
+// Verify payload before executing it. For APK payload, Full verification (which is slow) is done
+// when the root_hash values from the idsig file and the instance disk are different. This function
+// returns the verified root hash (for APK payload) and pubkeys (for APEX payloads) that can be
+// saved to the instance disk.
+fn verify_payload(
+ metadata: &Metadata,
+ saved_data: Option<&MicrodroidData>,
+) -> Result<MicrodroidData> {
let start_time = SystemTime::now();
+ let root_hash = saved_data.map(|d| &d.apk_data.root_hash);
let root_hash_from_idsig = get_apk_root_hash_from_idsig()?;
let root_hash_trustful = root_hash == Some(&root_hash_from_idsig);
@@ -156,6 +160,11 @@
// Start apkdmverity and wait for the dm-verify block
system_properties::write("ctl.start", "apkdmverity")?;
+
+ // While waiting for apkdmverity to mount APK, gathers APEX pubkeys used by APEXd.
+ // These will be compared ones from instance.img.
+ let apex_data_from_payload = get_apex_data_from_payload(metadata)?;
+
ioutil::wait_for_file(DM_MOUNTED_APK_PATH, WAIT_TIMEOUT)?;
// Do the full verification if the root_hash is un-trustful. This requires the full scanning of
@@ -171,7 +180,10 @@
// At this point, we can ensure that the root_hash from the idsig file is trusted, either by
// fully verifying the APK or by comparing it with the saved root_hash.
- Ok(root_hash_from_idsig)
+ Ok(MicrodroidData {
+ apk_data: ApkData { root_hash: root_hash_from_idsig },
+ apex_data: apex_data_from_payload,
+ })
}
// Waits until linker config is generated
diff --git a/microdroid_manager/src/metadata.rs b/microdroid_manager/src/metadata.rs
deleted file mode 100644
index 432a134..0000000
--- a/microdroid_manager/src/metadata.rs
+++ /dev/null
@@ -1,32 +0,0 @@
-// 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.
-
-//! Payload metadata from /dev/block/by-name/payload-metadata
-
-use crate::ioutil;
-
-use anyhow::Result;
-use log::info;
-use microdroid_metadata::{read_metadata, Metadata};
-use std::time::Duration;
-
-const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
-const PAYLOAD_METADATA_PATH: &str = "/dev/block/by-name/payload-metadata";
-
-/// loads payload metadata from /dev/block/by-name/paylaod-metadata
-pub fn load() -> Result<Metadata> {
- info!("loading payload metadata...");
- let file = ioutil::wait_for_file(PAYLOAD_METADATA_PATH, WAIT_TIMEOUT)?;
- read_metadata(file)
-}
diff --git a/microdroid_manager/src/payload.rs b/microdroid_manager/src/payload.rs
new file mode 100644
index 0000000..bfc6c09
--- /dev/null
+++ b/microdroid_manager/src/payload.rs
@@ -0,0 +1,61 @@
+// 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.
+
+//! Routines for handling payload
+
+use crate::instance::ApexData;
+use crate::ioutil::wait_for_file;
+use anyhow::Result;
+use log::info;
+use microdroid_metadata::{read_metadata, Metadata};
+use std::fs::File;
+use std::io::Read;
+use std::time::Duration;
+use zip::ZipArchive;
+
+const APEX_PUBKEY_ENTRY: &str = "apex_pubkey";
+const PAYLOAD_METADATA_PATH: &str = "/dev/block/by-name/payload-metadata";
+const WAIT_TIMEOUT: Duration = Duration::from_secs(10);
+
+/// Loads payload metadata from /dev/block/by-name/payload-metadata
+pub fn load_metadata() -> Result<Metadata> {
+ info!("loading payload metadata...");
+ let file = wait_for_file(PAYLOAD_METADATA_PATH, WAIT_TIMEOUT)?;
+ read_metadata(file)
+}
+
+/// Loads (name, pubkey) from payload apexes and returns them as sorted by name.
+pub fn get_apex_data_from_payload(metadata: &Metadata) -> Result<Vec<ApexData>> {
+ let mut apex_data: Vec<ApexData> = metadata
+ .apexes
+ .iter()
+ .map(|apex| {
+ let name = apex.name.clone();
+ let partition = format!("/dev/block/by-name/{}", apex.partition_name);
+ let pubkey = get_pubkey_from_apex(&partition)?;
+ Ok(ApexData { name, pubkey })
+ })
+ .collect::<Result<Vec<_>>>()?;
+ apex_data.sort_by(|a, b| a.name.cmp(&b.name));
+ Ok(apex_data)
+}
+
+fn get_pubkey_from_apex(path: &str) -> Result<Vec<u8>> {
+ let f = File::open(path)?;
+ let mut z = ZipArchive::new(f)?;
+ let mut pubkey_file = z.by_name(APEX_PUBKEY_ENTRY)?;
+ let mut pubkey = Vec::new();
+ pubkey_file.read_to_end(&mut pubkey)?;
+ Ok(pubkey)
+}
diff --git a/virtualizationservice/src/payload.rs b/virtualizationservice/src/payload.rs
index 75ba6c7..9662fa3 100644
--- a/virtualizationservice/src/payload.rs
+++ b/virtualizationservice/src/payload.rs
@@ -31,8 +31,7 @@
/// The list of APEXes which microdroid requires.
// TODO(b/192200378) move this to microdroid.json?
-const MICRODROID_REQUIRED_APEXES: [&str; 3] =
- ["com.android.adbd", "com.android.i18n", "com.android.os.statsd"];
+const MICRODROID_REQUIRED_APEXES: [&str; 2] = ["com.android.adbd", "com.android.os.statsd"];
const APEX_INFO_LIST_PATH: &str = "/apex/apex-info-list.xml";