|
|
|
@ -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 mount(int device_fd, const std::string& path) {
|
|
|
|
|
static android::status_t mountInNamespace(uid_t uid, int device_fd, const std::string& path) {
|
|
|
|
|
// Remove existing mount.
|
|
|
|
|
android::vold::ForceUnmount(path);
|
|
|
|
|
|
|
|
|
@ -1289,10 +1289,10 @@ static android::status_t mount(int device_fd, const std::string& path) {
|
|
|
|
|
"rootmode=40000,"
|
|
|
|
|
"default_permissions,"
|
|
|
|
|
"allow_other,"
|
|
|
|
|
"user_id=0,group_id=0,"
|
|
|
|
|
"user_id=%d,group_id=%d,"
|
|
|
|
|
"context=\"u:object_r:app_fuse_file:s0\","
|
|
|
|
|
"fscontext=u:object_r:app_fusefs:s0",
|
|
|
|
|
device_fd);
|
|
|
|
|
device_fd, uid, uid);
|
|
|
|
|
|
|
|
|
|
const int result =
|
|
|
|
|
TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse",
|
|
|
|
@ -1305,34 +1305,101 @@ static android::status_t mount(int device_fd, const std::string& path) {
|
|
|
|
|
return android::OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static android::status_t runCommand(const std::string& command, uid_t uid, const std::string& path,
|
|
|
|
|
int device_fd) {
|
|
|
|
|
static android::status_t runCommandInNamespace(const std::string& command, uid_t uid, pid_t pid,
|
|
|
|
|
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.";
|
|
|
|
|
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 (rmdir(path.c_str()) != 0) {
|
|
|
|
|
PLOG(ERROR) << "Failed to remove the mount 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;
|
|
|
|
|
}
|
|
|
|
|
return android::OK;
|
|
|
|
|
} else {
|
|
|
|
|
LOG(ERROR) << "Unknown appfuse command " << command;
|
|
|
|
|
return -EPERM;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return android::OK;
|
|
|
|
|
// 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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey,
|
|
|
|
@ -1387,7 +1454,7 @@ int VolumeManager::destroyStubVolume(const std::string& volId) {
|
|
|
|
|
return android::OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VolumeManager::mountAppFuse(uid_t uid, int mountId, unique_fd* device_fd) {
|
|
|
|
|
int VolumeManager::mountAppFuse(uid_t uid, pid_t pid, int mountId, unique_fd* device_fd) {
|
|
|
|
|
std::string name = std::to_string(mountId);
|
|
|
|
|
|
|
|
|
|
// Check mount point name.
|
|
|
|
@ -1412,10 +1479,10 @@ int VolumeManager::mountAppFuse(uid_t uid, int mountId, unique_fd* device_fd) {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Mount.
|
|
|
|
|
return runCommand("mount", uid, path, device_fd->get());
|
|
|
|
|
return runCommandInNamespace("mount", uid, pid, path, device_fd->get());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int VolumeManager::unmountAppFuse(uid_t uid, int mountId) {
|
|
|
|
|
int VolumeManager::unmountAppFuse(uid_t uid, pid_t pid, int mountId) {
|
|
|
|
|
std::string name = std::to_string(mountId);
|
|
|
|
|
|
|
|
|
|
// Check mount point name.
|
|
|
|
@ -1425,19 +1492,5 @@ int VolumeManager::unmountAppFuse(uid_t uid, int mountId) {
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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));
|
|
|
|
|
return runCommandInNamespace("unmount", uid, pid, path, -1 /* device_fd */);
|
|
|
|
|
}
|
|
|
|
|