Don't allow vendor APEXes in Microdroid

A supported way for loading vendor code into Microdroid VMs is by
providing a read-only dm-verity protected disk image (e.g.
microdroid-vendor.img) as a separate virtio-blk device.

Bug: 286390834
Test: add vendor apex to vm_config_apex.json of test apk & try to run VM
Test: atest virtualizationmanager_device_test
Change-Id: Ie6528a67185fffd52fabbb4123747f5bcb8bab67
diff --git a/virtualizationmanager/src/payload.rs b/virtualizationmanager/src/payload.rs
index ab6f31c..343f3cf 100644
--- a/virtualizationmanager/src/payload.rs
+++ b/virtualizationmanager/src/payload.rs
@@ -81,6 +81,9 @@
 
     #[serde(rename = "provideSharedApexLibs")]
     provide_shared_apex_libs: bool,
+
+    #[serde(rename = "preinstalledModulePath")]
+    preinstalled_path: PathBuf,
 }
 
 impl ApexInfoList {
@@ -275,7 +278,7 @@
     let apex_list = pm.get_apex_list(vm_payload_config.prefer_staged)?;
 
     // collect APEXes from config
-    let mut apex_infos = collect_apex_infos(&apex_list, &vm_payload_config.apexes, debug_config);
+    let mut apex_infos = collect_apex_infos(&apex_list, &vm_payload_config.apexes, debug_config)?;
 
     // Pass sorted list of apexes. Sorting key shouldn't use `path` because it will change after
     // reboot with prefer_staged. `last_update_seconds` is added to distinguish "samegrade"
@@ -376,18 +379,28 @@
     Ok(apexes)
 }
 
+fn check_apexes_are_from_allowed_partitions(requested_apexes: &Vec<&ApexInfo>) -> Result<()> {
+    const ALLOWED_PARTITIONS: [&str; 2] = ["/system", "/system_ext"];
+    for apex in requested_apexes {
+        if !ALLOWED_PARTITIONS.iter().any(|p| apex.preinstalled_path.starts_with(p)) {
+            bail!("Non-system APEX {} is not supported in Microdroid", apex.name);
+        }
+    }
+    Ok(())
+}
+
 // Collect ApexInfos from VM config
 fn collect_apex_infos<'a>(
     apex_list: &'a ApexInfoList,
     apex_configs: &[ApexConfig],
     debug_config: &DebugConfig,
-) -> Vec<&'a ApexInfo> {
+) -> Result<Vec<&'a ApexInfo>> {
     let mut additional_apexes: Vec<&str> = MICRODROID_REQUIRED_APEXES.to_vec();
     if debug_config.should_include_debug_apexes() {
         additional_apexes.extend(MICRODROID_REQUIRED_APEXES_DEBUG.to_vec());
     }
 
-    apex_list
+    let apex_infos = apex_list
         .list
         .iter()
         .filter(|ai| {
@@ -395,7 +408,10 @@
                 || additional_apexes.iter().any(|name| name == &ai.name && ai.is_active)
                 || ai.provide_shared_apex_libs
         })
-        .collect()
+        .collect();
+
+    check_apexes_are_from_allowed_partitions(&apex_infos)?;
+    Ok(apex_infos)
 }
 
 pub fn add_microdroid_vendor_image(vendor_image: File, vm_config: &mut VirtualMachineRawConfig) {
@@ -488,13 +504,14 @@
     }
 
     #[test]
-    fn test_collect_apexes() {
+    fn test_collect_apexes() -> Result<()> {
         let apex_info_list = ApexInfoList {
             list: vec![
                 ApexInfo {
                     // 0
                     name: "com.android.adbd".to_string(),
                     path: PathBuf::from("adbd"),
+                    preinstalled_path: PathBuf::from("/system/adbd"),
                     has_classpath_jar: false,
                     last_update_seconds: 12345678,
                     is_factory: true,
@@ -505,6 +522,7 @@
                     // 1
                     name: "com.android.os.statsd".to_string(),
                     path: PathBuf::from("statsd"),
+                    preinstalled_path: PathBuf::from("/system/statsd"),
                     has_classpath_jar: false,
                     last_update_seconds: 12345678,
                     is_factory: true,
@@ -515,6 +533,7 @@
                     // 2
                     name: "com.android.os.statsd".to_string(),
                     path: PathBuf::from("statsd/updated"),
+                    preinstalled_path: PathBuf::from("/system/statsd"),
                     has_classpath_jar: false,
                     last_update_seconds: 12345678 + 1,
                     is_factory: false,
@@ -545,6 +564,7 @@
                     // 5
                     name: "has_classpath".to_string(),
                     path: PathBuf::from("has_classpath/updated"),
+                    preinstalled_path: PathBuf::from("/system/has_classpath"),
                     has_classpath_jar: true,
                     last_update_seconds: 87654321 + 1,
                     is_factory: false,
@@ -555,6 +575,7 @@
                     // 6
                     name: "apex-foo".to_string(),
                     path: PathBuf::from("apex-foo"),
+                    preinstalled_path: PathBuf::from("/system/apex-foo"),
                     has_classpath_jar: false,
                     last_update_seconds: 87654321,
                     is_factory: true,
@@ -565,6 +586,7 @@
                     // 7
                     name: "apex-foo".to_string(),
                     path: PathBuf::from("apex-foo/updated"),
+                    preinstalled_path: PathBuf::from("/system/apex-foo"),
                     has_classpath_jar: false,
                     last_update_seconds: 87654321 + 1,
                     is_factory: false,
@@ -575,6 +597,7 @@
                     // 8
                     name: "sharedlibs".to_string(),
                     path: PathBuf::from("apex-foo"),
+                    preinstalled_path: PathBuf::from("/system/apex-foo"),
                     last_update_seconds: 87654321,
                     is_factory: true,
                     provide_shared_apex_libs: true,
@@ -584,6 +607,7 @@
                     // 9
                     name: "sharedlibs".to_string(),
                     path: PathBuf::from("apex-foo/updated"),
+                    preinstalled_path: PathBuf::from("/system/apex-foo"),
                     last_update_seconds: 87654321 + 1,
                     is_active: true,
                     provide_shared_apex_libs: true,
@@ -596,7 +620,11 @@
             ApexConfig { name: "{CLASSPATH}".to_string() },
         ];
         assert_eq!(
-            collect_apex_infos(&apex_info_list, &apex_configs, &DebugConfig::new(DebugLevel::FULL)),
+            collect_apex_infos(
+                &apex_info_list,
+                &apex_configs,
+                &DebugConfig::new(DebugLevel::FULL)
+            )?,
             vec![
                 // Pass active/required APEXes
                 &apex_info_list.list[0],
@@ -609,6 +637,55 @@
                 &apex_info_list.list[9],
             ]
         );
+        Ok(())
+    }
+
+    #[test]
+    fn test_check_allowed_partitions_vendor_not_allowed() -> Result<()> {
+        let apex_info_list = ApexInfoList {
+            list: vec![ApexInfo {
+                name: "apex-vendor".to_string(),
+                path: PathBuf::from("apex-vendor"),
+                preinstalled_path: PathBuf::from("/vendor/apex-vendor"),
+                is_active: true,
+                ..Default::default()
+            }],
+        };
+        let apex_configs = vec![ApexConfig { name: "apex-vendor".to_string() }];
+
+        let ret =
+            collect_apex_infos(&apex_info_list, &apex_configs, &DebugConfig::new(DebugLevel::NONE));
+        assert!(ret
+            .is_err_and(|ret| ret.to_string()
+                == "Non-system APEX apex-vendor is not supported in Microdroid"));
+
+        Ok(())
+    }
+
+    #[test]
+    fn test_check_allowed_partitions_system_ext_allowed() -> Result<()> {
+        let apex_info_list = ApexInfoList {
+            list: vec![ApexInfo {
+                name: "apex-system_ext".to_string(),
+                path: PathBuf::from("apex-system_ext"),
+                preinstalled_path: PathBuf::from("/system_ext/apex-system_ext"),
+                is_active: true,
+                ..Default::default()
+            }],
+        };
+
+        let apex_configs = vec![ApexConfig { name: "apex-system_ext".to_string() }];
+
+        assert_eq!(
+            collect_apex_infos(
+                &apex_info_list,
+                &apex_configs,
+                &DebugConfig::new(DebugLevel::NONE)
+            )?,
+            vec![&apex_info_list.list[0]]
+        );
+
+        Ok(())
     }
 
     #[test]