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/VoldNativeService.cpp b/VoldNativeService.cpp
index 014f8e1..c2d4e0b 100644
--- a/VoldNativeService.cpp
+++ b/VoldNativeService.cpp
@@ -654,19 +654,36 @@
return ok();
}
-binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t mountId,
android::base::unique_fd* _aidl_return) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
- return translate(VolumeManager::Instance()->mountAppFuse(uid, pid, mountId, _aidl_return));
+ return translate(VolumeManager::Instance()->mountAppFuse(uid, mountId, _aidl_return));
}
-binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId) {
+binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t mountId) {
ENFORCE_UID(AID_SYSTEM);
ACQUIRE_LOCK;
- return translate(VolumeManager::Instance()->unmountAppFuse(uid, pid, mountId));
+ return translate(VolumeManager::Instance()->unmountAppFuse(uid, mountId));
+}
+
+binder::Status VoldNativeService::openAppFuseFile(int32_t uid, int32_t mountId, int32_t fileId,
+ int32_t flags,
+ android::base::unique_fd* _aidl_return) {
+ ENFORCE_UID(AID_SYSTEM);
+ ACQUIRE_LOCK;
+
+ int fd = VolumeManager::Instance()->openAppFuseFile(uid, mountId, fileId, flags);
+ if (fd == -1) {
+ return error("Failed to open AppFuse file for uid: " + std::to_string(uid) +
+ " mountId: " + std::to_string(mountId) + " fileId: " + std::to_string(fileId) +
+ " flags: " + std::to_string(flags));
+ }
+
+ *_aidl_return = android::base::unique_fd(fd);
+ return ok();
}
binder::Status VoldNativeService::fdeCheckPassword(const std::string& password) {
diff --git a/VoldNativeService.h b/VoldNativeService.h
index 76a21fb..726de68 100644
--- a/VoldNativeService.h
+++ b/VoldNativeService.h
@@ -82,9 +82,11 @@
binder::Status runIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
binder::Status abortIdleMaint(const android::sp<android::os::IVoldTaskListener>& listener);
- binder::Status mountAppFuse(int32_t uid, int32_t pid, int32_t mountId,
+ binder::Status mountAppFuse(int32_t uid, int32_t mountId,
android::base::unique_fd* _aidl_return);
- binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId);
+ binder::Status unmountAppFuse(int32_t uid, int32_t mountId);
+ binder::Status openAppFuseFile(int32_t uid, int32_t mountId, int32_t fileId, int32_t flags,
+ android::base::unique_fd* _aidl_return);
binder::Status fdeCheckPassword(const std::string& password);
binder::Status fdeRestart();
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));
}
diff --git a/VolumeManager.h b/VolumeManager.h
index e25e244..6d3a987 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -141,8 +141,9 @@
const std::string& fsLabel, std::string* outVolId);
int destroyStubVolume(const std::string& volId);
- int mountAppFuse(uid_t uid, pid_t pid, int mountId, android::base::unique_fd* device_fd);
- int unmountAppFuse(uid_t uid, pid_t pid, int mountId);
+ int mountAppFuse(uid_t uid, int mountId, android::base::unique_fd* device_fd);
+ int unmountAppFuse(uid_t uid, int mountId);
+ int openAppFuseFile(uid_t uid, int mountId, int fileId, int flags);
private:
VolumeManager();
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index c45d509..2f7430f 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -62,8 +62,8 @@
void runIdleMaint(IVoldTaskListener listener);
void abortIdleMaint(IVoldTaskListener listener);
- FileDescriptor mountAppFuse(int uid, int pid, int mountId);
- void unmountAppFuse(int uid, int pid, int mountId);
+ FileDescriptor mountAppFuse(int uid, int mountId);
+ void unmountAppFuse(int uid, int mountId);
void fdeCheckPassword(@utf8InCpp String password);
void fdeRestart();
@@ -119,6 +119,8 @@
@utf8InCpp String fsUuid, @utf8InCpp String fsLabel);
void destroyStubVolume(@utf8InCpp String volId);
+ FileDescriptor openAppFuseFile(int uid, int mountId, int fileId, int flags);
+
const int ENCRYPTION_FLAG_NO_UI = 4;
const int ENCRYPTION_STATE_NONE = 1;