Add microdroid sepolicy neverallow test

Bug: 218461215
Test: atest MicrodroidHostTestCases
Change-Id: I2312954d6a96aea4f996c31363c57b43ac5dd612
diff --git a/tests/hostside/Android.bp b/tests/hostside/Android.bp
index bc8a4a5..10bcbf4 100644
--- a/tests/hostside/Android.bp
+++ b/tests/hostside/Android.bp
@@ -16,5 +16,9 @@
         "VirtualizationTestHelper",
     ],
     per_testcase_directory: true,
-    data: [":MicrodroidTestApp"],
+    data: [
+        ":MicrodroidTestApp",
+        ":microdroid_general_sepolicy.conf",
+    ],
+    data_native_bins: ["sepolicy-analyze"],
 }
diff --git a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
index e15f1ae..e3f1968 100644
--- a/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
+++ b/tests/hostside/helper/java/android/virt/test/VirtualizationTestCaseBase.java
@@ -149,9 +149,26 @@
     }
 
     public static CommandResult runOnMicrodroidForResult(String... cmd) {
-        final long timeout = 30000; // 30 sec. Microdroid is extremely slow on GCE-on-CF.
+        final long timeoutMs = 30000; // 30 sec. Microdroid is extremely slow on GCE-on-CF.
         return RunUtil.getDefault()
-                .runTimedCmd(timeout, "adb", "-s", MICRODROID_SERIAL, "shell", join(cmd));
+                .runTimedCmd(timeoutMs, "adb", "-s", MICRODROID_SERIAL, "shell", join(cmd));
+    }
+
+    public static void pullMicrodroidFile(String path, File target) {
+        final long timeoutMs = 30000; // 30 sec. Microdroid is extremely slow on GCE-on-CF.
+        CommandResult result =
+                RunUtil.getDefault()
+                        .runTimedCmd(
+                                timeoutMs,
+                                "adb",
+                                "-s",
+                                MICRODROID_SERIAL,
+                                "pull",
+                                path,
+                                target.getPath());
+        if (result.getStatus() != CommandStatus.SUCCESS) {
+            fail("pulling " + path + " has failed: " + result);
+        }
     }
 
     // Asserts the command will fail on Microdroid.
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index 6aa7566..25adc40 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -17,18 +17,24 @@
 package android.virt.test;
 
 import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import com.android.tradefed.device.DeviceNotAvailableException;
 import com.android.tradefed.testtype.DeviceJUnit4ClassRunner;
+import com.android.tradefed.util.CommandResult;
+import com.android.tradefed.util.CommandStatus;
+import com.android.tradefed.util.FileUtil;
+import com.android.tradefed.util.RunUtil;
 
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 
+import java.io.File;
 import java.util.Optional;
 
 @RunWith(DeviceJUnit4ClassRunner.class)
@@ -43,6 +49,16 @@
     private static final int NUM_VCPUS = 3;
     private static final String CPU_AFFINITY = "0,1,2";
 
+    // TODO(b/176805428): remove this
+    private boolean isCuttlefish() throws Exception {
+        String productName = getDevice().getProperty("ro.product.name");
+        return (null != productName)
+                && (productName.startsWith("aosp_cf_x86")
+                        || productName.startsWith("aosp_cf_arm")
+                        || productName.startsWith("cf_x86")
+                        || productName.startsWith("cf_arm"));
+    }
+
     private int minMemorySize() throws DeviceNotAvailableException {
         CommandRunner android = new CommandRunner(getDevice());
         String abi = android.run("getprop", "ro.product.cpu.abi");
@@ -103,6 +119,31 @@
         assertThat(runOnMicrodroid("cat /proc/cpuinfo | grep processor | wc -l"),
                 is(Integer.toString(NUM_VCPUS)));
 
+        // TODO(b/176805428): adb is broken for nested VM
+        if (!isCuttlefish()) {
+            // Check neverallow rules on microdroid
+            File policyFile = FileUtil.createTempFile("microdroid_sepolicy", "");
+            pullMicrodroidFile("/sys/fs/selinux/policy", policyFile);
+
+            File generalPolicyConfFile = findTestFile("microdroid_general_sepolicy.conf");
+            File sepolicyAnalyzeBin = findTestFile("sepolicy-analyze");
+
+            CommandResult result =
+                    RunUtil.getDefault()
+                            .runTimedCmd(
+                                    10000,
+                                    sepolicyAnalyzeBin.getPath(),
+                                    policyFile.getPath(),
+                                    "neverallow",
+                                    "-w",
+                                    "-f",
+                                    generalPolicyConfFile.getPath());
+            assertEquals(
+                    "neverallow check failed: " + result.getStderr().trim(),
+                    result.getStatus(),
+                    CommandStatus.SUCCESS);
+        }
+
         shutdownMicrodroid(getDevice(), cid);
     }