Merge "Increase max entry for directories to 1000"
diff --git a/authfs/tests/benchmarks/Android.bp b/authfs/tests/benchmarks/Android.bp
index 9bdef7b..38ece79 100644
--- a/authfs/tests/benchmarks/Android.bp
+++ b/authfs/tests/benchmarks/Android.bp
@@ -23,7 +23,6 @@
":authfs_test_files",
":CtsApkVerityTestPrebuiltFiles",
":MicrodroidTestApp",
- ":measure_io",
],
}
@@ -36,3 +35,19 @@
"libbase",
],
}
+
+// Package measure_io binary into a jar, to bundle with the MicrodroidTestApp.
+// When MicrodroidTestApp is mounted inside the Microdroid, the zipfuse will
+// add the +x permission on it.
+java_genrule {
+ name: "measure_io_as_jar",
+ out: ["measure_io.jar"],
+ srcs: [
+ ":measure_io",
+ ],
+ cmd: "out_dir=$$(dirname $(out))" +
+ "&& bin_dir=\"bin\" " +
+ "&& mkdir -p $$out_dir/$$bin_dir" +
+ "&& cp $(in) $$out_dir/$$bin_dir" +
+ "&& jar cf $(out) -C $$out_dir $$bin_dir",
+}
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 32eafb8..085d06e 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
@@ -18,7 +18,6 @@
import static com.android.tradefed.testtype.DeviceJUnit4ClassRunner.TestMetrics;
-import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assume.assumeFalse;
import static org.junit.Assume.assumeTrue;
@@ -45,7 +44,6 @@
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.UseParametersRunnerFactory;
-import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
@@ -57,11 +55,8 @@
public class AuthFsBenchmarks extends BaseHostJUnit4Test {
private static final int TRIAL_COUNT = 5;
- /** Name of the measure_io binary on host. */
- private static final String MEASURE_IO_BIN_NAME = "measure_io";
-
/** Path to measure_io on Microdroid. */
- private static final String MEASURE_IO_BIN_PATH = "/data/local/tmp/measure_io";
+ private static final String MEASURE_IO_BIN_PATH = "/mnt/apk/bin/measure_io";
/** fs-verity digest (sha256) of testdata/input.4m */
private static final String DIGEST_4M =
@@ -123,7 +118,6 @@
}
private void readRemoteFile(String mode) throws DeviceNotAvailableException {
- pushMeasureIoBinToMicrodroid();
// Cache the file in memory for the host.
mAuthFsTestRule
.getAndroid()
@@ -146,7 +140,6 @@
}
private void writeRemoteFile(String mode) throws DeviceNotAvailableException {
- pushMeasureIoBinToMicrodroid();
String filePath = mAuthFsTestRule.MOUNT_DIR + "/5";
int fileSizeMb = 8;
String cmd = MEASURE_IO_BIN_PATH + " " + filePath + " " + fileSizeMb + " " + mode + " w";
@@ -165,14 +158,6 @@
reportMetrics(rates, mode + "_write", "mb_per_sec");
}
- private void pushMeasureIoBinToMicrodroid() throws DeviceNotAvailableException {
- File measureReadBin = mAuthFsTestRule.findTestFile(getBuild(), MEASURE_IO_BIN_NAME);
- assertThat(measureReadBin.exists()).isTrue();
- mAuthFsTestRule.getMicrodroidDevice().pushFile(measureReadBin, MEASURE_IO_BIN_PATH);
- assertThat(mAuthFsTestRule.getMicrodroid().run("ls " + MEASURE_IO_BIN_PATH))
- .isEqualTo(MEASURE_IO_BIN_PATH);
- }
-
private void reportMetrics(List<Double> metrics, String name, String unit) {
Map<String, Double> stats = mMetricsProcessor.computeStats(metrics, name, unit);
for (Map.Entry<String, Double> entry : stats.entrySet()) {
diff --git a/microdroid/init.rc b/microdroid/init.rc
index ce0cab4..70c22d4 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 4611134..66dbe4b 100644
--- a/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
+++ b/tests/aidl/com/android/microdroid/testservice/ITestService.aidl
@@ -56,6 +56,12 @@
/* get the content of the specified file. */
String readFromFile(String path);
+ /* get file permissions of the give file by stat'ing it */
+ int getFilePermissions(String path);
+
+ /** Returns flags for the given mountPoint. */
+ int getMountFlags(String mountPoint);
+
/**
* Request the service to exit, triggering the termination of the VM. This may cause any
* requests in flight to fail.
diff --git a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
index be3c1da..2d568d0 100644
--- a/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
+++ b/tests/helper/src/java/com/android/microdroid/test/device/MicrodroidDeviceTestBase.java
@@ -443,6 +443,8 @@
public String mFileContent;
public byte[] mBcc;
public long[] mTimings;
+ public int mFileMode;
+ public int mMountFlags;
public void assertNoException() {
if (mException != null) {
diff --git a/tests/testapk/Android.bp b/tests/testapk/Android.bp
index bafab53..fe8f5c9 100644
--- a/tests/testapk/Android.bp
+++ b/tests/testapk/Android.bp
@@ -31,6 +31,7 @@
"cbor-java",
"truth-prebuilt",
"compatibility-common-util-devicesidelib",
+ "measure_io_as_jar",
],
jni_libs: [
"MicrodroidTestNativeLib",
@@ -62,6 +63,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 f3f1252..e0abe98 100644
--- a/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
+++ b/tests/testapk/src/java/com/android/microdroid/test/MicrodroidTests.java
@@ -45,6 +45,7 @@
import android.os.ParcelFileDescriptor.AutoCloseInputStream;
import android.os.ParcelFileDescriptor.AutoCloseOutputStream;
import android.os.SystemProperties;
+import android.system.OsConstants;
import android.system.virtualmachine.VirtualMachine;
import android.system.virtualmachine.VirtualMachineCallback;
import android.system.virtualmachine.VirtualMachineConfig;
@@ -1779,6 +1780,70 @@
}
}
+ @Test
+ @CddTest(requirements = {"9.17/C-1-5"})
+ public void testFileUnderBinHasExecutePermission() throws Exception {
+ assumeSupportedKernel();
+
+ VirtualMachineConfig vmConfig =
+ newVmConfigBuilder()
+ .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ .setMemoryBytes(minMemoryRequired())
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_perms", vmConfig);
+
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mFileMode = ts.getFilePermissions("/mnt/apk/bin/measure_io");
+ });
+
+ testResults.assertNoException();
+ int allPermissionsMask =
+ OsConstants.S_IRUSR
+ | OsConstants.S_IWUSR
+ | OsConstants.S_IXUSR
+ | OsConstants.S_IRGRP
+ | OsConstants.S_IWGRP
+ | OsConstants.S_IXGRP
+ | OsConstants.S_IROTH
+ | OsConstants.S_IWOTH
+ | OsConstants.S_IXOTH;
+ assertThat(testResults.mFileMode & allPermissionsMask)
+ .isEqualTo(OsConstants.S_IRUSR | OsConstants.S_IXUSR);
+ }
+
+ // Taken from bionic/libs/kernel/uapi/linux/mounth.h.
+ private static final int MS_NOEXEC = 8;
+
+ @Test
+ public void dataIsMountedWithNoExec() throws Exception {
+ assumeSupportedKernel();
+
+ VirtualMachineConfig vmConfig =
+ newVmConfigBuilder()
+ .setPayloadBinaryName("MicrodroidTestNativeLib.so")
+ .setDebugLevel(DEBUG_LEVEL_FULL)
+ .build();
+ VirtualMachine vm = forceCreateNewVirtualMachine("test_vm_data_mount", vmConfig);
+
+ TestResults testResults =
+ runVmTestService(
+ TAG,
+ vm,
+ (ts, tr) -> {
+ tr.mMountFlags = ts.getMountFlags("/data");
+ });
+
+ assertThat(testResults.mException).isNull();
+ assertWithMessage("/data should be mounted with MS_NOEXEC")
+ .that(testResults.mMountFlags & MS_NOEXEC)
+ .isEqualTo(MS_NOEXEC);
+ }
+
private static class VmShareServiceConnection implements ServiceConnection {
private final CountDownLatch mLatch = new CountDownLatch(1);
diff --git a/tests/testapk/src/native/testbinary.cpp b/tests/testapk/src/native/testbinary.cpp
index 19d6cd4..285dae9 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>
@@ -40,6 +41,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;
@@ -251,6 +256,34 @@
return ScopedAStatus::ok();
}
+ ScopedAStatus getFilePermissions(const std::string& path, int32_t* out) override {
+ struct stat sb;
+ if (stat(path.c_str(), &sb) != -1) {
+ *out = sb.st_mode;
+ } else {
+ std::string msg = "stat " + path + " failed : " + std::strerror(errno);
+ return ScopedAStatus::fromExceptionCodeWithMessage(EX_SERVICE_SPECIFIC,
+ msg.c_str());
+ }
+ 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();
+ }
+
ScopedAStatus quit() override { exit(0); }
};
auto testService = ndk::SharedRefBase::make<TestService>();
diff --git a/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java b/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
index 278e1a2..467b98b 100644
--- a/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
+++ b/tests/vmshareapp/src/java/com/android/microdroid/test/sharevm/VmShareServiceImpl.java
@@ -230,6 +230,16 @@
}
@Override
+ public int getFilePermissions(String path) throws RemoteException {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
+ public int getMountFlags(String path) throws RemoteException {
+ throw new UnsupportedOperationException("Not supported");
+ }
+
+ @Override
public void quit() throws RemoteException {
throw new UnsupportedOperationException("Not supported");
}
diff --git a/virtualizationmanager/src/crosvm.rs b/virtualizationmanager/src/crosvm.rs
index 6ac1658..942e69a 100644
--- a/virtualizationmanager/src/crosvm.rs
+++ b/virtualizationmanager/src/crosvm.rs
@@ -532,6 +532,9 @@
/// Checks if ramdump has been created. If so, send it to tombstoned.
fn handle_ramdump(&self) -> Result<(), Error> {
let ramdump_path = self.temporary_directory.join("ramdump");
+ if !ramdump_path.as_path().try_exists()? {
+ return Ok(());
+ }
if std::fs::metadata(&ramdump_path)?.len() > 0 {
Self::send_ramdump_to_tombstoned(&ramdump_path)?;
}
diff --git a/zipfuse/src/inode.rs b/zipfuse/src/inode.rs
index 3edbc49..ea63422 100644
--- a/zipfuse/src/inode.rs
+++ b/zipfuse/src/inode.rs
@@ -99,12 +99,8 @@
InodeData { mode, size: 0, data: InodeDataData::Directory(HashMap::new()) }
}
- fn new_file(zip_index: ZipIndex, zip_file: &zip::read::ZipFile) -> InodeData {
- InodeData {
- mode: zip_file.unix_mode().unwrap_or(DEFAULT_FILE_MODE),
- size: zip_file.size(),
- data: InodeDataData::File(zip_index),
- }
+ fn new_file(zip_index: ZipIndex, mode: u32, zip_file: &zip::read::ZipFile) -> InodeData {
+ InodeData { mode, size: zip_file.size(), data: InodeDataData::File(zip_index) }
}
fn add_to_directory(&mut self, name: CString, entry: DirectoryEntry) {
@@ -188,6 +184,16 @@
let mut parent = ROOT;
let mut iter = path.iter().peekable();
+
+ let mut file_mode = DEFAULT_FILE_MODE;
+ if path.starts_with("bin/") {
+ // Allow files under bin to have execute permission, this enables payloads to bundle
+ // additional binaries that they might want to execute.
+ // An example of such binary is measure_io one used in the authfs performance tests.
+ // More context available at b/265261525 and b/270955654.
+ file_mode |= libc::S_IXUSR;
+ }
+
while let Some(name) = iter.next() {
// TODO(jiyong): remove this check by canonicalizing `path`
if name == ".." {
@@ -211,8 +217,11 @@
}
// No inode found. Create a new inode and add it to the inode table.
+ // At the moment of writing this comment the apk file doesn't specify any
+ // permissions (apart from the ones on lib/), but it might change in the future.
+ // TODO(b/270955654): should we control the file permissions ourselves?
let inode = if is_file {
- InodeData::new_file(i, &file)
+ InodeData::new_file(i, file.unix_mode().unwrap_or(file_mode), &file)
} else if is_leaf {
InodeData::new_dir(file.unix_mode().unwrap_or(DEFAULT_DIR_MODE))
} else {