Merge "Add back "compos_verify --instance pending""
diff --git a/microdroid/dice/service.rs b/microdroid/dice/service.rs
index 8cb5cc3..8199c7c 100644
--- a/microdroid/dice/service.rs
+++ b/microdroid/dice/service.rs
@@ -30,6 +30,7 @@
 use std::slice;
 use std::sync::Arc;
 
+const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
 const DICE_HAL_SERVICE_NAME: &str = "android.hardware.security.dice.IDiceDevice/default";
 
 /// Artifacts that are mapped into the process address space from the driver.
@@ -135,16 +136,19 @@
 
 #[derive(Clone, Serialize, Deserialize)]
 enum DriverArtifactManager {
+    Invalid,
     Driver(PathBuf),
     Updated(RawArtifacts),
 }
 
 impl DriverArtifactManager {
     fn new(driver_path: &Path) -> Self {
-        // TODO(218793274): fail if driver is missing in protected mode
         if driver_path.exists() {
             log::info!("Using DICE values from driver");
             Self::Driver(driver_path.to_path_buf())
+        } else if Path::new(AVF_STRICT_BOOT).exists() {
+            log::error!("Strict boot requires DICE value from driver but none were found");
+            Self::Invalid
         } else {
             log::warn!("Using sample DICE values");
             let (cdi_attest, cdi_seal, bcc) = diced_sample_inputs::make_sample_bcc_and_cdis()
@@ -164,11 +168,15 @@
         F: FnOnce(&dyn DiceArtifacts) -> Result<T>,
     {
         match self {
+            Self::Invalid => bail!("No DICE artifacts available."),
             Self::Driver(driver_path) => f(&MappedDriverArtifacts::new(driver_path.as_path())?),
             Self::Updated(raw_artifacts) => f(raw_artifacts),
         }
     }
     fn update(self, new_artifacts: &impl DiceArtifacts) -> Result<Self> {
+        if let Self::Invalid = self {
+            bail!("Cannot update invalid DICE artifacts.");
+        }
         if let Self::Driver(driver_path) = self {
             // Writing to the device wipes the artifcates. The string is ignored
             // by the driver but included for documentation.
diff --git a/microdroid_manager/src/main.rs b/microdroid_manager/src/main.rs
index b644285..9e159d2 100644
--- a/microdroid_manager/src/main.rs
+++ b/microdroid_manager/src/main.rs
@@ -61,6 +61,8 @@
 const DM_MOUNTED_APK_PATH: &str = "/dev/block/mapper/microdroid-apk";
 const APKDMVERITY_BIN: &str = "/system/bin/apkdmverity";
 const ZIPFUSE_BIN: &str = "/system/bin/zipfuse";
+const AVF_STRICT_BOOT: &str = "/sys/firmware/devicetree/base/chosen/avf,strict-boot";
+const AVF_NEW_INSTANCE: &str = "/sys/firmware/devicetree/base/chosen/avf,new-instance";
 
 /// The CID representing the host VM
 const VMADDR_CID_HOST: u32 = 2;
@@ -193,12 +195,35 @@
     Ok(())
 }
 
+fn is_strict_boot() -> bool {
+    Path::new(AVF_STRICT_BOOT).exists()
+}
+
+fn is_new_instance() -> bool {
+    Path::new(AVF_NEW_INSTANCE).exists()
+}
+
 fn try_run_payload(service: &Strong<dyn IVirtualMachineService>) -> Result<i32> {
     let metadata = load_metadata().context("Failed to load payload metadata")?;
 
     let mut instance = InstanceDisk::new().context("Failed to load instance.img")?;
     let saved_data = instance.read_microdroid_data().context("Failed to read identity data")?;
 
+    if is_strict_boot() {
+        // Provisioning must happen on the first boot and never again.
+        if is_new_instance() {
+            ensure!(
+                saved_data.is_none(),
+                MicrodroidError::InvalidConfig("Found instance data on first boot.".to_string())
+            );
+        } else {
+            ensure!(
+                saved_data.is_some(),
+                MicrodroidError::InvalidConfig("Instance data not found.".to_string())
+            );
+        };
+    }
+
     // Verify the payload before using it.
     let verified_data =
         verify_payload(&metadata, saved_data.as_ref()).context("Payload verification failed")?;