Merge "Update name of hwtrust subcommand" into main
diff --git a/apex/virtualizationservice.rc b/apex/virtualizationservice.rc
index be90904..8283594 100644
--- a/apex/virtualizationservice.rc
+++ b/apex/virtualizationservice.rc
@@ -22,7 +22,7 @@
service vfio_handler /apex/com.android.virt/bin/vfio_handler
user root
- group root
+ group system
interface aidl android.system.virtualizationservice_internal.IVfioHandler
disabled
oneshot
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index 8a31c21..526f240 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -2,6 +2,17 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
+android_app_certificate {
+ name: "MicrodroidTestAppCert",
+
+ // The default app cert is the same as the default platform cert
+ // (on a test-keys build), which means we end up getting assigned
+ // the permissions via signature and can't reliably disclaim
+ // them. So instead we use our own custom cert. See b/290582742.
+ // Created via: development/tools/make_key microdroid_test_app '/CN=microdroid_test_app'
+ certificate: "microdroid_test_app",
+}
+
java_defaults {
name: "MicrodroidTestAppsDefaults",
test_suites: [
@@ -12,6 +23,7 @@
"com.android.microdroid.testservice-java",
"com.android.microdroid.test.vmshare_service-java",
],
+ certificate: ":MicrodroidTestAppCert",
sdk_version: "test_current",
jni_uses_platform_apis: true,
use_embedded_native_libs: true,
diff --git a/tests/testapk/microdroid_test_app.pk8 b/tests/testapk/microdroid_test_app.pk8
new file mode 100644
index 0000000..dc012bd
--- /dev/null
+++ b/tests/testapk/microdroid_test_app.pk8
Binary files differ
diff --git a/tests/testapk/microdroid_test_app.x509.pem b/tests/testapk/microdroid_test_app.x509.pem
new file mode 100644
index 0000000..9a0309c
--- /dev/null
+++ b/tests/testapk/microdroid_test_app.x509.pem
@@ -0,0 +1,19 @@
+-----BEGIN CERTIFICATE-----
+MIIDHzCCAgegAwIBAgIUNnOI4tOMieX67OtyD+6BjTsLm0IwDQYJKoZIhvcNAQEL
+BQAwHjEcMBoGA1UEAwwTbWljcm9kcm9pZF90ZXN0X2FwcDAgFw0yMzA4MTgxNDA4
+MDZaGA8yMDUxMDEwMzE0MDgwNlowHjEcMBoGA1UEAwwTbWljcm9kcm9pZF90ZXN0
+X2FwcDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK7B9xDTD2kS4xFQ
+gwQThRqnxKzOmckYqv2XznXq7tCuhU+RgXDrub7Aiq+QgA25Ouw8ORM5FkZAxD6j
+hCRSVo8cyXdNfPygRY/56umL6KqLMqB0tXLHPst3Lh8fl2su2S+jWL71lUwdOBmu
+nBIa1UqxI9PChR/uIqGyDxNRlUnqOA5/FgyX95P9wj8zmXEFe5No8rL/9hjpBvw1
+cOJCH4hea6JKDA15XYxDaTyj5pkmGb228ZbQb10XwOIhtS94CVxIvqmREzZHL7b0
+cjzCwFDDF6sQoVDi71eFYSWInxSNErDU6wv5h2t6+PV+9mGwTi/AJuxTmevSUoAp
+tGwq0NMCAwEAAaNTMFEwHQYDVR0OBBYEFI2m/0SoaNew99YPQlo6oYPJfh7lMB8G
+A1UdIwQYMBaAFI2m/0SoaNew99YPQlo6oYPJfh7lMA8GA1UdEwEB/wQFMAMBAf8w
+DQYJKoZIhvcNAQELBQADggEBABxIQ66ACIrSnDCiI/DqdPPwHf4vva2Y0bVJ5tXN
+ufFQN0Hr4UnttDzWPtfZHQTnrA478b9Z/g4Y0qg/tj2g5oZP50coF9a39mPe6v2k
+vazkMp2H/+ilG4c8L6QsC7UKXn7Lxxznn3ijlh1lYVJ3E6nMibGRKrfaVFpEwtvy
+zT0K8eK9KUZIyG5nf1v8On4Vfu7MnavuxNubKoUhfu0B8hSd5JKiGDuUkSk3MiFX
+uctYmJZEUD1xLI787SzqrhuYMGfuwmrrI0N46yvUgRgxpkVj2s6GNWqRD3F/fOG+
+qFbeenHjFoMJN9HIAZaz4OqzgGfhfMf596rn+HPAJnRMtsI=
+-----END CERTIFICATE-----
diff --git a/tests/testapk/test.keystore b/tests/testapk/test.keystore
deleted file mode 100644
index 2946641..0000000
--- a/tests/testapk/test.keystore
+++ /dev/null
Binary files differ
diff --git a/virtualizationservice/vfio_handler/Android.bp b/virtualizationservice/vfio_handler/Android.bp
index 9ed17f2..66662d5 100644
--- a/virtualizationservice/vfio_handler/Android.bp
+++ b/virtualizationservice/vfio_handler/Android.bp
@@ -27,6 +27,8 @@
"liblazy_static",
"liblog_rust",
"libnix",
+ "librustutils",
+ "libzerocopy",
],
apex_available: ["com.android.virt"],
}
diff --git a/virtualizationservice/vfio_handler/src/aidl.rs b/virtualizationservice/vfio_handler/src/aidl.rs
index a826c75..15acfb8 100644
--- a/virtualizationservice/vfio_handler/src/aidl.rs
+++ b/virtualizationservice/vfio_handler/src/aidl.rs
@@ -19,9 +19,15 @@
use android_system_virtualizationservice_internal::binder::ParcelFileDescriptor;
use binder::{self, ExceptionCode, Interface, IntoBinderResult};
use lazy_static::lazy_static;
-use std::fs::{read_link, write};
-use std::io::Write;
-use std::path::Path;
+use std::fs::{read_link, write, File};
+use std::io::{Read, Seek, SeekFrom, Write};
+use std::mem::size_of;
+use std::path::{Path, PathBuf};
+use rustutils::system_properties;
+use zerocopy::{
+ byteorder::{BigEndian, U32},
+ FromBytes,
+};
#[derive(Debug, Default)]
pub struct VfioHandler {}
@@ -45,18 +51,10 @@
return Err(anyhow!("VFIO-platform not supported"))
.or_binder_exception(ExceptionCode::UNSUPPORTED_OPERATION);
}
-
devices.iter().try_for_each(|x| bind_device(Path::new(x)))?;
- let mut dtbo = dtbo
- .as_ref()
- .try_clone()
- .context("Failed to clone File from ParcelFileDescriptor")
- .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?;
- // TODO(b/291191362): write DTBO for devices to dtbo.
- dtbo.write(b"\n")
- .context("Can't write to ParcelFileDescriptor")
- .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?;
+ write_dtbo(dtbo)?;
+
Ok(())
}
}
@@ -65,13 +63,52 @@
const SYSFS_PLATFORM_DEVICES_PATH: &str = "/sys/devices/platform/";
const VFIO_PLATFORM_DRIVER_PATH: &str = "/sys/bus/platform/drivers/vfio-platform";
const SYSFS_PLATFORM_DRIVERS_PROBE_PATH: &str = "/sys/bus/platform/drivers_probe";
+const DT_TABLE_MAGIC: u32 = 0xd7b7ab1e;
-lazy_static! {
- static ref IS_VFIO_SUPPORTED: bool = is_vfio_supported();
+/// The structure of DT table header in dtbo.img.
+/// https://source.android.com/docs/core/architecture/dto/partitions
+#[repr(C)]
+#[derive(Debug, FromBytes)]
+struct DtTableHeader {
+ /// DT_TABLE_MAGIC
+ magic: U32<BigEndian>,
+ /// includes dt_table_header + all dt_table_entry and all dtb/dtbo
+ _total_size: U32<BigEndian>,
+ /// sizeof(dt_table_header)
+ header_size: U32<BigEndian>,
+ /// sizeof(dt_table_entry)
+ dt_entry_size: U32<BigEndian>,
+ /// number of dt_table_entry
+ dt_entry_count: U32<BigEndian>,
+ /// offset to the first dt_table_entry from head of dt_table_header
+ dt_entries_offset: U32<BigEndian>,
+ /// flash page size we assume
+ _page_size: U32<BigEndian>,
+ /// DTBO image version, the current version is 0. The version will be
+ /// incremented when the dt_table_header struct is updated.
+ _version: U32<BigEndian>,
}
-fn is_vfio_supported() -> bool {
- Path::new(DEV_VFIO_PATH).exists() && Path::new(VFIO_PLATFORM_DRIVER_PATH).exists()
+/// The structure of each DT table entry (v0) in dtbo.img.
+/// https://source.android.com/docs/core/architecture/dto/partitions
+#[repr(C)]
+#[derive(Debug, FromBytes)]
+struct DtTableEntry {
+ /// size of each DT
+ dt_size: U32<BigEndian>,
+ /// offset from head of dt_table_header
+ dt_offset: U32<BigEndian>,
+ /// optional, must be zero if unused
+ _id: U32<BigEndian>,
+ /// optional, must be zero if unused
+ _rev: U32<BigEndian>,
+ /// optional, must be zero if unused
+ _custom: [U32<BigEndian>; 4],
+}
+
+lazy_static! {
+ static ref IS_VFIO_SUPPORTED: bool =
+ Path::new(DEV_VFIO_PATH).exists() && Path::new(VFIO_PLATFORM_DRIVER_PATH).exists();
}
fn check_platform_device(path: &Path) -> binder::Result<()> {
@@ -158,3 +195,102 @@
check_platform_device(&path)?;
bind_vfio_driver(&path)
}
+
+fn get_dtbo_img_path() -> binder::Result<PathBuf> {
+ let slot_suffix = system_properties::read("ro.boot.slot_suffix")
+ .context("Failed to read ro.boot.slot_suffix")
+ .or_service_specific_exception(-1)?
+ .ok_or_else(|| anyhow!("slot_suffix is none"))
+ .or_service_specific_exception(-1)?;
+ Ok(PathBuf::from(format!("/dev/block/by-name/dtbo{slot_suffix}")))
+}
+
+fn read_values(file: &mut File, size: usize, offset: u64) -> binder::Result<Vec<u8>> {
+ file.seek(SeekFrom::Start(offset))
+ .context("Cannot seek the offset")
+ .or_service_specific_exception(-1)?;
+ let mut buffer = vec![0_u8; size];
+ file.read_exact(&mut buffer)
+ .context("Failed to read buffer")
+ .or_service_specific_exception(-1)?;
+ Ok(buffer)
+}
+
+fn get_dt_table_header(file: &mut File) -> binder::Result<DtTableHeader> {
+ let values = read_values(file, size_of::<DtTableHeader>(), 0)?;
+ let dt_table_header = DtTableHeader::read_from(values.as_slice())
+ .context("DtTableHeader is invalid")
+ .or_service_specific_exception(-1)?;
+ if dt_table_header.magic.get() != DT_TABLE_MAGIC
+ || dt_table_header.header_size.get() as usize != size_of::<DtTableHeader>()
+ {
+ return Err(anyhow!("DtTableHeader is invalid")).or_service_specific_exception(-1)?;
+ }
+ Ok(dt_table_header)
+}
+
+fn get_dt_table_entry(
+ file: &mut File,
+ header: &DtTableHeader,
+ index: u32,
+) -> binder::Result<DtTableEntry> {
+ if index >= header.dt_entry_count.get() {
+ return Err(anyhow!("Invalid dtbo index {index}")).or_service_specific_exception(-1)?;
+ }
+ let Some(prev_dt_entry_total_size) = header.dt_entry_size.get().checked_mul(index) else {
+ return Err(anyhow!("Unexpected arithmetic result"))
+ .or_binder_exception(ExceptionCode::ILLEGAL_STATE);
+ };
+ let Some(dt_entry_offset) =
+ prev_dt_entry_total_size.checked_add(header.dt_entries_offset.get())
+ else {
+ return Err(anyhow!("Unexpected arithmetic result"))
+ .or_binder_exception(ExceptionCode::ILLEGAL_STATE);
+ };
+ let values = read_values(file, size_of::<DtTableEntry>(), dt_entry_offset.into())?;
+ let dt_table_entry = DtTableEntry::read_from(values.as_slice())
+ .with_context(|| format!("DtTableEntry at index {index} is invalid."))
+ .or_service_specific_exception(-1)?;
+ Ok(dt_table_entry)
+}
+
+fn filter_dtbo_from_img(
+ dtbo_img_file: &mut File,
+ entry: &DtTableEntry,
+ dtbo_fd: &ParcelFileDescriptor,
+) -> binder::Result<()> {
+ let dt_size = entry
+ .dt_size
+ .get()
+ .try_into()
+ .context("Failed to convert type")
+ .or_binder_exception(ExceptionCode::ILLEGAL_STATE)?;
+ let buffer = read_values(dtbo_img_file, dt_size, entry.dt_offset.get().into())?;
+
+ let mut dtbo_fd = dtbo_fd
+ .as_ref()
+ .try_clone()
+ .context("Failed to clone File from ParcelFileDescriptor")
+ .or_binder_exception(ExceptionCode::BAD_PARCELABLE)?;
+
+ // TODO(b/296796644): Filter dtbo.img, not writing all information.
+ dtbo_fd
+ .write_all(&buffer)
+ .context("Failed to write dtbo file")
+ .or_service_specific_exception(-1)?;
+ Ok(())
+}
+
+fn write_dtbo(dtbo_fd: &ParcelFileDescriptor) -> binder::Result<()> {
+ let dtbo_path = get_dtbo_img_path()?;
+ let mut dtbo_img = File::open(dtbo_path)
+ .context("Failed to open DTBO partition")
+ .or_service_specific_exception(-1)?;
+
+ let dt_table_header = get_dt_table_header(&mut dtbo_img)?;
+ // TODO(b/296799016): Use vm_dtbo_idx from bootconfig.
+ let vm_dtbo_idx = 20;
+ let dt_table_entry = get_dt_table_entry(&mut dtbo_img, &dt_table_header, vm_dtbo_idx)?;
+ filter_dtbo_from_img(&mut dtbo_img, &dt_table_entry, dtbo_fd)?;
+ Ok(())
+}