VolumeManager: limit the scope of remountUid post fork.
We want to be sure we're not allocating memory, holding locks or otherwise preventing the child process from making progress. This is a temporary fix of limited scope. In the medium term, it would be preferable to exec a binary that performs this work for us as soon as we fork. Test: manual Bug: 141678467 Change-Id: I57dbd9b3c887aa27e2dd609abf0ad43c66f4ef2a
This commit is contained in:
parent
fe83792eec
commit
02efdf55d2
2 changed files with 67 additions and 37 deletions
|
@ -28,6 +28,7 @@ cc_defaults {
|
||||||
name: "vold_default_libs",
|
name: "vold_default_libs",
|
||||||
|
|
||||||
static_libs: [
|
static_libs: [
|
||||||
|
"libasync_safe",
|
||||||
"libavb",
|
"libavb",
|
||||||
"libbootloader_message",
|
"libbootloader_message",
|
||||||
"libdm",
|
"libdm",
|
||||||
|
|
|
@ -40,6 +40,7 @@
|
||||||
#include <android-base/properties.h>
|
#include <android-base/properties.h>
|
||||||
#include <android-base/stringprintf.h>
|
#include <android-base/stringprintf.h>
|
||||||
#include <android-base/strings.h>
|
#include <android-base/strings.h>
|
||||||
|
#include <async_safe/log.h>
|
||||||
|
|
||||||
#include <cutils/fs.h>
|
#include <cutils/fs.h>
|
||||||
#include <utils/Trace.h>
|
#include <utils/Trace.h>
|
||||||
|
@ -516,6 +517,51 @@ int VolumeManager::setPrimary(const std::shared_ptr<android::vold::VolumeBase>&
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This code is executed after a fork so it's very important that the set of
|
||||||
|
// methods we call here is strictly limited.
|
||||||
|
//
|
||||||
|
// TODO: Get rid of this guesswork altogether and instead exec a process
|
||||||
|
// immediately after fork to do our bindding for us.
|
||||||
|
static bool childProcess(const char* storageSource, const char* userSource, int nsFd,
|
||||||
|
struct dirent* de) {
|
||||||
|
if (setns(nsFd, CLONE_NEWNS) != 0) {
|
||||||
|
async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns for %s :%s", de->d_name,
|
||||||
|
strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// NOTE: Inlined from vold::UnmountTree here to avoid using PLOG methods and
|
||||||
|
// to also protect against future changes that may cause issues across a
|
||||||
|
// fork.
|
||||||
|
if (TEMP_FAILURE_RETRY(umount2("/storage/", MNT_DETACH)) < 0 && errno != EINVAL &&
|
||||||
|
errno != ENOENT) {
|
||||||
|
async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to unmount /storage/ :%s",
|
||||||
|
strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEMP_FAILURE_RETRY(mount(storageSource, "/storage", NULL, MS_BIND | MS_REC, NULL)) == -1) {
|
||||||
|
async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s for %s :%s",
|
||||||
|
storageSource, de->d_name, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEMP_FAILURE_RETRY(mount(NULL, "/storage", NULL, MS_REC | MS_SLAVE, NULL)) == -1) {
|
||||||
|
async_safe_format_log(ANDROID_LOG_ERROR, "vold",
|
||||||
|
"Failed to set MS_SLAVE to /storage for %s :%s", de->d_name,
|
||||||
|
strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (TEMP_FAILURE_RETRY(mount(userSource, "/storage/self", NULL, MS_BIND, NULL)) == -1) {
|
||||||
|
async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s for %s :%s",
|
||||||
|
userSource, de->d_name, strerror(errno));
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
|
int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
|
||||||
if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) {
|
if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) {
|
||||||
// TODO(135341433): Implement fuse specific logic.
|
// TODO(135341433): Implement fuse specific logic.
|
||||||
|
@ -557,6 +603,8 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
|
||||||
int nsFd;
|
int nsFd;
|
||||||
struct stat sb;
|
struct stat sb;
|
||||||
pid_t child;
|
pid_t child;
|
||||||
|
std::string userSource;
|
||||||
|
std::string storageSource;
|
||||||
|
|
||||||
static bool apexUpdatable = android::sysprop::ApexProperties::updatable().value_or(false);
|
static bool apexUpdatable = android::sysprop::ApexProperties::updatable().value_or(false);
|
||||||
|
|
||||||
|
@ -632,15 +680,6 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
|
||||||
goto next;
|
goto next;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!(child = fork())) {
|
|
||||||
if (setns(nsFd, CLONE_NEWNS) != 0) {
|
|
||||||
PLOG(ERROR) << "Failed to setns for " << de->d_name;
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
android::vold::UnmountTree("/storage/");
|
|
||||||
|
|
||||||
std::string storageSource;
|
|
||||||
if (mode == "default") {
|
if (mode == "default") {
|
||||||
storageSource = "/mnt/runtime/default";
|
storageSource = "/mnt/runtime/default";
|
||||||
} else if (mode == "read") {
|
} else if (mode == "read") {
|
||||||
|
@ -650,29 +689,19 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) {
|
||||||
} else if (mode == "full") {
|
} else if (mode == "full") {
|
||||||
storageSource = "/mnt/runtime/full";
|
storageSource = "/mnt/runtime/full";
|
||||||
} else {
|
} else {
|
||||||
// Sane default of no storage visible
|
// Sane default of no storage visible. No need to fork a child
|
||||||
_exit(0);
|
// to remount uid.
|
||||||
}
|
goto next;
|
||||||
if (TEMP_FAILURE_RETRY(
|
|
||||||
mount(storageSource.c_str(), "/storage", NULL, MS_BIND | MS_REC, NULL)) == -1) {
|
|
||||||
PLOG(ERROR) << "Failed to mount " << storageSource << " for " << de->d_name;
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
if (TEMP_FAILURE_RETRY(mount(NULL, "/storage", NULL, MS_REC | MS_SLAVE, NULL)) == -1) {
|
|
||||||
PLOG(ERROR) << "Failed to set MS_SLAVE to /storage for " << de->d_name;
|
|
||||||
_exit(1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mount user-specific symlink helper into place
|
// Mount user-specific symlink helper into place
|
||||||
userid_t user_id = multiuser_get_user_id(uid);
|
userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid));
|
||||||
std::string userSource(StringPrintf("/mnt/user/%d", user_id));
|
if (!(child = fork())) {
|
||||||
if (TEMP_FAILURE_RETRY(
|
if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, de)) {
|
||||||
mount(userSource.c_str(), "/storage/self", NULL, MS_BIND, NULL)) == -1) {
|
_exit(0);
|
||||||
PLOG(ERROR) << "Failed to mount " << userSource << " for " << de->d_name;
|
} else {
|
||||||
_exit(1);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
_exit(0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (child == -1) {
|
if (child == -1) {
|
||||||
|
|
Loading…
Reference in a new issue