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.

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