From 8f6198d299026f3b3c727f5f044a6aee084ef6aa Mon Sep 17 00:00:00 2001 From: Risan Date: Fri, 26 Oct 2018 20:56:45 -0600 Subject: [PATCH] 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 --- VoldNativeService.cpp | 25 +++++-- VoldNativeService.h | 6 +- VolumeManager.cpp | 135 +++++++++++------------------------ VolumeManager.h | 5 +- binder/android/os/IVold.aidl | 6 +- 5 files changed, 73 insertions(+), 104 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 014f8e1..c2d4e0b 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -654,19 +654,36 @@ binder::Status VoldNativeService::abortIdleMaint( 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 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status runIdleMaint(const android::sp& listener); binder::Status abortIdleMaint(const android::sp& 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 @@ static android::status_t getMountPath(uid_t uid, const std::string& name, std::s 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 @@ static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::s "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 @@ static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::s 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 @@ int VolumeManager::destroyStubVolume(const std::string& volId) { 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 @@ int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId, unique_fd* de } // 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 @@ int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) { 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 @@ class VolumeManager { 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 @@ interface IVold { 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 @@ interface IVold { @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;