[service-vm] Start a bare-metal service VM from a client app
This cl mainly sets up the general pipeline to trigger the
bare-metal VM from a client app. The real implementation of the
API will be adjusted in the future.
Test: Runs the RkpvmClientApp in VM
Bug: 241428822
Change-Id: I92cef7033db9a2d8cf4ad1fec22fee8c93b1cef6
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index f7202da..6b39ff9 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -28,6 +28,7 @@
"libandroid_logger",
"libanyhow",
"libbinder_rs",
+ "libvmclient",
"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 5422a48..cc59b3f 100644
--- a/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
+++ b/virtualizationservice/aidl/android/system/virtualizationservice_internal/IVirtualizationServiceInternal.aidl
@@ -49,4 +49,14 @@
/** Get a list of all currently running VMs. */
VirtualMachineDebugInfo[] debugListVms();
+
+ /**
+ * Requests a certificate using the provided certificate signing request (CSR).
+ *
+ * @param csr the certificate signing request.
+ * @param instanceImgFd The file descriptor of the instance image. The file should be open for
+ * both reading and writing.
+ * @return the X.509 encoded certificate.
+ */
+ byte[] requestCertificate(in byte[] csr, in ParcelFileDescriptor instanceImgFd);
}
diff --git a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
index 3fdb48a..7b90714 100644
--- a/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
+++ b/virtualizationservice/aidl/android/system/virtualmachineservice/IVirtualMachineService.aidl
@@ -44,4 +44,12 @@
* Notifies that an error has occurred inside the VM.
*/
void notifyError(ErrorCode errorCode, in String message);
+
+ /**
+ * Requests a certificate using the provided certificate signing request (CSR).
+ *
+ * @param csr the certificate signing request.
+ * @return the X.509 encoded certificate.
+ */
+ byte[] requestCertificate(in byte[] csr);
}
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 3888df2..5c5a7e4 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -16,8 +16,12 @@
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 android_os_permissions_aidl::aidl::android::os::IPermissionController;
-use android_system_virtualizationservice::aidl::android::system::virtualizationservice::VirtualMachineDebugInfo::VirtualMachineDebugInfo;
+use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::VirtualMachineDebugInfo::VirtualMachineDebugInfo,
+ binder::ParcelFileDescriptor,
+};
use android_system_virtualizationservice_internal::aidl::android::system::virtualizationservice_internal::{
AtomVmBooted::AtomVmBooted,
AtomVmCreationRequested::AtomVmCreationRequested,
@@ -153,6 +157,19 @@
.collect();
Ok(cids)
}
+
+ fn requestCertificate(
+ &self,
+ csr: &[u8],
+ instance_img_fd: &ParcelFileDescriptor,
+ ) -> binder::Result<Vec<u8>> {
+ check_manage_access()?;
+ info!("Received csr. Getting certificate...");
+ request_certificate(csr, instance_img_fd).map_err(|e| {
+ error!("Failed to get certificate. Error: {e:?}");
+ Status::new_exception_str(ExceptionCode::SERVICE_SPECIFIC, Some(e.to_string()))
+ })
+ }
}
#[derive(Debug, Default)]
diff --git a/virtualizationservice/src/main.rs b/virtualizationservice/src/main.rs
index 64ccb13..bf8b944 100644
--- a/virtualizationservice/src/main.rs
+++ b/virtualizationservice/src/main.rs
@@ -16,6 +16,7 @@
mod aidl;
mod atom;
+mod rkpvm;
use crate::aidl::{
remove_temporary_dir, BINDER_SERVICE_IDENTIFIER, TEMPORARY_DIRECTORY,
diff --git a/virtualizationservice/src/rkpvm.rs b/virtualizationservice/src/rkpvm.rs
new file mode 100644
index 0000000..a4649f6
--- /dev/null
+++ b/virtualizationservice/src/rkpvm.rs
@@ -0,0 +1,95 @@
+// Copyright 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.
+
+//! Handles the RKP (Remote Key Provisioning) VM and host communication.
+//! The RKP VM will be recognized and attested by the RKP server periodically and
+//! serves as a trusted platform to attest a client VM.
+
+use android_system_virtualizationservice::{
+ aidl::android::system::virtualizationservice::{
+ CpuTopology::CpuTopology, DiskImage::DiskImage, Partition::Partition,
+ PartitionType::PartitionType, VirtualMachineConfig::VirtualMachineConfig,
+ VirtualMachineRawConfig::VirtualMachineRawConfig,
+ },
+ binder::{ParcelFileDescriptor, ProcessState},
+};
+use anyhow::{anyhow, Context, Result};
+use log::info;
+use std::fs::File;
+use std::time::Duration;
+use vmclient::VmInstance;
+
+const RIALTO_PATH: &str = "/apex/com.android.virt/etc/rialto.bin";
+
+pub(crate) fn request_certificate(
+ csr: &[u8],
+ instance_img_fd: &ParcelFileDescriptor,
+) -> Result<Vec<u8>> {
+ // We need to start the thread pool for Binder to work properly, especially link_to_death.
+ ProcessState::start_thread_pool();
+
+ let virtmgr = vmclient::VirtualizationService::new().context("Failed to spawn virtmgr")?;
+ let service = virtmgr.connect().context("virtmgr failed to connect")?;
+ info!("service_vm: Connected to VirtualizationService");
+ // TODO(b/272226230): Either turn rialto into the service VM or use an empty payload here.
+ // If using an empty payload, the service code will be part of pvmfw.
+ let rialto = File::open(RIALTO_PATH).context("Failed to open Rialto kernel binary")?;
+
+ // TODO(b/272226230): Initialize the partition from virtualization manager.
+ const INSTANCE_IMG_SIZE_BYTES: i64 = 1 << 20; // 1MB
+ service
+ .initializeWritablePartition(
+ instance_img_fd,
+ INSTANCE_IMG_SIZE_BYTES,
+ PartitionType::ANDROID_VM_INSTANCE,
+ )
+ .context("Failed to initialize instange.img")?;
+ let instance_img =
+ instance_img_fd.as_ref().try_clone().context("Failed to clone instance.img")?;
+ let instance_img = ParcelFileDescriptor::new(instance_img);
+ let writable_partitions = vec![Partition {
+ label: "vm-instance".to_owned(),
+ image: Some(instance_img),
+ writable: true,
+ }];
+ info!("service_vm: Finished initializing instance.img...");
+
+ let config = VirtualMachineConfig::RawConfig(VirtualMachineRawConfig {
+ name: String::from("Service VM"),
+ kernel: None,
+ initrd: None,
+ params: None,
+ bootloader: Some(ParcelFileDescriptor::new(rialto)),
+ disks: vec![DiskImage { image: None, partitions: writable_partitions, writable: true }],
+ protectedVm: true,
+ memoryMib: 300,
+ cpuTopology: CpuTopology::ONE_CPU,
+ platformVersion: "~1.0".to_string(),
+ taskProfiles: vec![],
+ gdbPort: 0, // No gdb
+ });
+ let vm = VmInstance::create(service.as_ref(), &config, None, None, None)
+ .context("Failed to create service VM")?;
+
+ info!("service_vm: Starting Service VM...");
+ vm.start().context("Failed to start service VM")?;
+
+ // TODO(b/274441673): The host can send the CSR to the RKP VM for attestation.
+ // Wait for VM to finish.
+ vm.wait_for_death_with_timeout(Duration::from_secs(10))
+ .ok_or_else(|| anyhow!("Timed out waiting for VM exit"))?;
+
+ info!("service_vm: Finished getting the certificate");
+ Ok([b"Return: ", csr].concat())
+}