[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) {
diff --git a/rialto/Android.bp b/rialto/Android.bp
index bbb5e54..5e7fe1f 100644
--- a/rialto/Android.bp
+++ b/rialto/Android.bp
@@ -63,6 +63,28 @@
srcs: [":avb_testkey_rsa4096"],
}
+// Both SERVICE_VM_VERSION and SERVICE_VM_VERSION_STRING should represent the
+// same version number for the service VM.
+SERVICE_VM_VERSION = 1
+SERVICE_VM_VERSION_STRING = "1"
+
+genrule {
+ name: "service_vm_version_rs",
+ out: ["lib.rs"],
+ cmd: "(" +
+ " echo '#![no_std]';" +
+ " echo '#![allow(missing_docs)]';" +
+ " echo 'pub const VERSION: u64 = " + SERVICE_VM_VERSION_STRING + ";'" +
+ ") > $(out)",
+}
+
+rust_library_rlib {
+ name: "libservice_vm_version",
+ crate_name: "service_vm_version",
+ defaults: ["vmbase_rlib_defaults"],
+ srcs: [":service_vm_version_rs"],
+}
+
avb_add_hash_footer {
name: "rialto_signed",
src: ":empty_file",
@@ -70,6 +92,7 @@
partition_name: "boot",
private_key: ":rialto_sign_key",
salt: rialto_salt,
+ rollback_index: SERVICE_VM_VERSION,
props: [
{
name: "com.android.virt.cap",