* commit '0deb385f85b4569d98ed9d1df96de1761b378c17': Let's reinvent storage, yet again!
This commit is contained in:
commit
c36ffa0010
10 changed files with 200 additions and 53 deletions
|
@ -262,6 +262,12 @@ int CommandListener::VolumeCmd::runCommand(SocketClient *cli,
|
|||
// forget_partition [partGuid]
|
||||
std::string partGuid(argv[2]);
|
||||
return sendGenericOkFail(cli, vm->forgetPartition(partGuid));
|
||||
|
||||
} else if (cmd == "remount_uid" && argc > 3) {
|
||||
// remount_uid [uid] [none|default|read|write]
|
||||
uid_t uid = atoi(argv[2]);
|
||||
std::string mode(argv[3]);
|
||||
return sendGenericOkFail(cli, vm->remountUid(uid, mode));
|
||||
}
|
||||
|
||||
return cli->sendMsg(ResponseCode::CommandSyntaxError, nullptr, false);
|
||||
|
|
|
@ -39,37 +39,45 @@ static const char* kFusePath = "/system/bin/sdcard";
|
|||
EmulatedVolume::EmulatedVolume(const std::string& rawPath) :
|
||||
VolumeBase(Type::kEmulated), mFusePid(0) {
|
||||
setId("emulated");
|
||||
mFusePath = "/storage/emulated";
|
||||
mRawPath = rawPath;
|
||||
mLabel = "emulated";
|
||||
}
|
||||
|
||||
EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device,
|
||||
const std::string& fsUuid) : VolumeBase(Type::kEmulated), mFusePid(0) {
|
||||
setId(StringPrintf("emulated:%u,%u", major(device), minor(device)));
|
||||
mFusePath = StringPrintf("/storage/%s", fsUuid.c_str());
|
||||
mRawPath = rawPath;
|
||||
mLabel = fsUuid;
|
||||
}
|
||||
|
||||
EmulatedVolume::~EmulatedVolume() {
|
||||
}
|
||||
|
||||
status_t EmulatedVolume::doMount() {
|
||||
if (fs_prepare_dir(mFusePath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
||||
PLOG(ERROR) << getId() << " failed to create mount point " << mFusePath;
|
||||
mFuseDefault = StringPrintf("/mnt/runtime_default/%s", mLabel.c_str());
|
||||
mFuseRead = StringPrintf("/mnt/runtime_read/%s", mLabel.c_str());
|
||||
mFuseWrite = StringPrintf("/mnt/runtime_write/%s", mLabel.c_str());
|
||||
|
||||
setInternalPath(mRawPath);
|
||||
setPath(StringPrintf("/storage/%s", mLabel.c_str()));
|
||||
|
||||
if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
|
||||
fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
|
||||
fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
||||
PLOG(ERROR) << getId() << " failed to create mount points";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
setInternalPath(mRawPath);
|
||||
setPath(mFusePath);
|
||||
dev_t before = GetDevice(mFuseWrite);
|
||||
|
||||
if (!(mFusePid = fork())) {
|
||||
// TODO: protect when not mounted as visible
|
||||
if (execl(kFusePath, kFusePath,
|
||||
"-u", "1023", // AID_MEDIA_RW
|
||||
"-g", "1023", // AID_MEDIA_RW
|
||||
"-l",
|
||||
"-m",
|
||||
"-w",
|
||||
mRawPath.c_str(),
|
||||
mFusePath.c_str(),
|
||||
mLabel.c_str(),
|
||||
NULL)) {
|
||||
PLOG(ERROR) << "Failed to exec";
|
||||
}
|
||||
|
@ -83,6 +91,11 @@ status_t EmulatedVolume::doMount() {
|
|||
return -errno;
|
||||
}
|
||||
|
||||
while (before == GetDevice(mFuseWrite)) {
|
||||
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
|
||||
usleep(50000); // 50ms
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -93,13 +106,17 @@ status_t EmulatedVolume::doUnmount() {
|
|||
mFusePid = 0;
|
||||
}
|
||||
|
||||
ForceUnmount(mFusePath);
|
||||
ForceUnmount(mRawPath);
|
||||
ForceUnmount(mFuseDefault);
|
||||
ForceUnmount(mFuseRead);
|
||||
ForceUnmount(mFuseWrite);
|
||||
|
||||
if (TEMP_FAILURE_RETRY(rmdir(mFusePath.c_str()))) {
|
||||
PLOG(ERROR) << getId() << " failed to rmdir mount point " << mFusePath;
|
||||
return -errno;
|
||||
}
|
||||
rmdir(mFuseDefault.c_str());
|
||||
rmdir(mFuseRead.c_str());
|
||||
rmdir(mFuseWrite.c_str());
|
||||
|
||||
mFuseDefault.clear();
|
||||
mFuseRead.clear();
|
||||
mFuseWrite.clear();
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
|
|
@ -46,10 +46,13 @@ protected:
|
|||
status_t doUnmount() override;
|
||||
|
||||
private:
|
||||
/* Mount point of raw storage */
|
||||
std::string mRawPath;
|
||||
/* Mount point of visible storage */
|
||||
std::string mFusePath;
|
||||
std::string mLabel;
|
||||
|
||||
std::string mFuseDefault;
|
||||
std::string mFuseRead;
|
||||
std::string mFuseWrite;
|
||||
|
||||
/* PID of FUSE wrapper */
|
||||
pid_t mFusePid;
|
||||
|
||||
|
|
|
@ -111,16 +111,19 @@ status_t PublicVolume::doMount() {
|
|||
}
|
||||
|
||||
mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str());
|
||||
mFusePath = StringPrintf("/storage/%s", stableName.c_str());
|
||||
setInternalPath(mRawPath);
|
||||
setPath(mFusePath);
|
||||
|
||||
if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
||||
PLOG(ERROR) << getId() << " failed to create mount point " << mRawPath;
|
||||
return -errno;
|
||||
}
|
||||
if (fs_prepare_dir(mFusePath.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
||||
PLOG(ERROR) << getId() << " failed to create mount point " << mFusePath;
|
||||
mFuseDefault = StringPrintf("/mnt/runtime_default/%s", stableName.c_str());
|
||||
mFuseRead = StringPrintf("/mnt/runtime_read/%s", stableName.c_str());
|
||||
mFuseWrite = StringPrintf("/mnt/runtime_write/%s", stableName.c_str());
|
||||
|
||||
setInternalPath(mRawPath);
|
||||
setPath(StringPrintf("/storage/%s", stableName.c_str()));
|
||||
|
||||
if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT) ||
|
||||
fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) ||
|
||||
fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) ||
|
||||
fs_prepare_dir(mFuseWrite.c_str(), 0700, AID_ROOT, AID_ROOT)) {
|
||||
PLOG(ERROR) << getId() << " failed to create mount points";
|
||||
return -errno;
|
||||
}
|
||||
|
||||
|
@ -134,25 +137,18 @@ status_t PublicVolume::doMount() {
|
|||
initAsecStage();
|
||||
}
|
||||
|
||||
// TODO: teach FUSE daemon to protect itself with user-specific GID
|
||||
dev_t before = GetDevice(mFuseWrite);
|
||||
|
||||
if (!(mFusePid = fork())) {
|
||||
if (!(getMountFlags() & MountFlags::kVisible)) {
|
||||
// TODO: mount so that only system apps can access
|
||||
if (execl(kFusePath, kFusePath,
|
||||
"-u", "1023", // AID_MEDIA_RW
|
||||
"-g", "1023", // AID_MEDIA_RW
|
||||
mRawPath.c_str(),
|
||||
mFusePath.c_str(),
|
||||
NULL)) {
|
||||
PLOG(ERROR) << "Failed to exec";
|
||||
}
|
||||
// TODO: do we need to wrap this device?
|
||||
} else if (getMountFlags() & MountFlags::kPrimary) {
|
||||
if (execl(kFusePath, kFusePath,
|
||||
"-u", "1023", // AID_MEDIA_RW
|
||||
"-g", "1023", // AID_MEDIA_RW
|
||||
"-d",
|
||||
"-w",
|
||||
mRawPath.c_str(),
|
||||
mFusePath.c_str(),
|
||||
stableName.c_str(),
|
||||
NULL)) {
|
||||
PLOG(ERROR) << "Failed to exec";
|
||||
}
|
||||
|
@ -160,10 +156,8 @@ status_t PublicVolume::doMount() {
|
|||
if (execl(kFusePath, kFusePath,
|
||||
"-u", "1023", // AID_MEDIA_RW
|
||||
"-g", "1023", // AID_MEDIA_RW
|
||||
"-w", "1023", // AID_MEDIA_RW
|
||||
"-d",
|
||||
mRawPath.c_str(),
|
||||
mFusePath.c_str(),
|
||||
stableName.c_str(),
|
||||
NULL)) {
|
||||
PLOG(ERROR) << "Failed to exec";
|
||||
}
|
||||
|
@ -178,6 +172,11 @@ status_t PublicVolume::doMount() {
|
|||
return -errno;
|
||||
}
|
||||
|
||||
while (before == GetDevice(mFuseWrite)) {
|
||||
LOG(VERBOSE) << "Waiting for FUSE to spin up...";
|
||||
usleep(50000); // 50ms
|
||||
}
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
|
@ -189,17 +188,20 @@ status_t PublicVolume::doUnmount() {
|
|||
}
|
||||
|
||||
ForceUnmount(kAsecPath);
|
||||
ForceUnmount(mFusePath);
|
||||
|
||||
ForceUnmount(mFuseDefault);
|
||||
ForceUnmount(mFuseRead);
|
||||
ForceUnmount(mFuseWrite);
|
||||
ForceUnmount(mRawPath);
|
||||
|
||||
if (TEMP_FAILURE_RETRY(rmdir(mRawPath.c_str()))) {
|
||||
PLOG(ERROR) << getId() << " failed to rmdir mount point " << mRawPath;
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY(rmdir(mFusePath.c_str()))) {
|
||||
PLOG(ERROR) << getId() << " failed to rmdir mount point " << mFusePath;
|
||||
}
|
||||
rmdir(mFuseDefault.c_str());
|
||||
rmdir(mFuseRead.c_str());
|
||||
rmdir(mFuseWrite.c_str());
|
||||
rmdir(mRawPath.c_str());
|
||||
|
||||
mFusePath.clear();
|
||||
mFuseDefault.clear();
|
||||
mFuseRead.clear();
|
||||
mFuseWrite.clear();
|
||||
mRawPath.clear();
|
||||
|
||||
return OK;
|
||||
|
|
|
@ -59,8 +59,11 @@ private:
|
|||
std::string mDevPath;
|
||||
/* Mount point of raw partition */
|
||||
std::string mRawPath;
|
||||
/* Mount point of FUSE wrapper */
|
||||
std::string mFusePath;
|
||||
|
||||
std::string mFuseDefault;
|
||||
std::string mFuseRead;
|
||||
std::string mFuseWrite;
|
||||
|
||||
/* PID of FUSE wrapper */
|
||||
pid_t mFusePid;
|
||||
|
||||
|
|
10
Utils.cpp
10
Utils.cpp
|
@ -522,5 +522,15 @@ std::string BuildKeyPath(const std::string& partGuid) {
|
|||
return StringPrintf("%s/expand_%s.key", kKeyPath, partGuid.c_str());
|
||||
}
|
||||
|
||||
dev_t GetDevice(const std::string& path) {
|
||||
struct stat sb;
|
||||
if (stat(path.c_str(), &sb)) {
|
||||
PLOG(WARNING) << "Failed to stat " << path;
|
||||
return 0;
|
||||
} else {
|
||||
return sb.st_dev;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
|
2
Utils.h
2
Utils.h
|
@ -90,6 +90,8 @@ status_t WipeBlockDevice(const std::string& path);
|
|||
|
||||
std::string BuildKeyPath(const std::string& partGuid);
|
||||
|
||||
dev_t GetDevice(const std::string& path);
|
||||
|
||||
} // namespace vold
|
||||
} // namespace android
|
||||
|
||||
|
|
|
@ -219,7 +219,6 @@ status_t VolumeBase::unmount() {
|
|||
}
|
||||
|
||||
setState(State::kEjecting);
|
||||
|
||||
for (auto vol : mVolumes) {
|
||||
if (vol->destroy()) {
|
||||
LOG(WARNING) << getId() << " failed to destroy " << vol->getId()
|
||||
|
|
|
@ -26,6 +26,7 @@
|
|||
#include <sys/mount.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <linux/kdev_t.h>
|
||||
|
@ -480,6 +481,108 @@ int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>&
|
|||
return 0;
|
||||
}
|
||||
|
||||
int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
|
||||
LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
|
||||
|
||||
DIR* dir;
|
||||
struct dirent* de;
|
||||
char rootName[PATH_MAX];
|
||||
char pidName[PATH_MAX];
|
||||
int pidFd;
|
||||
int nsFd;
|
||||
struct stat sb;
|
||||
pid_t child;
|
||||
|
||||
if (!(dir = opendir("/proc"))) {
|
||||
PLOG(ERROR) << "Failed to opendir";
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Figure out root namespace to compare against below
|
||||
if (readlinkat(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
|
||||
PLOG(ERROR) << "Failed to readlink";
|
||||
closedir(dir);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Poke through all running PIDs look for apps running as UID
|
||||
while ((de = readdir(dir))) {
|
||||
pidFd = -1;
|
||||
nsFd = -1;
|
||||
|
||||
pidFd = openat(dirfd(dir), de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC);
|
||||
if (pidFd < 0) {
|
||||
goto next;
|
||||
}
|
||||
if (fstat(pidFd, &sb) != 0) {
|
||||
PLOG(WARNING) << "Failed to stat " << de->d_name;
|
||||
goto next;
|
||||
}
|
||||
if (sb.st_uid != uid) {
|
||||
goto next;
|
||||
}
|
||||
|
||||
// Matches so far, but refuse to touch if in root namespace
|
||||
LOG(DEBUG) << "Found matching PID " << de->d_name;
|
||||
if (readlinkat(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) {
|
||||
PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
|
||||
goto next;
|
||||
}
|
||||
if (!strcmp(rootName, pidName)) {
|
||||
LOG(WARNING) << "Skipping due to root namespace";
|
||||
goto next;
|
||||
}
|
||||
|
||||
// We purposefully leave the namespace open across the fork
|
||||
nsFd = openat(pidFd, "ns/mnt", O_RDONLY);
|
||||
if (nsFd < 0) {
|
||||
PLOG(WARNING) << "Failed to open namespace";
|
||||
goto next;
|
||||
}
|
||||
|
||||
if (!(child = fork())) {
|
||||
if (setns(nsFd, CLONE_NEWNS) != 0) {
|
||||
PLOG(ERROR) << "Failed to setns";
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
// Unmount current view and replace with requested view
|
||||
umount2("/storage", MNT_FORCE);
|
||||
|
||||
std::string storageSource;
|
||||
if (mode == "default") {
|
||||
storageSource = "/mnt/runtime_default";
|
||||
} else if (mode == "read") {
|
||||
storageSource = "/mnt/runtime_read";
|
||||
} else if (mode == "write") {
|
||||
storageSource = "/mnt/runtime_write";
|
||||
} else {
|
||||
// Sane default of no storage visible
|
||||
_exit(0);
|
||||
}
|
||||
if (TEMP_FAILURE_RETRY(mount(storageSource.c_str(), "/storage",
|
||||
NULL, MS_BIND | MS_REC | MS_SLAVE, NULL)) == -1) {
|
||||
PLOG(WARNING) << "Failed to mount " << storageSource;
|
||||
return false;
|
||||
}
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
if (child == -1) {
|
||||
PLOG(ERROR) << "Failed to fork";
|
||||
goto next;
|
||||
} else {
|
||||
TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0));
|
||||
}
|
||||
|
||||
next:
|
||||
close(nsFd);
|
||||
close(pidFd);
|
||||
}
|
||||
closedir(dir);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int VolumeManager::reset() {
|
||||
// Tear down all existing disks/volumes and start from a blank slate so
|
||||
// newly connected framework hears all events.
|
||||
|
|
|
@ -129,6 +129,8 @@ public:
|
|||
|
||||
int setPrimary(const std::shared_ptr<android::vold::VolumeBase>& vol);
|
||||
|
||||
int remountUid(uid_t uid, const std::string& mode);
|
||||
|
||||
/* Reset all internal state, typically during framework boot */
|
||||
int reset();
|
||||
/* Prepare for device shutdown, safely unmounting all devices */
|
||||
|
|
Loading…
Reference in a new issue