Merge "Split vm_identifier of Compos into ComposComposd and ComposVerify"
diff --git a/authfs/service/authfs_service.rc b/authfs/service/authfs_service.rc
index 409e91c..bc67c83 100644
--- a/authfs/service/authfs_service.rc
+++ b/authfs/service/authfs_service.rc
@@ -3,3 +3,4 @@
     socket authfs_service stream 0666 root system
     # SYS_ADMIN capability allows to mount FUSE filesystem
     capabilities SYS_ADMIN
+    user root
diff --git a/authfs/tests/benchmarks/Android.bp b/authfs/tests/benchmarks/Android.bp
index 38ece79..b30ecdd 100644
--- a/authfs/tests/benchmarks/Android.bp
+++ b/authfs/tests/benchmarks/Android.bp
@@ -24,6 +24,7 @@
         ":CtsApkVerityTestPrebuiltFiles",
         ":MicrodroidTestApp",
     ],
+    required: ["MicrodroidTestPreparer"],
 }
 
 cc_binary {
diff --git a/compos/benchmark/Android.bp b/compos/benchmark/Android.bp
index 12b3ae8..dc0c01c 100644
--- a/compos/benchmark/Android.bp
+++ b/compos/benchmark/Android.bp
@@ -18,4 +18,6 @@
     sdk_version: "test_current",
     use_embedded_native_libs: true,
     compile_multilib: "64",
+
+    host_required: ["MicrodroidTestPreparer"],
 }
diff --git a/microdroid_manager/microdroid_manager.rc b/microdroid_manager/microdroid_manager.rc
index 97d14b5..e257547 100644
--- a/microdroid_manager/microdroid_manager.rc
+++ b/microdroid_manager/microdroid_manager.rc
@@ -11,4 +11,5 @@
     # CAP_SETCAP is required to allow microdroid_manager to drop capabilities
     #   before executing the payload
     capabilities AUDIT_CONTROL SYS_ADMIN SYS_BOOT SETPCAP
+    user root
     socket vm_payload_service stream 0666 system system
diff --git a/pvmfw/src/debug_policy.rs b/pvmfw/src/debug_policy.rs
deleted file mode 100644
index bbf7e04..0000000
--- a/pvmfw/src/debug_policy.rs
+++ /dev/null
@@ -1,78 +0,0 @@
-// 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.
-
-//! Support for the debug policy overlay in pvmfw
-
-use core::fmt;
-use libfdt::FdtError;
-
-#[derive(Debug, Clone)]
-pub enum DebugPolicyError {
-    /// The provided baseline FDT was invalid or malformed, so cannot access certain node/prop
-    Fdt(&'static str, FdtError),
-    /// The provided debug policy FDT was invalid or malformed.
-    DebugPolicyFdt(&'static str, FdtError),
-    /// The overlaid result FDT is invalid or malformed, and may be corrupted.
-    OverlaidFdt(&'static str, FdtError),
-}
-
-impl fmt::Display for DebugPolicyError {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        match self {
-            Self::Fdt(s, e) => write!(f, "Invalid baseline FDT. {s}: {e}"),
-            Self::DebugPolicyFdt(s, e) => write!(f, "Invalid overlay FDT. {s}: {e}"),
-            Self::OverlaidFdt(s, e) => write!(f, "Invalid overlaid FDT. {s}: {e}"),
-        }
-    }
-}
-
-/// Applies the debug policy device tree overlay to the pVM DT.
-///
-/// # Safety
-///
-/// When an error is returned by this function, the input `Fdt` should be
-/// discarded as it may have have been partially corrupted during the overlay
-/// application process.
-unsafe fn apply_debug_policy(
-    fdt: &mut libfdt::Fdt,
-    debug_policy: &mut [u8],
-) -> Result<(), DebugPolicyError> {
-    let overlay = libfdt::Fdt::from_mut_slice(debug_policy)
-        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to load debug policy overlay", e))?;
-
-    fdt.unpack().map_err(|e| DebugPolicyError::Fdt("Failed to unpack", e))?;
-
-    let fdt = fdt
-        .apply_overlay(overlay)
-        .map_err(|e| DebugPolicyError::DebugPolicyFdt("Failed to apply overlay", e))?;
-
-    fdt.pack().map_err(|e| DebugPolicyError::OverlaidFdt("Failed to re-pack", e))
-}
-
-/// Handles debug policies.
-///
-/// # Safety
-///
-/// This may corrupt the input `Fdt` when overlaying debug policy or applying
-/// ramdump configuration.
-pub unsafe fn handle_debug_policy(
-    fdt: &mut libfdt::Fdt,
-    debug_policy: Option<&mut [u8]>,
-) -> Result<(), DebugPolicyError> {
-    if let Some(dp) = debug_policy {
-        apply_debug_policy(fdt, dp)?;
-    }
-
-    Ok(())
-}
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index ffbc4a8..00f0e9b 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -16,7 +16,6 @@
 
 use crate::config;
 use crate::crypto;
-use crate::debug_policy::{handle_debug_policy, DebugPolicyError};
 use crate::fdt;
 use crate::heap;
 use crate::helpers;
@@ -54,16 +53,6 @@
     SecretDerivationError,
 }
 
-impl From<DebugPolicyError> for RebootReason {
-    fn from(error: DebugPolicyError) -> Self {
-        match error {
-            DebugPolicyError::Fdt(_, _) => RebootReason::InvalidFdt,
-            DebugPolicyError::DebugPolicyFdt(_, _) => RebootReason::InvalidConfig,
-            DebugPolicyError::OverlaidFdt(_, _) => RebootReason::InternalError,
-        }
-    }
-}
-
 main!(start);
 
 /// Entry point for pVM firmware.
@@ -237,19 +226,11 @@
     })?;
 
     // This wrapper allows main() to be blissfully ignorant of platform details.
-    crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, &mut memory)?;
+    crate::main(slices.fdt, slices.kernel, slices.ramdisk, bcc_slice, debug_policy, &mut memory)?;
 
     helpers::flushed_zeroize(bcc_slice);
     helpers::flush(slices.fdt.as_slice());
 
-    // SAFETY - As we `?` the result, there is no risk of using a bad `slices.fdt`.
-    unsafe {
-        handle_debug_policy(slices.fdt, debug_policy).map_err(|e| {
-            error!("Unexpected error when handling debug policy: {e:?}");
-            RebootReason::from(e)
-        })?;
-    }
-
     info!("Expecting a bug making MMIO_GUARD_UNMAP return NOT_SUPPORTED on success");
     memory.mmio_unmap_all().map_err(|e| {
         error!("Failed to unshare MMIO ranges: {e}");
diff --git a/pvmfw/src/fdt.rs b/pvmfw/src/fdt.rs
index 7d88455..d15eaba 100644
--- a/pvmfw/src/fdt.rs
+++ b/pvmfw/src/fdt.rs
@@ -22,6 +22,7 @@
 use crate::memory::MAX_ADDR;
 use crate::RebootReason;
 use alloc::ffi::CString;
+use alloc::vec::Vec;
 use core::cmp::max;
 use core::cmp::min;
 use core::ffi::CStr;
@@ -36,6 +37,7 @@
 use libfdt::FdtNode;
 use log::debug;
 use log::error;
+use log::info;
 use tinyvec::ArrayVec;
 
 /// Extract from /config the address range containing the pre-loaded kernel. Absence of /config is
@@ -672,6 +674,7 @@
     bcc: &[u8],
     new_instance: bool,
     strict_boot: bool,
+    debug_policy: Option<&mut [u8]>,
 ) -> libfdt::Result<()> {
     fdt.unpack()?;
 
@@ -680,6 +683,13 @@
     set_or_clear_chosen_flag(fdt, cstr!("avf,strict-boot"), strict_boot)?;
     set_or_clear_chosen_flag(fdt, cstr!("avf,new-instance"), new_instance)?;
 
+    if let Some(debug_policy) = debug_policy {
+        apply_debug_policy(fdt, debug_policy)?;
+        info!("Debug policy applied.");
+    } else {
+        info!("No debug policy found.");
+    }
+
     fdt.pack()?;
 
     Ok(())
@@ -712,3 +722,26 @@
 
     Ok(())
 }
+
+fn apply_debug_policy(fdt: &mut Fdt, debug_policy: &mut [u8]) -> libfdt::Result<()> {
+    let backup_fdt = Vec::from(fdt.as_slice());
+
+    let overlay = match Fdt::from_mut_slice(debug_policy) {
+        Ok(overlay) => overlay,
+        Err(e) => {
+            info!("Corrupted debug policy found: {e}. Not applying.");
+            return Ok(());
+        }
+    };
+    let backup_overlay = Vec::from(overlay.as_slice());
+
+    // SAFETY - on failure, the corrupted fdts are discarded and are restored using the backups.
+    if let Err(e) = unsafe { fdt.apply_overlay(overlay) } {
+        error!("Failed to apply debug policy: {e}. Recovering...");
+        fdt.copy_from_slice(backup_fdt.as_slice())?;
+        overlay.copy_from_slice(backup_overlay.as_slice())?;
+        // A successful restoration is considered success because an invalid debug policy
+        // shouldn't DOS the pvmfw
+    }
+    Ok(())
+}
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 00ff61f..06cc81e 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -21,7 +21,6 @@
 
 mod config;
 mod crypto;
-mod debug_policy;
 mod dice;
 mod entry;
 mod exceptions;
@@ -65,6 +64,7 @@
     signed_kernel: &[u8],
     ramdisk: Option<&[u8]>,
     current_bcc_handover: &[u8],
+    debug_policy: Option<&mut [u8]>,
     memory: &mut MemoryTracker,
 ) -> Result<(), RebootReason> {
     info!("pVM firmware");
@@ -122,7 +122,7 @@
     flush(next_bcc);
 
     let strict_boot = true;
-    modify_for_next_stage(fdt, next_bcc, new_instance, strict_boot).map_err(|e| {
+    modify_for_next_stage(fdt, next_bcc, new_instance, strict_boot, debug_policy).map_err(|e| {
         error!("Failed to configure device tree: {e}");
         RebootReason::InternalError
     })?;
diff --git a/tests/benchmark/Android.bp b/tests/benchmark/Android.bp
index dac4993..9c512bf 100644
--- a/tests/benchmark/Android.bp
+++ b/tests/benchmark/Android.bp
@@ -26,6 +26,7 @@
     sdk_version: "test_current",
     use_embedded_native_libs: true,
     compile_multilib: "64",
+    host_required: ["MicrodroidTestPreparer"],
 }
 
 cc_library_shared {
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index 248755f..c71a8ec 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -75,4 +75,5 @@
         "libsparse",
         "libz",
     ],
+    required: ["MicrodroidTestPreparer"],
 }
diff --git a/virtualizationmanager/src/atom.rs b/virtualizationmanager/src/atom.rs
index 02d46ec..d6eb141 100644
--- a/virtualizationmanager/src/atom.rs
+++ b/virtualizationmanager/src/atom.rs
@@ -93,6 +93,7 @@
 }
 
 /// Write the stats of VMCreation to statsd
+/// The function creates a separate thread which waits for statsd to start to push atom
 pub fn write_vm_creation_stats(
     config: &VirtualMachineConfig,
     is_protected: bool,
@@ -158,7 +159,7 @@
 }
 
 /// Write the stats of VM boot to statsd
-/// The function creates a separate thread which waits fro statsd to start to push atom
+/// The function creates a separate thread which waits for statsd to start to push atom
 pub fn write_vm_booted_stats(
     uid: i32,
     vm_identifier: &str,
@@ -182,8 +183,7 @@
 }
 
 /// Write the stats of VM exit to statsd
-/// The function creates a separate thread which waits fro statsd to start to push atom
-pub fn write_vm_exited_stats(
+pub fn write_vm_exited_stats_sync(
     uid: i32,
     vm_identifier: &str,
     reason: DeathReason,
@@ -207,9 +207,7 @@
     };
 
     info!("Writing VmExited atom into statsd.");
-    thread::spawn(move || {
-        GLOBAL_SERVICE.atomVmExited(&atom).unwrap_or_else(|e| {
-            warn!("Failed to write VmExited atom: {e}");
-        });
+    GLOBAL_SERVICE.atomVmExited(&atom).unwrap_or_else(|e| {
+        warn!("Failed to write VmExited atom: {e}");
     });
 }
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index a8cad94..60dd4cf 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -15,7 +15,7 @@
 //! Functions for running instances of `crosvm`.
 
 use crate::aidl::{remove_temporary_files, Cid, VirtualMachineCallbacks};
-use crate::atom::{get_num_cpus, write_vm_exited_stats};
+use crate::atom::{get_num_cpus, write_vm_exited_stats_sync};
 use crate::debug_config::DebugConfig;
 use anyhow::{anyhow, bail, Context, Error, Result};
 use command_fds::CommandFdExt;
@@ -381,7 +381,7 @@
         self.callbacks.callback_on_died(self.cid, death_reason);
 
         let vm_metric = self.vm_metric.lock().unwrap();
-        write_vm_exited_stats(
+        write_vm_exited_stats_sync(
             self.requester_uid as i32,
             &self.name,
             death_reason,