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
This commit is contained in:
Risan 2018-10-26 20:56:45 -06:00
parent 6a1c15cf5b
commit 8f6198d299
5 changed files with 73 additions and 104 deletions

View file

@ -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) {

View file

@ -82,9 +82,11 @@ class VoldNativeService : public BinderService<VoldNativeService>, public os::Bn
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 mountId);
binder::Status openAppFuseFile(int32_t uid, int32_t mountId, int32_t fileId, int32_t flags,
android::base::unique_fd* _aidl_return);
binder::Status unmountAppFuse(int32_t uid, int32_t pid, int32_t mountId);
binder::Status fdeCheckPassword(const std::string& password);
binder::Status fdeRestart();

View file

@ -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;
}
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;
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;
}
}
// 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);
LOG(DEBUG) << "Run app fuse command " << command << " for the path " << path << " and uid "
<< uid;
}
if (command == "mount") {
_exit(mountInNamespace(uid, device_fd, path));
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.";
_exit(-errno);
return -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;
}
return android::OK;
} else {
LOG(ERROR) << "Unknown appfuse command " << command;
return -EPERM;
}
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));
}

View file

@ -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();

View file

@ -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;