Change AppFuse mount location to vold namespace
Previously, AppFuse is mounted in system_server's mount namespace. This
CL moves the mount location to vold namespace.
Relanding this since it fails to be merged on ag/5521004 (blocked by
Presubmit, seems to be caused by temporary state) - this one now
passes presubmit without any changes.
Bug: 110379912
Test: testOpenProxyFileDescriptor passes
Change-Id: Id93c26d5a98842c78f27850c83e15df619cec1ab
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index f3604ee..91ee413 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -1280,7 +1280,7 @@
return android::OK;
}
-static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
+static android::status_t mount(int device_fd, const std::string& path) {
// Remove existing mount.
android::vold::ForceUnmount(path);
@@ -1289,10 +1289,10 @@
"rootmode=40000,"
"default_permissions,"
"allow_other,"
- "user_id=%d,group_id=%d,"
+ "user_id=0,group_id=0,"
"context=\"u:object_r:app_fuse_file:s0\","
"fscontext=u:object_r:app_fusefs:s0",
- device_fd, uid, uid);
+ device_fd);
const int result =
TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse",
@@ -1305,101 +1305,34 @@
return android::OK;
}
-static android::status_t runCommandInNamespace(const std::string& command, uid_t uid, pid_t pid,
- const std::string& path, int device_fd) {
+static android::status_t runCommand(const std::string& command, uid_t uid, const std::string& path,
+ int device_fd) {
if (DEBUG_APPFUSE) {
- LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path
- << " in namespace " << uid;
+ LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path << " and uid "
+ << uid;
}
- unique_fd dir(open("/proc", O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (dir.get() == -1) {
- PLOG(ERROR) << "Failed to open /proc";
- return -errno;
- }
-
- // Obtains process file descriptor.
- const std::string pid_str = StringPrintf("%d", pid);
- const unique_fd pid_fd(openat(dir.get(), pid_str.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
- if (pid_fd.get() == -1) {
- PLOG(ERROR) << "Failed to open /proc/" << pid;
- return -errno;
- }
-
- // Check UID of process.
- {
- struct stat sb;
- const int result = fstat(pid_fd.get(), &sb);
- if (result == -1) {
- PLOG(ERROR) << "Failed to stat /proc/" << pid;
+ if (command == "mount") {
+ return mount(device_fd, path);
+ } else if (command == "unmount") {
+ // If it's just after all FD opened on mount point are closed, umount2 can fail with
+ // EBUSY. To avoid the case, specify MNT_DETACH.
+ if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 && errno != EINVAL &&
+ errno != ENOENT) {
+ PLOG(ERROR) << "Failed to unmount directory.";
return -errno;
}
- if (sb.st_uid != AID_SYSTEM) {
- LOG(ERROR) << "Only system can mount appfuse. UID expected=" << AID_SYSTEM
- << ", actual=" << sb.st_uid;
- return -EPERM;
+ if (rmdir(path.c_str()) != 0) {
+ PLOG(ERROR) << "Failed to remove the mount directory.";
+ return -errno;
}
+ return android::OK;
+ } else {
+ LOG(ERROR) << "Unknown appfuse command " << command;
+ return -EPERM;
}
- // Matches so far, but refuse to touch if in root namespace
- {
- std::string rootName;
- std::string pidName;
- if (!android::vold::Readlinkat(dir.get(), "1/ns/mnt", &rootName) ||
- !android::vold::Readlinkat(pid_fd.get(), "ns/mnt", &pidName)) {
- PLOG(ERROR) << "Failed to read namespaces";
- return -EPERM;
- }
- if (rootName == pidName) {
- LOG(ERROR) << "Don't mount appfuse in root namespace";
- return -EPERM;
- }
- }
-
- // We purposefully leave the namespace open across the fork
- unique_fd ns_fd(openat(pid_fd.get(), "ns/mnt", O_RDONLY)); // not O_CLOEXEC
- if (ns_fd.get() < 0) {
- PLOG(ERROR) << "Failed to open namespace for /proc/" << pid << "/ns/mnt";
- return -errno;
- }
-
- int child = fork();
- if (child == 0) {
- if (setns(ns_fd.get(), CLONE_NEWNS) != 0) {
- PLOG(ERROR) << "Failed to setns";
- _exit(-errno);
- }
-
- if (command == "mount") {
- _exit(mountInNamespace(uid, device_fd, path));
- } else if (command == "unmount") {
- // If it's just after all FD opened on mount point are closed, umount2 can fail with
- // EBUSY. To avoid the case, specify MNT_DETACH.
- if (umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) != 0 && errno != EINVAL &&
- errno != ENOENT) {
- PLOG(ERROR) << "Failed to unmount directory.";
- _exit(-errno);
- }
- if (rmdir(path.c_str()) != 0) {
- PLOG(ERROR) << "Failed to remove the mount directory.";
- _exit(-errno);
- }
- _exit(android::OK);
- } else {
- LOG(ERROR) << "Unknown appfuse command " << command;
- _exit(-EPERM);
- }
- }
-
- if (child == -1) {
- PLOG(ERROR) << "Failed to folk child process";
- return -errno;
- }
-
- android::status_t status;
- TEMP_FAILURE_RETRY(waitpid(child, &status, 0));
-
- return status;
+ return android::OK;
}
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
@@ -1454,7 +1387,7 @@
return android::OK;
}
-int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId, unique_fd* device_fd) {
+int VolumeManager::mountAppFuse(uid_t uid, int mountId, unique_fd* device_fd) {
std::string name = std::to_string(mountId);
// Check mount point name.
@@ -1479,10 +1412,10 @@
}
// Mount.
- return runCommandInNamespace("mount", uid, pid, path, device_fd->get());
+ return runCommand("mount", uid, path, device_fd->get());
}
-int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) {
+int VolumeManager::unmountAppFuse(uid_t uid, int mountId) {
std::string name = std::to_string(mountId);
// Check mount point name.
@@ -1492,5 +1425,19 @@
return -1;
}
- return runCommandInNamespace("unmount", uid, pid, path, -1 /* device_fd */);
+ return runCommand("unmount", uid, path, -1 /* device_fd */);
+}
+
+int VolumeManager::openAppFuseFile(uid_t uid, int mountId, int fileId, int flags) {
+ std::string name = std::to_string(mountId);
+
+ // Check mount point name.
+ std::string mountPoint;
+ if (getMountPath(uid, name, &mountPoint) != android::OK) {
+ LOG(ERROR) << "Invalid mount point name";
+ return -1;
+ }
+
+ std::string path = StringPrintf("%s/%d", mountPoint.c_str(), fileId);
+ return TEMP_FAILURE_RETRY(open(path.c_str(), flags));
}