microdroid: apk is mounted via apkdmverity
In microdroid, APK and its idsig is used to dm-verity mount before
zipfuse mounts it into a filesystem.
Bug: 190343842
Test: MicrodroidHostTestCases
Change-Id: Icd48fb823eabc087c0266e46f9b3d302e90fd208
diff --git a/microdroid/init.rc b/microdroid/init.rc
index 2385d8f..4155da3 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -22,6 +22,8 @@
start ueventd
+ # TODO(b/190343842) verify apexes/apk before mounting them.
+
# Exec apexd in the VM mode to avoid unnecessary overhead of normal mode.
# (e.g. session management)
exec - root system -- /system/bin/apexd --vm
@@ -29,6 +31,7 @@
perform_apex_config
exec_start derive_sdk
+ exec - root system -- /system/bin/apkdmverity /dev/block/by-name/microdroid-apk /dev/block/by-name/microdroid-apk-idsig microdroid-apk
mkdir /mnt/apk 0755 system system
start zipfuse
diff --git a/microdroid/sepolicy/system/private/apkdmverity.te b/microdroid/sepolicy/system/private/apkdmverity.te
new file mode 100644
index 0000000..c6160be
--- /dev/null
+++ b/microdroid/sepolicy/system/private/apkdmverity.te
@@ -0,0 +1,29 @@
+# apkdmverity is a program that protects a signed APK file using dm-verity.
+
+type apkdmverity, domain, coredomain;
+type apkdmverity_exec, exec_type, file_type, system_file_type;
+
+# allow domain transition from init
+init_daemon_domain(apkdmverity)
+
+# apkdmverity accesses /dev/block/by-name/metadata which points to
+# a /dev/vd* block device file.
+allow apkdmverity block_device:dir r_dir_perms;
+allow apkdmverity block_device:lnk_file r_file_perms;
+allow apkdmverity vd_device:blk_file r_file_perms;
+
+# allow apkdmverity to create dm-verity devices
+allow apkdmverity dm_device:{chr_file blk_file} rw_file_perms;
+# sys_admin is required to access the device-mapper and mount
+allow apkdmverity self:global_capability_class_set sys_admin;
+
+# allow apkdmverity to create loop devices with /dev/loop-control
+allow apkdmverity loop_control_device:chr_file rw_file_perms;
+
+# allow apkdmverity to access loop devices
+allow apkdmverity loop_device:blk_file rw_file_perms;
+allowxperm apkdmverity loop_device:blk_file ioctl {
+ LOOP_SET_STATUS64
+ LOOP_SET_FD
+ LOOP_SET_DIRECT_IO
+};
diff --git a/microdroid/sepolicy/system/private/domain.te b/microdroid/sepolicy/system/private/domain.te
index c451fcf..4a59f73 100644
--- a/microdroid/sepolicy/system/private/domain.te
+++ b/microdroid/sepolicy/system/private/domain.te
@@ -501,7 +501,8 @@
# Only init and otapreopt_chroot should be mounting filesystems on locations
# labeled system or vendor (/product and /vendor respectively).
-neverallow { domain -init -otapreopt_chroot } { system_file_type vendor_file_type }:dir_file_class_set mounton;
+# In microdroid, zipfuse is allowed mounton /mnt/apk.
+neverallow { domain -init -otapreopt_chroot -zipfuse } { system_file_type vendor_file_type }:dir_file_class_set mounton;
# Only allow init and vendor_init to read/write mm_events properties
# NOTE: dumpstate is allowed to read any system property
diff --git a/microdroid/sepolicy/system/private/file_contexts b/microdroid/sepolicy/system/private/file_contexts
index 3c75e81..5615e75 100644
--- a/microdroid/sepolicy/system/private/file_contexts
+++ b/microdroid/sepolicy/system/private/file_contexts
@@ -377,6 +377,7 @@
/system/bin/zipfuse u:object_r:zipfuse_exec:s0
/system/bin/microdroid_launcher u:object_r:microdroid_launcher_exec:s0
/system/bin/microdroid_manager u:object_r:microdroid_manager_exec:s0
+/system/bin/apkdmverity u:object_r:apkdmverity_exec:s0
#############################
# Vendor files
diff --git a/microdroid/sepolicy/system/private/kernel.te b/microdroid/sepolicy/system/private/kernel.te
index cfec715..2d49445 100644
--- a/microdroid/sepolicy/system/private/kernel.te
+++ b/microdroid/sepolicy/system/private/kernel.te
@@ -32,3 +32,8 @@
allow kernel kmsg_device:chr_file write;
allow kernel gsid:fd use;
+
+# apkdmverity attaches a loop device to idsig file
+# and the loop device is used by zipfuse later.
+# This requires kernel to use the fd opened by apkdmverity.
+allow kernel apkdmverity:fd use;
diff --git a/microdroid/sepolicy/system/private/zipfuse.te b/microdroid/sepolicy/system/private/zipfuse.te
index 65da9d3..fb7527b 100644
--- a/microdroid/sepolicy/system/private/zipfuse.te
+++ b/microdroid/sepolicy/system/private/zipfuse.te
@@ -17,7 +17,9 @@
# /dev/block/by-name/*
allow zipfuse block_device:dir r_dir_perms;
allow zipfuse block_device:lnk_file r_file_perms;
-allow zipfuse vd_device:blk_file r_file_perms;
+
+# /dev/block/by-name/microdroid-apk is mapped to /dev/block/dm-*
+allow zipfuse dm_device:blk_file r_file_perms;
# allow mounting on /mnt/apk
allow zipfuse tmpfs:dir mounton;
diff --git a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
index 7f9b8de..268ee84 100644
--- a/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
+++ b/tests/hostside/java/android/virt/test/MicrodroidTestCase.java
@@ -21,6 +21,7 @@
import static org.hamcrest.CoreMatchers.not;
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
import static org.junit.Assume.assumeThat;
import com.android.compatibility.common.tradefed.build.CompatibilityBuildHelper;
@@ -79,9 +80,11 @@
runOnMicrodroid("echo MicrodroidTest > /data/local/tmp/test.txt");
assertThat(runOnMicrodroid("cat /data/local/tmp/test.txt"), is("MicrodroidTest"));
- // Check if the APK partition exists
+ // Check if the APK & its idsig partitions exist
final String apkPartition = "/dev/block/by-name/microdroid-apk";
assertThat(runOnMicrodroid("ls", apkPartition), is(apkPartition));
+ final String apkIdsigPartition = "/dev/block/by-name/microdroid-apk-idsig";
+ assertThat(runOnMicrodroid("ls", apkIdsigPartition), is(apkIdsigPartition));
// Check if the APK is mounted using zipfuse
final String mountEntry = "zipfuse on /mnt/apk type fuse.zipfuse";
@@ -126,7 +129,9 @@
// Run a shell command on Android
private String runOnAndroid(String... cmd) throws Exception {
CommandResult result = getDevice().executeShellV2Command(join(cmd));
- assertThat(result.getStatus(), is(CommandStatus.SUCCESS));
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ fail(join(cmd) + " has failed: " + result);
+ }
return result.getStdout().trim();
}
@@ -142,7 +147,9 @@
CommandResult result =
RunUtil.getDefault()
.runTimedCmd(timeout, "adb", "-s", MICRODROID_SERIAL, "shell", join(cmd));
- assertThat(result.getStatus(), is(CommandStatus.SUCCESS));
+ if (result.getStatus() != CommandStatus.SUCCESS) {
+ fail(join(cmd) + " has failed: " + result);
+ }
return result.getStdout().trim();
}
@@ -177,21 +184,21 @@
assertTrue(apkPath.startsWith("package:"));
apkPath = apkPath.substring("package:".length());
+ // Push the idsig file to the device
+ File idsigOnHost = findTestFile(apkName + ".idsig");
+ final String apkIdsigPath = TEST_ROOT + apkName + ".idsig";
+ getDevice().pushFile(idsigOnHost, apkIdsigPath);
+
// Create payload.json from the gathered data
JSONObject payloadObject = new JSONObject();
payloadObject.put("system_apexes", new JSONArray(apexNames));
payloadObject.put("payload_config_path", "/mnt/apk/" + configPath);
JSONObject apkObject = new JSONObject();
- apkObject.put("path", apkPath);
apkObject.put("name", packageName);
+ apkObject.put("path", apkPath);
+ apkObject.put("idsig_path", apkIdsigPath);
payloadObject.put("apk", apkObject);
- // Push the idsig file to the device
- // TODO(b/190343842): pass path to this file to payloadObject
- // File idsigOnHost = findTestFile(apkFile + ".idsig");
- // final String testApkIdsig = TEST_ROOT + apkFile + ".idsig";
- // getDevice().pushFile(idsigOnHost, testApkIdsig);
-
// Copy the json file to Android
File payloadJsonOnHost = File.createTempFile("payload", "json");
FileWriter writer = new FileWriter(payloadJsonOnHost);
diff --git a/zipfuse/zipfuse.rc b/zipfuse/zipfuse.rc
index ccd94b6..1905705 100644
--- a/zipfuse/zipfuse.rc
+++ b/zipfuse/zipfuse.rc
@@ -1,2 +1,2 @@
-service zipfuse /system/bin/zipfuse -o fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0 /dev/block/by-name/microdroid-apk /mnt/apk
+service zipfuse /system/bin/zipfuse -o fscontext=u:object_r:zipfusefs:s0,context=u:object_r:system_file:s0 /dev/block/mapper/microdroid-apk /mnt/apk
disabled