Merge "Restrict libraires from VM payload libraries"
diff --git a/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java b/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java
index e67a309..32eafb8 100644
--- a/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java
+++ b/authfs/tests/benchmarks/src/java/com/android/fs/benchmarks/AuthFsBenchmarks.java
@@ -140,6 +140,7 @@
 
             String rate = mAuthFsTestRule.getMicrodroid().run(cmd);
             rates.add(Double.parseDouble(rate));
+            mAuthFsTestRule.killFdServerOnAndroid();
         }
         reportMetrics(rates, mode + "_read", "mb_per_sec");
     }
@@ -152,11 +153,14 @@
         List<Double> rates = new ArrayList<>(TRIAL_COUNT);
         for (int i = 0; i < TRIAL_COUNT + 1; ++i) {
             mAuthFsTestRule.runFdServerOnAndroid(
-                    "--open-rw 5:" + mAuthFsTestRule.TEST_OUTPUT_DIR + "/out.file", "--rw-fds 5");
+                    "--open-rw 5:" + AuthFsTestRule.TEST_OUTPUT_DIR + "/out.file", "--rw-fds 5");
             mAuthFsTestRule.runAuthFsOnMicrodroid("--remote-new-rw-file 5");
 
             String rate = mAuthFsTestRule.getMicrodroid().run(cmd);
             rates.add(Double.parseDouble(rate));
+            mAuthFsTestRule.killFdServerOnAndroid();
+            AuthFsTestRule.getAndroid()
+                    .runForResult("rm", "-rf", AuthFsTestRule.TEST_OUTPUT_DIR + "/out.file");
         }
         reportMetrics(rates, mode + "_write", "mb_per_sec");
     }
diff --git a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
index 6087eef..357edea 100644
--- a/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
+++ b/authfs/tests/common/src/java/com/android/fs/common/AuthFsTestRule.java
@@ -181,6 +181,10 @@
         Future<?> unusedFuture = mThreadPool.submit(() -> runForResult(sAndroid, cmd, "fd_server"));
     }
 
+    public void killFdServerOnAndroid() throws DeviceNotAvailableException {
+        sAndroid.tryRun("killall fd_server");
+    }
+
     public void runAuthFsOnMicrodroid(String flags) {
         String cmd = AUTHFS_BIN + " " + MOUNT_DIR + " " + flags + " --cid " + VMADDR_CID_HOST;
 
@@ -250,7 +254,7 @@
         }
 
         assertNotNull(sAndroid);
-        sAndroid.tryRun("killall fd_server");
+        killFdServerOnAndroid();
 
         // Even though we only run one VM for the whole class, and could have collect the VM log
         // after all tests are done, TestLogData doesn't seem to work at class level. Hence,
diff --git a/docs/getting_started/index.md b/docs/getting_started/index.md
index a15c4c7..f184862 100644
--- a/docs/getting_started/index.md
+++ b/docs/getting_started/index.md
@@ -97,6 +97,15 @@
 If you run into problems, inspect the logs produced by `atest`. Their location is printed at the
 end. The `host_log_*.zip` file should contain the output of individual commands as well as VM logs.
 
+### Custom pvmfw
+
+Hostside tests, which run on the PC and extends `MicrodroidHostTestCaseBase`, can be run with
+a custom `pvmfw`. Use `--module-arg` to push `pvmfw` for individual test methods.
+
+```shell
+atest com.android.microdroid.test.MicrodroidHostTests -- --module-arg MicrodroidHostTestCases:set-option:pvmfw:pvmfw.img
+```
+
 ## Spawning your own VMs with custom kernel
 
 You can spawn your own VMs by passing a JSON config file to the VirtualizationService via the `vm`
@@ -120,6 +129,17 @@
 The `vm` command also has other subcommands for debugging; run `/apex/com.android.virt/bin/vm help`
 for details.
 
+## Spawning your own VMs with custom pvmfw
+
+Set system property `hypervisor.pvmfw.path` to custom `pvmfw` on the device before using `vm` tool.
+`virtualizationservice` will pass the specified `pvmfw` to `crosvm` for protected VMs.
+
+```shell
+adb push pvmfw.img /data/local/tmp/pvmfw.img
+adb root  # required for setprop
+adb shell setprop hypervisor.pvmfw.path /data/local/tmp/pvmfw.img
+```
+
 ## Spawning your own VMs with Microdroid
 
 [Microdroid](../../microdroid/README.md) is a lightweight version of Android that is intended to run
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachine.java b/javalib/src/android/system/virtualmachine/VirtualMachine.java
index d774cec..ffcdc51 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachine.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachine.java
@@ -418,7 +418,10 @@
     }
 
     @NonNull
-    private static File getVmDir(Context context, String name) {
+    private static File getVmDir(@NonNull Context context, @NonNull String name) {
+        if (name.contains(File.separator) || name.equals(".") || name.equals("..")) {
+            throw new IllegalArgumentException("Invalid VM name: " + name);
+        }
         File vmRoot = new File(context.getDataDir(), VM_DIR);
         return new File(vmRoot, name);
     }
diff --git a/javalib/src/android/system/virtualmachine/VirtualMachineManager.java b/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
index c179498..ea0a305 100644
--- a/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
+++ b/javalib/src/android/system/virtualmachine/VirtualMachineManager.java
@@ -43,6 +43,7 @@
  *
  * <p>Each virtual machine instance is named; the configuration and related state of each is
  * persisted in the app's private data directory and an instance can be retrieved given the name.
+ * The name must be a valid directory name and must not contain '/'.
  *
  * <p>The app can then start, stop and otherwise interact with the VM.
  *
diff --git a/pvmfw/src/entry.rs b/pvmfw/src/entry.rs
index b840488..7859ff3 100644
--- a/pvmfw/src/entry.rs
+++ b/pvmfw/src/entry.rs
@@ -236,16 +236,19 @@
 }
 
 fn jump_to_payload(fdt_address: u64, payload_start: u64) -> ! {
-    const SCTLR_EL1_RES1: usize = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
+    const SCTLR_EL1_RES1: u64 = (0b11 << 28) | (0b101 << 20) | (0b1 << 11);
     // Stage 1 instruction access cacheability is unaffected.
-    const SCTLR_EL1_I: usize = 0b1 << 12;
+    const SCTLR_EL1_I: u64 = 0b1 << 12;
     // SETEND instruction disabled at EL0 in aarch32 mode.
-    const SCTLR_EL1_SED: usize = 0b1 << 8;
+    const SCTLR_EL1_SED: u64 = 0b1 << 8;
     // Various IT instructions are disabled at EL0 in aarch32 mode.
-    const SCTLR_EL1_ITD: usize = 0b1 << 7;
+    const SCTLR_EL1_ITD: u64 = 0b1 << 7;
 
-    const SCTLR_EL1_VAL: usize = SCTLR_EL1_RES1 | SCTLR_EL1_ITD | SCTLR_EL1_SED | SCTLR_EL1_I;
+    const SCTLR_EL1_VAL: u64 = SCTLR_EL1_RES1 | SCTLR_EL1_ITD | SCTLR_EL1_SED | SCTLR_EL1_I;
 
+    // Disable the exception vector, caches and page table and then jump to the payload at the
+    // given address, passing it the given FDT pointer.
+    //
     // SAFETY - We're exiting pvmfw by passing the register values we need to a noreturn asm!().
     unsafe {
         asm!(
diff --git a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
index e5aa908..8816dbd 100644
--- a/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
+++ b/tests/hostside/helper/java/com/android/microdroid/test/host/MicrodroidHostTestCaseBase.java
@@ -29,6 +29,7 @@
 import com.android.microdroid.test.common.DeviceProperties;
 import com.android.microdroid.test.common.MetricsProcessor;
 import com.android.tradefed.build.IBuildInfo;
+import com.android.tradefed.config.Option;
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.device.ITestDevice;
 import com.android.tradefed.device.TestDevice;
@@ -41,12 +42,15 @@
 import java.util.Arrays;
 
 public abstract class MicrodroidHostTestCaseBase extends BaseHostJUnit4Test {
+
     protected static final String TEST_ROOT = "/data/local/tmp/virt/";
     protected static final String LOG_PATH = TEST_ROOT + "log.txt";
     protected static final String CONSOLE_PATH = TEST_ROOT + "console.txt";
     private static final int TEST_VM_ADB_PORT = 8000;
     private static final String MICRODROID_SERIAL = "localhost:" + TEST_VM_ADB_PORT;
     private static final String INSTANCE_IMG = "instance.img";
+    private static final String PVMFW_IMG_PATH = TEST_ROOT + "pvmfw.img";
+    private static final String PVMFW_IMG_PATH_PROP = "hypervisor.pvmfw.path";
 
     private static final long MICRODROID_ADB_CONNECT_TIMEOUT_MINUTES = 5;
     protected static final long MICRODROID_COMMAND_TIMEOUT_MILLIS = 30000;
@@ -55,6 +59,19 @@
             (int) (MICRODROID_ADB_CONNECT_TIMEOUT_MINUTES * 60 * 1000
                 / MICRODROID_COMMAND_RETRY_INTERVAL_MILLIS);
 
+    @Option(
+            name = "pvmfw",
+            description =
+                    "Custom pvmfw.img path on host device."
+                            + " If present, it will be pushed to "
+                            + PVMFW_IMG_PATH,
+            mandatory = false)
+    private static String sCustomPvmfwPathOnHost = "";
+
+    private static boolean isEmptyText(String str) {
+        return str == null || str.length() == 0;
+    }
+
     public static void prepareVirtualizationTestSetup(ITestDevice androidDevice)
             throws DeviceNotAvailableException {
         CommandRunner android = new CommandRunner(androidDevice);
@@ -67,6 +84,13 @@
 
         // remove any leftover files under test root
         android.tryRun("rm", "-rf", TEST_ROOT + "*");
+
+        // prepare custom pvmfw.img if necessary
+        if (!isEmptyText(sCustomPvmfwPathOnHost)) {
+            runOnHost("adb", "root");
+            runOnHost("adb", "push", sCustomPvmfwPathOnHost, PVMFW_IMG_PATH);
+            runOnHost("adb", "shell", "setprop", PVMFW_IMG_PATH_PROP, PVMFW_IMG_PATH);
+        }
     }
 
     public static void cleanUpVirtualizationTestSetup(ITestDevice androidDevice)
@@ -80,6 +104,10 @@
         android.tryRun("killall", "crosvm");
         android.tryRun("stop", "virtualizationservice");
         android.tryRun("rm", "-rf", "/data/misc/virtualizationservice/*");
+
+        if (!isEmptyText(sCustomPvmfwPathOnHost)) {
+            runOnHost("adb", "shell", "setprop", PVMFW_IMG_PATH_PROP, "\"\"");
+        }
     }
 
     protected boolean isCuttlefish() {
diff --git a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
index 8ea5426..679f6e7 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -318,8 +318,6 @@
             "9.17/C-1-1",
     })
     public void invalidApkPathIsRejected() {
-        assumeSupportedKernel();
-
         VirtualMachineConfig.Builder builder =
                 newVmConfigBuilder()
                         .setPayloadBinaryPath("MicrodroidTestNativeLib.so")
@@ -329,6 +327,14 @@
     }
 
     @Test
+    @CddTest(requirements = {"9.17/C-1-1"})
+    public void invalidVmNameIsRejected() {
+        VirtualMachineManager vmm = getVirtualMachineManager();
+        assertThrows(IllegalArgumentException.class, () -> vmm.get("../foo"));
+        assertThrows(IllegalArgumentException.class, () -> vmm.get(".."));
+    }
+
+    @Test
     @CddTest(requirements = {
             "9.17/C-1-1",
             "9.17/C-2-1"
diff --git a/virtualizationservice/src/crosvm.rs b/virtualizationservice/src/crosvm.rs
index 85a57c9..13e5c70 100644
--- a/virtualizationservice/src/crosvm.rs
+++ b/virtualizationservice/src/crosvm.rs
@@ -67,6 +67,8 @@
 
 const MILLIS_PER_SEC: i64 = 1000;
 
+const SYSPROP_CUSTOM_PVMFW_PATH: &str = "hypervisor.pvmfw.path";
+
 lazy_static! {
     /// If the VM doesn't move to the Started state within this amount time, a hang-up error is
     /// triggered.
@@ -601,7 +603,12 @@
     }
 
     if config.protected {
-        command.arg("--protected-vm");
+        match system_properties::read(SYSPROP_CUSTOM_PVMFW_PATH)? {
+            Some(pvmfw_path) if !pvmfw_path.is_empty() => {
+                command.arg("--protected-vm-with-firmware").arg(pvmfw_path)
+            }
+            _ => command.arg("--protected-vm"),
+        };
 
         // 3 virtio-console devices + vsock = 4.
         let virtio_pci_device_count = 4 + config.disks.len();