Merge "Flag APK permission changes" into main
diff --git a/apex/Android.bp b/apex/Android.bp
index a05f7b0..7983181 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -60,7 +60,20 @@
],
}
-apex_defaults {
+soong_config_module_type {
+ name: "flag_aware_apex_defaults",
+ module_type: "apex_defaults",
+ config_namespace: "ANDROID",
+ bool_variables: [
+ "release_avf_enable_remote_attestation",
+ ],
+ properties: [
+ "prebuilts",
+ "vintf_fragments",
+ ],
+}
+
+flag_aware_apex_defaults {
name: "com.android.virt_avf_enabled",
defaults: ["com.android.virt_common"],
@@ -92,8 +105,19 @@
"fd_server",
"vm",
],
+ soong_config_variables: {
+ release_avf_enable_remote_attestation: {
+ prebuilts: ["com.android.virt.init_attestation_enabled.rc"],
+ vintf_fragments: [
+ "virtualizationservice.xml",
+ ],
+ conditions_default: {
+ prebuilts: ["com.android.virt.init.rc"],
+ },
+ },
+ },
prebuilts: [
- "com.android.virt.init.rc",
+ "com.android.virt.vfio_handler.rc",
"features_com.android.virt.xml",
"microdroid_initrd_debuggable",
"microdroid_initrd_normal",
@@ -128,9 +152,23 @@
}
prebuilt_etc {
+ name: "com.android.virt.vfio_handler.rc",
+ src: "vfio_handler.rc",
+ filename: "vfio_handler.rc",
+ installable: false,
+}
+
+prebuilt_etc {
name: "com.android.virt.init.rc",
src: "virtualizationservice.rc",
- filename: "init.rc",
+ filename: "virtualizationservice.rc",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "com.android.virt.init_attestation_enabled.rc",
+ src: "virtualizationservice_attestation_enabled.rc",
+ filename: "virtualizationservice.rc",
installable: false,
}
diff --git a/apex/vfio_handler.rc b/apex/vfio_handler.rc
new file mode 100644
index 0000000..419acef
--- /dev/null
+++ b/apex/vfio_handler.rc
@@ -0,0 +1,20 @@
+# Copyright (C) 2023 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 vfio_handler /apex/com.android.virt/bin/vfio_handler
+ user root
+ group system
+ interface aidl android.system.virtualizationservice_internal.IVfioHandler
+ disabled
+ oneshot
diff --git a/apex/virtualizationservice.rc b/apex/virtualizationservice.rc
index 8283594..02b2081 100644
--- a/apex/virtualizationservice.rc
+++ b/apex/virtualizationservice.rc
@@ -19,10 +19,3 @@
interface aidl android.system.virtualizationservice
disabled
oneshot
-
-service vfio_handler /apex/com.android.virt/bin/vfio_handler
- user root
- group system
- interface aidl android.system.virtualizationservice_internal.IVfioHandler
- disabled
- oneshot
diff --git a/apex/virtualizationservice.xml b/apex/virtualizationservice.xml
index 0ce1e10..60f466f 100644
--- a/apex/virtualizationservice.xml
+++ b/apex/virtualizationservice.xml
@@ -1,6 +1,6 @@
<manifest version="1.0" type="framework">
<hal format="aidl">
- <name>android.system.virtualization</name>
+ <name>android.hardware.security.keymint</name>
<version>3</version>
<fqname>IRemotelyProvisionedComponent/avf</fqname>
</hal>
diff --git a/apex/virtualizationservice_attestation_enabled.rc b/apex/virtualizationservice_attestation_enabled.rc
new file mode 100644
index 0000000..8eaccae
--- /dev/null
+++ b/apex/virtualizationservice_attestation_enabled.rc
@@ -0,0 +1,22 @@
+# 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 virtualizationservice /apex/com.android.virt/bin/virtualizationservice
+ class main
+ user system
+ group system
+ interface aidl android.system.virtualizationservice
+ interface aidl android.hardware.security.keymint.IRemotelyProvisionedComponent/avf
+ disabled
+ oneshot
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index d800c13..96ac3f4 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -499,18 +499,30 @@
}
}
+impl<'a> PartialEq for FdtNode<'a> {
+ fn eq(&self, other: &Self) -> bool {
+ self.fdt.as_ptr() == other.fdt.as_ptr() && self.offset == other.offset
+ }
+}
+
/// Phandle of a FDT node
#[repr(transparent)]
#[derive(Debug, Copy, Clone, PartialEq)]
pub struct Phandle(u32);
impl Phandle {
+ /// Minimum valid value for device tree phandles.
+ pub const MIN: Self = Self(1);
+ /// Maximum valid value for device tree phandles.
+ pub const MAX: Self = Self(libfdt_bindgen::FDT_MAX_PHANDLE);
+
/// Creates a new Phandle
- pub fn new(value: u32) -> Result<Self> {
- if value == 0 || value > libfdt_bindgen::FDT_MAX_PHANDLE {
- return Err(FdtError::BadPhandle);
+ pub const fn new(value: u32) -> Option<Self> {
+ if Self::MIN.0 <= value && value <= Self::MAX.0 {
+ Some(Self(value))
+ } else {
+ None
}
- Ok(Self(value))
}
}
@@ -520,7 +532,16 @@
}
}
+impl TryFrom<u32> for Phandle {
+ type Error = FdtError;
+
+ fn try_from(value: u32) -> Result<Self> {
+ Self::new(value).ok_or(FdtError::BadPhandle)
+ }
+}
+
/// Mutable FDT node.
+#[derive(Debug)]
pub struct FdtNodeMut<'a> {
fdt: &'a mut Fdt,
offset: c_int,
@@ -964,7 +985,7 @@
let ret = unsafe { libfdt_bindgen::fdt_find_max_phandle(self.as_ptr(), &mut phandle) };
fdt_err_expect_zero(ret)?;
- Phandle::new(phandle)
+ phandle.try_into()
}
/// Returns a node with the phandle
diff --git a/libs/libfdt/tests/api_test.rs b/libs/libfdt/tests/api_test.rs
index 61503eb..78bb618 100644
--- a/libs/libfdt/tests/api_test.rs
+++ b/libs/libfdt/tests/api_test.rs
@@ -42,7 +42,7 @@
const EXPECTED_FIRST_MEMORY_RANGE: Range<usize> = 0..256;
let mut memory = fdt.memory().unwrap();
assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
- assert!(memory.next().is_none());
+ assert_eq!(memory.next(), None);
assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
}
@@ -56,7 +56,7 @@
let mut memory = fdt.memory().unwrap();
assert_eq!(memory.next(), Some(EXPECTED_FIRST_MEMORY_RANGE));
assert_eq!(memory.next(), Some(EXPECTED_SECOND_MEMORY_RANGE));
- assert!(memory.next().is_none());
+ assert_eq!(memory.next(), None);
assert_eq!(fdt.first_memory_range(), Ok(EXPECTED_FIRST_MEMORY_RANGE));
}
@@ -66,7 +66,7 @@
let fdt = Fdt::from_slice(&data).unwrap();
let mut memory = fdt.memory().unwrap();
- assert!(memory.next().is_none());
+ assert_eq!(memory.next(), None);
assert_eq!(fdt.first_memory_range(), Err(FdtError::NotFound));
}
@@ -85,14 +85,14 @@
let fdt = Fdt::from_slice(&data).unwrap();
let root = fdt.root().unwrap();
- assert_eq!(root.name().unwrap().to_str().unwrap(), "");
+ assert_eq!(root.name(), Ok(cstr!("")));
let chosen = fdt.chosen().unwrap().unwrap();
- assert_eq!(chosen.name().unwrap().to_str().unwrap(), "chosen");
+ assert_eq!(chosen.name(), Ok(cstr!("chosen")));
let nested_node_path = cstr!("/cpus/PowerPC,970@0");
let nested_node = fdt.node(nested_node_path).unwrap().unwrap();
- assert_eq!(nested_node.name().unwrap().to_str().unwrap(), "PowerPC,970@0");
+ assert_eq!(nested_node.name(), Ok(cstr!("PowerPC,970@0")));
}
#[test]
@@ -100,10 +100,10 @@
let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
let fdt = Fdt::from_slice(&data).unwrap();
let root = fdt.root().unwrap();
- let expected: Vec<&str> = vec!["cpus", "randomnode", "chosen"];
+ let expected = [cstr!("cpus"), cstr!("randomnode"), cstr!("chosen")];
for (node, name) in root.subnodes().unwrap().zip(expected) {
- assert_eq!(node.name().unwrap().to_str().unwrap(), name);
+ assert_eq!(node.name(), Ok(name));
}
}
@@ -113,17 +113,17 @@
let fdt = Fdt::from_slice(&data).unwrap();
let root = fdt.root().unwrap();
let one_be = 0x1_u32.to_be_bytes();
- let expected: Vec<(&str, &[u8])> = vec![
- ("model", b"MyBoardName\0"),
- ("compatible", b"MyBoardName\0MyBoardFamilyName\0"),
- ("#address-cells", &one_be),
- ("#size-cells", &one_be),
- ("empty_prop", b""),
+ let expected = [
+ (cstr!("model"), b"MyBoardName\0".as_ref()),
+ (cstr!("compatible"), b"MyBoardName\0MyBoardFamilyName\0".as_ref()),
+ (cstr!("#address-cells"), &one_be),
+ (cstr!("#size-cells"), &one_be),
+ (cstr!("empty_prop"), &[]),
];
- for (prop, (name, value)) in root.properties().unwrap().zip(expected) {
- assert_eq!(prop.name().unwrap().to_str().unwrap(), name);
- assert_eq!(prop.value().unwrap(), value);
+ let properties = root.properties().unwrap();
+ for (prop, (name, value)) in properties.zip(expected.into_iter()) {
+ assert_eq!((prop.name(), prop.value()), (Ok(name), Ok(value)));
}
}
@@ -132,28 +132,49 @@
let data = fs::read(TEST_TREE_WITH_NO_MEMORY_NODE_PATH).unwrap();
let fdt = Fdt::from_slice(&data).unwrap();
let node = fdt.node(cstr!("/cpus/PowerPC,970@1")).unwrap().unwrap();
- let expected = &["", "cpus", "PowerPC,970@1"];
+ let expected = [cstr!(""), cstr!("cpus"), cstr!("PowerPC,970@1")];
- for (depth, expect) in expected.iter().enumerate() {
+ for (depth, name) in expected.into_iter().enumerate() {
let supernode = node.supernode_at_depth(depth).unwrap();
- assert_eq!(supernode.name().unwrap().to_str().unwrap(), *expect);
+ assert_eq!(supernode.name(), Ok(name));
}
}
#[test]
fn phandle_new() {
- let phandle_u32 = 0x55;
- let phandle = Phandle::new(phandle_u32).unwrap();
+ let valid_phandles = [
+ u32::from(Phandle::MIN),
+ u32::from(Phandle::MIN).checked_add(1).unwrap(),
+ 0x55,
+ u32::from(Phandle::MAX).checked_sub(1).unwrap(),
+ u32::from(Phandle::MAX),
+ ];
- assert_eq!(u32::from(phandle), phandle_u32);
+ for value in valid_phandles {
+ let phandle = Phandle::new(value).unwrap();
+
+ assert_eq!(value.try_into(), Ok(phandle));
+ assert_eq!(u32::from(phandle), value);
+ }
+
+ let bad_phandles = [
+ u32::from(Phandle::MIN).checked_sub(1).unwrap(),
+ u32::from(Phandle::MAX).checked_add(1).unwrap(),
+ ];
+
+ for value in bad_phandles {
+ assert_eq!(Phandle::new(value), None);
+ assert_eq!(Phandle::try_from(value), Err(FdtError::BadPhandle));
+ }
}
#[test]
fn max_phandle() {
let data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
let fdt = Fdt::from_slice(&data).unwrap();
+ let phandle = Phandle::new(0xFF).unwrap();
- assert_eq!(fdt.max_phandle().unwrap(), Phandle::new(0xFF).unwrap());
+ assert_eq!(fdt.max_phandle(), Ok(phandle));
}
#[test]
@@ -162,32 +183,36 @@
let fdt = Fdt::from_slice(&data).unwrap();
// Test linux,phandle
- let node = fdt.node_with_phandle(Phandle::new(0xFF).unwrap()).unwrap().unwrap();
- assert_eq!(node.name().unwrap().to_str().unwrap(), "node_zz");
+ let phandle = Phandle::new(0xFF).unwrap();
+ let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
+ assert_eq!(node.name(), Ok(cstr!("node_zz")));
// Test phandle
- let node = fdt.node_with_phandle(Phandle::new(0x22).unwrap()).unwrap().unwrap();
- assert_eq!(node.name().unwrap().to_str().unwrap(), "node_abc");
+ let phandle = Phandle::new(0x22).unwrap();
+ let node = fdt.node_with_phandle(phandle).unwrap().unwrap();
+ assert_eq!(node.name(), Ok(cstr!("node_abc")));
}
#[test]
fn node_nop() {
let mut data = fs::read(TEST_TREE_PHANDLE_PATH).unwrap();
let fdt = Fdt::from_mut_slice(&mut data).unwrap();
+ let phandle = Phandle::new(0xFF).unwrap();
+ let path = cstr!("/node_z/node_zz");
- fdt.node_with_phandle(Phandle::new(0xFF).unwrap()).unwrap().unwrap();
- let node = fdt.node_mut(cstr!("/node_z/node_zz")).unwrap().unwrap();
+ fdt.node_with_phandle(phandle).unwrap().unwrap();
+ let node = fdt.node_mut(path).unwrap().unwrap();
node.nop().unwrap();
- assert!(fdt.node_with_phandle(Phandle::new(0xFF).unwrap()).unwrap().is_none());
- assert!(fdt.node(cstr!("/node_z/node_zz")).unwrap().is_none());
+ assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
+ assert_eq!(fdt.node(path), Ok(None));
fdt.unpack().unwrap();
fdt.pack().unwrap();
- assert!(fdt.node_with_phandle(Phandle::new(0xFF).unwrap()).unwrap().is_none());
- assert!(fdt.node(cstr!("/node_z/node_zz")).unwrap().is_none());
+ assert_eq!(fdt.node_with_phandle(phandle), Ok(None));
+ assert_eq!(fdt.node(path), Ok(None));
}
#[test]
@@ -216,7 +241,8 @@
for len in 1..subnode_name.to_bytes().len() {
let name = String::from_utf8(subnode_name.to_bytes()[..len].to_vec()).unwrap();
let path = CString::new(format!("{node_path}/{name}")).unwrap();
+ let name = CString::new(name).unwrap();
let subnode = fdt.node(&path).unwrap().unwrap();
- assert_eq!(subnode.name().unwrap().to_str().unwrap(), name);
+ assert_eq!(subnode.name(), Ok(name.as_c_str()));
}
}
diff --git a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
index 50d437f..b9a7a64 100644
--- a/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
+++ b/microdroid_manager/aidl/android/system/virtualization/payload/IVmPayloadService.aidl
@@ -69,11 +69,13 @@
byte[] getDiceAttestationCdi();
/**
- * Requests a certificate using the provided certificate signing request (CSR).
+ * Requests the remote attestation of the client VM.
*
- * TODO(b/271275206): Define the format of the CSR properly.
- * @param csr the certificate signing request.
+ * The challenge will be included in the certificate chain in the attestation result,
+ * serving as proof of the freshness of the result.
+ *
+ * @param challenge the maximum supported challenge size is 64 bytes.
* @return the X.509 encoded certificate.
*/
- byte[] requestCertificate(in byte[] csr);
+ byte[] requestAttestation(in byte[] challenge);
}
diff --git a/microdroid_manager/src/vm_payload_service.rs b/microdroid_manager/src/vm_payload_service.rs
index c611b11..5b5fb9e 100644
--- a/microdroid_manager/src/vm_payload_service.rs
+++ b/microdroid_manager/src/vm_payload_service.rs
@@ -66,9 +66,9 @@
Ok(self.secret.dice().cdi_attest().to_vec())
}
- fn requestCertificate(&self, csr: &[u8]) -> binder::Result<Vec<u8>> {
+ fn requestAttestation(&self, challenge: &[u8]) -> binder::Result<Vec<u8>> {
self.check_restricted_apis_allowed()?;
- self.virtual_machine_service.requestCertificate(csr)
+ self.virtual_machine_service.requestAttestation(challenge)
}
}
diff --git a/service_vm/client_apk/src/main.rs b/service_vm/client_apk/src/main.rs
index 08d4168..bd48dc3 100644
--- a/service_vm/client_apk/src/main.rs
+++ b/service_vm/client_apk/src/main.rs
@@ -17,7 +17,7 @@
use anyhow::Result;
use log::{error, info};
use std::{ffi::c_void, panic};
-use vm_payload_bindgen::AVmPayload_requestCertificate;
+use vm_payload_bindgen::AVmPayload_requestAttestation;
/// Entry point of the Service VM client.
#[allow(non_snake_case)]
@@ -40,25 +40,35 @@
fn try_main() -> Result<()> {
info!("Welcome to Service VM Client!");
- let csr = b"Hello from Service VM";
- info!("Sending: {:?}", csr);
- let certificate = request_certificate(csr);
+ // The data below is only a placeholder generated randomly with urandom
+ let challenge = &[
+ 0x6c, 0xad, 0x52, 0x50, 0x15, 0xe7, 0xf4, 0x1d, 0xa5, 0x60, 0x7e, 0xd2, 0x7d, 0xf1, 0x51,
+ 0x67, 0xc3, 0x3e, 0x73, 0x9b, 0x30, 0xbd, 0x04, 0x20, 0x2e, 0xde, 0x3b, 0x1d, 0xc8, 0x07,
+ 0x11, 0x7b,
+ ];
+ info!("Sending challenge: {:?}", challenge);
+ let certificate = request_attestation(challenge);
info!("Certificate: {:?}", certificate);
Ok(())
}
-fn request_certificate(csr: &[u8]) -> Vec<u8> {
+fn request_attestation(challenge: &[u8]) -> Vec<u8> {
// SAFETY: It is safe as we only request the size of the certificate in this call.
let certificate_size = unsafe {
- AVmPayload_requestCertificate(csr.as_ptr() as *const c_void, csr.len(), [].as_mut_ptr(), 0)
+ AVmPayload_requestAttestation(
+ challenge.as_ptr() as *const c_void,
+ challenge.len(),
+ [].as_mut_ptr(),
+ 0,
+ )
};
let mut certificate = vec![0u8; certificate_size];
// SAFETY: It is safe as we only write the data into the given buffer within the buffer
// size in this call.
unsafe {
- AVmPayload_requestCertificate(
- csr.as_ptr() as *const c_void,
- csr.len(),
+ AVmPayload_requestAttestation(
+ challenge.as_ptr() as *const c_void,
+ challenge.len(),
certificate.as_mut_ptr() as *mut c_void,
certificate.len(),
);
diff --git a/service_vm/requests/src/rkp.rs b/service_vm/requests/src/rkp.rs
index 8d7d771..f5b9203 100644
--- a/service_vm/requests/src/rkp.rs
+++ b/service_vm/requests/src/rkp.rs
@@ -75,10 +75,13 @@
public_keys.push(public_key.to_cbor_value()?);
}
// Builds `CsrPayload`.
+ // TODO(b/299256925): The device information is currently empty as we do not
+ // have sufficient details to include.
+ let device_info = Value::Map(Vec::new());
let csr_payload = cbor!([
Value::Integer(CSR_PAYLOAD_SCHEMA_V3.into()),
Value::Text(String::from(CERTIFICATE_TYPE)),
- // TODO(b/299256925): Add device info in CBOR format here.
+ device_info,
Value::Array(public_keys),
])?;
let csr_payload = cbor_util::serialize(&csr_payload)?;
diff --git a/virtualizationmanager/src/aidl.rs b/virtualizationmanager/src/aidl.rs
index 5283ffe..da7dffe 100644
--- a/virtualizationmanager/src/aidl.rs
+++ b/virtualizationmanager/src/aidl.rs
@@ -1245,8 +1245,8 @@
}
}
- fn requestCertificate(&self, csr: &[u8]) -> binder::Result<Vec<u8>> {
- GLOBAL_SERVICE.requestCertificate(csr)
+ fn requestAttestation(&self, csr: &[u8]) -> binder::Result<Vec<u8>> {
+ GLOBAL_SERVICE.requestAttestation(csr)
}
}
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index c00445d..7bdab0a 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -31,6 +31,7 @@
"libanyhow",
"libavflog",
"libbinder_rs",
+ "libhypervisor_props",
"liblibc",
"liblog_rust",
"libnix",
diff --git a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
index 172dc59..099a2c0 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
@@ -56,12 +56,13 @@
VirtualMachineDebugInfo[] debugListVms();
/**
- * Requests a certificate using the provided certificate signing request (CSR).
+ * Requests a certificate chain for the provided certificate signing request (CSR).
*
- * @param csr the certificate signing request.
- * @return the X.509 encoded certificate.
+ * @param csr The certificate signing request.
+ * @return A sequence of DER-encoded X.509 certificates that make up the attestation
+ * key's certificate chain. The attestation key is provided in the CSR.
*/
- byte[] requestCertificate(in byte[] csr);
+ byte[] requestAttestation(in byte[] csr);
/**
* Get a list of assignable devices.
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index 7b90714..87d3056 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -46,10 +46,11 @@
void notifyError(ErrorCode errorCode, in String message);
/**
- * Requests a certificate using the provided certificate signing request (CSR).
+ * Requests a certificate chain for the provided certificate signing request (CSR).
*
- * @param csr the certificate signing request.
- * @return the X.509 encoded certificate.
+ * @param csr The certificate signing request.
+ * @return A sequence of DER-encoded X.509 certificates that make up the attestation
+ * key's certificate chain. The attestation key is provided in the CSR.
*/
- byte[] requestCertificate(in byte[] csr);
+ byte[] requestAttestation(in byte[] csr);
}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index a19ecd2..4daa0cf 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -16,7 +16,7 @@
use crate::{get_calling_pid, get_calling_uid};
use crate::atom::{forward_vm_booted_atom, forward_vm_creation_atom, forward_vm_exited_atom};
-use crate::rkpvm::request_certificate;
+use crate::rkpvm::request_attestation;
use android_os_permissions_aidl::aidl::android::os::IPermissionController;
use android_system_virtualizationservice::{
aidl::android::system::virtualizationservice::AssignableDevice::AssignableDevice,
@@ -158,19 +158,20 @@
Ok(cids)
}
- fn requestCertificate(&self, csr: &[u8]) -> binder::Result<Vec<u8>> {
+ fn requestAttestation(&self, csr: &[u8]) -> binder::Result<Vec<u8>> {
check_manage_access()?;
- info!("Received csr. Getting certificate...");
+ info!("Received csr. Requestting attestation...");
if cfg!(remote_attestation) {
- request_certificate(csr)
- .context("Failed to get certificate")
+ request_attestation(csr)
+ .context("Failed to request attestation")
.with_log()
.or_service_specific_exception(-1)
} else {
Err(Status::new_exception_str(
ExceptionCode::UNSUPPORTED_OPERATION,
Some(
- "requestCertificate is not supported with the remote_attestation feature disabled",
+ "requestAttestation is not supported with the remote_attestation feature \
+ disabled",
),
))
.with_log()
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index fd668bc..c2e55eb 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -33,8 +33,8 @@
use std::path::Path;
const LOG_TAG: &str = "VirtualizationService";
-const _REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME: &str =
- "android.system.virtualization.IRemotelyProvisionedComponent/avf";
+const REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME: &str =
+ "android.hardware.security.keymint.IRemotelyProvisionedComponent/avf";
fn get_calling_pid() -> pid_t {
ThreadState::get_calling_pid()
@@ -69,10 +69,17 @@
register_lazy_service(BINDER_SERVICE_IDENTIFIER, service.as_binder()).unwrap();
info!("Registered Binder service {}.", BINDER_SERVICE_IDENTIFIER);
- // The IRemotelyProvisionedComponent service is only supposed to be triggered by rkpd for
- // RKP VM attestation.
- let _remote_provisioning_service = remote_provisioning::new_binder();
- // TODO(b/274881098): Register the RKP service when the implementation is ready.
+ if cfg!(remote_attestation) {
+ // The IRemotelyProvisionedComponent service is only supposed to be triggered by rkpd for
+ // RKP VM attestation.
+ let remote_provisioning_service = remote_provisioning::new_binder();
+ register_lazy_service(
+ REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME,
+ remote_provisioning_service.as_binder(),
+ )
+ .unwrap();
+ info!("Registered Binder service {}.", REMOTELY_PROVISIONED_COMPONENT_SERVICE_NAME);
+ }
ProcessState::join_thread_pool();
}
diff --git a/virtualizationservice/src/remote_provisioning.rs b/virtualizationservice/src/remote_provisioning.rs
index a9a07a5..40f54db 100644
--- a/virtualizationservice/src/remote_provisioning.rs
+++ b/virtualizationservice/src/remote_provisioning.rs
@@ -27,7 +27,11 @@
};
use anyhow::Context;
use avflog::LogResult;
-use binder::{BinderFeatures, Interface, IntoBinderResult, Result as BinderResult, Status, Strong};
+use binder::{
+ BinderFeatures, ExceptionCode, Interface, IntoBinderResult, Result as BinderResult, Status,
+ Strong,
+};
+use hypervisor_props::is_protected_vm_supported;
use service_vm_comm::{RequestProcessingError, Response};
/// Constructs a binder object that implements `IRemotelyProvisionedComponent`.
@@ -45,11 +49,13 @@
#[allow(non_snake_case)]
impl IRemotelyProvisionedComponent for AvfRemotelyProvisionedComponent {
fn getHardwareInfo(&self) -> BinderResult<RpcHardwareInfo> {
+ check_protected_vm_is_supported()?;
+
Ok(RpcHardwareInfo {
versionNumber: 3,
rpcAuthorName: String::from("Android Virtualization Framework"),
supportedEekCurve: CURVE_NONE,
- uniqueId: Some(String::from("Android Virtualization Framework 1")),
+ uniqueId: Some(String::from("AVF Remote Provisioning 1")),
supportedNumKeysInCsr: MIN_SUPPORTED_NUM_KEYS_IN_CSR,
})
}
@@ -59,6 +65,8 @@
testMode: bool,
macedPublicKey: &mut MacedPublicKey,
) -> BinderResult<Vec<u8>> {
+ check_protected_vm_is_supported()?;
+
if testMode {
return Err(Status::new_service_specific_error_str(
STATUS_REMOVED,
@@ -101,6 +109,8 @@
keysToSign: &[MacedPublicKey],
challenge: &[u8],
) -> BinderResult<Vec<u8>> {
+ check_protected_vm_is_supported()?;
+
const MAX_CHALLENGE_SIZE: usize = 64;
if challenge.len() > MAX_CHALLENGE_SIZE {
let message = format!(
@@ -123,6 +133,18 @@
}
}
+fn check_protected_vm_is_supported() -> BinderResult<()> {
+ if is_protected_vm_supported().unwrap_or(false) {
+ Ok(())
+ } else {
+ Err(Status::new_exception_str(
+ ExceptionCode::UNSUPPORTED_OPERATION,
+ Some("Protected VM support is missing for this operation"),
+ ))
+ .with_log()
+ }
+}
+
fn to_service_specific_error(response: Response) -> Status {
match response {
Response::Err(e) => match e {
diff --git a/virtualizationservice/src/rkpvm.rs b/virtualizationservice/src/rkpvm.rs
index d6e87eb..443b280 100644
--- a/virtualizationservice/src/rkpvm.rs
+++ b/virtualizationservice/src/rkpvm.rs
@@ -21,7 +21,7 @@
use service_vm_comm::{GenerateCertificateRequestParams, Request, Response};
use service_vm_manager::ServiceVm;
-pub(crate) fn request_certificate(csr: &[u8]) -> Result<Vec<u8>> {
+pub(crate) fn request_attestation(csr: &[u8]) -> Result<Vec<u8>> {
let mut vm = ServiceVm::start()?;
// TODO(b/271275206): Send the correct request type with client VM's
diff --git a/vm_payload/include-restricted/vm_payload_restricted.h b/vm_payload/include-restricted/vm_payload_restricted.h
index 1e0c3cc..ee92366 100644
--- a/vm_payload/include-restricted/vm_payload_restricted.h
+++ b/vm_payload/include-restricted/vm_payload_restricted.h
@@ -56,16 +56,21 @@
size_t AVmPayload_getDiceAttestationCdi(void* _Nullable data, size_t size);
/**
- * Requests a certificate using the provided certificate signing request (CSR).
+ * Requests the remote attestation of the client VM.
*
- * \param csr A pointer to the CSR buffer.
- * \param csr_size The size of the CSR buffer.
+ * The challenge will be included in the certificate chain in the attestation result,
+ * serving as proof of the freshness of the result.
+ *
+ * \param challenge A pointer to the challenge buffer.
+ * \param challenge_size size of the challenge, the maximum supported challenge size is
+ * 64 bytes. An error will be returned if an invalid challenge is
+ * passed.
* \param buffer A pointer to the certificate buffer.
* \param size number of bytes that can be written to the certificate buffer.
*
* \return the total size of the certificate
*/
-size_t AVmPayload_requestCertificate(const void* _Nonnull csr, size_t csr_size,
+size_t AVmPayload_requestAttestation(const void* _Nonnull challenge, size_t challenge_size,
void* _Nullable buffer, size_t size)
__INTRODUCED_IN(__ANDROID_API_V__);
diff --git a/vm_payload/libvm_payload.map.txt b/vm_payload/libvm_payload.map.txt
index f0d867e..32dd33b 100644
--- a/vm_payload/libvm_payload.map.txt
+++ b/vm_payload/libvm_payload.map.txt
@@ -1,13 +1,13 @@
LIBVM_PAYLOAD {
global:
- AVmPayload_notifyPayloadReady; # systemapi
- AVmPayload_runVsockRpcServer; # systemapi
- AVmPayload_getVmInstanceSecret; # systemapi
- AVmPayload_getDiceAttestationChain; # systemapi
- AVmPayload_getDiceAttestationCdi; # systemapi
- AVmPayload_getApkContentsPath; # systemapi
- AVmPayload_getEncryptedStoragePath; # systemapi
- AVmPayload_requestCertificate; # systemapi introduced=35
+ AVmPayload_notifyPayloadReady; # systemapi introduced=UpsideDownCake
+ AVmPayload_runVsockRpcServer; # systemapi introduced=UpsideDownCake
+ AVmPayload_getVmInstanceSecret; # systemapi introduced=UpsideDownCake
+ AVmPayload_getDiceAttestationChain; # systemapi introduced=UpsideDownCake
+ AVmPayload_getDiceAttestationCdi; # systemapi introduced=UpsideDownCake
+ AVmPayload_getApkContentsPath; # systemapi introduced=UpsideDownCake
+ AVmPayload_getEncryptedStoragePath; # systemapi introduced=UpsideDownCake
+ AVmPayload_requestAttestation; # systemapi introduced=VanillaIceCream
local:
*;
};
diff --git a/vm_payload/src/api.rs b/vm_payload/src/api.rs
index 00d7299..93dbd1c 100644
--- a/vm_payload/src/api.rs
+++ b/vm_payload/src/api.rs
@@ -253,29 +253,31 @@
get_vm_payload_service()?.getDiceAttestationCdi().context("Cannot get attestation CDI")
}
-/// Requests a certificate using the provided certificate signing request (CSR).
-/// Panics on failure.
+/// Requests the remote attestation of the client VM.
+///
+/// The challenge will be included in the certificate chain in the attestation result,
+/// serving as proof of the freshness of the result.
///
/// # Safety
///
/// Behavior is undefined if any of the following conditions are violated:
///
-/// * `csr` must be [valid] for reads of `csr_size` bytes.
+/// * `challenge` must be [valid] for reads of `challenge_size` bytes.
/// * `buffer` must be [valid] for writes of `size` bytes. `buffer` can be null if `size` is 0.
///
/// [valid]: ptr#safety
#[no_mangle]
-pub unsafe extern "C" fn AVmPayload_requestCertificate(
- csr: *const u8,
- csr_size: usize,
+pub unsafe extern "C" fn AVmPayload_requestAttestation(
+ challenge: *const u8,
+ challenge_size: usize,
buffer: *mut u8,
size: usize,
) -> usize {
initialize_logging();
- // SAFETY: See the requirements on `csr` above.
- let csr = unsafe { std::slice::from_raw_parts(csr, csr_size) };
- let certificate = unwrap_or_abort(try_request_certificate(csr));
+ // SAFETY: See the requirements on `challenge` above.
+ let challenge = unsafe { std::slice::from_raw_parts(challenge, challenge_size) };
+ let certificate = unwrap_or_abort(try_request_attestation(challenge));
if size != 0 || buffer.is_null() {
// SAFETY: See the requirements on `buffer` above. The number of bytes copied doesn't exceed
@@ -292,10 +294,10 @@
certificate.len()
}
-fn try_request_certificate(csr: &[u8]) -> Result<Vec<u8>> {
+fn try_request_attestation(challenge: &[u8]) -> Result<Vec<u8>> {
let certificate = get_vm_payload_service()?
- .requestCertificate(csr)
- .context("Failed to request certificate")?;
+ .requestAttestation(challenge)
+ .context("Failed to request attestation")?;
Ok(certificate)
}