diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index a06b357..c58ff01 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -529,19 +529,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 a02fa70..161acb8 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -75,9 +75,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 1fb7ce7..21136cf 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -648,7 +648,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); @@ -657,10 +657,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", @@ -673,101 +673,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, @@ -822,7 +755,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. @@ -847,10 +780,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. @@ -860,5 +793,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 2f76ddc..a2d6c5b 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -129,8 +129,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 ea98450..976eab1 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -58,8 +58,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(); @@ -110,6 +110,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;