From ac02a4863f36f28e2c50373102ae0dd1ae444e8f Mon Sep 17 00:00:00 2001 From: Risan Date: Wed, 31 Oct 2018 21:59:47 -0600 Subject: [PATCH] Extract AppFuse as a util Bug: 110379912 Test: testOpenProxyFileDescriptor Change-Id: I0429a498d7b54682efe9b05815f3470e8745609e --- Android.bp | 1 + AppFuseUtil.cpp | 164 ++++++++++++++++++++++++++++++++++++++++++++++ AppFuseUtil.h | 36 ++++++++++ VolumeManager.cpp | 122 ++-------------------------------- VolumeManager.h | 2 - 5 files changed, 205 insertions(+), 120 deletions(-) create mode 100644 AppFuseUtil.cpp create mode 100644 AppFuseUtil.h diff --git a/Android.bp b/Android.bp index 44e2317..b192b42 100644 --- a/Android.bp +++ b/Android.bp @@ -95,6 +95,7 @@ cc_library_static { ], srcs: [ + "AppFuseUtil.cpp", "Benchmark.cpp", "CheckEncryption.cpp", "Checkpoint.cpp", diff --git a/AppFuseUtil.cpp b/AppFuseUtil.cpp new file mode 100644 index 0000000..ba82ba5 --- /dev/null +++ b/AppFuseUtil.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "AppFuseUtil.h" + +#include +#include + +#include +#include + +#include "Utils.h" + +using android::base::StringPrintf; + +namespace android { +namespace vold { + +namespace { + +static size_t kAppFuseMaxMountPointName = 32; + +static android::status_t GetMountPath(uid_t uid, const std::string& name, std::string* path) { + if (name.size() > kAppFuseMaxMountPointName) { + LOG(ERROR) << "AppFuse mount name is too long."; + return -EINVAL; + } + for (size_t i = 0; i < name.size(); i++) { + if (!isalnum(name[i])) { + LOG(ERROR) << "AppFuse mount name contains invalid character."; + return -EINVAL; + } + } + *path = StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str()); + return android::OK; +} + +static android::status_t Mount(int device_fd, const std::string& path) { + // Remove existing mount. + android::vold::ForceUnmount(path); + + const auto opts = StringPrintf( + "fd=%i," + "rootmode=40000," + "default_permissions," + "allow_other," + "user_id=0,group_id=0," + "context=\"u:object_r:app_fuse_file:s0\"," + "fscontext=u:object_r:app_fusefs:s0", + device_fd); + + const int result = + TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse", + MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str())); + if (result != 0) { + PLOG(ERROR) << "Failed to mount " << path; + return -errno; + } + + return android::OK; +} + +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 << " and uid " + << uid; + } + + 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 (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; + } + + return android::OK; +} + +} // namespace + +int MountAppFuse(uid_t uid, int mountId, android::base::unique_fd* device_fd) { + std::string name = std::to_string(mountId); + + // Check mount point name. + std::string path; + if (GetMountPath(uid, name, &path) != android::OK) { + LOG(ERROR) << "Invalid mount point name"; + return -1; + } + + // Create directories. + const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << path; + return -1; + } + + // Open device FD. + device_fd->reset(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC + if (device_fd->get() == -1) { + PLOG(ERROR) << "Failed to open /dev/fuse"; + return -1; + } + + // Mount. + return RunCommand("mount", uid, path, device_fd->get()); +} + +int UnmountAppFuse(uid_t uid, int mountId) { + std::string name = std::to_string(mountId); + + // Check mount point name. + std::string path; + if (GetMountPath(uid, name, &path) != android::OK) { + LOG(ERROR) << "Invalid mount point name"; + return -1; + } + + return RunCommand("unmount", uid, path, -1 /* device_fd */); +} + +int 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)); +} + +} // namespace vold +} // namespace android diff --git a/AppFuseUtil.h b/AppFuseUtil.h new file mode 100644 index 0000000..463c6d0 --- /dev/null +++ b/AppFuseUtil.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_VOLD_APP_FUSE_UTIL_H_ +#define ANDROID_VOLD_APP_FUSE_UTIL_H_ + +#include + +#define DEBUG_APPFUSE 0 + +namespace android { +namespace vold { + +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); + +} // namespace vold +} // namespace android + +#endif // ANDROID_VOLD_APP_FUSE_UTIL_H_ diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 21136cf..e08319b 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -50,6 +50,7 @@ #include +#include "AppFuseUtil.h" #include "Devmapper.h" #include "FsCrypt.h" #include "Loop.h" @@ -631,78 +632,6 @@ int VolumeManager::mkdirs(const std::string& path) { } } -static size_t kAppFuseMaxMountPointName = 32; - -static android::status_t getMountPath(uid_t uid, const std::string& name, std::string* path) { - if (name.size() > kAppFuseMaxMountPointName) { - LOG(ERROR) << "AppFuse mount name is too long."; - return -EINVAL; - } - for (size_t i = 0; i < name.size(); i++) { - if (!isalnum(name[i])) { - LOG(ERROR) << "AppFuse mount name contains invalid character."; - return -EINVAL; - } - } - *path = StringPrintf("/mnt/appfuse/%d_%s", uid, name.c_str()); - return android::OK; -} - -static android::status_t mount(int device_fd, const std::string& path) { - // Remove existing mount. - android::vold::ForceUnmount(path); - - const auto opts = StringPrintf( - "fd=%i," - "rootmode=40000," - "default_permissions," - "allow_other," - "user_id=0,group_id=0," - "context=\"u:object_r:app_fuse_file:s0\"," - "fscontext=u:object_r:app_fusefs:s0", - device_fd); - - const int result = - TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse", - MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str())); - if (result != 0) { - PLOG(ERROR) << "Failed to mount " << path; - return -errno; - } - - return android::OK; -} - -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 << " and uid " - << uid; - } - - 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 (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; - } - - return android::OK; -} - int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, int32_t ownerGid, std::string* outVolId) { int id = mNextObbId++; @@ -756,56 +685,13 @@ int VolumeManager::destroyStubVolume(const std::string& volId) { } int VolumeManager::mountAppFuse(uid_t uid, int mountId, unique_fd* device_fd) { - std::string name = std::to_string(mountId); - - // Check mount point name. - std::string path; - if (getMountPath(uid, name, &path) != android::OK) { - LOG(ERROR) << "Invalid mount point name"; - return -1; - } - - // Create directories. - const android::status_t result = android::vold::PrepareDir(path, 0700, 0, 0); - if (result != android::OK) { - PLOG(ERROR) << "Failed to prepare directory " << path; - return -1; - } - - // Open device FD. - device_fd->reset(open("/dev/fuse", O_RDWR)); // not O_CLOEXEC - if (device_fd->get() == -1) { - PLOG(ERROR) << "Failed to open /dev/fuse"; - return -1; - } - - // Mount. - return runCommand("mount", uid, path, device_fd->get()); + return android::vold::MountAppFuse(uid, mountId, device_fd); } int VolumeManager::unmountAppFuse(uid_t uid, int mountId) { - std::string name = std::to_string(mountId); - - // Check mount point name. - std::string path; - if (getMountPath(uid, name, &path) != android::OK) { - LOG(ERROR) << "Invalid mount point name"; - return -1; - } - - return runCommand("unmount", uid, path, -1 /* device_fd */); + return android::vold::UnmountAppFuse(uid, mountId); } 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)); + return android::vold::OpenAppFuseFile(uid, mountId, fileId, flags); } diff --git a/VolumeManager.h b/VolumeManager.h index a2d6c5b..9227819 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -38,8 +38,6 @@ #include "model/Disk.h" #include "model/VolumeBase.h" -#define DEBUG_APPFUSE 0 - class VolumeManager { private: static VolumeManager* sInstance;