Mount /data with MS_NOEXEC
We want to ensure that W^X is guaranteed for Microdroid VMs. This change
doesn't guarantee that W^X is enforced for FULL_DEBUG VMs, as a user can
enable adb root, and remount the /data without MS_NOEXEC flag.
This is intended, as it allows developers to debug & get familiar with
the Microdroid execution environment.
Bug: 265261525
Test: atest MicrodroidTestApp
Change-Id: I622e3d95d9d8fd6d26bfb690499acf7208ca4d52
diff --git a/microdroid/init.rc b/microdroid/init.rc
index bc42791..d2c9c41 100644
--- a/microdroid/init.rc
+++ b/microdroid/init.rc
@@ -98,7 +98,7 @@
mount rootfs rootfs / remount bind ro nodev
# TODO(b/185767624): change the hard-coded size?
- mount tmpfs tmpfs /data noatime nosuid nodev rw size=128M
+ mount tmpfs tmpfs /data noatime nosuid nodev noexec rw size=128M
# We chown/chmod /data again so because mount is run as root + defaults
chown system system /data
diff --git a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
index 7ee1f01..aa5b32d 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -55,4 +55,7 @@
/* get the content of the specified file. */
String readFromFile(String path);
+
+ /** Returns flags for the given mountPoint. */
+ int getMountFlags(String mountPoint);
}
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index e3c9961..9eda246 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -47,6 +47,7 @@
static_libs: [
"com.android.microdroid.testservice-ndk",
"libbase",
+ "libfstab",
"libfsverity_digests_proto_cc",
"liblog",
"libprotobuf-cpp-lite-ndk",
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 e1a2e40..aba6f65 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -24,6 +24,7 @@
import static android.system.virtualmachine.VirtualMachineManager.CAPABILITY_PROTECTED_VM;
import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
import static com.google.common.truth.TruthJUnit.assume;
import static org.junit.Assert.assertThrows;
@@ -1400,6 +1401,34 @@
assertThat(checkVmOutputIsRedirectedToLogcat(false)).isFalse();
}
+ // Take from bionic/libs/kernel/uapi/linux/mounth.h.
+ private static final int MS_NOEXEC = 8;
+
+ @Test
+ public void dataIsMountedWithNoExec() throws Exception {
+ assumeSupportedKernel();
+
+ final VirtualMachineConfig vmConfig =
+ newVmConfigBuilder()
+ .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ .setMemoryMib(minMemoryRequired())
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+ final VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_data_mount", vmConfig);
+
+ final TestResults testResults =
+ runVmTestService(
+ vm,
+ (ts, tr) -> {
+ tr.mountFlags = ts.getMountFlags("/data");
+ });
+
+ assertThat(testResults.mException).isNull();
+ assertWithMessage("/data should be mounted with MS_NOEXEC")
+ .that(testResults.mountFlags & MS_NOEXEC)
+ .isEqualTo(MS_NOEXEC);
+ }
+
private void assertFileContentsAreEqualInTwoVms(String fileName, String vmName1, String vmName2)
throws IOException {
File file1 = getVmFile(vmName1, fileName);
@@ -1456,6 +1485,7 @@
String mEncryptedStoragePath;
String[] mEffectiveCapabilities;
String mFileContent;
+ int mountFlags;
}
private TestResults runVmTestService(VirtualMachine vm, RunTestsAgainstTestService testsToRun)
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 4ba502a..f5f6783 100644
--- a/tests/testapk/src/native/testbinary.cpp
+++ b/tests/testapk/src/native/testbinary.cpp
@@ -21,6 +21,7 @@
#include <android-base/scopeguard.h>
#include <android/log.h>
#include <fcntl.h>
+#include <fstab/fstab.h>
#include <fsverity_digests.pb.h>
#include <linux/vm_sockets.h>
#include <stdint.h>
@@ -31,6 +32,7 @@
#include <vm_main.h>
#include <vm_payload_restricted.h>
+#include <cstdint>
#include <string>
#include <thread>
@@ -40,6 +42,10 @@
using android::base::make_scope_guard;
using android::base::Result;
using android::base::unique_fd;
+using android::fs_mgr::Fstab;
+using android::fs_mgr::FstabEntry;
+using android::fs_mgr::GetEntryForMountPoint;
+using android::fs_mgr::ReadFstabFromFile;
using aidl::com::android::microdroid::testservice::BnTestService;
using ndk::ScopedAStatus;
@@ -255,6 +261,22 @@
}
return ScopedAStatus::ok();
}
+
+ ScopedAStatus getMountFlags(const std::string& mount_point, int32_t* out) override {
+ Fstab fstab;
+ if (!ReadFstabFromFile("/proc/mounts", &fstab)) {
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ "Failed to read /proc/mounts");
+ }
+ FstabEntry* entry = GetEntryForMountPoint(&fstab, mount_point);
+ if (entry == nullptr) {
+ std::string msg = mount_point + " not found in /proc/mounts";
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ msg.c_str());
+ }
+ *out = entry->flags;
+ return ScopedAStatus::ok();
+ }
};
auto testService = ndk::SharedRefBase::make<TestService>();