Merge "Changes for rust 1.72" into main
diff --git a/OWNERS b/OWNERS
index 310add7..e560cec 100644
--- a/OWNERS
+++ b/OWNERS
@@ -12,16 +12,19 @@
 # Other owners
 alanstokes@google.com
 aliceywang@google.com
-ardb@google.com
-ascull@google.com
 inseob@google.com
+jaewan@google.com
+jakobvukalovic@google.com
 jeffv@google.com
 jooyung@google.com
-mzyngier@google.com
+keirf@google.com
 ptosi@google.com
 qperret@google.com
 qwandor@google.com
-serbanc@google.com
+sebastianene@google.com
+seungjaeyoo@google.com
 shikhapanwar@google.com
+smostafa@google.com
 tabba@google.com
+vdonnefort@google.com
 victorhsieh@google.com
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/compos/tests/java/android/compos/test/ComposTestCase.java b/compos/tests/java/android/compos/test/ComposTestCase.java
index 244d34e..4851321 100644
--- a/compos/tests/java/android/compos/test/ComposTestCase.java
+++ b/compos/tests/java/android/compos/test/ComposTestCase.java
@@ -192,7 +192,7 @@
                         .runTimedCmd(
                                 10000,
                                 validator.getAbsolutePath(),
-                                "verify-dice-chain",
+                                "dice-chain",
                                 bcc_file.getAbsolutePath());
         assertWithMessage("hwtrust failed").about(command_results()).that(result).isSuccess();
     }
diff --git a/docs/getting_started.md b/docs/getting_started.md
index d970c12..74f2012 100644
--- a/docs/getting_started.md
+++ b/docs/getting_started.md
@@ -99,7 +99,7 @@
 payload using the following command:
 
 ```shell
-package/modules/Virtualization/vm/vm_shell.sh start-microdroid --auto-connect -- --protected
+packages/modules/Virtualization/vm/vm_shell.sh start-microdroid --auto-connect -- --protected
 ```
 
 You will see the log messages like the below.
diff --git a/libs/libfdt/src/lib.rs b/libs/libfdt/src/lib.rs
index afc36d0..a305e03 100644
--- a/libs/libfdt/src/lib.rs
+++ b/libs/libfdt/src/lib.rs
@@ -16,8 +16,6 @@
 //! to a bare-metal environment.
 
 #![no_std]
-#![deny(unsafe_op_in_unsafe_fn)]
-#![deny(clippy::undocumented_unsafe_blocks)]
 
 mod iterators;
 
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index bbe00b5..1aa5935 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -7,8 +7,6 @@
     crate_name: "pvmfw",
     defaults: ["vmbase_ffi_defaults"],
     srcs: ["src/main.rs"],
-    // Require unsafe blocks for inside unsafe functions.
-    flags: ["-Dunsafe_op_in_unsafe_fn"],
     features: [
         "legacy",
     ],
diff --git a/pvmfw/avb/Android.bp b/pvmfw/avb/Android.bp
index 49c4717..4efee6a 100644
--- a/pvmfw/avb/Android.bp
+++ b/pvmfw/avb/Android.bp
@@ -7,8 +7,6 @@
     crate_name: "pvmfw_avb",
     srcs: ["src/lib.rs"],
     prefer_rlib: true,
-    // Require unsafe blocks for inside unsafe functions.
-    flags: ["-Dunsafe_op_in_unsafe_fn"],
     rustlibs: [
         "libavb_bindgen_nostd",
         "libtinyvec_nostd",
diff --git a/pvmfw/src/dice.rs b/pvmfw/src/dice.rs
index 28271d3..9542429 100644
--- a/pvmfw/src/dice.rs
+++ b/pvmfw/src/dice.rs
@@ -18,8 +18,8 @@
 use core::mem::size_of;
 use core::slice;
 use diced_open_dice::{
-    bcc_format_config_descriptor, bcc_handover_main_flow, hash, Config, DiceMode, Hash,
-    InputValues, HIDDEN_SIZE,
+    bcc_format_config_descriptor, bcc_handover_main_flow, hash, Config, DiceConfigValues, DiceMode,
+    Hash, InputValues, HIDDEN_SIZE,
 };
 use pvmfw_avb::{DebugLevel, Digest, VerifiedBootData};
 use vmbase::cstr;
@@ -63,12 +63,10 @@
         next_bcc: &mut [u8],
     ) -> diced_open_dice::Result<()> {
         let mut config_descriptor_buffer = [0; 128];
-        let config_descriptor_size = bcc_format_config_descriptor(
-            Some(cstr!("vm_entry")),
-            None,  // component_version
-            false, // resettable
-            &mut config_descriptor_buffer,
-        )?;
+        let config_values =
+            DiceConfigValues { component_name: Some(cstr!("vm_entry")), ..Default::default() };
+        let config_descriptor_size =
+            bcc_format_config_descriptor(&config_values, &mut config_descriptor_buffer)?;
         let config = &config_descriptor_buffer[..config_descriptor_size];
 
         let dice_inputs = InputValues::new(
diff --git a/pvmfw/src/memory.rs b/pvmfw/src/memory.rs
index 27ab719..06158dd 100644
--- a/pvmfw/src/memory.rs
+++ b/pvmfw/src/memory.rs
@@ -14,8 +14,6 @@
 
 //! Low-level allocation and tracking of main memory.
 
-#![deny(unsafe_op_in_unsafe_fn)]
-
 use crate::helpers::PVMFW_PAGE_SIZE;
 use aarch64_paging::paging::VirtualAddress;
 use aarch64_paging::MapError;
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..bb9faf1 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,109 @@
     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)?;
+    let vm_dtbo_idx = system_properties::read("ro.boot.hypervisor.vm_dtbo_idx")
+        .context("Failed to read vm_dtbo_idx")
+        .or_service_specific_exception(-1)?
+        .ok_or_else(|| anyhow!("vm_dtbo_idx is none"))
+        .or_service_specific_exception(-1)?;
+    let vm_dtbo_idx = vm_dtbo_idx
+        .parse()
+        .context("vm_dtbo_idx is not an integer")
+        .or_service_specific_exception(-1)?;
+    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(())
+}
diff --git a/vm_payload/Android.bp b/vm_payload/Android.bp
index ae0d1a6..49b7f5f 100644
--- a/vm_payload/Android.bp
+++ b/vm_payload/Android.bp
@@ -10,8 +10,6 @@
     srcs: ["src/*.rs"],
     include_dirs: ["include"],
     prefer_rlib: true,
-    // Require unsafe blocks for inside unsafe functions.
-    flags: ["-Dunsafe_op_in_unsafe_fn"],
     rustlibs: [
         "android.system.virtualization.payload-rust",
         "libandroid_logger",
diff --git a/vmbase/example/src/main.rs b/vmbase/example/src/main.rs
index a6f3bfa..ebd981c 100644
--- a/vmbase/example/src/main.rs
+++ b/vmbase/example/src/main.rs
@@ -16,8 +16,6 @@
 
 #![no_main]
 #![no_std]
-#![deny(unsafe_op_in_unsafe_fn)]
-#![deny(clippy::undocumented_unsafe_blocks)]
 
 mod exceptions;
 mod layout;
diff --git a/vmbase/src/lib.rs b/vmbase/src/lib.rs
index ca8756d..431e899 100644
--- a/vmbase/src/lib.rs
+++ b/vmbase/src/lib.rs
@@ -15,8 +15,6 @@
 //! Basic functionality for bare-metal binaries to run in a VM under crosvm.
 
 #![no_std]
-#![deny(unsafe_op_in_unsafe_fn)]
-#![deny(clippy::undocumented_unsafe_blocks)]
 
 extern crate alloc;