[rkpvm] Implement RKP VM rollback protection in pvmfw

Bug: 313608221
Test: atest rialto_test
Change-Id: Iba3836cae1b2df16d0da69f80310ff0552961c95
diff --git a/pvmfw/Android.bp b/pvmfw/Android.bp
index d267e2e..a8494f8 100644
--- a/pvmfw/Android.bp
+++ b/pvmfw/Android.bp
@@ -26,6 +26,7 @@
         "libpvmfw_avb_nostd",
         "libpvmfw_embedded_key",
         "libpvmfw_fdt_template",
+        "libservice_vm_version",
         "libsmccc",
         "libstatic_assertions",
         "libtinyvec_nostd",
diff --git a/pvmfw/src/instance.rs b/pvmfw/src/instance.rs
index f2cd6a3..a998bfb 100644
--- a/pvmfw/src/instance.rs
+++ b/pvmfw/src/instance.rs
@@ -141,6 +141,17 @@
             let decrypted = aead.open(&mut entry, payload).map_err(Error::FailedOpen)?;
 
             let body = EntryBody::read_from(decrypted).unwrap();
+            if dice_inputs.rkp_vm_marker {
+                // The RKP VM is allowed to run if it has passed the verified boot check and
+                // contains the expected version in its AVB footer.
+                // The comparison below with the previous boot information is skipped to enable the
+                // simultaneous update of the pvmfw and RKP VM.
+                // For instance, when both the pvmfw and RKP VM are updated, the code hash of the
+                // RKP VM will differ from the one stored in the instance image. In this case, the
+                // RKP VM is still allowed to run.
+                // This ensures that the updated RKP VM will retain the same CDIs in the next stage.
+                return Ok((false, body.salt));
+            }
             if body.code_hash != dice_inputs.code_hash {
                 Err(Error::RecordedCodeHashMismatch)
             } else if body.auth_hash != dice_inputs.auth_hash {
diff --git a/pvmfw/src/main.rs b/pvmfw/src/main.rs
index 8aa5274..1d55a84 100644
--- a/pvmfw/src/main.rs
+++ b/pvmfw/src/main.rs
@@ -115,6 +115,17 @@
 
     if verified_boot_data.has_capability(Capability::RemoteAttest) {
         info!("Service VM capable of remote attestation detected");
+        if service_vm_version::VERSION != verified_boot_data.rollback_index {
+            // For RKP VM, we only boot if the version in the AVB footer of its kernel matches
+            // the one embedded in pvmfw at build time.
+            // This prevents the pvmfw from booting a roll backed RKP VM.
+            error!(
+                "Service VM version mismatch: expected {}, found {}",
+                service_vm_version::VERSION,
+                verified_boot_data.rollback_index
+            );
+            return Err(RebootReason::InvalidPayload);
+        }
     }
 
     if verified_boot_data.has_capability(Capability::SecretkeeperProtection) {