am c7b5b570: Null-terminate readlink() result, full remount.
* commit 'c7b5b570bd05ed3bc921b0c2dc346416a52b4e3e':
Null-terminate readlink() result, full remount.
diff --git a/EmulatedVolume.cpp b/EmulatedVolume.cpp
index e906fa7..d8d9198 100644
--- a/EmulatedVolume.cpp
+++ b/EmulatedVolume.cpp
@@ -82,7 +82,7 @@
PLOG(ERROR) << "Failed to exec";
}
- PLOG(DEBUG) << "FUSE exiting";
+ LOG(ERROR) << "FUSE exiting";
_exit(1);
}
diff --git a/PublicVolume.cpp b/PublicVolume.cpp
index e4fdb86..29a357f 100644
--- a/PublicVolume.cpp
+++ b/PublicVolume.cpp
@@ -137,12 +137,15 @@
initAsecStage();
}
+ if (!(getMountFlags() & MountFlags::kVisible)) {
+ // Not visible to apps, so no need to spin up FUSE
+ return OK;
+ }
+
dev_t before = GetDevice(mFuseWrite);
if (!(mFusePid = fork())) {
- if (!(getMountFlags() & MountFlags::kVisible)) {
- // TODO: do we need to wrap this device?
- } else if (getMountFlags() & MountFlags::kPrimary) {
+ if (getMountFlags() & MountFlags::kPrimary) {
if (execl(kFusePath, kFusePath,
"-u", "1023", // AID_MEDIA_RW
"-g", "1023", // AID_MEDIA_RW
@@ -163,7 +166,7 @@
}
}
- PLOG(DEBUG) << "FUSE exiting";
+ LOG(ERROR) << "FUSE exiting";
_exit(1);
}
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 6caa5c0..d1a0b2f 100755
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -481,6 +481,46 @@
return 0;
}
+static int sane_readlinkat(int dirfd, const char* path, char* buf, size_t bufsiz) {
+ ssize_t len = readlinkat(dirfd, path, buf, bufsiz);
+ if (len < 0) {
+ return -1;
+ } else if (len == (ssize_t) bufsiz) {
+ return -1;
+ } else {
+ buf[len] = '\0';
+ return 0;
+ }
+}
+
+static int unmount_tree(const char* path) {
+ size_t path_len = strlen(path);
+
+ FILE* fp = setmntent("/proc/mounts", "r");
+ if (fp == NULL) {
+ ALOGE("Error opening /proc/mounts: %s", strerror(errno));
+ return -errno;
+ }
+
+ // Some volumes can be stacked on each other, so force unmount in
+ // reverse order to give us the best chance of success.
+ std::list<std::string> toUnmount;
+ mntent* mentry;
+ while ((mentry = getmntent(fp)) != NULL) {
+ if (strncmp(mentry->mnt_dir, path, path_len) == 0) {
+ toUnmount.push_front(std::string(mentry->mnt_dir));
+ }
+ }
+ endmntent(fp);
+
+ for (auto path : toUnmount) {
+ if (umount2(path.c_str(), MNT_DETACH)) {
+ ALOGW("Failed to unmount %s: %s", path.c_str(), strerror(errno));
+ }
+ }
+ return 0;
+}
+
int VolumeManager::remountUid(uid_t uid, const std::string& mode) {
LOG(DEBUG) << "Remounting " << uid << " as mode " << mode;
@@ -499,7 +539,7 @@
}
// Figure out root namespace to compare against below
- if (readlinkat(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
+ if (sane_readlinkat(dirfd(dir), "1/ns/mnt", rootName, PATH_MAX) == -1) {
PLOG(ERROR) << "Failed to readlink";
closedir(dir);
return -1;
@@ -524,7 +564,7 @@
// 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) {
+ if (sane_readlinkat(pidFd, "ns/mnt", pidName, PATH_MAX) == -1) {
PLOG(WARNING) << "Failed to read namespace for " << de->d_name;
goto next;
}
@@ -536,18 +576,17 @@
// 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";
+ PLOG(WARNING) << "Failed to open namespace for " << de->d_name;
goto next;
}
if (!(child = fork())) {
if (setns(nsFd, CLONE_NEWNS) != 0) {
- PLOG(ERROR) << "Failed to setns";
+ PLOG(ERROR) << "Failed to setns for " << de->d_name;
_exit(1);
}
- // Unmount current view and replace with requested view
- umount2("/storage", MNT_FORCE);
+ unmount_tree("/storage");
std::string storageSource;
if (mode == "default") {
@@ -562,9 +601,21 @@
}
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;
+ PLOG(ERROR) << "Failed to mount " << storageSource << " for "
+ << de->d_name;
+ _exit(1);
}
+
+ // Mount user-specific symlink helper into place
+ userid_t user_id = multiuser_get_user_id(uid);
+ std::string userSource(StringPrintf("/mnt/user/%d", user_id));
+ if (TEMP_FAILURE_RETRY(mount(userSource.c_str(), "/storage/self",
+ NULL, MS_BIND, NULL)) == -1) {
+ PLOG(ERROR) << "Failed to mount " << userSource << " for "
+ << de->d_name;
+ _exit(1);
+ }
+
_exit(0);
}