Merge "Store/Pass root digests of APEX payload"
diff --git a/apex/Android.bp b/apex/Android.bp
index c568ae2..b1c5190 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -81,4 +81,5 @@
name: "com.android.virt.init.rc",
src: "virtualizationservice.rc",
filename: "init.rc",
+ installable: false,
}
diff --git a/apkdmverity/src/main.rs b/apkdmverity/src/main.rs
index cabeb35..16490b6 100644
--- a/apkdmverity/src/main.rs
+++ b/apkdmverity/src/main.rs
@@ -240,8 +240,7 @@
}
run_test(modified_apk.as_slice(), idsig.as_ref(), "incorrect_apk", |ctx| {
- let ret = fs::read(&ctx.result.mapper_device).map_err(|e| e.kind());
- assert_eq!(ret, Err(std::io::ErrorKind::Other));
+ fs::read(&ctx.result.mapper_device).expect_err("Should fail");
});
}
@@ -261,8 +260,7 @@
}
run_test(apk.as_ref(), modified_idsig.as_slice(), "incorrect_merkle_tree", |ctx| {
- let ret = fs::read(&ctx.result.mapper_device).map_err(|e| e.kind());
- assert_eq!(ret, Err(std::io::ErrorKind::Other));
+ fs::read(&ctx.result.mapper_device).expect_err("Should fail");
});
}
@@ -284,9 +282,7 @@
// Read around the modified location causes an error
let f = File::open(&ctx.result.mapper_device).unwrap();
let mut buf = vec![0; 10]; // just read 10 bytes
- let ret = f.read_at(&mut buf, MODIFIED_OFFSET).map_err(|e| e.kind());
- assert!(ret.is_err());
- assert_eq!(ret, Err(std::io::ErrorKind::Other));
+ f.read_at(&mut buf, MODIFIED_OFFSET).expect_err("Should fail");
});
}
diff --git a/apkverify/src/lib.rs b/apkverify/src/lib.rs
index f75913c..71ea857 100644
--- a/apkverify/src/lib.rs
+++ b/apkverify/src/lib.rs
@@ -26,8 +26,14 @@
use anyhow::Result;
use std::path::Path;
-/// Verifies APK/APEX signing with v2/v3 scheme
-pub fn verify<P: AsRef<Path>>(path: P) -> Result<()> {
+/// Verifies APK/APEX signing with v2/v3 scheme. On success, the public key (in DER format) is
+/// returned.
+pub fn verify<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
// TODO(jooyung) fallback to v2 when v3 not found
v3::verify(path)
}
+
+/// Gets the public key (in DER format) that was used to sign the given APK/APEX file
+pub fn get_public_key_der<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
+ v3::get_public_key_der(path)
+}
diff --git a/apkverify/src/v3.rs b/apkverify/src/v3.rs
index 2f9ce94..797911b 100644
--- a/apkverify/src/v3.rs
+++ b/apkverify/src/v3.rs
@@ -86,40 +86,50 @@
type X509Certificate = Bytes;
type AdditionalAttributes = Bytes;
-/// Verifies APK Signature Scheme v3 signatures of the provided APK and returns the certificates
-/// associated with each signer.
-pub fn verify<P: AsRef<Path>>(path: P) -> Result<()> {
+/// Verifies APK Signature Scheme v3 signatures of the provided APK and returns the public key
+/// associated with the signer.
+pub fn verify<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
let f = File::open(path.as_ref())?;
let mut sections = ApkSections::new(f)?;
- verify_signature(&mut sections)?;
- Ok(())
+ find_signer_and_then(&mut sections, |(signer, sections)| signer.verify(sections))
}
-/// Verifies the contents of the provided APK file against the provided APK Signature Scheme v3
-/// Block.
-fn verify_signature<R: Read + Seek>(sections: &mut ApkSections<R>) -> Result<()> {
+/// Finds the supported signer and execute a function on it.
+fn find_signer_and_then<R, U, F>(sections: &mut ApkSections<R>, f: F) -> Result<U>
+where
+ R: Read + Seek,
+ F: FnOnce((&Signer, &mut ApkSections<R>)) -> Result<U>,
+{
let mut block = sections.find_signature(APK_SIGNATURE_SCHEME_V3_BLOCK_ID)?;
-
// parse v3 scheme block
let signers = block.read::<Signers>()?;
// find supported by platform
- let mut supported =
- signers.iter().filter(|s| s.sdk_range().contains(&SDK_INT)).collect::<Vec<_>>();
+ let supported = signers.iter().filter(|s| s.sdk_range().contains(&SDK_INT)).collect::<Vec<_>>();
// there should be exactly one
if supported.len() != 1 {
- bail!("APK Signature Scheme V3 only supports one signer: {} signers found.", signers.len())
+ bail!(
+ "APK Signature Scheme V3 only supports one signer: {} signers found.",
+ supported.len()
+ )
}
- // and it should be verified
- supported.pop().unwrap().verify(sections)?;
+ // Call the supplied function
+ f((supported[0], sections))
+}
- Ok(())
+/// Gets the public key (in DER format) that was used to sign the given APK/APEX file
+pub fn get_public_key_der<P: AsRef<Path>>(path: P) -> Result<Box<[u8]>> {
+ let f = File::open(path.as_ref())?;
+ let mut sections = ApkSections::new(f)?;
+ find_signer_and_then(&mut sections, |(signer, _)| {
+ Ok(signer.public_key.to_vec().into_boxed_slice())
+ })
}
impl Signer {
- fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<()> {
+ fn verify<R: Read + Seek>(&self, sections: &mut ApkSections<R>) -> Result<Box<[u8]>> {
// 1. Choose the strongest supported signature algorithm ID from signatures. The strength
// ordering is up to each implementation/platform version.
let strongest: &Signature = self
@@ -181,7 +191,7 @@
}
// TODO(jooyung) 8. If the proof-of-rotation attribute exists for the signer verify that the struct is valid and this signer is the last certificate in the list.
- Ok(())
+ Ok(self.public_key.to_vec().into_boxed_slice())
}
}
diff --git a/compos/apex/Android.bp b/compos/apex/Android.bp
index 853b9f4..ada0976 100644
--- a/compos/apex/Android.bp
+++ b/compos/apex/Android.bp
@@ -40,6 +40,7 @@
binaries: [
"compos_key_cmd",
"compos_verify_key",
+ "composd",
"compsvc",
"pvm_exec",
],
@@ -50,5 +51,13 @@
prebuilts: [
"CompOSPayloadApp.apk.idsig",
+ "com.android.compos.init.rc",
],
}
+
+prebuilt_etc {
+ name: "com.android.compos.init.rc",
+ src: "composd.rc",
+ filename: "init.rc",
+ installable: false,
+}
diff --git a/compos/apex/composd.rc b/compos/apex/composd.rc
new file mode 100644
index 0000000..099a346
--- /dev/null
+++ b/compos/apex/composd.rc
@@ -0,0 +1,21 @@
+# Copyright (C) 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.
+
+service composd /apex/com.android.compos/bin/composd
+ class main
+ user system
+ group system
+ interface aidl android.system.composd
+ disabled
+ oneshot
diff --git a/compos/compos_key_cmd/Android.bp b/compos/compos_key_cmd/Android.bp
index e0584f4..36c1b5c 100644
--- a/compos/compos_key_cmd/Android.bp
+++ b/compos/compos_key_cmd/Android.bp
@@ -15,8 +15,8 @@
"android.system.virtualizationservice-ndk",
"compos_aidl_interface-ndk",
"libbase",
- "libbinder_rpc_unstable",
"libbinder_ndk",
+ "libbinder_rpc_unstable",
"libcrypto",
"libfsverity",
"libprotobuf-cpp-lite",
diff --git a/compos/compos_key_cmd/compos_key_cmd.cpp b/compos/compos_key_cmd/compos_key_cmd.cpp
index eb11d92..ff53548 100644
--- a/compos/compos_key_cmd/compos_key_cmd.cpp
+++ b/compos/compos_key_cmd/compos_key_cmd.cpp
@@ -33,6 +33,7 @@
#include <openssl/x509.h>
#include <unistd.h>
+#include <binder_rpc_unstable.hpp>
#include <chrono>
#include <condition_variable>
#include <filesystem>
@@ -43,11 +44,6 @@
#include "compos_signature.pb.h"
-// From frameworks/native/libs/binder/rust/src/binder_rpc_unstable.hpp
-extern "C" {
-AIBinder* RpcClient(unsigned int cid, unsigned int port);
-}
-
using namespace std::literals;
using aidl::android::system::virtualizationservice::BnVirtualMachineCallback;
diff --git a/compos/composd/Android.bp b/compos/composd/Android.bp
new file mode 100644
index 0000000..007eda9
--- /dev/null
+++ b/compos/composd/Android.bp
@@ -0,0 +1,22 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_binary {
+ name: "composd",
+ srcs: ["src/composd_main.rs"],
+ edition: "2018",
+ rustlibs: [
+ "android.system.composd-rust",
+ "compos_aidl_interface-rust",
+ "libandroid_logger",
+ "libanyhow",
+ "libbinder_rs",
+ "libcompos_common",
+ "liblog_rust",
+ ],
+ prefer_rlib: true,
+ apex_available: [
+ "com.android.compos",
+ ],
+}
diff --git a/compos/composd/aidl/Android.bp b/compos/composd/aidl/Android.bp
new file mode 100644
index 0000000..90c0de0
--- /dev/null
+++ b/compos/composd/aidl/Android.bp
@@ -0,0 +1,21 @@
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+aidl_interface {
+ name: "android.system.composd",
+ srcs: ["android/system/composd/*.aidl"],
+ // TODO: Make this stable when the APEX becomes updatable.
+ unstable: true,
+ backend: {
+ java: {
+ apex_available: ["//apex_available:platform"],
+ },
+ rust: {
+ enabled: true,
+ apex_available: [
+ "com.android.compos",
+ ],
+ },
+ },
+}
diff --git a/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
new file mode 100644
index 0000000..0dd5b6f
--- /dev/null
+++ b/compos/composd/aidl/android/system/composd/IIsolatedCompilationService.aidl
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+package android.system.composd;
+
+interface IIsolatedCompilationService {
+ // TODO: Add real methods
+ void doSomething();
+}
diff --git a/compos/composd/src/composd_main.rs b/compos/composd/src/composd_main.rs
new file mode 100644
index 0000000..f674448
--- /dev/null
+++ b/compos/composd/src/composd_main.rs
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//! Exposes an on-demand binder service to perform system compilation tasks using CompOS. It is
+//! responsible for managing the lifecycle of the CompOS VM instances, providing key management for
+//! them, and orchestrating trusted compilation.
+
+mod service;
+
+use android_system_composd::binder::{register_lazy_service, ProcessState};
+use anyhow::{Context, Result};
+use log::{error, info};
+
+fn try_main() -> Result<()> {
+ android_logger::init_once(
+ android_logger::Config::default().with_tag("composd").with_min_level(log::Level::Info),
+ );
+
+ let service = service::new_binder();
+ register_lazy_service("android.system.composd", service.as_binder())
+ .context("Registering service")?;
+
+ info!("Registered service, joining threadpool");
+ ProcessState::join_thread_pool();
+
+ info!("Exiting");
+ Ok(())
+}
+
+fn main() {
+ if let Err(e) = try_main() {
+ error!("{}", e);
+ std::process::exit(1)
+ }
+}
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
new file mode 100644
index 0000000..8fe28ec
--- /dev/null
+++ b/compos/composd/src/service.rs
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 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.
+ */
+
+//! Implementation of IIsolatedCompilationService, called from system server when compilation is
+//! desired.
+
+use android_system_composd::aidl::android::system::composd::IIsolatedCompilationService::{
+ BnIsolatedCompilationService, IIsolatedCompilationService,
+};
+use android_system_composd::binder::{self, BinderFeatures, Interface, Strong};
+
+pub struct IsolatedCompilationService {}
+
+pub fn new_binder() -> Strong<dyn IIsolatedCompilationService> {
+ let service = IsolatedCompilationService {};
+ BnIsolatedCompilationService::new_binder(service, BinderFeatures::default())
+}
+
+impl IsolatedCompilationService {}
+
+impl Interface for IsolatedCompilationService {}
+
+impl IIsolatedCompilationService for IsolatedCompilationService {
+ fn doSomething(&self) -> binder::Result<()> {
+ Ok(())
+ }
+}
diff --git a/microdroid_manager/src/instance.rs b/microdroid_manager/src/instance.rs
index e50f4a8..47230e3 100644
--- a/microdroid_manager/src/instance.rs
+++ b/microdroid_manager/src/instance.rs
@@ -320,7 +320,7 @@
#[derive(Debug, Serialize, Deserialize, PartialEq)]
pub struct ApkData {
pub root_hash: Box<RootHash>,
- // TODO(b/199143508) add cert
+ pub pubkey: Box<[u8]>,
}
pub type RootHash = [u8];
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index 8555892..4953a4c 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -20,7 +20,7 @@
use crate::instance::{ApkData, InstanceDisk, MicrodroidData, RootHash};
use anyhow::{anyhow, bail, ensure, Context, Result};
-use apkverify::verify;
+use apkverify::{get_public_key_der, verify};
use binder::unstable_api::{new_spibinder, AIBinder};
use binder::{FromIBinder, Strong};
use idsig::V4Signature;
@@ -188,16 +188,18 @@
// taken only when the root_hash is un-trustful which can be either when this is the first boot
// of the VM or APK was updated in the host.
// TODO(jooyung): consider multithreading to make this faster
- if !root_hash_trustful {
- verify(DM_MOUNTED_APK_PATH).context(format!("failed to verify {}", DM_MOUNTED_APK_PATH))?;
- }
+ let apk_pubkey = if !root_hash_trustful {
+ verify(DM_MOUNTED_APK_PATH).context(format!("failed to verify {}", DM_MOUNTED_APK_PATH))?
+ } else {
+ get_public_key_der(DM_MOUNTED_APK_PATH)?
+ };
info!("payload verification successful. took {:#?}", start_time.elapsed().unwrap());
// 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(MicrodroidData {
- apk_data: ApkData { root_hash: root_hash_from_idsig },
+ apk_data: ApkData { root_hash: root_hash_from_idsig, pubkey: apk_pubkey },
apex_data: apex_data_from_payload,
})
}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index b0ea0ba..449103e 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -35,7 +35,7 @@
VirtualMachineState::VirtualMachineState,
};
use android_system_virtualizationservice::binder::{
- self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, Strong, ThreadState,
+ self, force_lazy_services_persist, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Status, Strong, ThreadState,
};
use android_system_virtualmachineservice::aidl::android::system::virtualmachineservice::IVirtualMachineService::{
VM_BINDER_SERVICE_PORT, VM_STREAM_SERVICE_PORT, BnVirtualMachineService, IVirtualMachineService,
@@ -716,12 +716,20 @@
/// Store a strong VM reference.
fn debug_hold_vm(&mut self, vm: Strong<dyn IVirtualMachine>) {
self.debug_held_vms.push(vm);
+ // Make sure our process is not shut down while we hold the VM reference
+ // on behalf of the caller.
+ force_lazy_services_persist(true);
}
/// Retrieve and remove a strong VM reference.
fn debug_drop_vm(&mut self, cid: i32) -> Option<Strong<dyn IVirtualMachine>> {
let pos = self.debug_held_vms.iter().position(|vm| vm.getCid() == Ok(cid))?;
- Some(self.debug_held_vms.swap_remove(pos))
+ let vm = self.debug_held_vms.swap_remove(pos);
+ if self.debug_held_vms.is_empty() {
+ // Once we no longer hold any VM references it is ok for our process to be shut down.
+ force_lazy_services_persist(false);
+ }
+ Some(vm)
}
/// Get the next available CID, or an error if we have run out.
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index 8628c01..22ddf08 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -21,7 +21,7 @@
use crate::aidl::{VirtualizationService, BINDER_SERVICE_IDENTIFIER, TEMPORARY_DIRECTORY};
use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualizationService::BnVirtualizationService;
-use android_system_virtualizationservice::binder::{add_service, BinderFeatures, ProcessState};
+use android_system_virtualizationservice::binder::{register_lazy_service, BinderFeatures, ProcessState};
use anyhow::Error;
use log::{info, Level};
use std::fs::{remove_dir_all, remove_file, read_dir};
@@ -47,7 +47,7 @@
service,
BinderFeatures { set_requesting_sid: true, ..BinderFeatures::default() },
);
- add_service(BINDER_SERVICE_IDENTIFIER, service.as_binder()).unwrap();
+ register_lazy_service(BINDER_SERVICE_IDENTIFIER, service.as_binder()).unwrap();
info!("Registered Binder service, joining threadpool.");
ProcessState::join_thread_pool();
}