virtmgr: fix /system/[system_ext/product] path rebase am: 78dd87a809 am: ace4187864

Original change: https://android-review.googlesource.com/c/platform/packages/modules/Virtualization/+/3490888

Change-Id: Id6f71404f41ad183301455ba69642f58f55a3b9c
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
diff --git a/android/virtmgr/src/aidl.rs b/android/virtmgr/src/aidl.rs
index 5a52921..b5cf643 100644
--- a/android/virtmgr/src/aidl.rs
+++ b/android/virtmgr/src/aidl.rs
@@ -523,17 +523,7 @@
                     .or_service_specific_exception(-1)
             }
         };
-        let expected_exe_path = Path::new(&early_vm.path);
-        if expected_exe_path != calling_exe_path
-            && Path::new("/system").join(expected_exe_path) != calling_exe_path
-        {
-            return Err(anyhow!(
-                "VM '{name}' in partition '{calling_partition}' must be created with '{}', not '{}'",
-                &early_vm.path,
-                calling_exe_path.display()
-            ))
-            .or_service_specific_exception(-1);
-        }
+        early_vm.check_exe_paths_match(calling_exe_path)?;
 
         let cid = early_vm.cid as Cid;
         let temp_dir = PathBuf::from(format!("/mnt/vm/early/{cid}"));
@@ -2315,6 +2305,29 @@
     early_vm: Vec<EarlyVm>,
 }
 
+impl EarlyVm {
+    /// Verifies that the provided executable path matches the expected path stored in the XML
+    /// configuration.
+    /// If the provided path starts with `/system`, it will be stripped before comparison.
+    fn check_exe_paths_match<P: AsRef<Path>>(&self, calling_exe_path: P) -> binder::Result<()> {
+        let actual_path = calling_exe_path.as_ref();
+        if Path::new(&self.path)
+            == Path::new("/").join(actual_path.strip_prefix("/system").unwrap_or(actual_path))
+        {
+            return Ok(());
+        }
+        Err(Status::new_service_specific_error_str(
+            -1,
+            Some(format!(
+                "Early VM '{}' executable paths do not match. Expected: {}. Found: {:?}.",
+                self.name,
+                self.path,
+                actual_path.display()
+            )),
+        ))
+    }
+}
+
 static EARLY_VMS_CACHE: LazyLock<Mutex<HashMap<CallingPartition, Vec<EarlyVm>>>> =
     LazyLock::new(|| Mutex::new(HashMap::new()));
 
@@ -2743,6 +2756,39 @@
     }
 
     #[test]
+    fn early_vm_exe_paths_match_succeeds_with_same_paths() {
+        let early_vm = EarlyVm {
+            name: "vm_demo_native_early".to_owned(),
+            cid: 123,
+            path: "/system_ext/bin/vm_demo_native_early".to_owned(),
+        };
+        let calling_exe_path = "/system_ext/bin/vm_demo_native_early";
+        assert!(early_vm.check_exe_paths_match(calling_exe_path).is_ok())
+    }
+
+    #[test]
+    fn early_vm_exe_paths_match_succeeds_with_calling_exe_path_from_system() {
+        let early_vm = EarlyVm {
+            name: "vm_demo_native_early".to_owned(),
+            cid: 123,
+            path: "/system_ext/bin/vm_demo_native_early".to_owned(),
+        };
+        let calling_exe_path = "/system/system_ext/bin/vm_demo_native_early";
+        assert!(early_vm.check_exe_paths_match(calling_exe_path).is_ok())
+    }
+
+    #[test]
+    fn early_vm_exe_paths_match_fails_with_unmatched_paths() {
+        let early_vm = EarlyVm {
+            name: "vm_demo_native_early".to_owned(),
+            cid: 123,
+            path: "/system_ext/bin/vm_demo_native_early".to_owned(),
+        };
+        let calling_exe_path = "/system/etc/system_ext/bin/vm_demo_native_early";
+        assert!(early_vm.check_exe_paths_match(calling_exe_path).is_err())
+    }
+
+    #[test]
     fn test_duplicated_early_vms() -> Result<()> {
         let tmp_dir = tempfile::TempDir::new()?;
         let tmp_dir_path = tmp_dir.path().to_owned();