From 4112c12cb6873579e23adede3f67e553650f00fb Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Mon, 29 Apr 2019 10:46:35 -0700 Subject: [PATCH 001/112] Remove storage sandboxes related code. Bug: 131115422 Test: manual Test: atest --test-mapping packages/providers/MediaProvider Test: atest cts/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java Test: atest DownloadProviderTests Test: atest cts/tests/app/src/android/app/cts/DownloadManagerTest.java Test: atest cts/tests/app/DownloadManagerLegacyTest/src/android/app/cts/DownloadManagerLegacyTest.java Test: atest cts/tests/app/DownloadManagerApi28Test/src/android/app/cts/DownloadManagerApi28Test.java Change-Id: Ib3272a47a901ed106474039e72f123b11f5443ff --- VoldNativeService.cpp | 133 +------ VoldNativeService.h | 4 +- VolumeManager.cpp | 667 +---------------------------------- VolumeManager.h | 40 +-- binder/android/os/IVold.aidl | 3 +- model/EmulatedVolume.cpp | 1 - model/PublicVolume.cpp | 1 - model/VolumeBase.cpp | 24 +- model/VolumeBase.h | 8 - 9 files changed, 14 insertions(+), 867 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index eb40d84..84c06f1 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -147,69 +147,6 @@ binder::Status checkArgumentHex(const std::string& hex) { return ok(); } -binder::Status checkArgumentPackageName(const std::string& packageName) { - // This logic is borrowed from PackageParser.java - bool hasSep = false; - bool front = true; - - for (size_t i = 0; i < packageName.length(); ++i) { - char c = packageName[i]; - if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { - front = false; - continue; - } - if (!front) { - if ((c >= '0' && c <= '9') || c == '_') { - continue; - } - } - if (c == '.') { - hasSep = true; - front = true; - continue; - } - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, - StringPrintf("Bad package character %c in %s", c, packageName.c_str())); - } - - if (front) { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, - StringPrintf("Missing separator in %s", packageName.c_str())); - } - - return ok(); -} - -binder::Status checkArgumentPackageNames(const std::vector& packageNames) { - for (size_t i = 0; i < packageNames.size(); ++i) { - binder::Status status = checkArgumentPackageName(packageNames[i]); - if (!status.isOk()) { - return status; - } - } - return ok(); -} - -binder::Status checkArgumentSandboxId(const std::string& sandboxId) { - // sandboxId will be in either the format shared- or - // and name has same requirements as . - std::size_t nameStartIndex = 0; - if (android::base::StartsWith(sandboxId, "shared-")) { - nameStartIndex = 7; // len("shared-") - } - return checkArgumentPackageName(sandboxId.substr(nameStartIndex)); -} - -binder::Status checkArgumentSandboxIds(const std::vector& sandboxIds) { - for (size_t i = 0; i < sandboxIds.size(); ++i) { - binder::Status status = checkArgumentSandboxId(sandboxIds[i]); - if (!status.isOk()) { - return status; - } - } - return ok(); -} - #define ENFORCE_UID(uid) \ { \ binder::Status status = checkUid((uid)); \ @@ -242,38 +179,6 @@ binder::Status checkArgumentSandboxIds(const std::vector& sandboxId } \ } -#define CHECK_ARGUMENT_PACKAGE_NAMES(packageNames) \ - { \ - binder::Status status = checkArgumentPackageNames((packageNames)); \ - if (!status.isOk()) { \ - return status; \ - } \ - } - -#define CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds) \ - { \ - binder::Status status = checkArgumentSandboxIds((sandboxIds)); \ - if (!status.isOk()) { \ - return status; \ - } \ - } - -#define CHECK_ARGUMENT_PACKAGE_NAME(packageName) \ - { \ - binder::Status status = checkArgumentPackageName((packageName)); \ - if (!status.isOk()) { \ - return status; \ - } \ - } - -#define CHECK_ARGUMENT_SANDBOX_ID(sandboxId) \ - { \ - binder::Status status = checkArgumentSandboxId((sandboxId)); \ - if (!status.isOk()) { \ - return status; \ - } \ - } - #define ACQUIRE_LOCK \ std::lock_guard lock(VolumeManager::Instance()->getLock()); \ ATRACE_CALL(); @@ -357,17 +262,11 @@ binder::Status VoldNativeService::onUserRemoved(int32_t userId) { return translate(VolumeManager::Instance()->onUserRemoved(userId)); } -binder::Status VoldNativeService::onUserStarted(int32_t userId, - const std::vector& packageNames, - const std::vector& appIds, - const std::vector& sandboxIds) { +binder::Status VoldNativeService::onUserStarted(int32_t userId) { ENFORCE_UID(AID_SYSTEM); - CHECK_ARGUMENT_PACKAGE_NAMES(packageNames); - CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds); ACQUIRE_LOCK; - return translate( - VolumeManager::Instance()->onUserStarted(userId, packageNames, appIds, sandboxIds)); + return translate(VolumeManager::Instance()->onUserStarted(userId)); } binder::Status VoldNativeService::onUserStopped(int32_t userId) { @@ -379,20 +278,12 @@ binder::Status VoldNativeService::onUserStopped(int32_t userId) { binder::Status VoldNativeService::addAppIds(const std::vector& packageNames, const std::vector& appIds) { - ENFORCE_UID(AID_SYSTEM); - CHECK_ARGUMENT_PACKAGE_NAMES(packageNames); - ACQUIRE_LOCK; - - return translate(VolumeManager::Instance()->addAppIds(packageNames, appIds)); + return ok(); } binder::Status VoldNativeService::addSandboxIds(const std::vector& appIds, const std::vector& sandboxIds) { - ENFORCE_UID(AID_SYSTEM); - CHECK_ARGUMENT_SANDBOX_IDS(sandboxIds); - ACQUIRE_LOCK; - - return translate(VolumeManager::Instance()->addSandboxIds(appIds, sandboxIds)); + return ok(); } binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) { @@ -916,25 +807,13 @@ binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptrprepareSandboxForApp(packageName, appId, sandboxId, userId)); + return ok(); } binder::Status VoldNativeService::destroySandboxForApp(const std::string& packageName, const std::string& sandboxId, int32_t userId) { - ENFORCE_UID(AID_SYSTEM); - CHECK_ARGUMENT_PACKAGE_NAME(packageName); - CHECK_ARGUMENT_SANDBOX_ID(sandboxId); - ACQUIRE_LOCK; - - return translate( - VolumeManager::Instance()->destroySandboxForApp(packageName, sandboxId, userId)); + return ok(); } binder::Status VoldNativeService::startCheckpoint(int32_t retry) { diff --git a/VoldNativeService.h b/VoldNativeService.h index 3f5ae83..5ca298e 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -39,9 +39,7 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status onUserAdded(int32_t userId, int32_t userSerial); binder::Status onUserRemoved(int32_t userId); - binder::Status onUserStarted(int32_t userId, const std::vector& packageNames, - const std::vector& appIds, - const std::vector& sandboxIds); + binder::Status onUserStarted(int32_t userId); binder::Status onUserStopped(int32_t userId); binder::Status addAppIds(const std::vector& packageNames, diff --git a/VolumeManager.cpp b/VolumeManager.cpp index a6ead9d..637dc47 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -87,8 +87,6 @@ using android::vold::VoldNativeService; static const char* kPathUserMount = "/mnt/user"; static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk"; -static const char* kIsolatedStorage = "persist.sys.isolated_storage"; -static const char* kIsolatedStorageSnapshot = "sys.isolated_storage_snapshot"; static const char* kPropVirtualDisk = "persist.sys.virtual_disk"; static const std::string kEmptyString(""); @@ -118,11 +116,6 @@ VolumeManager::VolumeManager() { VolumeManager::~VolumeManager() {} -static bool hasIsolatedStorage() { - return false && - GetBoolProperty(kIsolatedStorageSnapshot, GetBoolProperty(kIsolatedStorage, true)); -} - int VolumeManager::updateVirtualDisk() { ATRACE_NAME("VolumeManager::updateVirtualDisk"); if (GetBoolProperty(kPropVirtualDisk, false)) { @@ -384,399 +377,6 @@ int VolumeManager::linkPrimary(userid_t userId) { return 0; } -int VolumeManager::mountPkgSpecificDir(const std::string& mntSourceRoot, - const std::string& mntTargetRoot, - const std::string& packageName, const char* dirName) { - std::string mntSourceDir = - StringPrintf("%s/Android/%s/%s", mntSourceRoot.c_str(), dirName, packageName.c_str()); - if (CreateDir(mntSourceDir, 0755) < 0) { - return -errno; - } - std::string mntTargetDir = - StringPrintf("%s/Android/%s/%s", mntTargetRoot.c_str(), dirName, packageName.c_str()); - if (CreateDir(mntTargetDir, 0755) < 0) { - return -errno; - } - return BindMount(mntSourceDir, mntTargetDir); -} - -int VolumeManager::mountPkgSpecificDirsForRunningProcs( - userid_t userId, const std::vector& packageNames, - const std::vector& visibleVolLabels, int remountMode) { - std::unique_ptr dirp(opendir("/proc"), closedir); - if (!dirp) { - PLOG(ERROR) << "Failed to opendir /proc"; - return -1; - } - - std::string rootName; - // Figure out root namespace to compare against below - if (!android::vold::Readlinkat(dirfd(dirp.get()), "1/ns/mnt", &rootName)) { - PLOG(ERROR) << "Failed to read root namespace"; - return -1; - } - - struct stat mntFullSb; - struct stat mntWriteSb; - if (TEMP_FAILURE_RETRY(stat("/mnt/runtime/full", &mntFullSb)) == -1) { - PLOG(ERROR) << "Failed to stat /mnt/runtime/full"; - return -1; - } - if (TEMP_FAILURE_RETRY(stat("/mnt/runtime/write", &mntWriteSb)) == -1) { - PLOG(ERROR) << "Failed to stat /mnt/runtime/write"; - return -1; - } - - std::string obbMountDir = StringPrintf("/mnt/user/%d/obb_mount", userId); - if (fs_prepare_dir(obbMountDir.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) { - PLOG(ERROR) << "Failed to fs_prepare_dir " << obbMountDir; - return -1; - } - const unique_fd obbMountDirFd( - TEMP_FAILURE_RETRY(open(obbMountDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC))); - if (obbMountDirFd.get() < 0) { - PLOG(ERROR) << "Failed to open " << obbMountDir; - return -1; - } - - std::unordered_set validAppIds; - for (auto& package : packageNames) { - validAppIds.insert(mAppIds[package]); - } - std::vector& userPackages = mUserPackages[userId]; - - std::vector childPids; - - struct dirent* de; - // Poke through all running PIDs look for apps running in userId - while ((de = readdir(dirp.get()))) { - pid_t pid; - if (de->d_type != DT_DIR) continue; - if (!android::base::ParseInt(de->d_name, &pid)) continue; - - const unique_fd pidFd( - openat(dirfd(dirp.get()), de->d_name, O_RDONLY | O_DIRECTORY | O_CLOEXEC)); - if (pidFd.get() < 0) { - PLOG(WARNING) << "Failed to open /proc/" << pid; - continue; - } - struct stat sb; - if (fstat(pidFd.get(), &sb) != 0) { - PLOG(WARNING) << "Failed to stat " << de->d_name; - continue; - } - if (multiuser_get_user_id(sb.st_uid) != userId) { - continue; - } - - // Matches so far, but refuse to touch if in root namespace - LOG(VERBOSE) << "Found matching PID " << de->d_name; - std::string pidName; - if (!android::vold::Readlinkat(pidFd.get(), "ns/mnt", &pidName)) { - PLOG(WARNING) << "Failed to read namespace for " << de->d_name; - continue; - } - if (rootName == pidName) { - LOG(WARNING) << "Skipping due to root namespace"; - continue; - } - - // Only update the mount points of processes running with one of validAppIds. - // This should skip any isolated uids. - appid_t appId = multiuser_get_app_id(sb.st_uid); - if (validAppIds.find(appId) == validAppIds.end()) { - continue; - } - - std::vector packagesForUid; - for (auto& package : userPackages) { - if (mAppIds[package] == appId) { - packagesForUid.push_back(package); - } - } - if (packagesForUid.empty()) { - continue; - } - const std::string& sandboxId = mSandboxIds[appId]; - - // We purposefully leave the namespace open across the fork - // NOLINTNEXTLINE(android-cloexec-open): Deliberately not O_CLOEXEC - unique_fd nsFd(openat(pidFd.get(), "ns/mnt", O_RDONLY)); - if (nsFd.get() < 0) { - PLOG(WARNING) << "Failed to open namespace for " << de->d_name; - continue; - } - - pid_t child; - if (!(child = fork())) { - if (setns(nsFd.get(), CLONE_NEWNS) != 0) { - PLOG(ERROR) << "Failed to setns for " << de->d_name; - _exit(1); - } - - int mountMode; - if (remountMode == -1) { - mountMode = - getMountModeForRunningProc(packagesForUid, userId, mntWriteSb, mntFullSb); - if (mountMode == -1) { - _exit(1); - } - } else { - mountMode = remountMode; - if (handleMountModeInstaller(mountMode, obbMountDirFd.get(), obbMountDir, - sandboxId) < 0) { - _exit(1); - } - } - if (mountMode == VoldNativeService::REMOUNT_MODE_FULL || - mountMode == VoldNativeService::REMOUNT_MODE_LEGACY || - mountMode == VoldNativeService::REMOUNT_MODE_NONE) { - // These mount modes are not going to change dynamically, so don't bother - // unmounting/remounting dirs. - _exit(0); - } - - for (auto& volumeLabel : visibleVolLabels) { - std::string mntSource = StringPrintf("/mnt/runtime/write/%s", volumeLabel.c_str()); - std::string mntTarget = StringPrintf("/storage/%s", volumeLabel.c_str()); - if (volumeLabel == "emulated") { - StringAppendF(&mntSource, "/%d", userId); - StringAppendF(&mntTarget, "/%d", userId); - } - - std::string sandboxSource = - StringPrintf("%s/Android/sandbox/%s", mntSource.c_str(), sandboxId.c_str()); - if (CreateDir(sandboxSource, 0755) < 0) { - continue; - } - if (BindMount(sandboxSource, mntTarget) < 0) { - continue; - } - - std::string obbSourceDir = StringPrintf("%s/Android/obb", mntSource.c_str()); - std::string obbTargetDir = StringPrintf("%s/Android/obb", mntTarget.c_str()); - if (UnmountTree(obbTargetDir) < 0) { - continue; - } - if (!createPkgSpecificDirRoots(mntSource) || !createPkgSpecificDirRoots(mntTarget)) { - continue; - } - for (auto& package : packagesForUid) { - mountPkgSpecificDir(mntSource, mntTarget, package, "data"); - mountPkgSpecificDir(mntSource, mntTarget, package, "media"); - if (mountMode != VoldNativeService::REMOUNT_MODE_INSTALLER) { - mountPkgSpecificDir(mntSource, mntTarget, package, "obb"); - } - } - if (mountMode == VoldNativeService::REMOUNT_MODE_INSTALLER) { - if (BindMount(obbSourceDir, obbTargetDir) < 0) { - continue; - } - } - } - _exit(0); - } - - if (child == -1) { - PLOG(ERROR) << "Failed to fork"; - } else { - childPids.push_back(child); - } - } - for (auto& child : childPids) { - TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0)); - } - return 0; -} - -int VolumeManager::getMountModeForRunningProc(const std::vector& packagesForUid, - userid_t userId, struct stat& mntWriteStat, - struct stat& mntFullStat) { - struct stat storageSb; - if (TEMP_FAILURE_RETRY(stat("/storage", &storageSb)) == -1) { - PLOG(ERROR) << "Failed to stat /storage"; - return -1; - } - - // Some packages have access to full external storage, identify processes belonging - // to those packages by comparing inode no.s of /mnt/runtime/full and /storage - if (storageSb.st_dev == mntFullStat.st_dev && storageSb.st_ino == mntFullStat.st_ino) { - return VoldNativeService::REMOUNT_MODE_FULL; - } else if (storageSb.st_dev == mntWriteStat.st_dev && storageSb.st_ino == mntWriteStat.st_ino) { - return VoldNativeService::REMOUNT_MODE_LEGACY; - } - - std::string obbMountFile = - StringPrintf("/mnt/user/%d/obb_mount/%s", userId, packagesForUid[0].c_str()); - if (TEMP_FAILURE_RETRY(access(obbMountFile.c_str(), F_OK)) != -1) { - return VoldNativeService::REMOUNT_MODE_INSTALLER; - } else if (errno != ENOENT) { - PLOG(ERROR) << "Failed to access " << obbMountFile; - return -1; - } - - // Some packages don't have access to external storage and processes belonging to - // those packages don't have anything mounted at /storage. So, identify those - // processes by comparing inode no.s of /mnt/user/%d/package - // and /storage - std::string sandbox = StringPrintf("/mnt/user/%d/package", userId); - struct stat sandboxStat; - if (TEMP_FAILURE_RETRY(stat(sandbox.c_str(), &sandboxStat)) == -1) { - PLOG(ERROR) << "Failed to stat " << sandbox; - return -1; - } - if (storageSb.st_dev == sandboxStat.st_dev && storageSb.st_ino == sandboxStat.st_ino) { - return VoldNativeService::REMOUNT_MODE_WRITE; - } - - return VoldNativeService::REMOUNT_MODE_NONE; -} - -int VolumeManager::handleMountModeInstaller(int mountMode, int obbMountDirFd, - const std::string& obbMountDir, - const std::string& sandboxId) { - if (mountMode == VoldNativeService::REMOUNT_MODE_INSTALLER) { - if (TEMP_FAILURE_RETRY(faccessat(obbMountDirFd, sandboxId.c_str(), F_OK, 0)) != -1) { - return 0; - } else if (errno != ENOENT) { - PLOG(ERROR) << "Failed to access " << obbMountDir << "/" << sandboxId; - return -errno; - } - const unique_fd fd(TEMP_FAILURE_RETRY( - openat(obbMountDirFd, sandboxId.c_str(), O_RDWR | O_CREAT | O_CLOEXEC, 0600))); - if (fd.get() < 0) { - PLOG(ERROR) << "Failed to create " << obbMountDir << "/" << sandboxId; - return -errno; - } - } else { - if (TEMP_FAILURE_RETRY(faccessat(obbMountDirFd, sandboxId.c_str(), F_OK, 0)) != -1) { - if (TEMP_FAILURE_RETRY(unlinkat(obbMountDirFd, sandboxId.c_str(), 0)) == -1) { - PLOG(ERROR) << "Failed to unlink " << obbMountDir << "/" << sandboxId; - return -errno; - } - } else if (errno != ENOENT) { - PLOG(ERROR) << "Failed to access " << obbMountDir << "/" << sandboxId; - return -errno; - } - } - return 0; -} - -int VolumeManager::prepareSandboxes(userid_t userId, const std::vector& packageNames, - const std::vector& visibleVolLabels) { - if (visibleVolLabels.empty()) { - return 0; - } - for (auto& volumeLabel : visibleVolLabels) { - std::string volumeRoot(StringPrintf("/mnt/runtime/write/%s", volumeLabel.c_str())); - bool isVolPrimaryEmulated = (volumeLabel == mPrimary->getLabel() && mPrimary->isEmulated()); - if (isVolPrimaryEmulated) { - StringAppendF(&volumeRoot, "/%d", userId); - if (CreateDir(volumeRoot, 0755) < 0) { - return -errno; - } - } - - std::string sandboxRoot = - prepareSubDirs(volumeRoot, "Android/sandbox/", 0700, AID_ROOT, AID_ROOT); - if (sandboxRoot.empty()) { - return -errno; - } - } - - if (prepareSandboxTargets(userId, visibleVolLabels) < 0) { - return -errno; - } - - if (mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels, -1) < 0) { - PLOG(ERROR) << "Failed to setup sandboxes for already running processes"; - return -errno; - } - return 0; -} - -int VolumeManager::prepareSandboxTargets(userid_t userId, - const std::vector& visibleVolLabels) { - std::string mntTargetRoot = StringPrintf("/mnt/user/%d", userId); - if (fs_prepare_dir(mntTargetRoot.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) { - PLOG(ERROR) << "Failed to fs_prepare_dir " << mntTargetRoot; - return -errno; - } - - StringAppendF(&mntTargetRoot, "/package"); - if (fs_prepare_dir(mntTargetRoot.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) { - PLOG(ERROR) << "Failed to fs_prepare_dir " << mntTargetRoot; - return -errno; - } - - for (auto& volumeLabel : visibleVolLabels) { - std::string sandboxTarget = - StringPrintf("%s/%s", mntTargetRoot.c_str(), volumeLabel.c_str()); - if (fs_prepare_dir(sandboxTarget.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) { - PLOG(ERROR) << "Failed to fs_prepare_dir " << sandboxTarget; - return -errno; - } - - if (mPrimary && volumeLabel == mPrimary->getLabel() && mPrimary->isEmulated()) { - StringAppendF(&sandboxTarget, "/%d", userId); - if (fs_prepare_dir(sandboxTarget.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) { - PLOG(ERROR) << "Failed to fs_prepare_dir " << sandboxTarget; - return -errno; - } - } - } - - StringAppendF(&mntTargetRoot, "/self"); - if (fs_prepare_dir(mntTargetRoot.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) { - PLOG(ERROR) << "Failed to fs_prepare_dir " << mntTargetRoot; - return -errno; - } - - if (mPrimary) { - std::string pkgPrimarySource(mPrimary->getPath()); - if (mPrimary->isEmulated()) { - StringAppendF(&pkgPrimarySource, "/%d", userId); - } - StringAppendF(&mntTargetRoot, "/primary"); - if (Symlink(pkgPrimarySource, mntTargetRoot) < 0) { - return -errno; - } - } - return 0; -} - -std::string VolumeManager::prepareSubDirs(const std::string& pathPrefix, const std::string& subDirs, - mode_t mode, uid_t uid, gid_t gid) { - std::string path(pathPrefix); - std::vector subDirList = android::base::Split(subDirs, "/"); - for (size_t i = 0; i < subDirList.size(); ++i) { - std::string subDir = subDirList[i]; - if (subDir.empty()) { - continue; - } - StringAppendF(&path, "/%s", subDir.c_str()); - if (CreateDir(path, mode) < 0) { - return kEmptyString; - } - } - return path; -} - -bool VolumeManager::createPkgSpecificDirRoots(const std::string& volumeRoot) { - std::string volumeAndroidRoot = StringPrintf("%s/Android", volumeRoot.c_str()); - if (CreateDir(volumeAndroidRoot, 0700) < 0) { - return false; - } - std::array dirs = {"data", "media", "obb"}; - for (auto& dir : dirs) { - std::string path = StringPrintf("%s/%s", volumeAndroidRoot.c_str(), dir.c_str()); - if (CreateDir(path, 0700) < 0) { - return false; - } - } - return true; -} - int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) { mAddedUsers[userId] = userSerialNumber; return 0; @@ -787,9 +387,7 @@ int VolumeManager::onUserRemoved(userid_t userId) { return 0; } -int VolumeManager::onUserStarted(userid_t userId, const std::vector& packageNames, - const std::vector& appIds, - const std::vector& sandboxIds) { +int VolumeManager::onUserStarted(userid_t userId) { LOG(VERBOSE) << "onUserStarted: " << userId; // Note that sometimes the system will spin up processes from Zygote // before actually starting the user, so we're okay if Zygote @@ -798,159 +396,15 @@ int VolumeManager::onUserStarted(userid_t userId, const std::vector fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT); mStartedUsers.insert(userId); - mUserPackages[userId] = packageNames; - for (size_t i = 0; i < packageNames.size(); ++i) { - mAppIds[packageNames[i]] = appIds[i]; - mSandboxIds[appIds[i]] = sandboxIds[i]; - } if (mPrimary) { linkPrimary(userId); } - if (hasIsolatedStorage()) { - std::vector visibleVolLabels; - for (auto& volId : mVisibleVolumeIds) { - auto vol = findVolume(volId); - userid_t mountUserId = vol->getMountUserId(); - if (mountUserId == userId || vol->isEmulated()) { - visibleVolLabels.push_back(vol->getLabel()); - } - } - if (prepareSandboxes(userId, packageNames, visibleVolLabels) != 0) { - return -errno; - } - } return 0; } int VolumeManager::onUserStopped(userid_t userId) { LOG(VERBOSE) << "onUserStopped: " << userId; mStartedUsers.erase(userId); - - if (hasIsolatedStorage()) { - auto& userPackages = mUserPackages[userId]; - std::string userMntTargetRoot = StringPrintf("/mnt/user/%d", userId); - std::string pkgPrimaryDir = - StringPrintf("%s/package/self/primary", userMntTargetRoot.c_str()); - if (Unlink(pkgPrimaryDir) < 0) { - return -errno; - } - mUserPackages.erase(userId); - if (DeleteDirContentsAndDir(userMntTargetRoot) < 0) { - PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << userMntTargetRoot; - return -errno; - } - LOG(VERBOSE) << "Success: DeleteDirContentsAndDir on " << userMntTargetRoot; - } - return 0; -} - -int VolumeManager::addAppIds(const std::vector& packageNames, - const std::vector& appIds) { - for (size_t i = 0; i < packageNames.size(); ++i) { - mAppIds[packageNames[i]] = appIds[i]; - } - return 0; -} - -int VolumeManager::addSandboxIds(const std::vector& appIds, - const std::vector& sandboxIds) { - for (size_t i = 0; i < appIds.size(); ++i) { - mSandboxIds[appIds[i]] = sandboxIds[i]; - } - return 0; -} - -int VolumeManager::prepareSandboxForApp(const std::string& packageName, appid_t appId, - const std::string& sandboxId, userid_t userId) { - if (!hasIsolatedStorage()) { - return 0; - } else if (mStartedUsers.find(userId) == mStartedUsers.end()) { - // User not started, no need to do anything now. Required bind mounts for the package will - // be created when the user starts. - return 0; - } - - auto& userPackages = mUserPackages[userId]; - if (std::find(userPackages.begin(), userPackages.end(), packageName) != userPackages.end()) { - return 0; - } - - LOG(VERBOSE) << "prepareSandboxForApp: " << packageName << ", appId=" << appId - << ", sandboxId=" << sandboxId << ", userId=" << userId; - mUserPackages[userId].push_back(packageName); - mAppIds[packageName] = appId; - mSandboxIds[appId] = sandboxId; - - std::vector visibleVolLabels; - for (auto& volId : mVisibleVolumeIds) { - auto vol = findVolume(volId); - userid_t mountUserId = vol->getMountUserId(); - if (mountUserId == userId || vol->isEmulated()) { - visibleVolLabels.push_back(vol->getLabel()); - } - } - return prepareSandboxes(userId, {packageName}, visibleVolLabels); -} - -int VolumeManager::destroySandboxForApp(const std::string& packageName, - const std::string& sandboxId, userid_t userId) { - if (!hasIsolatedStorage()) { - return 0; - } - LOG(VERBOSE) << "destroySandboxForApp: " << packageName << ", sandboxId=" << sandboxId - << ", userId=" << userId; - auto& userPackages = mUserPackages[userId]; - userPackages.erase(std::remove(userPackages.begin(), userPackages.end(), packageName), - userPackages.end()); - // If the package is not uninstalled in any other users, remove appId and sandboxId - // corresponding to it from the internal state. - bool installedInAnyUser = false; - for (auto& it : mUserPackages) { - auto& packages = it.second; - if (std::find(packages.begin(), packages.end(), packageName) != packages.end()) { - installedInAnyUser = true; - break; - } - } - if (!installedInAnyUser) { - const auto& entry = mAppIds.find(packageName); - if (entry != mAppIds.end()) { - mSandboxIds.erase(entry->second); - mAppIds.erase(entry); - } - } - - std::vector visibleVolLabels; - for (auto& volId : mVisibleVolumeIds) { - auto vol = findVolume(volId); - userid_t mountUserId = vol->getMountUserId(); - if (mountUserId == userId || vol->isEmulated()) { - if (destroySandboxForAppOnVol(packageName, sandboxId, userId, vol->getLabel()) < 0) { - return -errno; - } - } - } - - return 0; -} - -int VolumeManager::destroySandboxForAppOnVol(const std::string& packageName, - const std::string& sandboxId, userid_t userId, - const std::string& volLabel) { - LOG(VERBOSE) << "destroySandboxOnVol: " << packageName << ", userId=" << userId - << ", volLabel=" << volLabel; - - std::string sandboxDir = StringPrintf("/mnt/runtime/write/%s", volLabel.c_str()); - if (volLabel == mPrimary->getLabel() && mPrimary->isEmulated()) { - StringAppendF(&sandboxDir, "/%d", userId); - } - StringAppendF(&sandboxDir, "/Android/sandbox/%s", sandboxId.c_str()); - - if (DeleteDirContentsAndDir(sandboxDir) < 0) { - PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << sandboxDir; - return -errno; - } - return 0; } @@ -968,86 +422,7 @@ int VolumeManager::onSecureKeyguardStateChanged(bool isShowing) { return 0; } -int VolumeManager::onVolumeMounted(android::vold::VolumeBase* vol) { - if (!hasIsolatedStorage()) { - return 0; - } - - if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_VISIBLE) == 0) { - return 0; - } - - mVisibleVolumeIds.insert(vol->getId()); - userid_t mountUserId = vol->getMountUserId(); - if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_PRIMARY) != 0) { - // We don't want to create another shared_ptr here because then we will end up with - // two shared_ptrs owning the underlying pointer without sharing it. - mPrimary = findVolume(vol->getId()); - for (userid_t userId : mStartedUsers) { - if (linkPrimary(userId) != 0) { - return -errno; - } - } - } - if (vol->isEmulated()) { - for (userid_t userId : mStartedUsers) { - if (prepareSandboxes(userId, mUserPackages[userId], {vol->getLabel()}) != 0) { - return -errno; - } - } - } else if (mStartedUsers.find(mountUserId) != mStartedUsers.end()) { - if (prepareSandboxes(mountUserId, mUserPackages[mountUserId], {vol->getLabel()}) != 0) { - return -errno; - } - } - return 0; -} - -int VolumeManager::onVolumeUnmounted(android::vold::VolumeBase* vol) { - if (!hasIsolatedStorage()) { - return 0; - } - - if (mVisibleVolumeIds.erase(vol->getId()) == 0) { - return 0; - } - - if ((vol->getMountFlags() & android::vold::VoldNativeService::MOUNT_FLAG_PRIMARY) != 0) { - mPrimary = nullptr; - } - - LOG(VERBOSE) << "visibleVolumeUnmounted: " << vol; - userid_t mountUserId = vol->getMountUserId(); - if (vol->isEmulated()) { - for (userid_t userId : mStartedUsers) { - if (destroySandboxesForVol(vol, userId) != 0) { - return -errno; - } - } - } else if (mStartedUsers.find(mountUserId) != mStartedUsers.end()) { - if (destroySandboxesForVol(vol, mountUserId) != 0) { - return -errno; - } - } - return 0; -} - -int VolumeManager::destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId) { - LOG(VERBOSE) << "destroysandboxesForVol: " << vol << " for user=" << userId; - std::string volSandboxRoot = - StringPrintf("/mnt/user/%d/package/%s", userId, vol->getLabel().c_str()); - if (android::vold::DeleteDirContentsAndDir(volSandboxRoot) < 0) { - PLOG(ERROR) << "DeleteDirContentsAndDir failed on " << volSandboxRoot; - return -errno; - } - LOG(VERBOSE) << "Success: DeleteDirContentsAndDir on " << volSandboxRoot; - return 0; -} - int VolumeManager::setPrimary(const std::shared_ptr& vol) { - if (hasIsolatedStorage()) { - return 0; - } mPrimary = vol; for (userid_t userId : mStartedUsers) { linkPrimary(userId); @@ -1056,37 +431,6 @@ int VolumeManager::setPrimary(const std::shared_ptr& } int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { - if (!hasIsolatedStorage()) { - return remountUidLegacy(uid, mountMode); - } - - appid_t appId = multiuser_get_app_id(uid); - userid_t userId = multiuser_get_user_id(uid); - std::vector visibleVolLabels; - for (auto& volId : mVisibleVolumeIds) { - auto vol = findVolume(volId); - userid_t mountUserId = vol->getMountUserId(); - if (mountUserId == userId || vol->isEmulated()) { - visibleVolLabels.push_back(vol->getLabel()); - } - } - - // Finding one package with appId is enough - std::vector packageNames; - for (auto it = mAppIds.begin(); it != mAppIds.end(); ++it) { - if (it->second == appId) { - packageNames.push_back(it->first); - break; - } - } - if (packageNames.empty()) { - PLOG(ERROR) << "Failed to find packageName for " << uid; - return -1; - } - return mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels, mountMode); -} - -int VolumeManager::remountUidLegacy(uid_t uid, int32_t mountMode) { std::string mode; switch (mountMode) { case VoldNativeService::REMOUNT_MODE_NONE: @@ -1264,15 +608,6 @@ int VolumeManager::reset() { } updateVirtualDisk(); mAddedUsers.clear(); - - mUserPackages.clear(); - mAppIds.clear(); - mSandboxIds.clear(); - mVisibleVolumeIds.clear(); - - for (userid_t userId : mStartedUsers) { - DeleteDirContents(StringPrintf("/mnt/user/%d/package", userId)); - } mStartedUsers.clear(); return 0; } diff --git a/VolumeManager.h b/VolumeManager.h index bb93b13..9bf7599 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -88,27 +88,14 @@ class VolumeManager { int onUserAdded(userid_t userId, int userSerialNumber); int onUserRemoved(userid_t userId); - int onUserStarted(userid_t userId, const std::vector& packageNames, - const std::vector& appIds, const std::vector& sandboxIds); + int onUserStarted(userid_t userId); int onUserStopped(userid_t userId); - int addAppIds(const std::vector& packageNames, const std::vector& appIds); - int addSandboxIds(const std::vector& appIds, - const std::vector& sandboxIds); - int prepareSandboxForApp(const std::string& packageName, appid_t appId, - const std::string& sandboxId, userid_t userId); - int destroySandboxForApp(const std::string& packageName, const std::string& sandboxId, - userid_t userId); - - int onVolumeMounted(android::vold::VolumeBase* vol); - int onVolumeUnmounted(android::vold::VolumeBase* vol); - int onSecureKeyguardStateChanged(bool isShowing); int setPrimary(const std::shared_ptr& vol); int remountUid(uid_t uid, int32_t remountMode); - int remountUidLegacy(uid_t uid, int32_t remountMode); /* Reset all internal state, typically during framework boot */ int reset(); @@ -150,26 +137,6 @@ class VolumeManager { int linkPrimary(userid_t userId); - int prepareSandboxes(userid_t userId, const std::vector& packageNames, - const std::vector& visibleVolLabels); - int prepareSandboxTargets(userid_t userId, const std::vector& visibleVolLabels); - int handleMountModeInstaller(int mountMode, int obbMountDirFd, const std::string& obbMountDir, - const std::string& sandboxId); - int mountPkgSpecificDirsForRunningProcs(userid_t userId, - const std::vector& packageNames, - const std::vector& visibleVolLabels, - int remountMode); - int destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId); - std::string prepareSubDirs(const std::string& pathPrefix, const std::string& subDirs, - mode_t mode, uid_t uid, gid_t gid); - bool createPkgSpecificDirRoots(const std::string& volumeRoot); - int mountPkgSpecificDir(const std::string& mntSourceRoot, const std::string& mntTargetRoot, - const std::string& packageName, const char* dirName); - int destroySandboxForAppOnVol(const std::string& packageName, const std::string& sandboxId, - userid_t userId, const std::string& volLabel); - int getMountModeForRunningProc(const std::vector& packagesForUid, userid_t userId, - struct stat& mntWriteStat, struct stat& mntFullStat); - void handleDiskAdded(const std::shared_ptr& disk); void handleDiskChanged(dev_t device); void handleDiskRemoved(dev_t device); @@ -193,11 +160,6 @@ class VolumeManager { std::shared_ptr mInternalEmulated; std::shared_ptr mPrimary; - std::unordered_map mAppIds; - std::unordered_map mSandboxIds; - std::unordered_map> mUserPackages; - std::unordered_set mVisibleVolumeIds; - int mNextObbId; int mNextStubVolumeId; bool mSecureKeyguardShowing; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index cc23498..75fef06 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -29,8 +29,7 @@ interface IVold { void onUserAdded(int userId, int userSerial); void onUserRemoved(int userId); - void onUserStarted(int userId, in @utf8InCpp String[] packageNames, in int[] appIds, - in @utf8InCpp String[] sandboxIds); + void onUserStarted(int userId); void onUserStopped(int userId); void addAppIds(in @utf8InCpp String[] packageNames, in int[] appIds); diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 73bf6d1..552fe2f 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -70,7 +70,6 @@ status_t EmulatedVolume::doMount() { setInternalPath(mRawPath); setPath(StringPrintf("/storage/%s", label.c_str())); - setLabel(label); if (fs_prepare_dir(mFuseDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || fs_prepare_dir(mFuseRead.c_str(), 0700, AID_ROOT, AID_ROOT) || diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 1eb6008..0a6b351 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -129,7 +129,6 @@ status_t PublicVolume::doMount() { } else { setPath(mRawPath); } - setLabel(stableName); if (fs_prepare_dir(mRawPath.c_str(), 0700, AID_ROOT, AID_ROOT)) { PLOG(ERROR) << getId() << " failed to create mount points"; diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index a9c7fa3..ffc7900 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -143,16 +143,6 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) { return OK; } -status_t VolumeBase::setLabel(const std::string& label) { - if (mState != State::kChecking) { - LOG(WARNING) << getId() << " label change requires state checking"; - return -EBUSY; - } - - mLabel = label; - return OK; -} - android::sp VolumeBase::getListener() const { if (mSilent) { return nullptr; @@ -229,9 +219,6 @@ status_t VolumeBase::mount() { setState(State::kChecking); status_t res = doMount(); - if (res == OK) { - res = VolumeManager::Instance()->onVolumeMounted(this); - } setState(res == OK ? State::kMounted : State::kUnmountable); return res; @@ -251,11 +238,8 @@ status_t VolumeBase::unmount() { } mVolumes.clear(); - status_t res = VolumeManager::Instance()->onVolumeUnmounted(this); - if (res == OK) { - res = doUnmount(); - setState(State::kUnmounted); - } + status_t res = doUnmount(); + setState(State::kUnmounted); return res; } @@ -280,8 +264,8 @@ status_t VolumeBase::doFormat(const std::string& fsType) { } std::ostream& VolumeBase::operator<<(std::ostream& stream) const { - return stream << " VolumeBase{id=" << mId << ",label=" << mLabel - << ",mountFlags=" << mMountFlags << ",mountUserId=" << mMountUserId << "}"; + return stream << " VolumeBase{id=" << mId << ",mountFlags=" << mMountFlags + << ",mountUserId=" << mMountUserId << "}"; } } // namespace vold diff --git a/model/VolumeBase.h b/model/VolumeBase.h index e6c47f0..53eeb6f 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -87,7 +87,6 @@ class VolumeBase { State getState() const { return mState; } const std::string& getPath() const { return mPath; } const std::string& getInternalPath() const { return mInternalPath; } - const std::string& getLabel() const { return mLabel; } status_t setDiskId(const std::string& diskId); status_t setPartGuid(const std::string& partGuid); @@ -122,7 +121,6 @@ class VolumeBase { status_t setId(const std::string& id); status_t setPath(const std::string& path); status_t setInternalPath(const std::string& internalPath); - status_t setLabel(const std::string& label); android::sp getListener() const; @@ -149,12 +147,6 @@ class VolumeBase { std::string mInternalPath; /* Flag indicating that volume should emit no events */ bool mSilent; - /** - * Label used for representing the package sandboxes on external storage volumes. - * For emulated volume, this would be "emulated" and for public volumes, UUID if available, - * otherwise some other unique id. - */ - std::string mLabel; /* Volumes stacked on top of this volume */ std::list> mVolumes; From 1e782f02778521f42f4db86b73bcc67b68de9550 Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Wed, 12 Jun 2019 13:27:20 -0700 Subject: [PATCH 002/112] Keymaster memory management is inconsistent Objects derived from RefBase should always be owned by sp rather then unique_ptr or other smart pointer implementations. Bug: 79474587 Change-Id: I6a3ca04b3a3bab74c6114643ffdaeac537188d12 --- Android.bp | 1 + Keymaster.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Android.bp b/Android.bp index f565732..a4cbd88 100644 --- a/Android.bp +++ b/Android.bp @@ -230,6 +230,7 @@ cc_binary { "libhidlbase", "libhwbinder", "libkeymaster4support", + "libutils", ], } diff --git a/Keymaster.h b/Keymaster.h index 42a2b5d..9a0616d 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -115,7 +115,7 @@ class Keymaster { bool isSecure(); private: - std::unique_ptr mDevice; + sp mDevice; DISALLOW_COPY_AND_ASSIGN(Keymaster); static bool hmacKeyGenerated; }; From e3c2f4158a337ed76bcd5efe0aba8b67b8b198c3 Mon Sep 17 00:00:00 2001 From: Ruslan Tkhakokhov Date: Fri, 21 Jun 2019 10:31:11 +0000 Subject: [PATCH 003/112] Merged-In Revert "vold: use RAII wake locks" This reverts commit 242130f3f8180baef35649f350ca737d0b0c6ae3. Reason for revert: breaks the build Change-Id: Ide809a114b2a04538f3ba4ed8af934bf326e54f3 --- Benchmark.cpp | 4 +++- IdleMaint.cpp | 11 ++++++++--- MoveStorage.cpp | 4 +++- cryptfs.cpp | 12 ++++++++++-- 4 files changed, 24 insertions(+), 7 deletions(-) diff --git a/Benchmark.cpp b/Benchmark.cpp index 9548956..b0a3b85 100644 --- a/Benchmark.cpp +++ b/Benchmark.cpp @@ -181,7 +181,7 @@ static status_t benchmarkInternal(const std::string& rootPath, void Benchmark(const std::string& path, const android::sp& listener) { std::lock_guard lock(kBenchmarkLock); - android::power::WakeLock wl{kWakeLock}; + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); PerformanceBoost boost; android::os::PersistableBundle extras; @@ -190,6 +190,8 @@ void Benchmark(const std::string& path, if (listener) { listener->onFinished(res, extras); } + + release_wake_lock(kWakeLock); } } // namespace vold diff --git a/IdleMaint.cpp b/IdleMaint.cpp index e9f1364..bca22f6 100644 --- a/IdleMaint.cpp +++ b/IdleMaint.cpp @@ -145,7 +145,7 @@ static void addFromFstab(std::list* paths, PathTypes path_type) { } void Trim(const android::sp& listener) { - android::power::WakeLock wl{kWakeLock}; + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); // Collect both fstab and vold volumes std::list paths; @@ -195,6 +195,7 @@ void Trim(const android::sp& listener) { listener->onFinished(0, extras); } + release_wake_lock(kWakeLock); } static bool waitForGc(const std::list& paths) { @@ -369,7 +370,7 @@ int RunIdleMaint(const android::sp& listener) { LOG(DEBUG) << "idle maintenance started"; - android::power::WakeLock wl{kWakeLock}; + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); std::list paths; addFromFstab(&paths, PathTypes::kBlkDevice); @@ -399,11 +400,13 @@ int RunIdleMaint(const android::sp& listener) { LOG(DEBUG) << "idle maintenance completed"; + release_wake_lock(kWakeLock); + return android::OK; } int AbortIdleMaint(const android::sp& listener) { - android::power::WakeLock wl{kWakeLock}; + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); std::unique_lock lk(cv_m); if (idle_maint_stat != IdleMaintStats::kStopped) { @@ -421,6 +424,8 @@ int AbortIdleMaint(const android::sp& listener) listener->onFinished(0, extras); } + release_wake_lock(kWakeLock); + LOG(DEBUG) << "idle maintenance stopped"; return android::OK; diff --git a/MoveStorage.cpp b/MoveStorage.cpp index 9b806ec..79a47ae 100644 --- a/MoveStorage.cpp +++ b/MoveStorage.cpp @@ -258,13 +258,15 @@ fail: void MoveStorage(const std::shared_ptr& from, const std::shared_ptr& to, const android::sp& listener) { - android::power::WakeLock wl{kWakeLock}; + acquire_wake_lock(PARTIAL_WAKE_LOCK, kWakeLock); android::os::PersistableBundle extras; status_t res = moveStorageInternal(from, to, listener); if (listener) { listener->onFinished(res, extras); } + + release_wake_lock(kWakeLock); } } // namespace vold diff --git a/cryptfs.cpp b/cryptfs.cpp index 7d59b2d..c5d0307 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -2007,7 +2007,6 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { off64_t previously_encrypted_upto = 0; bool rebootEncryption = false; bool onlyCreateHeader = false; - std::unique_ptr wakeLock = nullptr; if (get_crypt_ftr_and_key(&crypt_ftr) == 0) { if (crypt_ftr.flags & CRYPT_ENCRYPTION_IN_PROGRESS) { @@ -2074,7 +2073,7 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { * wants to keep the screen on, it can grab a full wakelock. */ snprintf(lockid, sizeof(lockid), "enablecrypto%d", (int)getpid()); - wakeLock = std::make_unique(lockid); + acquire_wake_lock(PARTIAL_WAKE_LOCK, lockid); /* The init files are setup to stop the class main and late start when * vold sets trigger_shutdown_framework. @@ -2255,6 +2254,7 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { /* default encryption - continue first boot sequence */ property_set("ro.crypto.state", "encrypted"); property_set("ro.crypto.type", "block"); + release_wake_lock(lockid); if (rebootEncryption && crypt_ftr.crypt_type != CRYPT_TYPE_DEFAULT) { // Bring up cryptkeeper that will check the password and set it property_set("vold.decrypt", "trigger_shutdown_framework"); @@ -2291,6 +2291,7 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { } else { /* set property to trigger dialog */ property_set("vold.encrypt_progress", "error_partially_encrypted"); + release_wake_lock(lockid); } return -1; } @@ -2300,10 +2301,14 @@ int cryptfs_enable_internal(int crypt_type, const char* passwd, int no_ui) { * Set the property and return. Hope the framework can deal with it. */ property_set("vold.encrypt_progress", "error_reboot_failed"); + release_wake_lock(lockid); return rc; error_unencrypted: property_set("vold.encrypt_progress", "error_not_encrypted"); + if (lockid[0]) { + release_wake_lock(lockid); + } return -1; error_shutting_down: @@ -2318,6 +2323,9 @@ error_shutting_down: /* shouldn't get here */ property_set("vold.encrypt_progress", "error_shutting_down"); + if (lockid[0]) { + release_wake_lock(lockid); + } return -1; } From 3623a212e305f022a2fe279a4c13ec2a6513d6e7 Mon Sep 17 00:00:00 2001 From: Zim Date: Fri, 19 Jul 2019 16:46:53 +0100 Subject: [PATCH 004/112] Mount /dev/fuse on /mnt/user// Since system_server cannot mount devices by itself, add a binder interface to vold that system_server can call to initiate this mount when required. BUG: 135341433 Test: manual Test: atest --test-mapping packages/providers/MediaProvider Test: ExternalStorageHostTest DownloadProviderTests Change-Id: If4fd02a1f1a8d921a3f96783d8c73e085c5b7ca1 --- Utils.cpp | 47 +++++++++++++++++++++++++++++++++++- Utils.h | 5 ++++ VoldNativeService.cpp | 11 ++++++++- VoldNativeService.h | 3 ++- VolumeManager.cpp | 36 +++++++++++++++++++++++++++ binder/android/os/IVold.aidl | 2 +- model/EmulatedVolume.cpp | 43 +++++++++++++++++++++++++++++++++ model/PublicVolume.cpp | 40 ++++++++++++++++++++++++++++++ model/VolumeBase.cpp | 10 ++++++++ model/VolumeBase.h | 4 +++ 10 files changed, 197 insertions(+), 4 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 1616d80..bd3d452 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -165,7 +165,7 @@ status_t ForceUnmount(const std::string& path) { if (!umount2(cpath, UMOUNT_NOFOLLOW) || errno == EINVAL || errno == ENOENT) { return OK; } - + PLOG(INFO) << "ForceUnmount failed"; return -errno; } @@ -985,5 +985,50 @@ bool writeStringToFile(const std::string& payload, const std::string& filename) return true; } +int MountUserFuse(userid_t user_id, const std::string& relative_path, int* device_fd) { + std::string path(StringPrintf("/mnt/user/%d/%s", user_id, relative_path.c_str())); + + // Force remove the existing mount before we attempt to prepare the + // directory. If we have a dangling mount, then PrepareDir may fail if the + // indirection to FUSE doesn't work. + android::status_t result = android::vold::ForceUnmount(path); + if (result != android::OK) { + PLOG(ERROR) << "Failed to unmount " << path; + return -1; + } + + // Create directories. + result = android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << path; + return -1; + } + + // Open device fd. + *device_fd = open("/dev/fuse", O_RDWR | O_CLOEXEC); + if (*device_fd == -1) { + PLOG(ERROR) << "Failed to open /dev/fuse"; + return -1; + } + + // Note: leaving out default_permissions since we don't want kernel to do lower filesystem + // permission checks before routing to FUSE daemon. + const auto opts = StringPrintf( + "fd=%i," + "rootmode=40000," + "allow_other," + "user_id=0,group_id=0,", + *device_fd); + + const int result_int = + TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse", + MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str())); + if (result_int != 0) { + PLOG(ERROR) << "Failed to mount " << path; + return -errno; + } + return 0; +} + } // namespace vold } // namespace android diff --git a/Utils.h b/Utils.h index af4e401..cd55b09 100644 --- a/Utils.h +++ b/Utils.h @@ -33,6 +33,8 @@ struct DIR; namespace android { namespace vold { +static const char* kPropFuse = "persist.sys.fuse"; + /* SELinux contexts used depending on the block device type */ extern security_context_t sBlkidContext; extern security_context_t sBlkidUntrustedContext; @@ -147,6 +149,9 @@ status_t WaitForFile(const char* filename, std::chrono::nanoseconds timeout); bool FsyncDirectory(const std::string& dirname); bool writeStringToFile(const std::string& payload, const std::string& filename); + +int MountUserFuse(userid_t user_id, const std::string& relative_path, int* device_fd); + } // namespace vold } // namespace android diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 1762b70..9004b40 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -326,7 +326,8 @@ binder::Status VoldNativeService::forgetPartition(const std::string& partGuid, } binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, - int32_t mountUserId) { + int32_t mountUserId, + android::base::unique_fd* _aidl_return) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -343,6 +344,14 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF if (res != OK) { return translate(res); } + + _aidl_return->reset(vol->getDeviceFd()); + if (_aidl_return->get() == -1) { + // Let's not return invalid fd since binder will not allow null fds. Instead give it a + // default value. + _aidl_return->reset(open("/dev/null", O_RDONLY | O_CLOEXEC)); + } + if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) { res = VolumeManager::Instance()->setPrimary(vol); if (res != OK) { diff --git a/VoldNativeService.h b/VoldNativeService.h index 07a0b9f..b1cf620 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -52,7 +52,8 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status partition(const std::string& diskId, int32_t partitionType, int32_t ratio); binder::Status forgetPartition(const std::string& partGuid, const std::string& fsUuid); - binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId); + binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId, + android::base::unique_fd* _aidl_return); binder::Status unmount(const std::string& volId); binder::Status format(const std::string& volId, const std::string& fsType); binder::Status benchmark(const std::string& volId, diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 44bff5a..2eb1ed5 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include @@ -100,6 +101,22 @@ static const unsigned int kMajorBlockExperimentalMax = 254; VolumeManager* VolumeManager::sInstance = NULL; +static void* symlinkPrimary(void* data) { + std::unique_ptr> linkInfo( + static_cast*>(data)); + std::string* source = &linkInfo->first; + std::string* target = &linkInfo->second; + + fs_prepare_dir(source->c_str(), 0755, AID_ROOT, AID_ROOT); + fs_prepare_dir(target->c_str(), 0755, AID_ROOT, AID_ROOT); + *target = *target + "/primary"; + + // Link source to target + LOG(DEBUG) << "Linking " << *source << " to " << *target; + Symlink(*source, *target); + return nullptr; +} + VolumeManager* VolumeManager::Instance() { if (!sInstance) sInstance = new VolumeManager(); return sInstance; @@ -365,6 +382,21 @@ int VolumeManager::forgetPartition(const std::string& partGuid, const std::strin } int VolumeManager::linkPrimary(userid_t userId) { + bool isFuse = GetBoolProperty(android::vold::kPropFuse, false); + + if (isFuse) { + // Here we have to touch /mnt/user/userid>/ which was already mounted as part of + // the boot sequence, requiring waiting till a fuse handler is available. If we do this work + // in foreground we could hang the caller, i.e. system server, which needs to start the fuse + // handler. So do it in the background. + std::string source( + StringPrintf("/mnt/user/%d/%s/%d", userId, mPrimary->getId().c_str(), userId)); + std::string target(StringPrintf("/mnt/user/%d/self", userId)); + + auto symlinkInfo = new std::pair(source, target); + std::thread(symlinkPrimary, symlinkInfo).detach(); + } + std::string source(mPrimary->getPath()); if (mPrimary->isEmulated()) { source = StringPrintf("%s/%d", source.c_str(), userId); @@ -431,6 +463,10 @@ int VolumeManager::setPrimary(const std::shared_ptr& } int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { + if (GetBoolProperty(android::vold::kPropFuse, false)) { + // TODO(135341433): Implement fuse specific logic. + return 0; + } std::string mode; switch (mountMode) { case VoldNativeService::REMOUNT_MODE_NONE: diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 03fe258..b1af587 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -40,7 +40,7 @@ interface IVold { void partition(@utf8InCpp String diskId, int partitionType, int ratio); void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid); - void mount(@utf8InCpp String volId, int mountFlags, int mountUserId); + FileDescriptor mount(@utf8InCpp String volId, int mountFlags, int mountUserId); void unmount(@utf8InCpp String volId); void format(@utf8InCpp String volId, @utf8InCpp String fsType); void benchmark(@utf8InCpp String volId, IVoldTaskListener listener); diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 552fe2f..ca314ef 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -15,10 +15,13 @@ */ #include "EmulatedVolume.h" + +#include "AppFuseUtil.h" #include "Utils.h" #include "VolumeManager.h" #include +#include #include #include #include @@ -81,7 +84,22 @@ status_t EmulatedVolume::doMount() { dev_t before = GetDevice(mFuseFull); + bool isFuse = base::GetBoolProperty(kPropFuse, false); + + if (isFuse) { + LOG(INFO) << "Mounting emulated fuse volume"; + int fd = -1; + int result = MountUserFuse(getMountUserId(), label, &fd); + if (result != 0) { + PLOG(ERROR) << "Failed to mount emulated fuse volume"; + return -result; + } + setDeviceFd(fd); + return OK; + } + if (!(mFusePid = fork())) { + LOG(INFO) << "Executing sdcardfs"; // clang-format off if (execl(kFusePath, kFusePath, "-u", "1023", // AID_MEDIA_RW @@ -131,6 +149,31 @@ status_t EmulatedVolume::doUnmount() { // ENOTCONN until the unmount completes. This is an exotic and unusual // error code and might cause broken behaviour in applications. KillProcessesUsingPath(getPath()); + + bool isFuse = base::GetBoolProperty(kPropFuse, false); + if (isFuse) { + // We could have migrated storage to an adopted private volume, so always + // call primary storage "emulated" to avoid media rescans. + std::string label = mLabel; + if (getMountFlags() & MountFlags::kPrimary) { + label = "emulated"; + } + std::string path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str())); + status_t result = ForceUnmount(path); + if (result != OK) { + // TODO(135341433): MNT_DETACH is needed for fuse because umount2 can fail with EBUSY. + // Figure out why we get EBUSY and remove this special casing if possible. + if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL || + errno == ENOENT) { + PLOG(INFO) << "ForceUnmount failed on emulated fuse volume"; + } + } + + rmdir(path.c_str()); + setDeviceFd(-1); + return OK; + } + ForceUnmount(mFuseDefault); ForceUnmount(mFuseRead); ForceUnmount(mFuseWrite); diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 0a6b351..2c0b4cc 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -15,6 +15,8 @@ */ #include "PublicVolume.h" + +#include "AppFuseUtil.h" #include "Utils.h" #include "VolumeManager.h" #include "fs/Exfat.h" @@ -167,6 +169,20 @@ status_t PublicVolume::doMount() { dev_t before = GetDevice(mFuseFull); + bool isFuse = base::GetBoolProperty(kPropFuse, false); + + if (isFuse) { + LOG(INFO) << "Mounting public fuse volume"; + int fd = -1; + int result = MountUserFuse(getMountUserId(), stableName, &fd); + if (result != 0) { + LOG(ERROR) << "Failed to mount public fuse volume"; + return -result; + } + setDeviceFd(fd); + return OK; + } + if (!(mFusePid = fork())) { if (getMountFlags() & MountFlags::kPrimary) { // clang-format off @@ -229,6 +245,30 @@ status_t PublicVolume::doUnmount() { // error code and might cause broken behaviour in applications. KillProcessesUsingPath(getPath()); + bool isFuse = base::GetBoolProperty(kPropFuse, false); + if (isFuse) { + // Use UUID as stable name, if available + std::string stableName = getId(); + if (!mFsUuid.empty()) { + stableName = mFsUuid; + } + + std::string path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str())); + status_t result = ForceUnmount(path); + if (result != OK) { + // TODO(135341433): MNT_DETACH is needed for fuse because umount2 can fail with EBUSY. + // Figure out why we get EBUSY and remove this special casing if possible. + if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL || + errno == ENOENT) { + PLOG(INFO) << "ForceUnmount failed on public fuse volume"; + } + } + + rmdir(path.c_str()); + setDeviceFd(-1); + return OK; + } + ForceUnmount(kAsecPath); ForceUnmount(mFuseDefault); diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index ffc7900..fa007ad 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -143,6 +143,16 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) { return OK; } +status_t VolumeBase::setDeviceFd(int deviceFd) { + if ((mState != State::kChecking)) { + LOG(WARNING) << getId() << " device fd change requires state checking"; + return -EBUSY; + } + + mDeviceFd.reset(deviceFd); + return OK; +} + android::sp VolumeBase::getListener() const { if (mSilent) { return nullptr; diff --git a/model/VolumeBase.h b/model/VolumeBase.h index 53eeb6f..fa9eee4 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -87,6 +87,7 @@ class VolumeBase { State getState() const { return mState; } const std::string& getPath() const { return mPath; } const std::string& getInternalPath() const { return mInternalPath; } + int getDeviceFd() const { return dup(mDeviceFd.get()); } status_t setDiskId(const std::string& diskId); status_t setPartGuid(const std::string& partGuid); @@ -121,6 +122,7 @@ class VolumeBase { status_t setId(const std::string& id); status_t setPath(const std::string& path); status_t setInternalPath(const std::string& internalPath); + status_t setDeviceFd(int deviceFd); android::sp getListener() const; @@ -147,6 +149,8 @@ class VolumeBase { std::string mInternalPath; /* Flag indicating that volume should emit no events */ bool mSilent; + /* The filedescriptor for the fuse device, if the volume uses fuse, or -1 otherwise */ + android::base::unique_fd mDeviceFd; /* Volumes stacked on top of this volume */ std::list> mVolumes; From a914cc764e255b639f2463976c98e92316ee27ea Mon Sep 17 00:00:00 2001 From: Nandana Dutt Date: Thu, 29 Aug 2019 15:22:42 +0100 Subject: [PATCH 005/112] Use unique_fd Also allow the state just before doMount() as a valid state for setting fuse fd. Test: manual BUG:140173712 Change-Id: I012f8a83fef00e68f33010954fbc2ebc53cf8f1d --- Utils.cpp | 11 ++++++----- Utils.h | 4 +++- VoldNativeService.cpp | 2 +- model/EmulatedVolume.cpp | 6 +++--- model/PublicVolume.cpp | 6 +++--- model/VolumeBase.cpp | 8 ++++---- model/VolumeBase.h | 6 +++--- 7 files changed, 23 insertions(+), 20 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index bd3d452..5e284b2 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -985,7 +985,8 @@ bool writeStringToFile(const std::string& payload, const std::string& filename) return true; } -int MountUserFuse(userid_t user_id, const std::string& relative_path, int* device_fd) { +int MountUserFuse(userid_t user_id, const std::string& relative_path, + android::base::unique_fd* fuse_fd) { std::string path(StringPrintf("/mnt/user/%d/%s", user_id, relative_path.c_str())); // Force remove the existing mount before we attempt to prepare the @@ -1004,9 +1005,9 @@ int MountUserFuse(userid_t user_id, const std::string& relative_path, int* devic return -1; } - // Open device fd. - *device_fd = open("/dev/fuse", O_RDWR | O_CLOEXEC); - if (*device_fd == -1) { + // Open fuse fd. + fuse_fd->reset(open("/dev/fuse", O_RDWR | O_CLOEXEC)); + if (fuse_fd->get() == -1) { PLOG(ERROR) << "Failed to open /dev/fuse"; return -1; } @@ -1018,7 +1019,7 @@ int MountUserFuse(userid_t user_id, const std::string& relative_path, int* devic "rootmode=40000," "allow_other," "user_id=0,group_id=0,", - *device_fd); + fuse_fd->get()); const int result_int = TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse", diff --git a/Utils.h b/Utils.h index cd55b09..e0102a7 100644 --- a/Utils.h +++ b/Utils.h @@ -20,6 +20,7 @@ #include "KeyBuffer.h" #include +#include #include #include #include @@ -150,7 +151,8 @@ bool FsyncDirectory(const std::string& dirname); bool writeStringToFile(const std::string& payload, const std::string& filename); -int MountUserFuse(userid_t user_id, const std::string& relative_path, int* device_fd); +int MountUserFuse(userid_t user_id, const std::string& relative_path, + android::base::unique_fd* fuse_fd); } // namespace vold } // namespace android diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 9004b40..9b223c7 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -345,7 +345,7 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF return translate(res); } - _aidl_return->reset(vol->getDeviceFd()); + _aidl_return->reset(dup(vol->getFuseFd().get())); if (_aidl_return->get() == -1) { // Let's not return invalid fd since binder will not allow null fds. Instead give it a // default value. diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index ca314ef..022ff42 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -88,13 +88,13 @@ status_t EmulatedVolume::doMount() { if (isFuse) { LOG(INFO) << "Mounting emulated fuse volume"; - int fd = -1; + android::base::unique_fd fd; int result = MountUserFuse(getMountUserId(), label, &fd); if (result != 0) { PLOG(ERROR) << "Failed to mount emulated fuse volume"; return -result; } - setDeviceFd(fd); + setFuseFd(std::move(fd)); return OK; } @@ -170,7 +170,7 @@ status_t EmulatedVolume::doUnmount() { } rmdir(path.c_str()); - setDeviceFd(-1); + setFuseFd(android::base::unique_fd()); return OK; } diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 2c0b4cc..ebcb91a 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -173,13 +173,13 @@ status_t PublicVolume::doMount() { if (isFuse) { LOG(INFO) << "Mounting public fuse volume"; - int fd = -1; + android::base::unique_fd fd; int result = MountUserFuse(getMountUserId(), stableName, &fd); if (result != 0) { LOG(ERROR) << "Failed to mount public fuse volume"; return -result; } - setDeviceFd(fd); + setFuseFd(std::move(fd)); return OK; } @@ -265,7 +265,7 @@ status_t PublicVolume::doUnmount() { } rmdir(path.c_str()); - setDeviceFd(-1); + setFuseFd(android::base::unique_fd()); return OK; } diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index fa007ad..d6e4288 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -143,13 +143,13 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) { return OK; } -status_t VolumeBase::setDeviceFd(int deviceFd) { - if ((mState != State::kChecking)) { - LOG(WARNING) << getId() << " device fd change requires state checking"; +status_t VolumeBase::setFuseFd(android::base::unique_fd fuseFd) { + if ((mState != State::kChecking) && (mState != State::kEjecting)) { + LOG(WARNING) << getId() << " fuse fd change requires state checking or ejecting"; return -EBUSY; } - mDeviceFd.reset(deviceFd); + mFuseFd.reset(std::move(fuseFd.get())); return OK; } diff --git a/model/VolumeBase.h b/model/VolumeBase.h index fa9eee4..6afb88e 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -87,7 +87,7 @@ class VolumeBase { State getState() const { return mState; } const std::string& getPath() const { return mPath; } const std::string& getInternalPath() const { return mInternalPath; } - int getDeviceFd() const { return dup(mDeviceFd.get()); } + const android::base::unique_fd& getFuseFd() const { return mFuseFd; } status_t setDiskId(const std::string& diskId); status_t setPartGuid(const std::string& partGuid); @@ -122,7 +122,7 @@ class VolumeBase { status_t setId(const std::string& id); status_t setPath(const std::string& path); status_t setInternalPath(const std::string& internalPath); - status_t setDeviceFd(int deviceFd); + status_t setFuseFd(android::base::unique_fd fuseFd); android::sp getListener() const; @@ -150,7 +150,7 @@ class VolumeBase { /* Flag indicating that volume should emit no events */ bool mSilent; /* The filedescriptor for the fuse device, if the volume uses fuse, or -1 otherwise */ - android::base::unique_fd mDeviceFd; + android::base::unique_fd mFuseFd; /* Volumes stacked on top of this volume */ std::list> mVolumes; From 1711236e02b8083f7c123a532a028e2a849364d2 Mon Sep 17 00:00:00 2001 From: Zim Date: Tue, 3 Sep 2019 20:50:53 +0100 Subject: [PATCH 006/112] Avoid touching FUSE mounts on vold binder threads On user unlock when persist.sys.fuse property is set, StorageManagerService calls into vold to link the primary volumes. Because this involves accessing a FUSE path that has not been initialized, vold should offload this work from the binder thread, otherwise it would wedge and the system server would wedge causing a Watchdog trigger. This fixes a bug where we 'link primary' twice and vold gets wedged on system server restarts. Bug: 140064376 Test: with the FUSE property set: adb shell stop && adb shell start && adb shell ls /sdcard Change-Id: I0eb86f8ba256c385c916e2a0389a4f7482fc3775 --- VolumeManager.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 2eb1ed5..adb4a5c 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -395,6 +395,7 @@ int VolumeManager::linkPrimary(userid_t userId) { auto symlinkInfo = new std::pair(source, target); std::thread(symlinkPrimary, symlinkInfo).detach(); + return 0; } std::string source(mPrimary->getPath()); From 23edfac445f17daac50f5206e626164c6e073753 Mon Sep 17 00:00:00 2001 From: Nandana Dutt Date: Tue, 3 Sep 2019 12:44:08 +0100 Subject: [PATCH 007/112] Fix fdsan check BUG: 140376618 Test: Downloaded a picture on Chrome (this would crash previously) Change-Id: I7a750cde1131d19d140140dfaa0bd09131974fc0 --- model/VolumeBase.cpp | 2 +- model/VolumeBase.h | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index d6e4288..08da8f6 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -149,7 +149,7 @@ status_t VolumeBase::setFuseFd(android::base::unique_fd fuseFd) { return -EBUSY; } - mFuseFd.reset(std::move(fuseFd.get())); + mFuseFd = std::move(fuseFd); return OK; } diff --git a/model/VolumeBase.h b/model/VolumeBase.h index 6afb88e..5deecdb 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -122,6 +122,7 @@ class VolumeBase { status_t setId(const std::string& id); status_t setPath(const std::string& path); status_t setInternalPath(const std::string& internalPath); + // Takes ownership of the fd passed in. status_t setFuseFd(android::base::unique_fd fuseFd); android::sp getListener() const; From 981222f500baffae98bfd5949de41257a8238074 Mon Sep 17 00:00:00 2001 From: Zim Date: Mon, 9 Sep 2019 10:24:44 +0100 Subject: [PATCH 008/112] Bind mount lower filesystem during FUSE mount When mounting a FUSE device on /mnt/user//, bind mount the correspoinding lower filesystem path to /mnt/pass_through//. At Zygote fork time, an app with the right privilege will have the pass_through path bind mounted into /storage instead of the /mnt/user path. This provides such an app direct access to the lower filesystem without going through FUSE. Bug: 140064376 Test: mount(8) shows /mnt/pass_through/0/emulated is a bind mount of the lower fs Change-Id: I32c3cad64138910fcec9fb8f66b206706b5fd139 --- VolumeManager.cpp | 3 +++ binder/android/os/IVold.aidl | 1 + model/EmulatedVolume.cpp | 9 +++++++-- model/PublicVolume.cpp | 9 +++++++-- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index adb4a5c..0bb87a4 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -487,6 +487,9 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { case VoldNativeService::REMOUNT_MODE_FULL: mode = "full"; break; + case VoldNativeService::REMOUNT_MODE_PASS_THROUGH: + mode = "pass_through"; + break; default: PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode); return -1; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index b1af587..ae5a3bc 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -157,6 +157,7 @@ interface IVold { const int REMOUNT_MODE_LEGACY = 4; const int REMOUNT_MODE_INSTALLER = 5; const int REMOUNT_MODE_FULL = 6; + const int REMOUNT_MODE_PASS_THROUGH = 7; const int VOLUME_STATE_UNMOUNTED = 0; const int VOLUME_STATE_CHECKING = 1; diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 022ff42..4910803 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -89,13 +89,18 @@ status_t EmulatedVolume::doMount() { if (isFuse) { LOG(INFO) << "Mounting emulated fuse volume"; android::base::unique_fd fd; - int result = MountUserFuse(getMountUserId(), label, &fd); + int user_id = getMountUserId(); + int result = MountUserFuse(user_id, label, &fd); + if (result != 0) { PLOG(ERROR) << "Failed to mount emulated fuse volume"; return -result; } setFuseFd(std::move(fd)); - return OK; + + std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s", + user_id, label.c_str())); + return BindMount(getInternalPath(), pass_through_path); } if (!(mFusePid = fork())) { diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index ebcb91a..d2fcc18 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -174,13 +174,18 @@ status_t PublicVolume::doMount() { if (isFuse) { LOG(INFO) << "Mounting public fuse volume"; android::base::unique_fd fd; - int result = MountUserFuse(getMountUserId(), stableName, &fd); + int user_id = getMountUserId(); + int result = MountUserFuse(user_id, stableName, &fd); + if (result != 0) { LOG(ERROR) << "Failed to mount public fuse volume"; return -result; } setFuseFd(std::move(fd)); - return OK; + + std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s", + user_id, stableName.c_str())); + return BindMount(getInternalPath(), pass_through_path); } if (!(mFusePid = fork())) { From 5cf32b52a6f91771506020dd8ea69bab01290dbf Mon Sep 17 00:00:00 2001 From: shafik Date: Wed, 25 Sep 2019 13:56:01 +0100 Subject: [PATCH 009/112] Use snapshot value sys.fuse_snapshot instead of persist.sys.fuse This will allow us to receive values from server flags and store them in persist.sys.fuse without risking flag consistency during a boot. Test: manual - flip persist.sys.fuse both ways and make sure FuseDaemon works as expected. Bug: 140803239 Change-Id: I839a1973c98b4eda982226d20be48d1c08e7464a --- Utils.h | 2 +- VolumeManager.cpp | 4 ++-- model/EmulatedVolume.cpp | 4 ++-- model/PublicVolume.cpp | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/Utils.h b/Utils.h index e0102a7..f607c81 100644 --- a/Utils.h +++ b/Utils.h @@ -34,7 +34,7 @@ struct DIR; namespace android { namespace vold { -static const char* kPropFuse = "persist.sys.fuse"; +static const char* kPropFuseSnapshot = "sys.fuse_snapshot"; /* SELinux contexts used depending on the block device type */ extern security_context_t sBlkidContext; diff --git a/VolumeManager.cpp b/VolumeManager.cpp index adb4a5c..5b23116 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -382,7 +382,7 @@ int VolumeManager::forgetPartition(const std::string& partGuid, const std::strin } int VolumeManager::linkPrimary(userid_t userId) { - bool isFuse = GetBoolProperty(android::vold::kPropFuse, false); + bool isFuse = GetBoolProperty(android::vold::kPropFuseSnapshot, false); if (isFuse) { // Here we have to touch /mnt/user/userid>/ which was already mounted as part of @@ -464,7 +464,7 @@ int VolumeManager::setPrimary(const std::shared_ptr& } int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { - if (GetBoolProperty(android::vold::kPropFuse, false)) { + if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { // TODO(135341433): Implement fuse specific logic. return 0; } diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 022ff42..41f42d1 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -84,7 +84,7 @@ status_t EmulatedVolume::doMount() { dev_t before = GetDevice(mFuseFull); - bool isFuse = base::GetBoolProperty(kPropFuse, false); + bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); if (isFuse) { LOG(INFO) << "Mounting emulated fuse volume"; @@ -150,7 +150,7 @@ status_t EmulatedVolume::doUnmount() { // error code and might cause broken behaviour in applications. KillProcessesUsingPath(getPath()); - bool isFuse = base::GetBoolProperty(kPropFuse, false); + bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); if (isFuse) { // We could have migrated storage to an adopted private volume, so always // call primary storage "emulated" to avoid media rescans. diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index ebcb91a..3f003a9 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -169,7 +169,7 @@ status_t PublicVolume::doMount() { dev_t before = GetDevice(mFuseFull); - bool isFuse = base::GetBoolProperty(kPropFuse, false); + bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); if (isFuse) { LOG(INFO) << "Mounting public fuse volume"; @@ -245,7 +245,7 @@ status_t PublicVolume::doUnmount() { // error code and might cause broken behaviour in applications. KillProcessesUsingPath(getPath()); - bool isFuse = base::GetBoolProperty(kPropFuse, false); + bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); if (isFuse) { // Use UUID as stable name, if available std::string stableName = getId(); From aeb87efb1ffe2ed425965e2c8e3bbd2bf80947dc Mon Sep 17 00:00:00 2001 From: Zim Date: Thu, 26 Sep 2019 16:06:05 +0100 Subject: [PATCH 010/112] Lazily write inode timestamps to FUSE Before this, the FUSE daemon receives a setattr inode timestamp request for every write request. This can be crippling for write performance or read performance during writes especially random writes where the write back cache does not effectively coagulate requests. We now add the MS_LAZYTIME mount flag (http://man7.org/linux/man-pages/man2/mount.2.html) to lazily flush the timestamp updates from memory to disk Test: m Bug: 135341433 Change-Id: I95a467d5682a325b4099f32634d93ed2921f815e --- Utils.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 5e284b2..e5bf33d 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1023,7 +1023,8 @@ int MountUserFuse(userid_t user_id, const std::string& relative_path, const int result_int = TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse", - MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME, opts.c_str())); + MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_LAZYTIME, + opts.c_str())); if (result_int != 0) { PLOG(ERROR) << "Failed to mount " << path; return -errno; From 5d85bf31273504d175333cf258eec485327ae21d Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Wed, 23 Oct 2019 17:19:13 +0100 Subject: [PATCH 011/112] Rename ENFORCE_UID to ENFORCE_SYSTEM_OR_ROOT A little bit more self-explanatory name that explicitly says that root is also allowed. Test: builds Change-Id: Ice20ffcba2a0994c599dbebace252138ffd827de --- VoldNativeService.cpp | 148 +++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 7ffdda0..20e1290 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -92,7 +92,7 @@ binder::Status checkPermission(const char* permission) { } } -binder::Status checkUid(uid_t expectedUid) { +binder::Status checkUidOrRoot(uid_t expectedUid) { uid_t uid = IPCThreadState::self()->getCallingUid(); if (uid == expectedUid || uid == AID_ROOT) { return ok(); @@ -147,12 +147,12 @@ binder::Status checkArgumentHex(const std::string& hex) { return ok(); } -#define ENFORCE_UID(uid) \ - { \ - binder::Status status = checkUid((uid)); \ - if (!status.isOk()) { \ - return status; \ - } \ +#define ENFORCE_SYSTEM_OR_ROOT \ + { \ + binder::Status status = checkUidOrRoot(AID_SYSTEM); \ + if (!status.isOk()) { \ + return status; \ + } \ } #define CHECK_ARGUMENT_ID(id) \ @@ -217,7 +217,7 @@ status_t VoldNativeService::dump(int fd, const Vector& /* args */) { binder::Status VoldNativeService::setListener( const android::sp& listener) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; VolumeManager::Instance()->setListener(listener); @@ -225,7 +225,7 @@ binder::Status VoldNativeService::setListener( } binder::Status VoldNativeService::monitor() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; // Simply acquire/release each lock for watchdog { ACQUIRE_LOCK; } @@ -235,42 +235,42 @@ binder::Status VoldNativeService::monitor() { } binder::Status VoldNativeService::reset() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->reset()); } binder::Status VoldNativeService::shutdown() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->shutdown()); } binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->onUserAdded(userId, userSerial)); } binder::Status VoldNativeService::onUserRemoved(int32_t userId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->onUserRemoved(userId)); } binder::Status VoldNativeService::onUserStarted(int32_t userId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->onUserStarted(userId)); } binder::Status VoldNativeService::onUserStopped(int32_t userId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->onUserStopped(userId)); @@ -287,7 +287,7 @@ binder::Status VoldNativeService::addSandboxIds(const std::vector& appI } binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->onSecureKeyguardStateChanged(isShowing)); @@ -295,7 +295,7 @@ binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) { binder::Status VoldNativeService::partition(const std::string& diskId, int32_t partitionType, int32_t ratio) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(diskId); ACQUIRE_LOCK; @@ -317,7 +317,7 @@ binder::Status VoldNativeService::partition(const std::string& diskId, int32_t p binder::Status VoldNativeService::forgetPartition(const std::string& partGuid, const std::string& fsUuid) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_HEX(partGuid); CHECK_ARGUMENT_HEX(fsUuid); ACQUIRE_LOCK; @@ -328,7 +328,7 @@ binder::Status VoldNativeService::forgetPartition(const std::string& partGuid, binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId, android::base::unique_fd* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -362,7 +362,7 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF } binder::Status VoldNativeService::unmount(const std::string& volId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -374,7 +374,7 @@ binder::Status VoldNativeService::unmount(const std::string& volId) { } binder::Status VoldNativeService::format(const std::string& volId, const std::string& fsType) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -409,7 +409,7 @@ static binder::Status pathForVolId(const std::string& volId, std::string* path) binder::Status VoldNativeService::benchmark( const std::string& volId, const android::sp& listener) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -422,7 +422,7 @@ binder::Status VoldNativeService::benchmark( } binder::Status VoldNativeService::checkEncryption(const std::string& volId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -435,7 +435,7 @@ binder::Status VoldNativeService::checkEncryption(const std::string& volId) { binder::Status VoldNativeService::moveStorage( const std::string& fromVolId, const std::string& toVolId, const android::sp& listener) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(fromVolId); CHECK_ARGUMENT_ID(toVolId); ACQUIRE_LOCK; @@ -453,14 +453,14 @@ binder::Status VoldNativeService::moveStorage( } binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->remountUid(uid, remountMode)); } binder::Status VoldNativeService::mkdirs(const std::string& path) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(path); ACQUIRE_LOCK; @@ -470,7 +470,7 @@ binder::Status VoldNativeService::mkdirs(const std::string& path) { binder::Status VoldNativeService::createObb(const std::string& sourcePath, const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(sourcePath); CHECK_ARGUMENT_HEX(sourceKey); ACQUIRE_LOCK; @@ -480,7 +480,7 @@ binder::Status VoldNativeService::createObb(const std::string& sourcePath, } binder::Status VoldNativeService::destroyObb(const std::string& volId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -490,7 +490,7 @@ binder::Status VoldNativeService::destroyObb(const std::string& volId) { binder::Status VoldNativeService::createStubVolume( const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, const std::string& fsUuid, const std::string& fsLabel, std::string* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(sourcePath); CHECK_ARGUMENT_PATH(mountPath); CHECK_ARGUMENT_HEX(fsUuid); @@ -503,7 +503,7 @@ binder::Status VoldNativeService::createStubVolume( } binder::Status VoldNativeService::destroyStubVolume(const std::string& volId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -512,7 +512,7 @@ binder::Status VoldNativeService::destroyStubVolume(const std::string& volId) { binder::Status VoldNativeService::fstrim( int32_t fstrimFlags, const android::sp& listener) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; std::thread([=]() { android::vold::Trim(listener); }).detach(); @@ -521,7 +521,7 @@ binder::Status VoldNativeService::fstrim( binder::Status VoldNativeService::runIdleMaint( const android::sp& listener) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; std::thread([=]() { android::vold::RunIdleMaint(listener); }).detach(); @@ -530,7 +530,7 @@ binder::Status VoldNativeService::runIdleMaint( binder::Status VoldNativeService::abortIdleMaint( const android::sp& listener) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; std::thread([=]() { android::vold::AbortIdleMaint(listener); }).detach(); @@ -539,14 +539,14 @@ binder::Status VoldNativeService::abortIdleMaint( binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t mountId, android::base::unique_fd* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->mountAppFuse(uid, mountId, _aidl_return)); } binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t mountId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translate(VolumeManager::Instance()->unmountAppFuse(uid, mountId)); @@ -555,7 +555,7 @@ binder::Status VoldNativeService::unmountAppFuse(int32_t uid, int32_t 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); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; int fd = VolumeManager::Instance()->openAppFuseFile(uid, mountId, fileId, flags); @@ -570,14 +570,14 @@ binder::Status VoldNativeService::openAppFuseFile(int32_t uid, int32_t mountId, } binder::Status VoldNativeService::fdeCheckPassword(const std::string& password) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translate(cryptfs_check_passwd(password.c_str())); } binder::Status VoldNativeService::fdeRestart() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; // Spawn as thread so init can issue commands back to vold without @@ -587,7 +587,7 @@ binder::Status VoldNativeService::fdeRestart() { } binder::Status VoldNativeService::fdeComplete(int32_t* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; *_aidl_return = cryptfs_crypto_complete(); @@ -618,7 +618,7 @@ static int fdeEnableInternal(int32_t passwordType, const std::string& password, binder::Status VoldNativeService::fdeEnable(int32_t passwordType, const std::string& password, int32_t encryptionFlags) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; LOG(DEBUG) << "fdeEnable(" << passwordType << ", *, " << encryptionFlags << ")"; @@ -636,21 +636,21 @@ binder::Status VoldNativeService::fdeEnable(int32_t passwordType, const std::str binder::Status VoldNativeService::fdeChangePassword(int32_t passwordType, const std::string& password) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translate(cryptfs_changepw(passwordType, password.c_str())); } binder::Status VoldNativeService::fdeVerifyPassword(const std::string& password) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translate(cryptfs_verify_passwd(password.c_str())); } binder::Status VoldNativeService::fdeGetField(const std::string& key, std::string* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; char buf[PROPERTY_VALUE_MAX]; @@ -663,14 +663,14 @@ binder::Status VoldNativeService::fdeGetField(const std::string& key, std::strin } binder::Status VoldNativeService::fdeSetField(const std::string& key, const std::string& value) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translate(cryptfs_setfield(key.c_str(), value.c_str())); } binder::Status VoldNativeService::fdeGetPasswordType(int32_t* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; *_aidl_return = cryptfs_get_password_type(); @@ -678,7 +678,7 @@ binder::Status VoldNativeService::fdeGetPasswordType(int32_t* _aidl_return) { } binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; const char* res = cryptfs_get_password(); @@ -689,7 +689,7 @@ binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) { } binder::Status VoldNativeService::fdeClearPassword() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; cryptfs_clear_password(); @@ -697,14 +697,14 @@ binder::Status VoldNativeService::fdeClearPassword() { } binder::Status VoldNativeService::fbeEnable() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_initialize_systemwide_keys()); } binder::Status VoldNativeService::mountDefaultEncrypted() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; if (!fscrypt_is_native()) { @@ -716,14 +716,14 @@ binder::Status VoldNativeService::mountDefaultEncrypted() { } binder::Status VoldNativeService::initUser0() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_init_user0()); } binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; *_aidl_return = cryptfs_isConvertibleToFBE() != 0; @@ -732,7 +732,7 @@ binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) { binder::Status VoldNativeService::mountFstab(const std::string& blkDevice, const std::string& mountPoint) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translateBool(fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, false)); @@ -740,21 +740,21 @@ binder::Status VoldNativeService::mountFstab(const std::string& blkDevice, binder::Status VoldNativeService::encryptFstab(const std::string& blkDevice, const std::string& mountPoint) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return translateBool(fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, true)); } binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial, bool ephemeral) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_vold_create_user_key(userId, userSerial, ephemeral)); } binder::Status VoldNativeService::destroyUserKey(int32_t userId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_destroy_user_key(userId)); @@ -763,14 +763,14 @@ binder::Status VoldNativeService::destroyUserKey(int32_t userId) { binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSerial, const std::string& token, const std::string& secret) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_add_user_key_auth(userId, userSerial, token, secret)); } binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_fixate_newest_user_key_auth(userId)); @@ -779,14 +779,14 @@ binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) { binder::Status VoldNativeService::unlockUserKey(int32_t userId, int32_t userSerial, const std::string& token, const std::string& secret) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_unlock_user_key(userId, userSerial, token, secret)); } binder::Status VoldNativeService::lockUserKey(int32_t userId) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; return translateBool(fscrypt_lock_user_key(userId)); @@ -795,7 +795,7 @@ binder::Status VoldNativeService::lockUserKey(int32_t userId) { binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr& uuid, int32_t userId, int32_t userSerial, int32_t flags) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; std::string empty_string = ""; auto uuid_ = uuid ? *uuid : empty_string; CHECK_ARGUMENT_HEX(uuid_); @@ -806,7 +806,7 @@ binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr& uuid, int32_t userId, int32_t flags) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; std::string empty_string = ""; auto uuid_ = uuid ? *uuid : empty_string; CHECK_ARGUMENT_HEX(uuid_); @@ -828,14 +828,14 @@ binder::Status VoldNativeService::destroySandboxForApp(const std::string& packag } binder::Status VoldNativeService::startCheckpoint(int32_t retry) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return cp_startCheckpoint(retry); } binder::Status VoldNativeService::needsRollback(bool* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; *_aidl_return = cp_needsRollback(); @@ -843,7 +843,7 @@ binder::Status VoldNativeService::needsRollback(bool* _aidl_return) { } binder::Status VoldNativeService::needsCheckpoint(bool* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; *_aidl_return = cp_needsCheckpoint(); @@ -851,21 +851,21 @@ binder::Status VoldNativeService::needsCheckpoint(bool* _aidl_return) { } binder::Status VoldNativeService::commitChanges() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return cp_commitChanges(); } binder::Status VoldNativeService::prepareCheckpoint() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return cp_prepareCheckpoint(); } binder::Status VoldNativeService::restoreCheckpoint(const std::string& mountPoint) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(mountPoint); ACQUIRE_LOCK; @@ -873,7 +873,7 @@ binder::Status VoldNativeService::restoreCheckpoint(const std::string& mountPoin } binder::Status VoldNativeService::restoreCheckpointPart(const std::string& mountPoint, int count) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(mountPoint); ACQUIRE_LOCK; @@ -881,14 +881,14 @@ binder::Status VoldNativeService::restoreCheckpointPart(const std::string& mount } binder::Status VoldNativeService::markBootAttempt() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return cp_markBootAttempt(); } binder::Status VoldNativeService::abortChanges(const std::string& message, bool retry) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; cp_abortChanges(message, retry); @@ -896,28 +896,28 @@ binder::Status VoldNativeService::abortChanges(const std::string& message, bool } binder::Status VoldNativeService::supportsCheckpoint(bool* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return cp_supportsCheckpoint(*_aidl_return); } binder::Status VoldNativeService::supportsBlockCheckpoint(bool* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return cp_supportsBlockCheckpoint(*_aidl_return); } binder::Status VoldNativeService::supportsFileCheckpoint(bool* _aidl_return) { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; return cp_supportsFileCheckpoint(*_aidl_return); } binder::Status VoldNativeService::resetCheckpoint() { - ENFORCE_UID(AID_SYSTEM); + ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; cp_resetCheckpoint(); From a438b2436886a9d1dbb865c891cc5ec9ececba09 Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 25 Sep 2019 14:37:38 +0100 Subject: [PATCH 012/112] Fix multi-user and multi-storage with FUSE Up until now, the FUSE mount logic has made two assumptions: 1. The primary external volume is an emulated volume on /data/media 2. Only the primary user is running, as user zero These assumptions are fixed by the following changes creating an EmulatedVolume per Android user and changing the VolumeBase id format to append the user to the id, so s/emulated/emulated-0/. This allows us mount separate volumes per user Some additional refactorings to re-use/clean up code. Test: adb shell sm set-virtual-disk and partition disk operations work even after setting up a work profile Bug: 135341433 Change-Id: Ifabaa12368e5a591fbcdce4ee71c83ff35fdac6b --- Utils.cpp | 83 +++++++++-- Utils.h | 6 +- VoldNativeService.cpp | 2 +- VolumeManager.cpp | 209 ++++++++++++++++++--------- VolumeManager.h | 7 +- binder/android/os/IVoldListener.aidl | 2 +- model/EmulatedVolume.cpp | 35 ++--- model/EmulatedVolume.h | 4 +- model/PrivateVolume.cpp | 16 +- model/PrivateVolume.h | 2 + model/PublicVolume.cpp | 33 +++-- model/VolumeBase.cpp | 3 +- model/VolumeBase.h | 1 + 13 files changed, 272 insertions(+), 131 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index e5bf33d..48e5ce0 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -985,26 +985,61 @@ bool writeStringToFile(const std::string& payload, const std::string& filename) return true; } -int MountUserFuse(userid_t user_id, const std::string& relative_path, - android::base::unique_fd* fuse_fd) { - std::string path(StringPrintf("/mnt/user/%d/%s", user_id, relative_path.c_str())); +status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, + const std::string& relative_upper_path, android::base::unique_fd* fuse_fd) { + std::string pre_fuse_path(StringPrintf("/mnt/user/%d", user_id)); + std::string fuse_path( + StringPrintf("%s/%s", pre_fuse_path.c_str(), relative_upper_path.c_str())); + + std::string pre_pass_through_path(StringPrintf("/mnt/pass_through/%d", user_id)); + std::string pass_through_path( + StringPrintf("%s/%s", pre_pass_through_path.c_str(), relative_upper_path.c_str())); // Force remove the existing mount before we attempt to prepare the // directory. If we have a dangling mount, then PrepareDir may fail if the // indirection to FUSE doesn't work. - android::status_t result = android::vold::ForceUnmount(path); + android::status_t result = UnmountUserFuse(pass_through_path, fuse_path); if (result != android::OK) { - PLOG(ERROR) << "Failed to unmount " << path; return -1; } // Create directories. - result = android::vold::PrepareDir(path, 0700, AID_ROOT, AID_ROOT); + result = PrepareDir(pre_fuse_path, 0700, AID_ROOT, AID_ROOT); if (result != android::OK) { - PLOG(ERROR) << "Failed to prepare directory " << path; + PLOG(ERROR) << "Failed to prepare directory " << pre_fuse_path; return -1; } + result = PrepareDir(fuse_path, 0700, AID_ROOT, AID_ROOT); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << fuse_path; + return -1; + } + + result = PrepareDir(pre_pass_through_path, 0755, AID_ROOT, AID_ROOT); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << pre_pass_through_path; + return -1; + } + + result = PrepareDir(pass_through_path, 0755, AID_ROOT, AID_ROOT); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << pass_through_path; + return -1; + } + + if (relative_upper_path == "emulated") { + std::string target(StringPrintf("/mnt/user/%d/self", user_id)); + result = PrepareDir(target, 0755, AID_ROOT, AID_ROOT); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << target; + return -1; + } + target += "/primary"; + + Symlink(fuse_path + "/" + std::to_string(user_id), target); + } + // Open fuse fd. fuse_fd->reset(open("/dev/fuse", O_RDWR | O_CLOEXEC)); if (fuse_fd->get() == -1) { @@ -1021,15 +1056,35 @@ int MountUserFuse(userid_t user_id, const std::string& relative_path, "user_id=0,group_id=0,", fuse_fd->get()); - const int result_int = - TEMP_FAILURE_RETRY(mount("/dev/fuse", path.c_str(), "fuse", - MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_LAZYTIME, - opts.c_str())); - if (result_int != 0) { - PLOG(ERROR) << "Failed to mount " << path; + result = TEMP_FAILURE_RETRY(mount("/dev/fuse", fuse_path.c_str(), "fuse", + MS_NOSUID | MS_NODEV | MS_NOEXEC | MS_NOATIME | MS_LAZYTIME, + opts.c_str())); + if (result != 0) { + PLOG(ERROR) << "Failed to mount " << fuse_path; return -errno; } - return 0; + LOG(INFO) << "Bind mounting to " << absolute_lower_path; + return BindMount(absolute_lower_path, pass_through_path); +} + +status_t UnmountUserFuse(const std::string& pass_through_path, const std::string& fuse_path) { + // Best effort unmount pass_through path + sSleepOnUnmount = false; + ForceUnmount(pass_through_path); + android::status_t result = ForceUnmount(fuse_path); + sSleepOnUnmount = true; + if (result != android::OK) { + // TODO(b/135341433): MNT_DETACH is needed for fuse because umount2 can fail with EBUSY. + // Figure out why we get EBUSY and remove this special casing if possible. + PLOG(ERROR) << "Failed to unmount. Trying MNT_DETACH " << fuse_path << " ..."; + if (umount2(fuse_path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) && errno != EINVAL && + errno != ENOENT) { + PLOG(ERROR) << "Failed to unmount with MNT_DETACH " << fuse_path; + return -errno; + } + return android::OK; + } + return result; } } // namespace vold diff --git a/Utils.h b/Utils.h index f607c81..375e175 100644 --- a/Utils.h +++ b/Utils.h @@ -151,8 +151,10 @@ bool FsyncDirectory(const std::string& dirname); bool writeStringToFile(const std::string& payload, const std::string& filename); -int MountUserFuse(userid_t user_id, const std::string& relative_path, - android::base::unique_fd* fuse_fd); +status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, + const std::string& relative_upper_path, android::base::unique_fd* fuse_fd); + +status_t UnmountUserFuse(const std::string& pass_through_path, const std::string& fuse_path); } // namespace vold } // namespace android diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 20e1290..e20d68e 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -107,7 +107,7 @@ binder::Status checkArgumentId(const std::string& id) { return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing ID"); } for (const char& c : id) { - if (!std::isalnum(c) && c != ':' && c != ',') { + if (!std::isalnum(c) && c != ':' && c != ',' && c != ';') { return exception(binder::Status::EX_ILLEGAL_ARGUMENT, StringPrintf("ID %s is malformed", id.c_str())); } diff --git a/VolumeManager.cpp b/VolumeManager.cpp index b0e0b23..3e7101c 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -31,7 +31,6 @@ #include #include #include -#include #include @@ -68,6 +67,7 @@ #include "fs/Vfat.h" #include "model/EmulatedVolume.h" #include "model/ObbVolume.h" +#include "model/PrivateVolume.h" #include "model/StubVolume.h" using android::OK; @@ -80,10 +80,12 @@ using android::vold::BindMount; using android::vold::CreateDir; using android::vold::DeleteDirContents; using android::vold::DeleteDirContentsAndDir; +using android::vold::PrivateVolume; using android::vold::Symlink; using android::vold::Unlink; using android::vold::UnmountTree; using android::vold::VoldNativeService; +using android::vold::VolumeBase; static const char* kPathUserMount = "/mnt/user"; static const char* kPathVirtualDisk = "/data/misc/vold/virtual_disk"; @@ -101,22 +103,6 @@ static const unsigned int kMajorBlockExperimentalMax = 254; VolumeManager* VolumeManager::sInstance = NULL; -static void* symlinkPrimary(void* data) { - std::unique_ptr> linkInfo( - static_cast*>(data)); - std::string* source = &linkInfo->first; - std::string* target = &linkInfo->second; - - fs_prepare_dir(source->c_str(), 0755, AID_ROOT, AID_ROOT); - fs_prepare_dir(target->c_str(), 0755, AID_ROOT, AID_ROOT); - *target = *target + "/primary"; - - // Link source to target - LOG(DEBUG) << "Linking " << *source << " to " << *target; - Symlink(*source, *target); - return nullptr; -} - VolumeManager* VolumeManager::Instance() { if (!sInstance) sInstance = new VolumeManager(); return sInstance; @@ -191,10 +177,13 @@ int VolumeManager::start() { // Assume that we always have an emulated volume on internal // storage; the framework will decide if it should be mounted. - CHECK(mInternalEmulated == nullptr); - mInternalEmulated = std::shared_ptr( - new android::vold::EmulatedVolume("/data/media")); - mInternalEmulated->create(); + CHECK(mInternalEmulatedVolumes.empty()); + + auto vol = std::shared_ptr( + new android::vold::EmulatedVolume("/data/media", 0)); + vol->setMountUserId(0); + vol->create(); + mInternalEmulatedVolumes.push_back(vol); // Consider creating a virtual disk updateVirtualDisk(); @@ -203,9 +192,12 @@ int VolumeManager::start() { } int VolumeManager::stop() { - CHECK(mInternalEmulated != nullptr); - mInternalEmulated->destroy(); - mInternalEmulated = nullptr; + CHECK(!mInternalEmulatedVolumes.empty()); + for (const auto& vol : mInternalEmulatedVolumes) { + vol->destroy(); + } + mInternalEmulatedVolumes.clear(); + return 0; } @@ -327,11 +319,10 @@ std::shared_ptr VolumeManager::findDisk(const std::string& } std::shared_ptr VolumeManager::findVolume(const std::string& id) { - // Vold could receive "mount" after "shutdown" command in the extreme case. - // If this happens, mInternalEmulated will equal nullptr and - // we need to deal with it in order to avoid null pointer crash. - if (mInternalEmulated != nullptr && mInternalEmulated->getId() == id) { - return mInternalEmulated; + for (const auto& vol : mInternalEmulatedVolumes) { + if (vol->getId() == id) { + return vol; + } } for (const auto& disk : mDisks) { auto vol = disk->findVolume(id); @@ -382,61 +373,129 @@ int VolumeManager::forgetPartition(const std::string& partGuid, const std::strin } int VolumeManager::linkPrimary(userid_t userId) { - bool isFuse = GetBoolProperty(android::vold::kPropFuseSnapshot, false); + if (!GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { + std::string source(mPrimary->getPath()); + if (mPrimary->isEmulated()) { + source = StringPrintf("%s/%d", source.c_str(), userId); + fs_prepare_dir(source.c_str(), 0755, AID_ROOT, AID_ROOT); + } - if (isFuse) { - // Here we have to touch /mnt/user/userid>/ which was already mounted as part of - // the boot sequence, requiring waiting till a fuse handler is available. If we do this work - // in foreground we could hang the caller, i.e. system server, which needs to start the fuse - // handler. So do it in the background. - std::string source( - StringPrintf("/mnt/user/%d/%s/%d", userId, mPrimary->getId().c_str(), userId)); - std::string target(StringPrintf("/mnt/user/%d/self", userId)); - - auto symlinkInfo = new std::pair(source, target); - std::thread(symlinkPrimary, symlinkInfo).detach(); - return 0; + std::string target(StringPrintf("/mnt/user/%d/primary", userId)); + LOG(DEBUG) << "Linking " << source << " to " << target; + Symlink(source, target); } - - std::string source(mPrimary->getPath()); - if (mPrimary->isEmulated()) { - source = StringPrintf("%s/%d", source.c_str(), userId); - fs_prepare_dir(source.c_str(), 0755, AID_ROOT, AID_ROOT); - } - - std::string target(StringPrintf("/mnt/user/%d/primary", userId)); - LOG(DEBUG) << "Linking " << source << " to " << target; - Symlink(source, target); return 0; } +void VolumeManager::destroyEmulatedVolumesForUser(userid_t userId) { + // Destroy and remove all unstacked EmulatedVolumes for the user + auto i = mInternalEmulatedVolumes.begin(); + while (i != mInternalEmulatedVolumes.end()) { + auto vol = *i; + if (vol->getMountUserId() == userId) { + vol->destroy(); + i = mInternalEmulatedVolumes.erase(i); + } else { + i++; + } + } + + // Destroy and remove all stacked EmulatedVolumes for the user on each mounted private volume + std::list private_vols; + listVolumes(VolumeBase::Type::kPrivate, private_vols); + for (const std::string& id : private_vols) { + PrivateVolume* pvol = static_cast(findVolume(id).get()); + std::list> vols_to_remove; + if (pvol->getState() == VolumeBase::State::kMounted) { + for (const auto& vol : pvol->getVolumes()) { + if (vol->getMountUserId() == userId) { + vols_to_remove.push_back(vol); + } + } + for (const auto& vol : vols_to_remove) { + vol->destroy(); + pvol->removeVolume(vol); + } + } // else EmulatedVolumes will be destroyed on VolumeBase#unmount + } +} + +void VolumeManager::createEmulatedVolumesForUser(userid_t userId) { + // Create unstacked EmulatedVolumes for the user + auto vol = std::shared_ptr( + new android::vold::EmulatedVolume("/data/media", userId)); + vol->setMountUserId(userId); + mInternalEmulatedVolumes.push_back(vol); + vol->create(); + + // Create stacked EmulatedVolumes for the user on each PrivateVolume + std::list private_vols; + listVolumes(VolumeBase::Type::kPrivate, private_vols); + for (const std::string& id : private_vols) { + PrivateVolume* pvol = static_cast(findVolume(id).get()); + if (pvol->getState() == VolumeBase::State::kMounted) { + auto evol = + std::shared_ptr(new android::vold::EmulatedVolume( + pvol->getPath() + "/media", pvol->getRawDevice(), pvol->getFsUuid(), + userId)); + evol->setMountUserId(userId); + pvol->addVolume(evol); + evol->create(); + } // else EmulatedVolumes will be created per user when on PrivateVolume#doMount + } +} + int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) { + LOG(INFO) << "onUserAdded: " << userId; + mAddedUsers[userId] = userSerialNumber; return 0; } int VolumeManager::onUserRemoved(userid_t userId) { + LOG(INFO) << "onUserRemoved: " << userId; + + if (GetBoolProperty(android::vold::kPropFuseSnapshot, false) && + mAddedUsers.find(userId) != mAddedUsers.end()) { + destroyEmulatedVolumesForUser(userId); + } + mAddedUsers.erase(userId); + mStartedUsers.erase(userId); return 0; } int VolumeManager::onUserStarted(userid_t userId) { - LOG(VERBOSE) << "onUserStarted: " << userId; - // Note that sometimes the system will spin up processes from Zygote - // before actually starting the user, so we're okay if Zygote - // already created this directory. - std::string path(StringPrintf("%s/%d", kPathUserMount, userId)); - fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT); + LOG(INFO) << "onUserStarted: " << userId; + + if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { + if (mStartedUsers.find(userId) == mStartedUsers.end()) { + createEmulatedVolumesForUser(userId); + } + } else { + // Note that sometimes the system will spin up processes from Zygote + // before actually starting the user, so we're okay if Zygote + // already created this directory. + std::string path(StringPrintf("%s/%d", kPathUserMount, userId)); + fs_prepare_dir(path.c_str(), 0755, AID_ROOT, AID_ROOT); + + if (mPrimary) { + linkPrimary(userId); + } + } mStartedUsers.insert(userId); - if (mPrimary) { - linkPrimary(userId); - } return 0; } int VolumeManager::onUserStopped(userid_t userId) { LOG(VERBOSE) << "onUserStopped: " << userId; + + if (GetBoolProperty(android::vold::kPropFuseSnapshot, false) && + mStartedUsers.find(userId) != mStartedUsers.end()) { + destroyEmulatedVolumesForUser(userId); + } + mStartedUsers.erase(userId); return 0; } @@ -640,10 +699,17 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { int VolumeManager::reset() { // Tear down all existing disks/volumes and start from a blank slate so // newly connected framework hears all events. - if (mInternalEmulated != nullptr) { - mInternalEmulated->destroy(); - mInternalEmulated->create(); + for (const auto& vol : mInternalEmulatedVolumes) { + vol->destroy(); } + mInternalEmulatedVolumes.clear(); + // Add user 0 cos it's always running and started + auto vol = std::shared_ptr( + new android::vold::EmulatedVolume("/data/media", 0)); + vol->setMountUserId(0); + vol->create(); + mInternalEmulatedVolumes.push_back(vol); + for (const auto& disk : mDisks) { disk->destroy(); disk->create(); @@ -651,20 +717,25 @@ int VolumeManager::reset() { updateVirtualDisk(); mAddedUsers.clear(); mStartedUsers.clear(); + + mStartedUsers.insert(0); return 0; } // Can be called twice (sequentially) during shutdown. should be safe for that. int VolumeManager::shutdown() { - if (mInternalEmulated == nullptr) { + if (mInternalEmulatedVolumes.empty()) { return 0; // already shutdown } android::vold::sSleepOnUnmount = false; - mInternalEmulated->destroy(); - mInternalEmulated = nullptr; + for (const auto& vol : mInternalEmulatedVolumes) { + vol->destroy(); + } for (const auto& disk : mDisks) { disk->destroy(); } + + mInternalEmulatedVolumes.clear(); mStubVolumes.clear(); mDisks.clear(); mPendingDisks.clear(); @@ -677,8 +748,8 @@ int VolumeManager::unmountAll() { ATRACE_NAME("VolumeManager::unmountAll()"); // First, try gracefully unmounting all known devices - if (mInternalEmulated != nullptr) { - mInternalEmulated->unmount(); + for (const auto& vol : mInternalEmulatedVolumes) { + vol->unmount(); } for (const auto& stub : mStubVolumes) { stub->unmount(); diff --git a/VolumeManager.h b/VolumeManager.h index 9bf7599..aff5aaf 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -84,6 +84,8 @@ class VolumeManager { void listVolumes(android::vold::VolumeBase::Type type, std::list& list) const; + const std::unordered_set& getStartedUsers() const { return mStartedUsers; } + int forgetPartition(const std::string& partGuid, const std::string& fsUuid); int onUserAdded(userid_t userId, int userSerialNumber); @@ -137,6 +139,9 @@ class VolumeManager { int linkPrimary(userid_t userId); + void createEmulatedVolumesForUser(userid_t userId); + void destroyEmulatedVolumesForUser(userid_t userId); + void handleDiskAdded(const std::shared_ptr& disk); void handleDiskChanged(dev_t device); void handleDiskRemoved(dev_t device); @@ -151,13 +156,13 @@ class VolumeManager { std::list> mPendingDisks; std::list> mObbVolumes; std::list> mStubVolumes; + std::list> mInternalEmulatedVolumes; std::unordered_map mAddedUsers; std::unordered_set mStartedUsers; std::string mVirtualDiskPath; std::shared_ptr mVirtualDisk; - std::shared_ptr mInternalEmulated; std::shared_ptr mPrimary; int mNextObbId; diff --git a/binder/android/os/IVoldListener.aidl b/binder/android/os/IVoldListener.aidl index 0dcfc04..b3e4ba5 100644 --- a/binder/android/os/IVoldListener.aidl +++ b/binder/android/os/IVoldListener.aidl @@ -25,7 +25,7 @@ oneway interface IVoldListener { void onDiskDestroyed(@utf8InCpp String diskId); void onVolumeCreated(@utf8InCpp String volId, - int type, @utf8InCpp String diskId, @utf8InCpp String partGuid); + int type, @utf8InCpp String diskId, @utf8InCpp String partGuid, int userId); void onVolumeStateChanged(@utf8InCpp String volId, int state); void onVolumeMetadataChanged(@utf8InCpp String volId, @utf8InCpp String fsType, @utf8InCpp String fsUuid, @utf8InCpp String fsLabel); diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index c84fbb7..e6702c9 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -42,16 +42,17 @@ namespace vold { static const char* kFusePath = "/system/bin/sdcard"; -EmulatedVolume::EmulatedVolume(const std::string& rawPath) +EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) : VolumeBase(Type::kEmulated), mFusePid(0) { - setId("emulated"); + setId(StringPrintf("emulated;%u", userId)); mRawPath = rawPath; mLabel = "emulated"; } -EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid) +EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, + int userId) : VolumeBase(Type::kEmulated), mFusePid(0) { - setId(StringPrintf("emulated:%u,%u", major(device), minor(device))); + setId(StringPrintf("emulated:%u,%u;%u", major(device), minor(device), userId)); mRawPath = rawPath; mLabel = fsUuid; } @@ -90,17 +91,14 @@ status_t EmulatedVolume::doMount() { LOG(INFO) << "Mounting emulated fuse volume"; android::base::unique_fd fd; int user_id = getMountUserId(); - int result = MountUserFuse(user_id, label, &fd); + int result = MountUserFuse(user_id, getInternalPath(), label, &fd); if (result != 0) { PLOG(ERROR) << "Failed to mount emulated fuse volume"; return -result; } setFuseFd(std::move(fd)); - - std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s", - user_id, label.c_str())); - return BindMount(getInternalPath(), pass_through_path); + return 0; } if (!(mFusePid = fork())) { @@ -163,18 +161,17 @@ status_t EmulatedVolume::doUnmount() { if (getMountFlags() & MountFlags::kPrimary) { label = "emulated"; } - std::string path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str())); - status_t result = ForceUnmount(path); - if (result != OK) { - // TODO(135341433): MNT_DETACH is needed for fuse because umount2 can fail with EBUSY. - // Figure out why we get EBUSY and remove this special casing if possible. - if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL || - errno == ENOENT) { - PLOG(INFO) << "ForceUnmount failed on emulated fuse volume"; - } + + std::string fuse_path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str())); + std::string pass_through_path( + StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), label.c_str())); + if (UnmountUserFuse(pass_through_path, fuse_path) != OK) { + PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; + return -errno; } - rmdir(path.c_str()); + rmdir(fuse_path.c_str()); + rmdir(pass_through_path.c_str()); setFuseFd(android::base::unique_fd()); return OK; } diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index fddfe4e..8d4c490 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -37,8 +37,8 @@ namespace vold { */ class EmulatedVolume : public VolumeBase { public: - explicit EmulatedVolume(const std::string& rawPath); - EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid); + explicit EmulatedVolume(const std::string& rawPath, int userId); + EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, int userId); virtual ~EmulatedVolume(); protected: diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index de2a09f..5098e5d 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -155,12 +155,18 @@ status_t PrivateVolume::doMount() { return -EIO; } - // Create a new emulated volume stacked above us, it will automatically - // be destroyed during unmount + auto vol_manager = VolumeManager::Instance(); std::string mediaPath(mPath + "/media"); - auto vol = std::shared_ptr(new EmulatedVolume(mediaPath, mRawDevice, mFsUuid)); - addVolume(vol); - vol->create(); + + // Create a new emulated volume stacked above us for all added users, they will automatically + // be destroyed during unmount + for (userid_t user : vol_manager->getStartedUsers()) { + auto vol = std::shared_ptr( + new EmulatedVolume(mediaPath, mRawDevice, mFsUuid, user)); + vol->setMountUserId(user); + addVolume(vol); + vol->create(); + } return OK; } diff --git a/model/PrivateVolume.h b/model/PrivateVolume.h index cb8e75d..656172f 100644 --- a/model/PrivateVolume.h +++ b/model/PrivateVolume.h @@ -42,6 +42,8 @@ class PrivateVolume : public VolumeBase { const std::string& getFsType() const { return mFsType; }; const std::string& getRawDevPath() const { return mRawDevPath; }; const std::string& getRawDmDevPath() const { return mDmDevPath; }; + const std::string& getFsUuid() const { return mFsUuid; }; + dev_t getRawDevice() const { return mRawDevice; }; protected: status_t doCreate() override; diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 7b8a21f..403e85c 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -170,22 +170,18 @@ status_t PublicVolume::doMount() { dev_t before = GetDevice(mFuseFull); bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); - if (isFuse) { LOG(INFO) << "Mounting public fuse volume"; android::base::unique_fd fd; int user_id = getMountUserId(); - int result = MountUserFuse(user_id, stableName, &fd); + int result = MountUserFuse(user_id, getInternalPath(), stableName, &fd); if (result != 0) { LOG(ERROR) << "Failed to mount public fuse volume"; return -result; } setFuseFd(std::move(fd)); - - std::string pass_through_path(StringPrintf("/mnt/pass_through/%d/%s", - user_id, stableName.c_str())); - return BindMount(getInternalPath(), pass_through_path); + return OK; } if (!(mFusePid = fork())) { @@ -258,19 +254,24 @@ status_t PublicVolume::doUnmount() { stableName = mFsUuid; } - std::string path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str())); - status_t result = ForceUnmount(path); - if (result != OK) { - // TODO(135341433): MNT_DETACH is needed for fuse because umount2 can fail with EBUSY. - // Figure out why we get EBUSY and remove this special casing if possible. - if (!umount2(path.c_str(), UMOUNT_NOFOLLOW | MNT_DETACH) || errno == EINVAL || - errno == ENOENT) { - PLOG(INFO) << "ForceUnmount failed on public fuse volume"; - } + std::string fuse_path( + StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str())); + std::string pass_through_path( + StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), stableName.c_str())); + if (UnmountUserFuse(pass_through_path, fuse_path) != OK) { + PLOG(INFO) << "UnmountUserFuse failed on public fuse volume"; + return -errno; } + ForceUnmount(kAsecPath); + ForceUnmount(mRawPath); + + rmdir(fuse_path.c_str()); + rmdir(pass_through_path.c_str()); + rmdir(mRawPath.c_str()); + mRawPath.clear(); - rmdir(path.c_str()); setFuseFd(android::base::unique_fd()); + return OK; } diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index 08da8f6..ae45f7e 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -186,7 +186,8 @@ status_t VolumeBase::create() { auto listener = getListener(); if (listener) { - listener->onVolumeCreated(getId(), static_cast(mType), mDiskId, mPartGuid); + listener->onVolumeCreated(getId(), static_cast(mType), mDiskId, mPartGuid, + mMountUserId); } setState(State::kUnmounted); diff --git a/model/VolumeBase.h b/model/VolumeBase.h index 5deecdb..82b0ae0 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -88,6 +88,7 @@ class VolumeBase { const std::string& getPath() const { return mPath; } const std::string& getInternalPath() const { return mInternalPath; } const android::base::unique_fd& getFuseFd() const { return mFuseFd; } + const std::list>& getVolumes() const { return mVolumes; } status_t setDiskId(const std::string& diskId); status_t setPartGuid(const std::string& partGuid); From 2d45d9b42063d57f8be769555fc9c47eabe74f9a Mon Sep 17 00:00:00 2001 From: Zim Date: Thu, 14 Nov 2019 16:19:05 +0000 Subject: [PATCH 013/112] Fix emulated volumes not created for secondary users Ifabaa12368e5a591fbcdce4ee71c83ff35fdac6b introduced individual emulated volumes for each Android user. The change however didn't create the volumes for the secondary users on user start in vold without the persist.sys.fuse flag Now we always create the volumes but only mount sdcardfs volumes for user 0 because the sdcardfs mount paths do not change with for different users unlike the FUSE mount paths. Bug: 144473552 Test: atest AdoptableHostTest Test: Start a guest user in Settings and launch chrome browser in that user, verify that chrome does not crash Change-Id: I89f3591d0197d86267f0e3934f496273e2f9fd7e --- VolumeManager.cpp | 20 +++++++------------- model/EmulatedVolume.cpp | 9 +++++++++ 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 3e7101c..546f802 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -455,24 +455,19 @@ int VolumeManager::onUserAdded(userid_t userId, int userSerialNumber) { int VolumeManager::onUserRemoved(userid_t userId) { LOG(INFO) << "onUserRemoved: " << userId; - if (GetBoolProperty(android::vold::kPropFuseSnapshot, false) && - mAddedUsers.find(userId) != mAddedUsers.end()) { - destroyEmulatedVolumesForUser(userId); - } - + onUserStopped(userId); mAddedUsers.erase(userId); - mStartedUsers.erase(userId); return 0; } int VolumeManager::onUserStarted(userid_t userId) { LOG(INFO) << "onUserStarted: " << userId; - if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { - if (mStartedUsers.find(userId) == mStartedUsers.end()) { - createEmulatedVolumesForUser(userId); - } - } else { + if (mStartedUsers.find(userId) == mStartedUsers.end()) { + createEmulatedVolumesForUser(userId); + } + + if (!GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { // Note that sometimes the system will spin up processes from Zygote // before actually starting the user, so we're okay if Zygote // already created this directory. @@ -491,8 +486,7 @@ int VolumeManager::onUserStarted(userid_t userId) { int VolumeManager::onUserStopped(userid_t userId) { LOG(VERBOSE) << "onUserStopped: " << userId; - if (GetBoolProperty(android::vold::kPropFuseSnapshot, false) && - mStartedUsers.find(userId) != mStartedUsers.end()) { + if (mStartedUsers.find(userId) != mStartedUsers.end()) { destroyEmulatedVolumesForUser(userId); } diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index e6702c9..e0d0109 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -99,6 +99,11 @@ status_t EmulatedVolume::doMount() { } setFuseFd(std::move(fd)); return 0; + } else if (getMountUserId() != 0) { + // For sdcardfs, only mount for user 0, since user 0 will always be running + // and the paths don't change for different users. Trying to double mount + // will cause sepolicy to scream since sdcardfs prevents 'mounton' + return OK; } if (!(mFusePid = fork())) { @@ -174,6 +179,10 @@ status_t EmulatedVolume::doUnmount() { rmdir(pass_through_path.c_str()); setFuseFd(android::base::unique_fd()); return OK; + } else if (getMountUserId() != 0) { + // For sdcardfs, only unmount for user 0, since user 0 will always be running + // and the paths don't change for different users. + return OK; } ForceUnmount(mFuseDefault); From e5393d437c1111a9ffb614e428e6acadc893f757 Mon Sep 17 00:00:00 2001 From: Zim Date: Fri, 15 Nov 2019 11:44:12 +0000 Subject: [PATCH 014/112] Fix wrong symlink terminology symlink(2) creates a symbolic link 'linkpath' containing a string 'target'. linkpath was misnamed as target in MountUserFuse. This cl s/target/linkpath/ in Utils#MountUserFuse. Test: m Change-Id: I274823da16b87ffc124e2e8c4563b1d16546a6e7 --- Utils.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 48e5ce0..af93824 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1029,15 +1029,15 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, } if (relative_upper_path == "emulated") { - std::string target(StringPrintf("/mnt/user/%d/self", user_id)); - result = PrepareDir(target, 0755, AID_ROOT, AID_ROOT); + std::string linkpath(StringPrintf("/mnt/user/%d/self", user_id)); + result = PrepareDir(linkpath, 0755, AID_ROOT, AID_ROOT); if (result != android::OK) { - PLOG(ERROR) << "Failed to prepare directory " << target; + PLOG(ERROR) << "Failed to prepare directory " << linkpath; return -1; } - target += "/primary"; + linkpath += "/primary"; - Symlink(fuse_path + "/" + std::to_string(user_id), target); + Symlink(fuse_path + "/" + std::to_string(user_id), linkpath); } // Open fuse fd. From 5048b4b2bc89a888595db79f2f480c8dacf72c43 Mon Sep 17 00:00:00 2001 From: Zim Date: Tue, 19 Nov 2019 09:16:03 +0000 Subject: [PATCH 015/112] Add mount callback Mounting a FUSE path needs two steps: 1. Mounting the filesystem 2. Starting the FUSE session in the FUSE daemon The second part requires retriving an fd from (1) and the mount paths and passing it to the FUSE daemon. Previously, we'd return from the Vold mount call and mark the volume as mounted while we scramble to do (2). This means there's a time period where the Volume is marked as MOUNTED but not actually ready and any IO access on the paths will hang forever. This could also be misleading when interpreting bug reports. Now, we block the Vold mount call until the FUSE session is started Test: atest AdoptableHostTest Bug: 144275217 Change-Id: I45238a31df71286f67ef1c65c711d0085d72e97f --- Android.bp | 1 + VoldNativeService.cpp | 16 ++++++---------- VoldNativeService.h | 2 +- binder/android/os/IVold.aidl | 4 +++- binder/android/os/IVoldMountCallback.aidl | 23 +++++++++++++++++++++++ model/EmulatedVolume.cpp | 14 +++++++++++--- model/PublicVolume.cpp | 14 ++++++++++---- model/VolumeBase.cpp | 14 +++++++------- model/VolumeBase.h | 9 ++++----- 9 files changed, 66 insertions(+), 31 deletions(-) create mode 100644 binder/android/os/IVoldMountCallback.aidl diff --git a/Android.bp b/Android.bp index 323bc3c..5d93bfa 100644 --- a/Android.bp +++ b/Android.bp @@ -265,6 +265,7 @@ filegroup { srcs: [ "binder/android/os/IVold.aidl", "binder/android/os/IVoldListener.aidl", + "binder/android/os/IVoldMountCallback.aidl", "binder/android/os/IVoldTaskListener.aidl", ], path: "binder", diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index e20d68e..1f7638f 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -325,9 +325,9 @@ binder::Status VoldNativeService::forgetPartition(const std::string& partGuid, return translate(VolumeManager::Instance()->forgetPartition(partGuid, fsUuid)); } -binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountFlags, - int32_t mountUserId, - android::base::unique_fd* _aidl_return) { +binder::Status VoldNativeService::mount( + const std::string& volId, int32_t mountFlags, int32_t mountUserId, + const android::sp& callback) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -340,18 +340,14 @@ binder::Status VoldNativeService::mount(const std::string& volId, int32_t mountF vol->setMountFlags(mountFlags); vol->setMountUserId(mountUserId); + vol->setMountCallback(callback); int res = vol->mount(); + vol->setMountCallback(nullptr); + if (res != OK) { return translate(res); } - _aidl_return->reset(dup(vol->getFuseFd().get())); - if (_aidl_return->get() == -1) { - // Let's not return invalid fd since binder will not allow null fds. Instead give it a - // default value. - _aidl_return->reset(open("/dev/null", O_RDONLY | O_CLOEXEC)); - } - if ((mountFlags & MOUNT_FLAG_PRIMARY) != 0) { res = VolumeManager::Instance()->setPrimary(vol); if (res != OK) { diff --git a/VoldNativeService.h b/VoldNativeService.h index 744ff84..cc4dd1b 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -53,7 +53,7 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status forgetPartition(const std::string& partGuid, const std::string& fsUuid); binder::Status mount(const std::string& volId, int32_t mountFlags, int32_t mountUserId, - android::base::unique_fd* _aidl_return); + const android::sp& callback); binder::Status unmount(const std::string& volId); binder::Status format(const std::string& volId, const std::string& fsType); binder::Status benchmark(const std::string& volId, diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 91c0172..8412f9a 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -17,6 +17,7 @@ package android.os; import android.os.IVoldListener; +import android.os.IVoldMountCallback; import android.os.IVoldTaskListener; /** {@hide} */ @@ -40,7 +41,8 @@ interface IVold { void partition(@utf8InCpp String diskId, int partitionType, int ratio); void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid); - FileDescriptor mount(@utf8InCpp String volId, int mountFlags, int mountUserId); + void mount(@utf8InCpp String volId, int mountFlags, int mountUserId, + IVoldMountCallback callback); void unmount(@utf8InCpp String volId); void format(@utf8InCpp String volId, @utf8InCpp String fsType); void benchmark(@utf8InCpp String volId, IVoldTaskListener listener); diff --git a/binder/android/os/IVoldMountCallback.aidl b/binder/android/os/IVoldMountCallback.aidl new file mode 100644 index 0000000..6bf46d7 --- /dev/null +++ b/binder/android/os/IVoldMountCallback.aidl @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +/** {@hide} */ +interface IVoldMountCallback { + boolean onVolumeChecking(FileDescriptor fuseFd, @utf8InCpp String path, + @utf8InCpp String internalPath); +} diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index e0d0109..8224e61 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -97,8 +97,17 @@ status_t EmulatedVolume::doMount() { PLOG(ERROR) << "Failed to mount emulated fuse volume"; return -result; } - setFuseFd(std::move(fd)); - return 0; + + auto callback = getMountCallback(); + if (callback) { + bool is_ready = false; + callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready); + if (!is_ready) { + return -EIO; + } + } + + return OK; } else if (getMountUserId() != 0) { // For sdcardfs, only mount for user 0, since user 0 will always be running // and the paths don't change for different users. Trying to double mount @@ -177,7 +186,6 @@ status_t EmulatedVolume::doUnmount() { rmdir(fuse_path.c_str()); rmdir(pass_through_path.c_str()); - setFuseFd(android::base::unique_fd()); return OK; } else if (getMountUserId() != 0) { // For sdcardfs, only unmount for user 0, since user 0 will always be running diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 403e85c..d1b63a3 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -180,7 +180,16 @@ status_t PublicVolume::doMount() { LOG(ERROR) << "Failed to mount public fuse volume"; return -result; } - setFuseFd(std::move(fd)); + + auto callback = getMountCallback(); + if (callback) { + bool is_ready = false; + callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready); + if (!is_ready) { + return -EIO; + } + } + return OK; } @@ -269,9 +278,6 @@ status_t PublicVolume::doUnmount() { rmdir(pass_through_path.c_str()); rmdir(mRawPath.c_str()); mRawPath.clear(); - - setFuseFd(android::base::unique_fd()); - return OK; } diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index ae45f7e..636c065 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -143,16 +143,16 @@ status_t VolumeBase::setInternalPath(const std::string& internalPath) { return OK; } -status_t VolumeBase::setFuseFd(android::base::unique_fd fuseFd) { - if ((mState != State::kChecking) && (mState != State::kEjecting)) { - LOG(WARNING) << getId() << " fuse fd change requires state checking or ejecting"; - return -EBUSY; - } - - mFuseFd = std::move(fuseFd); +status_t VolumeBase::setMountCallback( + const android::sp& callback) { + mMountCallback = callback; return OK; } +sp VolumeBase::getMountCallback() const { + return mMountCallback; +} + android::sp VolumeBase::getListener() const { if (mSilent) { return nullptr; diff --git a/model/VolumeBase.h b/model/VolumeBase.h index 82b0ae0..1d88d1b 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -19,6 +19,7 @@ #include "Utils.h" #include "android/os/IVoldListener.h" +#include "android/os/IVoldMountCallback.h" #include #include @@ -87,13 +88,13 @@ class VolumeBase { State getState() const { return mState; } const std::string& getPath() const { return mPath; } const std::string& getInternalPath() const { return mInternalPath; } - const android::base::unique_fd& getFuseFd() const { return mFuseFd; } const std::list>& getVolumes() const { return mVolumes; } status_t setDiskId(const std::string& diskId); status_t setPartGuid(const std::string& partGuid); status_t setMountFlags(int mountFlags); status_t setMountUserId(userid_t mountUserId); + status_t setMountCallback(const android::sp& callback); status_t setSilent(bool silent); void addVolume(const std::shared_ptr& volume); @@ -123,10 +124,9 @@ class VolumeBase { status_t setId(const std::string& id); status_t setPath(const std::string& path); status_t setInternalPath(const std::string& internalPath); - // Takes ownership of the fd passed in. - status_t setFuseFd(android::base::unique_fd fuseFd); android::sp getListener() const; + android::sp getMountCallback() const; private: /* ID that uniquely references volume while alive */ @@ -151,8 +151,7 @@ class VolumeBase { std::string mInternalPath; /* Flag indicating that volume should emit no events */ bool mSilent; - /* The filedescriptor for the fuse device, if the volume uses fuse, or -1 otherwise */ - android::base::unique_fd mFuseFd; + android::sp mMountCallback; /* Volumes stacked on top of this volume */ std::list> mVolumes; From 54bf4c03d13f53e45b46819cd0e1123d1d9e6afc Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 18 Nov 2019 14:26:54 +0100 Subject: [PATCH 016/112] Don't automatically start user 0. It's the responsibility of the StorageManagerService to send down started users after a reset(); and with the latest multi-user FUSE changes, the manual start is no longer necessary. Bug: 135341433 Test: atest AdoptableHostTest Change-Id: I3c9c1d7c25ad10787212d7902fa3f1878ee5f896 --- VolumeManager.cpp | 8 -------- 1 file changed, 8 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 546f802..3b7e6e1 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -697,12 +697,6 @@ int VolumeManager::reset() { vol->destroy(); } mInternalEmulatedVolumes.clear(); - // Add user 0 cos it's always running and started - auto vol = std::shared_ptr( - new android::vold::EmulatedVolume("/data/media", 0)); - vol->setMountUserId(0); - vol->create(); - mInternalEmulatedVolumes.push_back(vol); for (const auto& disk : mDisks) { disk->destroy(); @@ -711,8 +705,6 @@ int VolumeManager::reset() { updateVirtualDisk(); mAddedUsers.clear(); mStartedUsers.clear(); - - mStartedUsers.insert(0); return 0; } From 02efdf55d2cd8224d98b3df4180184542c7672d7 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Wed, 27 Nov 2019 10:53:51 +0000 Subject: [PATCH 017/112] 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 --- Android.bp | 1 + VolumeManager.cpp | 103 +++++++++++++++++++++++++++++----------------- 2 files changed, 67 insertions(+), 37 deletions(-) diff --git a/Android.bp b/Android.bp index 5d93bfa..1c800fe 100644 --- a/Android.bp +++ b/Android.bp @@ -28,6 +28,7 @@ cc_defaults { name: "vold_default_libs", static_libs: [ + "libasync_safe", "libavb", "libbootloader_message", "libdm", diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 3b7e6e1..f1cd232 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -516,6 +517,51 @@ int VolumeManager::setPrimary(const std::shared_ptr& 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) { if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { // TODO(135341433): Implement fuse specific logic. @@ -557,6 +603,8 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { int nsFd; struct stat sb; pid_t child; + std::string userSource; + std::string storageSource; static bool apexUpdatable = android::sysprop::ApexProperties::updatable().value_or(false); @@ -632,47 +680,28 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { goto next; } + if (mode == "default") { + storageSource = "/mnt/runtime/default"; + } else if (mode == "read") { + storageSource = "/mnt/runtime/read"; + } else if (mode == "write") { + storageSource = "/mnt/runtime/write"; + } else if (mode == "full") { + storageSource = "/mnt/runtime/full"; + } else { + // Sane default of no storage visible. No need to fork a child + // to remount uid. + goto next; + } + + // Mount user-specific symlink helper into place + userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid)); 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") { - storageSource = "/mnt/runtime/default"; - } else if (mode == "read") { - storageSource = "/mnt/runtime/read"; - } else if (mode == "write") { - storageSource = "/mnt/runtime/write"; - } else if (mode == "full") { - storageSource = "/mnt/runtime/full"; - } else { - // Sane default of no storage visible + if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, de)) { _exit(0); - } - 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; + } else { _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 - 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); } if (child == -1) { From 9d1425c09bed6cfa7da8f295991c646e99d2cad8 Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 27 Nov 2019 18:15:14 +0000 Subject: [PATCH 018/112] Allow null IVoldMountCallback in Vold#mount Test: m Bug: 145231499 Change-Id: I51cb4424d821078a3604d5b3a42e99d3aaf658c3 --- binder/android/os/IVold.aidl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 8412f9a..f4528d9 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -42,7 +42,7 @@ interface IVold { void forgetPartition(@utf8InCpp String partGuid, @utf8InCpp String fsUuid); void mount(@utf8InCpp String volId, int mountFlags, int mountUserId, - IVoldMountCallback callback); + @nullable IVoldMountCallback callback); void unmount(@utf8InCpp String volId); void format(@utf8InCpp String volId, @utf8InCpp String fsType); void benchmark(@utf8InCpp String volId, IVoldTaskListener listener); From 10b122b4e9dfabf873f8301b97f193141bdac859 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 4 Dec 2019 15:48:42 +0100 Subject: [PATCH 019/112] Don't LOG() after fork() and before exec(). LOG() can hang, because another vold thread may have been holding a libc lock at the time we forked. Simply moving the log line to before the fork(). Bug: 135341433 Test: atest AdoptableHostTest Change-Id: I6063eb33f35c835a226bc1e56de97ace426747ff --- model/EmulatedVolume.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 8224e61..eb6b8a3 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -115,8 +115,8 @@ status_t EmulatedVolume::doMount() { return OK; } + LOG(INFO) << "Executing sdcardfs"; if (!(mFusePid = fork())) { - LOG(INFO) << "Executing sdcardfs"; // clang-format off if (execl(kFusePath, kFusePath, "-u", "1023", // AID_MEDIA_RW From adcc8452314e4245305bbaef7b8bd1789768aed7 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 9 Dec 2019 14:18:01 +0100 Subject: [PATCH 020/112] Get rid of confusing FUSE variables and comments. Long before scoped storage, FUSE was used to create several views of the filesystem; this was later replaced by sdcardfs, yet the code still references FUSE in variables and log messages. Fix those up to avoid confusion with the "new FUSE". Bug: 135341433 Test: atest AdoptableHostTest Change-Id: I2966c5f95d6f38df36a20cdfdd0b95b3051f3f1e --- model/EmulatedVolume.cpp | 68 ++++++++++++++++++------------------- model/EmulatedVolume.h | 13 +++----- model/PublicVolume.cpp | 72 ++++++++++++++++++++-------------------- model/PublicVolume.h | 13 +++----- 4 files changed, 80 insertions(+), 86 deletions(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index eb6b8a3..705bf79 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -40,10 +40,10 @@ using android::base::StringPrintf; namespace android { namespace vold { -static const char* kFusePath = "/system/bin/sdcard"; +static const char* kSdcardFsPath = "/system/bin/sdcard"; EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) - : VolumeBase(Type::kEmulated), mFusePid(0) { + : VolumeBase(Type::kEmulated) { setId(StringPrintf("emulated;%u", userId)); mRawPath = rawPath; mLabel = "emulated"; @@ -51,7 +51,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, int userId) - : VolumeBase(Type::kEmulated), mFusePid(0) { + : VolumeBase(Type::kEmulated) { setId(StringPrintf("emulated:%u,%u;%u", major(device), minor(device), userId)); mRawPath = rawPath; mLabel = fsUuid; @@ -67,23 +67,23 @@ status_t EmulatedVolume::doMount() { label = "emulated"; } - mFuseDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str()); - mFuseRead = StringPrintf("/mnt/runtime/read/%s", label.c_str()); - mFuseWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str()); - mFuseFull = StringPrintf("/mnt/runtime/full/%s", label.c_str()); + mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str()); + mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", label.c_str()); + mSdcardFsWrite = StringPrintf("/mnt/runtime/write/%s", label.c_str()); + mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", label.c_str()); setInternalPath(mRawPath); setPath(StringPrintf("/storage/%s", label.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) || - fs_prepare_dir(mFuseFull.c_str(), 0700, AID_ROOT, AID_ROOT)) { + if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) { PLOG(ERROR) << getId() << " failed to create mount points"; return -errno; } - dev_t before = GetDevice(mFuseFull); + dev_t before = GetDevice(mSdcardFsFull); bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); @@ -116,9 +116,10 @@ status_t EmulatedVolume::doMount() { } LOG(INFO) << "Executing sdcardfs"; - if (!(mFusePid = fork())) { + int sdcardFsPid; + if (!(sdcardFsPid = fork())) { // clang-format off - if (execl(kFusePath, kFusePath, + if (execl(kSdcardFsPath, kSdcardFsPath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-m", @@ -133,29 +134,28 @@ status_t EmulatedVolume::doMount() { PLOG(ERROR) << "Failed to exec"; } - LOG(ERROR) << "FUSE exiting"; + LOG(ERROR) << "sdcardfs exiting"; _exit(1); } - if (mFusePid == -1) { + if (sdcardFsPid == -1) { PLOG(ERROR) << getId() << " failed to fork"; return -errno; } nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); - while (before == GetDevice(mFuseFull)) { - LOG(DEBUG) << "Waiting for FUSE to spin up..."; + while (before == GetDevice(mSdcardFsFull)) { + LOG(DEBUG) << "Waiting for sdcardfs to spin up..."; usleep(50000); // 50ms nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME); if (nanoseconds_to_milliseconds(now - start) > 5000) { - LOG(WARNING) << "Timed out while waiting for FUSE to spin up"; + LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up"; return -ETIMEDOUT; } } - /* sdcardfs will have exited already. FUSE will still be running */ - TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0)); - mFusePid = 0; + /* sdcardfs will have exited already. The filesystem will still be running */ + TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); return OK; } @@ -193,20 +193,20 @@ status_t EmulatedVolume::doUnmount() { return OK; } - ForceUnmount(mFuseDefault); - ForceUnmount(mFuseRead); - ForceUnmount(mFuseWrite); - ForceUnmount(mFuseFull); + ForceUnmount(mSdcardFsDefault); + ForceUnmount(mSdcardFsRead); + ForceUnmount(mSdcardFsWrite); + ForceUnmount(mSdcardFsFull); - rmdir(mFuseDefault.c_str()); - rmdir(mFuseRead.c_str()); - rmdir(mFuseWrite.c_str()); - rmdir(mFuseFull.c_str()); + rmdir(mSdcardFsDefault.c_str()); + rmdir(mSdcardFsRead.c_str()); + rmdir(mSdcardFsWrite.c_str()); + rmdir(mSdcardFsFull.c_str()); - mFuseDefault.clear(); - mFuseRead.clear(); - mFuseWrite.clear(); - mFuseFull.clear(); + mSdcardFsDefault.clear(); + mSdcardFsRead.clear(); + mSdcardFsWrite.clear(); + mSdcardFsFull.clear(); return OK; } diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index 8d4c490..6692b23 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -27,7 +27,7 @@ namespace vold { /* * Shared storage emulated on top of private storage. * - * Knows how to spawn a FUSE daemon to synthesize permissions. ObbVolume + * Knows how to spawn a sdcardfs daemon to synthesize permissions. ObbVolume * can be stacked above it. * * This volume is always multi-user aware, but is only binds itself to @@ -49,13 +49,10 @@ class EmulatedVolume : public VolumeBase { std::string mRawPath; std::string mLabel; - std::string mFuseDefault; - std::string mFuseRead; - std::string mFuseWrite; - std::string mFuseFull; - - /* PID of FUSE wrapper */ - pid_t mFusePid; + std::string mSdcardFsDefault; + std::string mSdcardFsRead; + std::string mSdcardFsWrite; + std::string mSdcardFsFull; DISALLOW_COPY_AND_ASSIGN(EmulatedVolume); }; diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index d1b63a3..007fd60 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -43,11 +43,11 @@ using android::base::StringPrintf; namespace android { namespace vold { -static const char* kFusePath = "/system/bin/sdcard"; +static const char* kSdcardFsPath = "/system/bin/sdcard"; static const char* kAsecPath = "/mnt/secure/asec"; -PublicVolume::PublicVolume(dev_t device) : VolumeBase(Type::kPublic), mDevice(device), mFusePid(0) { +PublicVolume::PublicVolume(dev_t device) : VolumeBase(Type::kPublic), mDevice(device) { setId(StringPrintf("public:%u,%u", major(device), minor(device))); mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str()); } @@ -120,10 +120,10 @@ status_t PublicVolume::doMount() { mRawPath = StringPrintf("/mnt/media_rw/%s", stableName.c_str()); - 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()); - mFuseFull = StringPrintf("/mnt/runtime/full/%s", stableName.c_str()); + mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", stableName.c_str()); + mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", stableName.c_str()); + mSdcardFsWrite = StringPrintf("/mnt/runtime/write/%s", stableName.c_str()); + mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", stableName.c_str()); setInternalPath(mRawPath); if (getMountFlags() & MountFlags::kVisible) { @@ -155,19 +155,19 @@ status_t PublicVolume::doMount() { } if (!(getMountFlags() & MountFlags::kVisible)) { - // Not visible to apps, so no need to spin up FUSE + // Not visible to apps, so no need to spin up sdcardfs or FUSE return OK; } - 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) || - fs_prepare_dir(mFuseFull.c_str(), 0700, AID_ROOT, AID_ROOT)) { - PLOG(ERROR) << getId() << " failed to create FUSE mount points"; + if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) { + PLOG(ERROR) << getId() << " failed to create sdcardfs mount points"; return -errno; } - dev_t before = GetDevice(mFuseFull); + dev_t before = GetDevice(mSdcardFsFull); bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); if (isFuse) { @@ -193,10 +193,11 @@ status_t PublicVolume::doMount() { return OK; } - if (!(mFusePid = fork())) { + int sdcardFsPid; + if (!(sdcardFsPid = fork())) { if (getMountFlags() & MountFlags::kPrimary) { // clang-format off - if (execl(kFusePath, kFusePath, + if (execl(kSdcardFsPath, kSdcardFsPath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-U", std::to_string(getMountUserId()).c_str(), @@ -209,7 +210,7 @@ status_t PublicVolume::doMount() { } } else { // clang-format off - if (execl(kFusePath, kFusePath, + if (execl(kSdcardFsPath, kSdcardFsPath, "-u", "1023", // AID_MEDIA_RW "-g", "1023", // AID_MEDIA_RW "-U", std::to_string(getMountUserId()).c_str(), @@ -221,29 +222,28 @@ status_t PublicVolume::doMount() { } } - LOG(ERROR) << "FUSE exiting"; + LOG(ERROR) << "sdcardfs exiting"; _exit(1); } - if (mFusePid == -1) { + if (sdcardFsPid == -1) { PLOG(ERROR) << getId() << " failed to fork"; return -errno; } nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); - while (before == GetDevice(mFuseFull)) { - LOG(DEBUG) << "Waiting for FUSE to spin up..."; + while (before == GetDevice(mSdcardFsFull)) { + LOG(DEBUG) << "Waiting for sdcardfs to spin up..."; usleep(50000); // 50ms nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME); if (nanoseconds_to_milliseconds(now - start) > 5000) { - LOG(WARNING) << "Timed out while waiting for FUSE to spin up"; + LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up"; return -ETIMEDOUT; } } - /* sdcardfs will have exited already. FUSE will still be running */ - TEMP_FAILURE_RETRY(waitpid(mFusePid, nullptr, 0)); - mFusePid = 0; + /* sdcardfs will have exited already. The filesystem will still be running */ + TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); return OK; } @@ -283,22 +283,22 @@ status_t PublicVolume::doUnmount() { ForceUnmount(kAsecPath); - ForceUnmount(mFuseDefault); - ForceUnmount(mFuseRead); - ForceUnmount(mFuseWrite); - ForceUnmount(mFuseFull); + ForceUnmount(mSdcardFsDefault); + ForceUnmount(mSdcardFsRead); + ForceUnmount(mSdcardFsWrite); + ForceUnmount(mSdcardFsFull); ForceUnmount(mRawPath); - rmdir(mFuseDefault.c_str()); - rmdir(mFuseRead.c_str()); - rmdir(mFuseWrite.c_str()); - rmdir(mFuseFull.c_str()); + rmdir(mSdcardFsDefault.c_str()); + rmdir(mSdcardFsRead.c_str()); + rmdir(mSdcardFsWrite.c_str()); + rmdir(mSdcardFsFull.c_str()); rmdir(mRawPath.c_str()); - mFuseDefault.clear(); - mFuseRead.clear(); - mFuseWrite.clear(); - mFuseFull.clear(); + mSdcardFsDefault.clear(); + mSdcardFsRead.clear(); + mSdcardFsWrite.clear(); + mSdcardFsFull.clear(); mRawPath.clear(); return OK; diff --git a/model/PublicVolume.h b/model/PublicVolume.h index 2feccca..a9bc1ab 100644 --- a/model/PublicVolume.h +++ b/model/PublicVolume.h @@ -27,7 +27,7 @@ namespace vold { /* * Shared storage provided by public (vfat) partition. * - * Knows how to mount itself and then spawn a FUSE daemon to synthesize + * Knows how to mount itself and then spawn a sdcardfs daemon to synthesize * permissions. AsecVolume and ObbVolume can be stacked above it. * * This volume is not inherently multi-user aware, so it has two possible @@ -60,13 +60,10 @@ class PublicVolume : public VolumeBase { /* Mount point of raw partition */ std::string mRawPath; - std::string mFuseDefault; - std::string mFuseRead; - std::string mFuseWrite; - std::string mFuseFull; - - /* PID of FUSE wrapper */ - pid_t mFusePid; + std::string mSdcardFsDefault; + std::string mSdcardFsRead; + std::string mSdcardFsWrite; + std::string mSdcardFsFull; /* Filesystem type */ std::string mFsType; From 6f5802e16022f2921162d54c1a6fafb8bcfc1c82 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 28 Nov 2019 11:53:53 +0100 Subject: [PATCH 021/112] Use sdcardfs for pass-through mounts. The pass-through mount is used by MediaProvider to access external storage. Previously, it was the raw filesystem (eg ext4/f2fs); the problem with that is that the permissions on that filesystem don't allow MediaProvider to access all the files it needs to - in particular directories under Android/ To solve this problem, we can have the pass-through mount sit on top of sdcardfs instead of the raw filesystem. This means we need to mount sdcardfs even in case we're using FUSE, but we already needed to do this anyway for other performance reasons. Bug: 135341433 Test: atest AdoptableHostTest Change-Id: I893d5e5076c5096d2d55212f643c9a857242e964 --- Utils.cpp | 31 ++++++---- Utils.h | 3 +- model/EmulatedVolume.cpp | 128 +++++++++++++++++++-------------------- model/EmulatedVolume.h | 4 ++ model/PublicVolume.cpp | 74 +++++++++++----------- model/PublicVolume.h | 3 + 6 files changed, 128 insertions(+), 115 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index af93824..841aab6 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -995,16 +995,11 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, std::string pass_through_path( StringPrintf("%s/%s", pre_pass_through_path.c_str(), relative_upper_path.c_str())); - // Force remove the existing mount before we attempt to prepare the - // directory. If we have a dangling mount, then PrepareDir may fail if the - // indirection to FUSE doesn't work. - android::status_t result = UnmountUserFuse(pass_through_path, fuse_path); - if (result != android::OK) { - return -1; - } + std::string sdcardfs_path( + StringPrintf("/mnt/runtime/full/%s", relative_upper_path.c_str())); // Create directories. - result = PrepareDir(pre_fuse_path, 0700, AID_ROOT, AID_ROOT); + auto result = PrepareDir(pre_fuse_path, 0700, AID_ROOT, AID_ROOT); if (result != android::OK) { PLOG(ERROR) << "Failed to prepare directory " << pre_fuse_path; return -1; @@ -1063,14 +1058,26 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, PLOG(ERROR) << "Failed to mount " << fuse_path; return -errno; } - LOG(INFO) << "Bind mounting to " << absolute_lower_path; - return BindMount(absolute_lower_path, pass_through_path); + + LOG(INFO) << "Bind mounting " << sdcardfs_path << " to " << pass_through_path; + return BindMount(sdcardfs_path, pass_through_path); } -status_t UnmountUserFuse(const std::string& pass_through_path, const std::string& fuse_path) { +status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_path, + const std::string& relative_upper_path) { + std::string fuse_path(StringPrintf("/mnt/user/%d/%s", user_id, relative_upper_path.c_str())); + std::string pass_through_path( + StringPrintf("/mnt/pass_through/%d/%s", user_id, relative_upper_path.c_str())); + // Best effort unmount pass_through path sSleepOnUnmount = false; - ForceUnmount(pass_through_path); + LOG(INFO) << "Unmounting pass_through_path " << pass_through_path; + auto status = ForceUnmount(pass_through_path); + if (status != android::OK) { + LOG(ERROR) << "Failed to unmount " << pass_through_path; + } + + LOG(INFO) << "Unmounting fuse path " << fuse_path; android::status_t result = ForceUnmount(fuse_path); sSleepOnUnmount = true; if (result != android::OK) { diff --git a/Utils.h b/Utils.h index 375e175..5bb2855 100644 --- a/Utils.h +++ b/Utils.h @@ -154,7 +154,8 @@ bool writeStringToFile(const std::string& payload, const std::string& filename); status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, const std::string& relative_upper_path, android::base::unique_fd* fuse_fd); -status_t UnmountUserFuse(const std::string& pass_through_path, const std::string& fuse_path); +status_t UnmountUserFuse(userid_t userId, const std::string& absolute_lower_path, + const std::string& relative_upper_path); } // namespace vold } // namespace android diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 705bf79..99abdd5 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -59,13 +59,19 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s EmulatedVolume::~EmulatedVolume() {} -status_t EmulatedVolume::doMount() { +std::string EmulatedVolume::getLabel() { // We could have migrated storage to an adopted private volume, so always // call primary storage "emulated" to avoid media rescans. - std::string label = mLabel; if (getMountFlags() & MountFlags::kPrimary) { - label = "emulated"; + return "emulated"; + } else { + return mLabel; } +} + +status_t EmulatedVolume::doMount() { + std::string label = getLabel(); + bool isVisible = getMountFlags() & MountFlags::kVisible; mSdcardFsDefault = StringPrintf("/mnt/runtime/default/%s", label.c_str()); mSdcardFsRead = StringPrintf("/mnt/runtime/read/%s", label.c_str()); @@ -87,7 +93,53 @@ status_t EmulatedVolume::doMount() { bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); - if (isFuse) { + // Mount sdcardfs regardless of FUSE, since we need it to bind-mount on top of the + // FUSE volume for various reasons. + if (getMountUserId() == 0) { + LOG(INFO) << "Executing sdcardfs"; + int sdcardFsPid; + if (!(sdcardFsPid = fork())) { + // clang-format off + if (execl(kSdcardFsPath, kSdcardFsPath, + "-u", "1023", // AID_MEDIA_RW + "-g", "1023", // AID_MEDIA_RW + "-m", + "-w", + "-G", + "-i", + "-o", + mRawPath.c_str(), + label.c_str(), + NULL)) { + // clang-format on + PLOG(ERROR) << "Failed to exec"; + } + + LOG(ERROR) << "sdcardfs exiting"; + _exit(1); + } + + if (sdcardFsPid == -1) { + PLOG(ERROR) << getId() << " failed to fork"; + return -errno; + } + + nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); + while (before == GetDevice(mSdcardFsFull)) { + LOG(DEBUG) << "Waiting for sdcardfs to spin up..."; + usleep(50000); // 50ms + + nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME); + if (nanoseconds_to_milliseconds(now - start) > 5000) { + LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up"; + return -ETIMEDOUT; + } + } + /* sdcardfs will have exited already. The filesystem will still be running */ + TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); + sdcardFsPid = 0; + } + if (isFuse && isVisible) { LOG(INFO) << "Mounting emulated fuse volume"; android::base::unique_fd fd; int user_id = getMountUserId(); @@ -98,6 +150,7 @@ status_t EmulatedVolume::doMount() { return -result; } + mFuseMounted = true; auto callback = getMountCallback(); if (callback) { bool is_ready = false; @@ -106,57 +159,8 @@ status_t EmulatedVolume::doMount() { return -EIO; } } - - return OK; - } else if (getMountUserId() != 0) { - // For sdcardfs, only mount for user 0, since user 0 will always be running - // and the paths don't change for different users. Trying to double mount - // will cause sepolicy to scream since sdcardfs prevents 'mounton' - return OK; } - LOG(INFO) << "Executing sdcardfs"; - int sdcardFsPid; - if (!(sdcardFsPid = fork())) { - // clang-format off - if (execl(kSdcardFsPath, kSdcardFsPath, - "-u", "1023", // AID_MEDIA_RW - "-g", "1023", // AID_MEDIA_RW - "-m", - "-w", - "-G", - "-i", - "-o", - mRawPath.c_str(), - label.c_str(), - NULL)) { - // clang-format on - PLOG(ERROR) << "Failed to exec"; - } - - LOG(ERROR) << "sdcardfs exiting"; - _exit(1); - } - - if (sdcardFsPid == -1) { - PLOG(ERROR) << getId() << " failed to fork"; - return -errno; - } - - nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); - while (before == GetDevice(mSdcardFsFull)) { - LOG(DEBUG) << "Waiting for sdcardfs to spin up..."; - usleep(50000); // 50ms - - nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME); - if (nanoseconds_to_milliseconds(now - start) > 5000) { - LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up"; - return -ETIMEDOUT; - } - } - /* sdcardfs will have exited already. The filesystem will still be running */ - TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); - return OK; } @@ -167,27 +171,23 @@ status_t EmulatedVolume::doUnmount() { // error code and might cause broken behaviour in applications. KillProcessesUsingPath(getPath()); - bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); - if (isFuse) { - // We could have migrated storage to an adopted private volume, so always - // call primary storage "emulated" to avoid media rescans. - std::string label = mLabel; - if (getMountFlags() & MountFlags::kPrimary) { - label = "emulated"; - } + if (mFuseMounted) { + std::string label = getLabel(); std::string fuse_path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str())); std::string pass_through_path( StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), label.c_str())); - if (UnmountUserFuse(pass_through_path, fuse_path) != OK) { + if (UnmountUserFuse(getMountUserId(), getInternalPath(), label) != OK) { PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; return -errno; } rmdir(fuse_path.c_str()); rmdir(pass_through_path.c_str()); - return OK; - } else if (getMountUserId() != 0) { + + mFuseMounted = false; + } + if (getMountUserId() != 0) { // For sdcardfs, only unmount for user 0, since user 0 will always be running // and the paths don't change for different users. return OK; diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index 6692b23..131761c 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -46,6 +46,7 @@ class EmulatedVolume : public VolumeBase { status_t doUnmount() override; private: + std::string getLabel(); std::string mRawPath; std::string mLabel; @@ -54,6 +55,9 @@ class EmulatedVolume : public VolumeBase { std::string mSdcardFsWrite; std::string mSdcardFsFull; + /* Whether we mounted FUSE for this volume */ + bool mFuseMounted; + DISALLOW_COPY_AND_ASSIGN(EmulatedVolume); }; diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 007fd60..e1606a3 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -95,6 +95,7 @@ status_t PublicVolume::doDestroy() { } status_t PublicVolume::doMount() { + bool isVisible = getMountFlags() & MountFlags::kVisible; readMetadata(); if (mFsType == "vfat" && vfat::IsSupported()) { @@ -126,7 +127,7 @@ status_t PublicVolume::doMount() { mSdcardFsFull = StringPrintf("/mnt/runtime/full/%s", stableName.c_str()); setInternalPath(mRawPath); - if (getMountFlags() & MountFlags::kVisible) { + if (isVisible) { setPath(StringPrintf("/storage/%s", stableName.c_str())); } else { setPath(mRawPath); @@ -154,7 +155,7 @@ status_t PublicVolume::doMount() { initAsecStage(); } - if (!(getMountFlags() & MountFlags::kVisible)) { + if (!isVisible) { // Not visible to apps, so no need to spin up sdcardfs or FUSE return OK; } @@ -169,30 +170,6 @@ status_t PublicVolume::doMount() { dev_t before = GetDevice(mSdcardFsFull); - bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); - if (isFuse) { - LOG(INFO) << "Mounting public fuse volume"; - android::base::unique_fd fd; - int user_id = getMountUserId(); - int result = MountUserFuse(user_id, getInternalPath(), stableName, &fd); - - if (result != 0) { - LOG(ERROR) << "Failed to mount public fuse volume"; - return -result; - } - - auto callback = getMountCallback(); - if (callback) { - bool is_ready = false; - callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready); - if (!is_ready) { - return -EIO; - } - } - - return OK; - } - int sdcardFsPid; if (!(sdcardFsPid = fork())) { if (getMountFlags() & MountFlags::kPrimary) { @@ -245,6 +222,31 @@ status_t PublicVolume::doMount() { /* sdcardfs will have exited already. The filesystem will still be running */ TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); + bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); + if (isFuse) { + // We need to mount FUSE *after* sdcardfs, since the FUSE daemon may depend + // on sdcardfs being up. + LOG(INFO) << "Mounting public fuse volume"; + android::base::unique_fd fd; + int user_id = getMountUserId(); + int result = MountUserFuse(user_id, getInternalPath(), stableName, &fd); + + if (result != 0) { + LOG(ERROR) << "Failed to mount public fuse volume"; + return -result; + } + + mFuseMounted = true; + auto callback = getMountCallback(); + if (callback) { + bool is_ready = false; + callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready); + if (!is_ready) { + return -EIO; + } + } + } + return OK; } @@ -255,30 +257,26 @@ status_t PublicVolume::doUnmount() { // error code and might cause broken behaviour in applications. KillProcessesUsingPath(getPath()); - bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); - if (isFuse) { + if (mFuseMounted) { // Use UUID as stable name, if available std::string stableName = getId(); if (!mFsUuid.empty()) { stableName = mFsUuid; } + if (UnmountUserFuse(getMountUserId(), getInternalPath(), stableName) != OK) { + PLOG(INFO) << "UnmountUserFuse failed on public fuse volume"; + return -errno; + } + std::string fuse_path( StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str())); std::string pass_through_path( StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), stableName.c_str())); - if (UnmountUserFuse(pass_through_path, fuse_path) != OK) { - PLOG(INFO) << "UnmountUserFuse failed on public fuse volume"; - return -errno; - } - ForceUnmount(kAsecPath); - ForceUnmount(mRawPath); - rmdir(fuse_path.c_str()); rmdir(pass_through_path.c_str()); - rmdir(mRawPath.c_str()); - mRawPath.clear(); - return OK; + + mFuseMounted = false; } ForceUnmount(kAsecPath); diff --git a/model/PublicVolume.h b/model/PublicVolume.h index a9bc1ab..dd76373 100644 --- a/model/PublicVolume.h +++ b/model/PublicVolume.h @@ -65,6 +65,9 @@ class PublicVolume : public VolumeBase { std::string mSdcardFsWrite; std::string mSdcardFsFull; + /* Whether we mounted FUSE for this volume */ + bool mFuseMounted; + /* Filesystem type */ std::string mFsType; /* Filesystem UUID */ From 5700261e5a5e308fbbec9347e7009fa3917c2571 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 28 Nov 2019 11:56:13 +0100 Subject: [PATCH 022/112] Bind mount Android/ directory in FUSE. For apps seeing the FUSE filesystem, we want to bind-mount the Android/ directory to the lower filesystem. The main reason for this is game performance - Android/ contains both OBBs and app-private external data, and both are heavily accessed during game startup. This is a pretty straightforward bind-mount on top of /mnt/user. Bug: 137890172 Test: Running the following: df /storge/emulated/0 ==> /dev/fuse (FUSE) df /storage/emulated/0/Android ==> /data/media (sdcardfs) Test: atest AdoptableHostTest Change-Id: Ic17a5751b5a94846ee565ff935644a078044ab06 --- Utils.cpp | 5 +++- model/EmulatedVolume.cpp | 55 +++++++++++++++++++++++++++++++++++----- model/PublicVolume.cpp | 7 ----- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 841aab6..d483418 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1076,6 +1076,7 @@ status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_pat if (status != android::OK) { LOG(ERROR) << "Failed to unmount " << pass_through_path; } + rmdir(pass_through_path.c_str()); LOG(INFO) << "Unmounting fuse path " << fuse_path; android::status_t result = ForceUnmount(fuse_path); @@ -1089,8 +1090,10 @@ status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_pat PLOG(ERROR) << "Failed to unmount with MNT_DETACH " << fuse_path; return -errno; } - return android::OK; + result = android::OK; } + rmdir(fuse_path.c_str()); + return result; } diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 99abdd5..9abab89 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -69,6 +69,46 @@ std::string EmulatedVolume::getLabel() { } } +static status_t mountFuseBindMounts(int userId, const std::string& label) { + // TODO(b/134706060) we don't actually want to mount the "write" view by + // default, since it gives write access to all OBB dirs. + std::string androidSource( + StringPrintf("/mnt/runtime/write/%s/%d/Android", label.c_str(), userId)); + std::string androidTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); + + if (access(androidSource.c_str(), F_OK) != 0) { + // Android path may not exist yet if users has just been created; create it on + // the lower fs. + if (fs_prepare_dir(androidSource.c_str(), 0771, AID_ROOT, AID_ROOT) != 0) { + PLOG(ERROR) << "Failed to create " << androidSource; + return -errno; + } + } + LOG(INFO) << "Bind mounting " << androidSource << " on " << androidTarget; + auto status = BindMount(androidSource, androidTarget); + if (status != OK) { + return status; + } + LOG(INFO) << "Bind mounted " << androidSource << " on " << androidTarget; + + return OK; +} + +static status_t unmountFuseBindMounts(int userId, const std::string& label) { + std::string androidTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); + + LOG(INFO) << "Unmounting " << androidTarget; + auto status = UnmountTree(androidTarget); + if (status != OK) { + return status; + } + LOG(INFO) << "Unmounted " << androidTarget; + + return OK; +} + status_t EmulatedVolume::doMount() { std::string label = getLabel(); bool isVisible = getMountFlags() & MountFlags::kVisible; @@ -159,6 +199,9 @@ status_t EmulatedVolume::doMount() { return -EIO; } } + + // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path. + return mountFuseBindMounts(user_id, label); } return OK; @@ -171,20 +214,18 @@ status_t EmulatedVolume::doUnmount() { // error code and might cause broken behaviour in applications. KillProcessesUsingPath(getPath()); + int userId = getMountUserId(); if (mFuseMounted) { std::string label = getLabel(); + // Ignoring unmount return status because we do want to try to unmount + // the rest cleanly. - std::string fuse_path(StringPrintf("/mnt/user/%d/%s", getMountUserId(), label.c_str())); - std::string pass_through_path( - StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), label.c_str())); - if (UnmountUserFuse(getMountUserId(), getInternalPath(), label) != OK) { + unmountFuseBindMounts(userId, label); + if (UnmountUserFuse(userId, getInternalPath(), label) != OK) { PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; return -errno; } - rmdir(fuse_path.c_str()); - rmdir(pass_through_path.c_str()); - mFuseMounted = false; } if (getMountUserId() != 0) { diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index e1606a3..3b5e6f0 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -269,13 +269,6 @@ status_t PublicVolume::doUnmount() { return -errno; } - std::string fuse_path( - StringPrintf("/mnt/user/%d/%s", getMountUserId(), stableName.c_str())); - std::string pass_through_path( - StringPrintf("/mnt/pass_through/%d/%s", getMountUserId(), stableName.c_str())); - rmdir(fuse_path.c_str()); - rmdir(pass_through_path.c_str()); - mFuseMounted = false; } From 8f1e7f289ff2d65e719ad640abc9421ed67e1bf7 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 29 Nov 2019 15:38:55 +0100 Subject: [PATCH 023/112] When unmounting, only kill user-specific paths. The path for emulated volumes is set to /storage/emulated, not /storage/emulated/ . When unmounting, we only want to kill process with a reference to /; this prevents killing processed needlessly. Bug: 137890172 Test: atest AdoptableHostTest Change-Id: I70e36e87077e87db9b3c7e07dc0e481ba06c2c14 --- model/EmulatedVolume.cpp | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 9abab89..7fbfcec 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -208,13 +208,22 @@ status_t EmulatedVolume::doMount() { } status_t EmulatedVolume::doUnmount() { - // Unmount the storage before we kill the FUSE process. If we kill - // the FUSE process first, most file system operations will return + int userId = getMountUserId(); + + // Kill all processes using the filesystem before we unmount it. If we + // unmount the filesystem first, most file system operations will return // ENOTCONN until the unmount completes. This is an exotic and unusual // error code and might cause broken behaviour in applications. - KillProcessesUsingPath(getPath()); + if (mFuseMounted) { + // For FUSE specifically, we have an emulated volume per user, so only kill + // processes using files from this particular user. + std::string user_path(StringPrintf("%s/%d", getPath().c_str(), getMountUserId())); + LOG(INFO) << "Killing all processes referencing " << user_path; + KillProcessesUsingPath(user_path); + } else { + KillProcessesUsingPath(getPath()); + } - int userId = getMountUserId(); if (mFuseMounted) { std::string label = getLabel(); // Ignoring unmount return status because we do want to try to unmount From 745e0a9acbe2c4f5f2de02ed49317dfaafa890a7 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 3 Dec 2019 16:11:39 +0100 Subject: [PATCH 024/112] Use a regular set for started users. We want started users to be an ordered set; eg user 0 should always go first. This is because volumes for users other than 0 depend on user 0 coming up first, because the volume for user 0 is the one mounting sdcardfs. Bug: 13789012 Test: atest AdoptableHostTest Change-Id: Ic9119f0a24bd261e5362019836ac240b90c681c0 --- VolumeManager.h | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/VolumeManager.h b/VolumeManager.h index aff5aaf..fad3c00 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -84,7 +85,7 @@ class VolumeManager { void listVolumes(android::vold::VolumeBase::Type type, std::list& list) const; - const std::unordered_set& getStartedUsers() const { return mStartedUsers; } + const std::set& getStartedUsers() const { return mStartedUsers; } int forgetPartition(const std::string& partGuid, const std::string& fsUuid); @@ -159,7 +160,9 @@ class VolumeManager { std::list> mInternalEmulatedVolumes; std::unordered_map mAddedUsers; - std::unordered_set mStartedUsers; + // This needs to be a regular set because we care about the ordering here; + // user 0 should always go first, because it is responsible for sdcardfs. + std::set mStartedUsers; std::string mVirtualDiskPath; std::shared_ptr mVirtualDisk; From fd7362d2a8a063ae4f0251e908a48b84f63542b9 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 11 Dec 2019 14:57:59 +0100 Subject: [PATCH 025/112] Correctly initialize mFuseMounted. Wasn't done before. Bug: 137890172 Test: builds Change-Id: I413505fae23031a2da71086cbfd85e0b1aec459c --- model/EmulatedVolume.cpp | 1 + model/PublicVolume.cpp | 1 + 2 files changed, 2 insertions(+) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 7fbfcec..b42bd49 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -47,6 +47,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) setId(StringPrintf("emulated;%u", userId)); mRawPath = rawPath; mLabel = "emulated"; + mFuseMounted = false; } EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 3b5e6f0..b9164f5 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -50,6 +50,7 @@ static const char* kAsecPath = "/mnt/secure/asec"; PublicVolume::PublicVolume(dev_t device) : VolumeBase(Type::kPublic), mDevice(device) { setId(StringPrintf("public:%u,%u", major(device), minor(device))); mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str()); + mFuseMounted = false; } PublicVolume::~PublicVolume() {} From 5298ccc2a70c5d21e502302107ea9f41e9ef8b32 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Thu, 12 Dec 2019 05:41:46 -0800 Subject: [PATCH 026/112] Initialize mFuseMounted We missed one of the constructors before. Bug: 137890172 Test: TreeHugger Change-Id: If2f8a15d5abdff6e3a457a76e9d54b2c58d80422 --- model/EmulatedVolume.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index b42bd49..f4d18e4 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -56,6 +56,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s setId(StringPrintf("emulated:%u,%u;%u", major(device), minor(device), userId)); mRawPath = rawPath; mLabel = fsUuid; + mFuseMounted = false; } EmulatedVolume::~EmulatedVolume() {} From 01fa0e0d8dc0a3606faf902a4753e32a74c3889d Mon Sep 17 00:00:00 2001 From: Abhijeet Kaur Date: Fri, 13 Dec 2019 10:26:32 +0000 Subject: [PATCH 027/112] Replace "sys.fuse_snapshot" with "persist.sys.fuse" With the newly added flag for Settings developer options, which is now used to change the state of FUSE, PROP_FUSE now acts as the snapshot feature flag for the current boot. Bug: 145391093 Test: atest AdoptableHostTest Change-Id: I22363b088e88c764294cbd61c6d94160c907fae3 --- Utils.h | 2 +- VolumeManager.cpp | 6 +++--- model/EmulatedVolume.cpp | 2 +- model/PublicVolume.cpp | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Utils.h b/Utils.h index 5bb2855..4c0114a 100644 --- a/Utils.h +++ b/Utils.h @@ -34,7 +34,7 @@ struct DIR; namespace android { namespace vold { -static const char* kPropFuseSnapshot = "sys.fuse_snapshot"; +static const char* kPropFuse = "persist.sys.fuse"; /* SELinux contexts used depending on the block device type */ extern security_context_t sBlkidContext; diff --git a/VolumeManager.cpp b/VolumeManager.cpp index f1cd232..8b9c29c 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -374,7 +374,7 @@ int VolumeManager::forgetPartition(const std::string& partGuid, const std::strin } int VolumeManager::linkPrimary(userid_t userId) { - if (!GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { + if (!GetBoolProperty(android::vold::kPropFuse, false)) { std::string source(mPrimary->getPath()); if (mPrimary->isEmulated()) { source = StringPrintf("%s/%d", source.c_str(), userId); @@ -468,7 +468,7 @@ int VolumeManager::onUserStarted(userid_t userId) { createEmulatedVolumesForUser(userId); } - if (!GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { + if (!GetBoolProperty(android::vold::kPropFuse, false)) { // Note that sometimes the system will spin up processes from Zygote // before actually starting the user, so we're okay if Zygote // already created this directory. @@ -563,7 +563,7 @@ static bool childProcess(const char* storageSource, const char* userSource, int } int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { - if (GetBoolProperty(android::vold::kPropFuseSnapshot, false)) { + if (GetBoolProperty(android::vold::kPropFuse, false)) { // TODO(135341433): Implement fuse specific logic. return 0; } diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index b42bd49..d1940f0 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -132,7 +132,7 @@ status_t EmulatedVolume::doMount() { dev_t before = GetDevice(mSdcardFsFull); - bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); + bool isFuse = base::GetBoolProperty(kPropFuse, false); // Mount sdcardfs regardless of FUSE, since we need it to bind-mount on top of the // FUSE volume for various reasons. diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index b9164f5..78f150d 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -223,7 +223,7 @@ status_t PublicVolume::doMount() { /* sdcardfs will have exited already. The filesystem will still be running */ TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); - bool isFuse = base::GetBoolProperty(kPropFuseSnapshot, false); + bool isFuse = base::GetBoolProperty(kPropFuse, false); if (isFuse) { // We need to mount FUSE *after* sdcardfs, since the FUSE daemon may depend // on sdcardfs being up. From adecd0ae753ae1f5dd7e4e807d5f831bf6376eb0 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 13 Dec 2019 16:05:03 +0100 Subject: [PATCH 028/112] Use the default sdcardfs view for the Android/ bind-mount. Now that StorageManager asks vold to create package directories again, apps only need write access in their own app-private directory. Both app-private and OBB dirs will be created by privileged daemons as needed. This means we can use the "default" sdcardfs view for the Android/ bind-mount again. This has the added benefit that it fixes shell, which wasn't in the "everybody" group, and therefore suddenly couldn't enter /sdcard/Android anymore. Bug: 146189163 Test: atest AdoptableHostTest Change-Id: I37ca3b19ea4d11ed866efa808f51be945a4dc080 --- model/EmulatedVolume.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 130e747..aef7b77 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -75,7 +75,7 @@ static status_t mountFuseBindMounts(int userId, const std::string& label) { // TODO(b/134706060) we don't actually want to mount the "write" view by // default, since it gives write access to all OBB dirs. std::string androidSource( - StringPrintf("/mnt/runtime/write/%s/%d/Android", label.c_str(), userId)); + StringPrintf("/mnt/runtime/default/%s/%d/Android", label.c_str(), userId)); std::string androidTarget( StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); From 1986bfda8d84246637a286e079a0e322d438acc2 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 17 Dec 2019 09:41:42 +0100 Subject: [PATCH 029/112] Vold mkdirs should use lower filesystem. If vold's view of /storage is FUSE, it means that creation of directories in Android/ will go through FUSE as well. The implementation of fs_mkdirs() tries to opendir() individual parts of the entire path; so for a path "/storage/emulated/0/Android", it will try to opendir() "/storage", "/storage/emulated", etc. By default, "/storage/emulated" is created with 711 permissions; while vold itself is root, access to /storage/emulated is routed through MediaProvider (because of FUSE), and MediaProvider doesn't run as root, nor does it have the capabilities to bypass the ACL. This means that fs_mkdirs() as it is will fail, because opendir("/storage/emulated") will fail from MediaProvider. To prevent this, route these accesses directly to the lower filesystem (currently, sdcardfs), by renaming the paths. Bug: 146189163 Test: atest AdoptableHostTest Change-Id: Idbb41b9ffad9713f3b255c51bd4de16f4d090223 --- VolumeManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 8b9c29c..143f53c 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -809,8 +809,9 @@ int VolumeManager::unmountAll() { int VolumeManager::mkdirs(const std::string& path) { // Only offer to create directories for paths managed by vold if (StartsWith(path, "/storage/")) { + std::string lower_path = "/mnt/runtime/default/" + path.substr(9); // fs_mkdirs() does symlink checking and relative path enforcement - return fs_mkdirs(path.c_str(), 0700); + return fs_mkdirs(lower_path.c_str(), 0700); } else { LOG(ERROR) << "Failed to find mounted volume for " << path; return -EINVAL; From 13ff668775d1cc8fcbccc59b9bfe4df5324de1b1 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 24 Dec 2019 12:57:16 +0100 Subject: [PATCH 030/112] Replace mkdirs() with setupAppDir(). vold historically offerred functionality to create directories on behalf of others. This functionality was purely used to create app-specific data/obb/media dirs. Make this more explicit by renaming the method to indicate this. Additionally, in the past, we never needed to care about the UID set on these directories, because sdcardfs would take care of that for us automatically. But with sdcardfs going away, we need to make sure the UID of the app-specific directories is set correctly. Allow the caller to pass this in as an argument. Bug: 146419093 Test: atest FuseDaemonHostTest Change-Id: Ibeb5fdc91b40d53583bc0960ee11c4d640549c34 --- Utils.cpp | 22 ++++++++++++++++++++++ Utils.h | 6 ++++++ VoldNativeService.cpp | 6 ++++-- VoldNativeService.h | 3 ++- VolumeManager.cpp | 18 ++++++++++++------ VolumeManager.h | 29 +++++++++++++++++++++++------ binder/android/os/IVold.aidl | 2 +- 7 files changed, 70 insertions(+), 16 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index d483418..67c48ad 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -55,6 +55,7 @@ using namespace std::chrono_literals; using android::base::ReadFileToString; +using android::base::StartsWith; using android::base::StringPrintf; namespace android { @@ -114,6 +115,27 @@ status_t DestroyDeviceNode(const std::string& path) { } } +int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) { + int ret = 0; + if (!StartsWith(path, root)) { + return -1; + } + std::string to_create_from_root = path.substr(root.length()); + + size_t pos = 0; + while ((pos = to_create_from_root.find('/')) != std::string::npos) { + auto component = to_create_from_root.substr(0, pos); + to_create_from_root.erase(0, pos + 1); + root = root + component + "/"; + ret = fs_prepare_dir(root.c_str(), mode, uid, gid); + if (ret) { + break; + } + } + + return ret; +} + status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { std::lock_guard lock(kSecurityLock); const char* cpath = path.c_str(); diff --git a/Utils.h b/Utils.h index 4c0114a..056a635 100644 --- a/Utils.h +++ b/Utils.h @@ -48,6 +48,12 @@ extern bool sSleepOnUnmount; status_t CreateDeviceNode(const std::string& path, dev_t dev); status_t DestroyDeviceNode(const std::string& path); +/* + * Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'. + * 'path' must start with 'root' + */ +int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid); + /* fs_prepare_dir wrapper that creates with SELinux context */ status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index b82ea06..78d7ed3 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -456,12 +456,14 @@ binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { return translate(VolumeManager::Instance()->remountUid(uid, remountMode)); } -binder::Status VoldNativeService::mkdirs(const std::string& path) { +binder::Status VoldNativeService::setupAppDir(const std::string& path, + const std::string& appDirRoot, int32_t appUid) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(path); + CHECK_ARGUMENT_PATH(appDirRoot); ACQUIRE_LOCK; - return translate(VolumeManager::Instance()->mkdirs(path)); + return translate(VolumeManager::Instance()->setupAppDir(path, appDirRoot, appUid)); } binder::Status VoldNativeService::createObb(const std::string& sourcePath, diff --git a/VoldNativeService.h b/VoldNativeService.h index ebd9041..5753b0b 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -65,7 +65,8 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status remountUid(int32_t uid, int32_t remountMode); - binder::Status mkdirs(const std::string& path); + binder::Status setupAppDir(const std::string& path, const std::string& appDirRoot, + int32_t appUid); binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 143f53c..bc843b4 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -81,6 +81,7 @@ using android::vold::BindMount; using android::vold::CreateDir; using android::vold::DeleteDirContents; using android::vold::DeleteDirContentsAndDir; +using android::vold::PrepareDirsFromRoot; using android::vold::PrivateVolume; using android::vold::Symlink; using android::vold::Unlink; @@ -806,16 +807,21 @@ int VolumeManager::unmountAll() { return 0; } -int VolumeManager::mkdirs(const std::string& path) { +int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot, + int32_t appUid) { // Only offer to create directories for paths managed by vold - if (StartsWith(path, "/storage/")) { - std::string lower_path = "/mnt/runtime/default/" + path.substr(9); - // fs_mkdirs() does symlink checking and relative path enforcement - return fs_mkdirs(lower_path.c_str(), 0700); - } else { + if (!StartsWith(path, "/storage/")) { LOG(ERROR) << "Failed to find mounted volume for " << path; return -EINVAL; } + + // First create the root which holds app dirs, if needed. + int ret = PrepareDirsFromRoot(appDirRoot, "/storage/", 0771, AID_MEDIA_RW, AID_MEDIA_RW); + if (ret != 0) { + return ret; + } + // Then, create app-specific dirs with the correct UID/GID + return PrepareDirsFromRoot(path, appDirRoot, 0770, appUid, AID_MEDIA_RW); } int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, diff --git a/VolumeManager.h b/VolumeManager.h index fad3c00..db32ecd 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -113,13 +113,30 @@ class VolumeManager { static VolumeManager* Instance(); /* - * Ensure that all directories along given path exist, creating parent - * directories as needed. Validates that given path is absolute and that - * it contains no relative "." or ".." paths or symlinks. Last path segment - * is treated as filename and ignored, unless the path ends with "/". Also - * ensures that path belongs to a volume managed by vold. + * Creates a directory 'path' for an application, automatically creating + * directories along the given path if they don't exist yet. 'appDirRoot' + * is the "root" directory for app-specific directories of this kind; + * 'path' must always start with 'appDirRoot'. + * + * Example: + * path = /storage/emulated/0/Android/data/com.foo/files/ + * appDirRoot = /storage/emulated/0/Android/data/ + * + * This function will set the UID of all app-specific directories below + * 'appDirRoot' to the 'appUid' argument. In the given example, the UID + * of /storage/emulated/0/Android/data/com.foo and + * /storage/emulated/0/Android/data/com.foo/files would be set to 'appUid'. + * + * The UID of the parent directories will be set according to the + * requirements of the underlying filesystem and are of no concern to the + * caller. + * + * Validates that given paths are absolute and that they contain no relative + * "." or ".." paths or symlinks. Last path segment is treated as filename + * and ignored, unless the path ends with "/". Also ensures that path + * belongs to a volume managed by vold. */ - int mkdirs(const std::string& path); + int setupAppDir(const std::string& path, const std::string& appDirRoot, int32_t appUid); int createObb(const std::string& path, const std::string& key, int32_t ownerGid, std::string* outVolId); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 975d94c..cec38c5 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -54,7 +54,7 @@ interface IVold { void remountUid(int uid, int remountMode); - void mkdirs(@utf8InCpp String path); + void setupAppDir(@utf8InCpp String path, @utf8InCpp String appDirRoot, int appUid); @utf8InCpp String createObb(@utf8InCpp String sourcePath, @utf8InCpp String sourceKey, int ownerGid); From cf5916f3fa9e5eabc143dfb3669198e9ba3c3634 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 3 Jan 2020 14:36:45 +0100 Subject: [PATCH 031/112] Also delay creating found disks until user 0 is started. Public and private volumes can be discovered before user 0 is up and running; when using FUSE however, we can't mount these disks yet, because we depend on the user to become unlocked before we can start the FUSE daemon (which is the MediaProvider application process). So besides waiting for any secure keyguard to be dismissed, also wait for user 0 to be started. Bug: 146419093 Test: Boot cuttlefish with a fake public volume; is available after repeated boots. Change-Id: I06fe4d336d1baec3a49886c3cf12d844a1d0eb26 --- VolumeManager.cpp | 24 +++++++++++++++++++----- VolumeManager.h | 1 + 2 files changed, 20 insertions(+), 5 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index bc843b4..4d850fb 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -264,10 +264,17 @@ void VolumeManager::handleBlockEvent(NetlinkEvent* evt) { void VolumeManager::handleDiskAdded(const std::shared_ptr& disk) { // For security reasons, if secure keyguard is showing, wait // until the user unlocks the device to actually touch it + // Additionally, wait until user 0 is actually started, since we need + // the user to be up before we can mount a FUSE daemon to handle the disk. + bool userZeroStarted = mStartedUsers.find(0) != mStartedUsers.end(); if (mSecureKeyguardShowing) { LOG(INFO) << "Found disk at " << disk->getEventPath() << " but delaying scan due to secure keyguard"; mPendingDisks.push_back(disk); + } else if (!userZeroStarted) { + LOG(INFO) << "Found disk at " << disk->getEventPath() + << " but delaying scan due to user zero not having started"; + mPendingDisks.push_back(disk); } else { disk->create(); mDisks.push_back(disk); @@ -482,6 +489,8 @@ int VolumeManager::onUserStarted(userid_t userId) { } mStartedUsers.insert(userId); + + createPendingDisksIfNeeded(); return 0; } @@ -496,17 +505,22 @@ int VolumeManager::onUserStopped(userid_t userId) { return 0; } -int VolumeManager::onSecureKeyguardStateChanged(bool isShowing) { - mSecureKeyguardShowing = isShowing; - if (!mSecureKeyguardShowing) { - // Now that secure keyguard has been dismissed, process - // any pending disks +void VolumeManager::createPendingDisksIfNeeded() { + bool userZeroStarted = mStartedUsers.find(0) != mStartedUsers.end(); + if (!mSecureKeyguardShowing && userZeroStarted) { + // Now that secure keyguard has been dismissed and user 0 has + // started, process any pending disks for (const auto& disk : mPendingDisks) { disk->create(); mDisks.push_back(disk); } mPendingDisks.clear(); } +} + +int VolumeManager::onSecureKeyguardStateChanged(bool isShowing) { + mSecureKeyguardShowing = isShowing; + createPendingDisksIfNeeded(); return 0; } diff --git a/VolumeManager.h b/VolumeManager.h index db32ecd..cacab85 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -94,6 +94,7 @@ class VolumeManager { int onUserStarted(userid_t userId); int onUserStopped(userid_t userId); + void createPendingDisksIfNeeded(); int onSecureKeyguardStateChanged(bool isShowing); int setPrimary(const std::shared_ptr& vol); From 06b0cafb29d1b6b968534c19aeb0815b0beb7c48 Mon Sep 17 00:00:00 2001 From: Zim Date: Sun, 5 Jan 2020 02:11:47 +0000 Subject: [PATCH 032/112] Fix /mnt/user/ permission bits Previously, when mounting a FUSE volume, the permission bits for /mnt/user/ were very strict, 700 which was good, however this value was ignored because it was overriden in zygote to 755. In fact if it wasn't ignored, apps wouldn't have had access to /sdcard becase they would lack the directory 'execute' bit for /mnt/user/ needed while looking up /mnt/user//emulated Now we set it to a strict enough value, 710 that only allows apps running under the same user id to lookup /mnt/user/. This ensures that user 10 cannot access /mnt/user/0. A special case is added for /mnt/user/0 for shell since it is not in the 'everybody' group and would otherwise not be able to 'adb shell ls /sdcard' Bug: 135341433 Test: atest -c android.appsecurity.cts.ExternalStorageHostTest#testSecondaryUsersInaccessible Change-Id: Ia427d1b69c7140254ae3459b98e51531d8322f1a --- Utils.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 67c48ad..968f22f 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1021,7 +1021,13 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, StringPrintf("/mnt/runtime/full/%s", relative_upper_path.c_str())); // Create directories. - auto result = PrepareDir(pre_fuse_path, 0700, AID_ROOT, AID_ROOT); + // Shell is neither AID_ROOT nor AID_EVERYBODY. Since it equally needs 'execute' access to + // /mnt/user/0 to 'adb shell ls /sdcard' for instance, we set the uid bit of /mnt/user/0 to + // AID_SHELL. This gives shell access along with apps running as group everybody (user 0 apps) + // These bits should be consistent with what is set in zygote in + // com_android_internal_os_Zygote#MountEmulatedStorage on volume bind mount during app fork + auto result = PrepareDir(pre_fuse_path, 0710, user_id ? AID_ROOT : AID_SHELL, + multiuser_get_uid(user_id, AID_EVERYBODY)); if (result != android::OK) { PLOG(ERROR) << "Failed to prepare directory " << pre_fuse_path; return -1; From c59d774149d4786e71de085fa96e9a42aeb8cfb3 Mon Sep 17 00:00:00 2001 From: Zim Date: Mon, 6 Jan 2020 21:48:16 +0000 Subject: [PATCH 033/112] Convert paths to lower filesystem paths during setupAppDir Making FUSE request from vold is risky because the FUSE daemon may be down and vold could get wedged. Additionally, the FUSE daemon only responds to requests with matching user id paths, i.e requests on /mnt/user/0/emulated/10 will fail. So if vold (running as user 0) makes a request on /storage/emulated/10, it really means /mnt/user/0/emulated/10 which will fail if it gets to the FUSE daemon. TODO: Fix the lower filesystem paths to support devices without sdcardfs Bug: 141540368 Change-Id: I90d698f6aecd114d75b6d578ad08620988da7d7d atest: atest android.appsecurity.cts.ExternalStorageHostTest#testMediaSandboxedFull --- VolumeManager.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index bc843b4..3c5e659 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -815,13 +815,21 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi return -EINVAL; } + // Convert paths to lower filesystem paths to avoid making FUSE requests for these reasons: + // 1. A FUSE request from vold puts vold at risk of hanging if the FUSE daemon is down + // 2. The FUSE daemon prevents requests on /mnt/user/0/emulated/ and a request + // on /storage/emulated/10 means /mnt/user/0/emulated/10 + // TODO(b/146419093): Use lower filesystem paths that don't depend on sdcardfs + const std::string lowerPath = "/mnt/runtime/default/" + path.substr(9); + const std::string lowerAppDirRoot = "/mnt/runtime/default/" + appDirRoot.substr(9); + // First create the root which holds app dirs, if needed. - int ret = PrepareDirsFromRoot(appDirRoot, "/storage/", 0771, AID_MEDIA_RW, AID_MEDIA_RW); + int ret = PrepareDirsFromRoot(lowerAppDirRoot, "/mnt/runtime/default/", 0771, AID_MEDIA_RW, AID_MEDIA_RW); if (ret != 0) { return ret; } // Then, create app-specific dirs with the correct UID/GID - return PrepareDirsFromRoot(path, appDirRoot, 0770, appUid, AID_MEDIA_RW); + return PrepareDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, AID_MEDIA_RW); } int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, From 86f21a2211d23bcf87953e7129bec601a6dce2c9 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 6 Jan 2020 09:48:14 +0100 Subject: [PATCH 034/112] Conditionally use sdcardfs. In preparation of sdcardfs going away on devices launching with R, conditionally use it. Bug: 146419093 Test: cuttlefish with sdcardfs, cuttlefish without sdcardfs but with FUSE Change-Id: I2c1d4b428dcb43c3fd274dde84d5088984161993 --- Utils.cpp | 15 ++-- model/EmulatedVolume.cpp | 32 ++++++--- model/EmulatedVolume.h | 6 ++ model/PublicVolume.cpp | 143 ++++++++++++++++++++------------------- model/PublicVolume.h | 3 + 5 files changed, 114 insertions(+), 85 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 67c48ad..0375765 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1017,9 +1017,6 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, std::string pass_through_path( StringPrintf("%s/%s", pre_pass_through_path.c_str(), relative_upper_path.c_str())); - std::string sdcardfs_path( - StringPrintf("/mnt/runtime/full/%s", relative_upper_path.c_str())); - // Create directories. auto result = PrepareDir(pre_fuse_path, 0700, AID_ROOT, AID_ROOT); if (result != android::OK) { @@ -1081,8 +1078,16 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, return -errno; } - LOG(INFO) << "Bind mounting " << sdcardfs_path << " to " << pass_through_path; - return BindMount(sdcardfs_path, pass_through_path); + if (IsFilesystemSupported("sdcardfs")) { + std::string sdcardfs_path( + StringPrintf("/mnt/runtime/full/%s", relative_upper_path.c_str())); + + LOG(INFO) << "Bind mounting " << sdcardfs_path << " to " << pass_through_path; + return BindMount(sdcardfs_path, pass_through_path); + } else { + LOG(INFO) << "Bind mounting " << absolute_lower_path << " to " << pass_through_path; + return BindMount(absolute_lower_path, pass_through_path); + } } status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_path, diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index aef7b77..d7b22e3 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -48,6 +48,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) mRawPath = rawPath; mLabel = "emulated"; mFuseMounted = false; + mUseSdcardFs = IsFilesystemSupported("sdcardfs"); } EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, @@ -57,6 +58,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s mRawPath = rawPath; mLabel = fsUuid; mFuseMounted = false; + mUseSdcardFs = IsFilesystemSupported("sdcardfs"); } EmulatedVolume::~EmulatedVolume() {} @@ -71,18 +73,23 @@ std::string EmulatedVolume::getLabel() { } } -static status_t mountFuseBindMounts(int userId, const std::string& label) { - // TODO(b/134706060) we don't actually want to mount the "write" view by - // default, since it gives write access to all OBB dirs. - std::string androidSource( - StringPrintf("/mnt/runtime/default/%s/%d/Android", label.c_str(), userId)); +status_t EmulatedVolume::mountFuseBindMounts() { + std::string androidSource; + std::string label = getLabel(); + int userId = getMountUserId(); + + if (mUseSdcardFs) { + androidSource = StringPrintf("/mnt/runtime/default/%s/%d/Android", label.c_str(), userId); + } else { + androidSource = StringPrintf("/%s/%d/Android", mRawPath.c_str(), userId); + } std::string androidTarget( StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); if (access(androidSource.c_str(), F_OK) != 0) { // Android path may not exist yet if users has just been created; create it on // the lower fs. - if (fs_prepare_dir(androidSource.c_str(), 0771, AID_ROOT, AID_ROOT) != 0) { + if (fs_prepare_dir(androidSource.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { PLOG(ERROR) << "Failed to create " << androidSource; return -errno; } @@ -97,7 +104,10 @@ static status_t mountFuseBindMounts(int userId, const std::string& label) { return OK; } -static status_t unmountFuseBindMounts(int userId, const std::string& label) { +status_t EmulatedVolume::unmountFuseBindMounts() { + std::string label = getLabel(); + int userId = getMountUserId(); + std::string androidTarget( StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); @@ -137,7 +147,7 @@ status_t EmulatedVolume::doMount() { // Mount sdcardfs regardless of FUSE, since we need it to bind-mount on top of the // FUSE volume for various reasons. - if (getMountUserId() == 0) { + if (mUseSdcardFs && getMountUserId() == 0) { LOG(INFO) << "Executing sdcardfs"; int sdcardFsPid; if (!(sdcardFsPid = fork())) { @@ -203,7 +213,7 @@ status_t EmulatedVolume::doMount() { } // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path. - return mountFuseBindMounts(user_id, label); + return mountFuseBindMounts(); } return OK; @@ -231,7 +241,7 @@ status_t EmulatedVolume::doUnmount() { // Ignoring unmount return status because we do want to try to unmount // the rest cleanly. - unmountFuseBindMounts(userId, label); + unmountFuseBindMounts(); if (UnmountUserFuse(userId, getInternalPath(), label) != OK) { PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; return -errno; @@ -239,7 +249,7 @@ status_t EmulatedVolume::doUnmount() { mFuseMounted = false; } - if (getMountUserId() != 0) { + if (getMountUserId() != 0 || !mUseSdcardFs) { // For sdcardfs, only unmount for user 0, since user 0 will always be running // and the paths don't change for different users. return OK; diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index 131761c..4f76a60 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -46,6 +46,9 @@ class EmulatedVolume : public VolumeBase { status_t doUnmount() override; private: + status_t mountFuseBindMounts(); + status_t unmountFuseBindMounts(); + std::string getLabel(); std::string mRawPath; std::string mLabel; @@ -58,6 +61,9 @@ class EmulatedVolume : public VolumeBase { /* Whether we mounted FUSE for this volume */ bool mFuseMounted; + /* Whether to use sdcardfs for this volume */ + bool mUseSdcardFs; + DISALLOW_COPY_AND_ASSIGN(EmulatedVolume); }; diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 78f150d..b246c95 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -51,6 +51,7 @@ PublicVolume::PublicVolume(dev_t device) : VolumeBase(Type::kPublic), mDevice(de setId(StringPrintf("public:%u,%u", major(device), minor(device))); mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str()); mFuseMounted = false; + mUseSdcardFs = IsFilesystemSupported("sdcardfs"); } PublicVolume::~PublicVolume() {} @@ -161,67 +162,69 @@ status_t PublicVolume::doMount() { return OK; } - if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || - fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) || - fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) || - fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) { - PLOG(ERROR) << getId() << " failed to create sdcardfs mount points"; - return -errno; - } - - dev_t before = GetDevice(mSdcardFsFull); - - int sdcardFsPid; - if (!(sdcardFsPid = fork())) { - if (getMountFlags() & MountFlags::kPrimary) { - // clang-format off - if (execl(kSdcardFsPath, kSdcardFsPath, - "-u", "1023", // AID_MEDIA_RW - "-g", "1023", // AID_MEDIA_RW - "-U", std::to_string(getMountUserId()).c_str(), - "-w", - mRawPath.c_str(), - stableName.c_str(), - NULL)) { - // clang-format on - PLOG(ERROR) << "Failed to exec"; - } - } else { - // clang-format off - if (execl(kSdcardFsPath, kSdcardFsPath, - "-u", "1023", // AID_MEDIA_RW - "-g", "1023", // AID_MEDIA_RW - "-U", std::to_string(getMountUserId()).c_str(), - mRawPath.c_str(), - stableName.c_str(), - NULL)) { - // clang-format on - PLOG(ERROR) << "Failed to exec"; - } + if (mUseSdcardFs) { + if (fs_prepare_dir(mSdcardFsDefault.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsRead.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsWrite.c_str(), 0700, AID_ROOT, AID_ROOT) || + fs_prepare_dir(mSdcardFsFull.c_str(), 0700, AID_ROOT, AID_ROOT)) { + PLOG(ERROR) << getId() << " failed to create sdcardfs mount points"; + return -errno; } - LOG(ERROR) << "sdcardfs exiting"; - _exit(1); - } + dev_t before = GetDevice(mSdcardFsFull); - if (sdcardFsPid == -1) { - PLOG(ERROR) << getId() << " failed to fork"; - return -errno; - } + int sdcardFsPid; + if (!(sdcardFsPid = fork())) { + if (getMountFlags() & MountFlags::kPrimary) { + // clang-format off + if (execl(kSdcardFsPath, kSdcardFsPath, + "-u", "1023", // AID_MEDIA_RW + "-g", "1023", // AID_MEDIA_RW + "-U", std::to_string(getMountUserId()).c_str(), + "-w", + mRawPath.c_str(), + stableName.c_str(), + NULL)) { + // clang-format on + PLOG(ERROR) << "Failed to exec"; + } + } else { + // clang-format off + if (execl(kSdcardFsPath, kSdcardFsPath, + "-u", "1023", // AID_MEDIA_RW + "-g", "1023", // AID_MEDIA_RW + "-U", std::to_string(getMountUserId()).c_str(), + mRawPath.c_str(), + stableName.c_str(), + NULL)) { + // clang-format on + PLOG(ERROR) << "Failed to exec"; + } + } - nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); - while (before == GetDevice(mSdcardFsFull)) { - LOG(DEBUG) << "Waiting for sdcardfs to spin up..."; - usleep(50000); // 50ms - - nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME); - if (nanoseconds_to_milliseconds(now - start) > 5000) { - LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up"; - return -ETIMEDOUT; + LOG(ERROR) << "sdcardfs exiting"; + _exit(1); } + + if (sdcardFsPid == -1) { + PLOG(ERROR) << getId() << " failed to fork"; + return -errno; + } + + nsecs_t start = systemTime(SYSTEM_TIME_BOOTTIME); + while (before == GetDevice(mSdcardFsFull)) { + LOG(DEBUG) << "Waiting for sdcardfs to spin up..."; + usleep(50000); // 50ms + + nsecs_t now = systemTime(SYSTEM_TIME_BOOTTIME); + if (nanoseconds_to_milliseconds(now - start) > 5000) { + LOG(WARNING) << "Timed out while waiting for sdcardfs to spin up"; + return -ETIMEDOUT; + } + } + /* sdcardfs will have exited already. The filesystem will still be running */ + TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); } - /* sdcardfs will have exited already. The filesystem will still be running */ - TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); bool isFuse = base::GetBoolProperty(kPropFuse, false); if (isFuse) { @@ -275,22 +278,24 @@ status_t PublicVolume::doUnmount() { ForceUnmount(kAsecPath); - ForceUnmount(mSdcardFsDefault); - ForceUnmount(mSdcardFsRead); - ForceUnmount(mSdcardFsWrite); - ForceUnmount(mSdcardFsFull); + if (mUseSdcardFs) { + ForceUnmount(mSdcardFsDefault); + ForceUnmount(mSdcardFsRead); + ForceUnmount(mSdcardFsWrite); + ForceUnmount(mSdcardFsFull); + + rmdir(mSdcardFsDefault.c_str()); + rmdir(mSdcardFsRead.c_str()); + rmdir(mSdcardFsWrite.c_str()); + rmdir(mSdcardFsFull.c_str()); + + mSdcardFsDefault.clear(); + mSdcardFsRead.clear(); + mSdcardFsWrite.clear(); + mSdcardFsFull.clear(); + } ForceUnmount(mRawPath); - - rmdir(mSdcardFsDefault.c_str()); - rmdir(mSdcardFsRead.c_str()); - rmdir(mSdcardFsWrite.c_str()); - rmdir(mSdcardFsFull.c_str()); rmdir(mRawPath.c_str()); - - mSdcardFsDefault.clear(); - mSdcardFsRead.clear(); - mSdcardFsWrite.clear(); - mSdcardFsFull.clear(); mRawPath.clear(); return OK; diff --git a/model/PublicVolume.h b/model/PublicVolume.h index dd76373..3156b53 100644 --- a/model/PublicVolume.h +++ b/model/PublicVolume.h @@ -68,6 +68,9 @@ class PublicVolume : public VolumeBase { /* Whether we mounted FUSE for this volume */ bool mFuseMounted; + /* Whether to use sdcardfs for this volume */ + bool mUseSdcardFs; + /* Filesystem type */ std::string mFsType; /* Filesystem UUID */ From aea1247706bd730a30cf6aee293c0f81d806c86a Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 8 Jan 2020 11:09:47 +0000 Subject: [PATCH 035/112] Add self/primary symlink on /mnt/pass_through We bind mount /mnt/user/ onto /storage for normal apps and /mnt/pass_through/ for special apps like the FUSE daemon or the old android.process.media hosting the DownloadManager. This bind mount allows app have /storage/self/primary which is what /sdcard symlinks to. Before this change, we were not creating the self/primary symlink on /mnt/pass_through/ so trying to access /sdcard from the DownloadManager would fail. Bug: 135341433 Test: atest android.app.cts.DownloadManagerTest#testAddCompletedDownload_invalidPaths Change-Id: I660139be3d850e6e9ea4705f86ef2b5872ddca16 --- Utils.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 46272f6..a798b27 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1056,8 +1056,16 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, return -1; } linkpath += "/primary"; - Symlink(fuse_path + "/" + std::to_string(user_id), linkpath); + + std::string pass_through_linkpath(StringPrintf("/mnt/pass_through/%d/self", user_id)); + result = PrepareDir(pass_through_linkpath, 0755, AID_ROOT, AID_ROOT); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory " << pass_through_linkpath; + return -1; + } + pass_through_linkpath += "/primary"; + Symlink(pass_through_path + "/" + std::to_string(user_id), pass_through_linkpath); } // Open fuse fd. From b52eb852974e49c32233ed1de5d71e83ad09ddb1 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 8 Jan 2020 15:04:21 +0100 Subject: [PATCH 036/112] Add REMOUNT_MODE_ANDROID_WRITABLE. Constant to indicate a regular scoped storage view, with the sole exception that Android/ should be writable. Bug: 134706060 Bug: 146490513 Test: builds Change-Id: Ifbcd4fd912ed4cc18d7c6e3eab2c582bc862e10c --- binder/android/os/IVold.aidl | 1 + 1 file changed, 1 insertion(+) diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index cec38c5..1002c9a 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -167,6 +167,7 @@ interface IVold { const int REMOUNT_MODE_INSTALLER = 5; const int REMOUNT_MODE_FULL = 6; const int REMOUNT_MODE_PASS_THROUGH = 7; + const int REMOUNT_MODE_ANDROID_WRITABLE = 8; const int VOLUME_STATE_UNMOUNTED = 0; const int VOLUME_STATE_CHECKING = 1; From b0e977a0b1f226e8a88a5e61cc415a424fcda21a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Sat, 11 Jan 2020 19:24:26 +0100 Subject: [PATCH 037/112] vold: Don't unmount /mnt/installer on start. This is a slave bind mount of /mnt/user, created before we create the two mount namespaces. Unmounting it here prevents us from re-creating it in the right way, so leave it alone. Bug: 134706060 Test: verify mount is still there after vold starts Change-Id: Iaac91953cbb9abfef0aaac60f74b99b16c943f87 --- VolumeManager.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 98cb060..d8b1e32 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -806,7 +806,8 @@ int VolumeManager::unmountAll() { #ifdef __ANDROID_DEBUGGABLE__ !StartsWith(test, "/mnt/scratch") && #endif - !StartsWith(test, "/mnt/vendor") && !StartsWith(test, "/mnt/product")) || + !StartsWith(test, "/mnt/vendor") && !StartsWith(test, "/mnt/product") && + !StartsWith(test, "/mnt/installer")) || StartsWith(test, "/storage/")) { toUnmount.push_front(test); } From 3a2dbfee88f5061c1450445863a4f3300f8a422a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Sat, 11 Jan 2020 19:38:37 +0100 Subject: [PATCH 038/112] Bind mount write view of Android/obb for installers. Installers will be allowed to write OBB for any application; this is not easy to achieve on sdcardfs, where the GID of Android/obb is the same as the GID of Android/data (app-private data), meaning giving installers write access to Android/obb would also give them write access to Android/data. Instead, we create a /mnt/installer view, which is exactly the same as /mnt/user, with the sole exception that the write sdcardfs view of Android/obb is mounted on top. This is what will allow installers to write there, while still being restricted with respect to app-private data in Android/data. Bug: 134706060 Test: atest AdoptableHostTest Change-Id: If2b93870a877efef182bdc06466552a7527499ad --- model/EmulatedVolume.cpp | 59 ++++++++++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 11 deletions(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index d7b22e3..054a58b 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -73,6 +73,26 @@ std::string EmulatedVolume::getLabel() { } } +// Creates a bind mount from source to target, creating the source (!) directory +// if not yet present. +static status_t doFuseBindMount(const std::string& source, const std::string& target) { + if (access(source.c_str(), F_OK) != 0) { + // Android path may not exist yet if users has just been created; create it on + // the lower fs. + if (fs_prepare_dir(source.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { + PLOG(ERROR) << "Failed to create " << source; + return -errno; + } + } + LOG(INFO) << "Bind mounting " << source << " on " << target; + auto status = BindMount(source, target); + if (status != OK) { + return status; + } + LOG(INFO) << "Bind mounted " << source << " on " << target; + return OK; +} + status_t EmulatedVolume::mountFuseBindMounts() { std::string androidSource; std::string label = getLabel(); @@ -86,21 +106,27 @@ status_t EmulatedVolume::mountFuseBindMounts() { std::string androidTarget( StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); - if (access(androidSource.c_str(), F_OK) != 0) { - // Android path may not exist yet if users has just been created; create it on - // the lower fs. - if (fs_prepare_dir(androidSource.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { - PLOG(ERROR) << "Failed to create " << androidSource; - return -errno; - } - } - LOG(INFO) << "Bind mounting " << androidSource << " on " << androidTarget; - auto status = BindMount(androidSource, androidTarget); + auto status = doFuseBindMount(androidSource, androidTarget); if (status != OK) { return status; } - LOG(INFO) << "Bind mounted " << androidSource << " on " << androidTarget; + // Installers get the same view as all other apps, with the sole exception that the + // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires + // a special bind mount, since app-private and OBB dirs share the same GID, but we + // only want to give access to the latter. + if (!mUseSdcardFs) { + return OK; + } + std::string installerSource( + StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", label.c_str(), userId)); + std::string installerTarget( + StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); + + status = doFuseBindMount(installerSource, installerTarget); + if (status != OK) { + return status; + } return OK; } @@ -108,6 +134,17 @@ status_t EmulatedVolume::unmountFuseBindMounts() { std::string label = getLabel(); int userId = getMountUserId(); + if (mUseSdcardFs) { + std::string installerTarget( + StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); + LOG(INFO) << "Unmounting " << installerTarget; + auto status = UnmountTree(installerTarget); + if (status != OK) { + LOG(ERROR) << "Failed to unmount " << installerTarget; + // Intentional continue to try to unmount the other bind mount + } + } + std::string androidTarget( StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); From df073f50d2bf0cbdcec1cd922ac2f59d82a56df1 Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 15 Jan 2020 15:00:07 +0000 Subject: [PATCH 039/112] Handle failures after partial mounts When we try mounting an EmulatedVolume, we may mount sdcardfs but fail in any of the FUSE mounts, in this case we should unmount whatever mounts we made during the mount. Test: Intentionally causing a partial failure, verified that sdcardfs gets unmounted Bug: 147610762 Change-Id: I29ed044ed8ab8aa3dd83bc97a49eb3140ce4fe27 --- model/EmulatedVolume.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 054a58b..082dea5 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -245,12 +245,19 @@ status_t EmulatedVolume::doMount() { bool is_ready = false; callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready); if (!is_ready) { + fd.reset(); + doUnmount(); return -EIO; } } // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path. - return mountFuseBindMounts(); + status_t res = mountFuseBindMounts(); + if (res != OK) { + fd.reset(); + doUnmount(); + } + return res; } return OK; From 9ad51adeb987ed0d3260267075fcfe6925de654a Mon Sep 17 00:00:00 2001 From: Barani Muthukumaran Date: Thu, 31 Oct 2019 22:59:34 -0700 Subject: [PATCH 040/112] vold: Do not cache CE keys in vold CE keys were cached in vold to support untrusted reset by a device admin, this is now supported by Locksettingservice using synthetic password. This change requires a secret to be provided to retrieve the CE key and re-wrap without the secret when user removes the credential. Test: Set credential, remove credential, swipe to none and vice-versa. Bug: 26948053 Change-Id: I4cb1c035a472477e70c1ff5bf0b2c3fcfad495e5 --- FsCrypt.cpp | 85 ++++++++++++++++++++++++------------ FsCrypt.h | 2 + VoldNativeService.cpp | 9 ++++ VoldNativeService.h | 2 + binder/android/os/IVold.aidl | 2 + 5 files changed, 71 insertions(+), 29 deletions(-) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index c101ba8..603362f 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -23,6 +23,7 @@ #include #include +#include #include #include #include @@ -88,8 +89,6 @@ std::set s_ephemeral_users; // Map user ids to key references std::map s_de_key_raw_refs; std::map s_ce_key_raw_refs; -// TODO abolish this map, per b/26948053 -std::map s_ce_keys; } // namespace @@ -243,7 +242,6 @@ static bool read_and_install_user_ce_key(userid_t user_id, if (!read_and_fixate_user_ce_key(user_id, auth, &ce_key)) return false; std::string ce_raw_ref; if (!install_data_key(ce_key, &ce_raw_ref)) return false; - s_ce_keys[user_id] = std::move(ce_key); s_ce_key_raw_refs[user_id] = ce_raw_ref; LOG(DEBUG) << "Installed ce key for user " << user_id; return true; @@ -296,7 +294,6 @@ static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral s_de_key_raw_refs[user_id] = de_raw_ref; std::string ce_raw_ref; if (!install_data_key(ce_key, &ce_raw_ref)) return false; - s_ce_keys[user_id] = ce_key; s_ce_key_raw_refs[user_id] = ce_raw_ref; LOG(DEBUG) << "Created keys for user " << user_id; return true; @@ -468,7 +465,6 @@ static void drop_caches_if_needed() { } static bool evict_ce_key(userid_t user_id) { - s_ce_keys.erase(user_id); bool success = true; std::string raw_ref; // If we haven't loaded the CE key, no need to evict it. @@ -549,6 +545,18 @@ static bool parse_hex(const std::string& hex, std::string* result) { return true; } +static std::optional authentication_from_hex( + const std::string& token_hex, const std::string& secret_hex) { + std::string token, secret; + if (!parse_hex(token_hex, &token)) return std::optional(); + if (!parse_hex(secret_hex, &secret)) return std::optional(); + if (secret.empty()) { + return kEmptyAuthentication; + } else { + return android::vold::KeyAuthentication(token, secret); + } +} + static std::string volkey_path(const std::string& misc_path, const std::string& volume_uuid) { return misc_path + "/vold/volume_keys/" + volume_uuid + "/default"; } @@ -592,30 +600,51 @@ static bool destroy_volkey(const std::string& misc_path, const std::string& volu return android::vold::destroyKey(path); } +static bool fscrypt_rewrap_user_key(userid_t user_id, int serial, + const android::vold::KeyAuthentication& retrieve_auth, + const android::vold::KeyAuthentication& store_auth) { + if (s_ephemeral_users.count(user_id) != 0) return true; + auto const directory_path = get_ce_key_directory_path(user_id); + KeyBuffer ce_key; + std::string ce_key_current_path = get_ce_key_current_path(directory_path); + if (android::vold::retrieveKey(ce_key_current_path, retrieve_auth, &ce_key)) { + LOG(DEBUG) << "Successfully retrieved key"; + // TODO(147732812): Remove this once Locksettingservice is fixed. + // Currently it calls fscrypt_clear_user_key_auth with a secret when lockscreen is + // changed from swipe to none or vice-versa + } else if (android::vold::retrieveKey(ce_key_current_path, kEmptyAuthentication, &ce_key)) { + LOG(DEBUG) << "Successfully retrieved key with empty auth"; + } else { + LOG(ERROR) << "Failed to retrieve key for user " << user_id; + return false; + } + auto const paths = get_ce_key_paths(directory_path); + std::string ce_key_path; + if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false; + if (!android::vold::storeKeyAtomically(ce_key_path, user_key_temp, store_auth, ce_key)) + return false; + if (!android::vold::FsyncDirectory(directory_path)) return false; + return true; +} + bool fscrypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token_hex, const std::string& secret_hex) { LOG(DEBUG) << "fscrypt_add_user_key_auth " << user_id << " serial=" << serial << " token_present=" << (token_hex != "!"); if (!fscrypt_is_native()) return true; - if (s_ephemeral_users.count(user_id) != 0) return true; - std::string token, secret; - if (!parse_hex(token_hex, &token)) return false; - if (!parse_hex(secret_hex, &secret)) return false; - auto auth = - secret.empty() ? kEmptyAuthentication : android::vold::KeyAuthentication(token, secret); - auto it = s_ce_keys.find(user_id); - if (it == s_ce_keys.end()) { - LOG(ERROR) << "Key not loaded into memory, can't change for user " << user_id; - return false; - } - const auto& ce_key = it->second; - auto const directory_path = get_ce_key_directory_path(user_id); - auto const paths = get_ce_key_paths(directory_path); - std::string ce_key_path; - if (!get_ce_key_new_path(directory_path, paths, &ce_key_path)) return false; - if (!android::vold::storeKeyAtomically(ce_key_path, user_key_temp, auth, ce_key)) return false; - if (!android::vold::FsyncDirectory(directory_path)) return false; - return true; + auto auth = authentication_from_hex(token_hex, secret_hex); + if (!auth) return false; + return fscrypt_rewrap_user_key(user_id, serial, kEmptyAuthentication, *auth); +} + +bool fscrypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& token_hex, + const std::string& secret_hex) { + LOG(DEBUG) << "fscrypt_clear_user_key_auth " << user_id << " serial=" << serial + << " token_present=" << (token_hex != "!"); + if (!fscrypt_is_native()) return true; + auto auth = authentication_from_hex(token_hex, secret_hex); + if (!auth) return false; + return fscrypt_rewrap_user_key(user_id, serial, *auth, kEmptyAuthentication); } bool fscrypt_fixate_newest_user_key_auth(userid_t user_id) { @@ -642,11 +671,9 @@ bool fscrypt_unlock_user_key(userid_t user_id, int serial, const std::string& to LOG(WARNING) << "Tried to unlock already-unlocked key for user " << user_id; return true; } - std::string token, secret; - if (!parse_hex(token_hex, &token)) return false; - if (!parse_hex(secret_hex, &secret)) return false; - android::vold::KeyAuthentication auth(token, secret); - if (!read_and_install_user_ce_key(user_id, auth)) { + auto auth = authentication_from_hex(token_hex, secret_hex); + if (!auth) return false; + if (!read_and_install_user_ce_key(user_id, *auth)) { LOG(ERROR) << "Couldn't read key for " << user_id; return false; } diff --git a/FsCrypt.h b/FsCrypt.h index 03ec2e1..641991a 100644 --- a/FsCrypt.h +++ b/FsCrypt.h @@ -25,6 +25,8 @@ bool fscrypt_vold_create_user_key(userid_t user_id, int serial, bool ephemeral); bool fscrypt_destroy_user_key(userid_t user_id); bool fscrypt_add_user_key_auth(userid_t user_id, int serial, const std::string& token, const std::string& secret); +bool fscrypt_clear_user_key_auth(userid_t user_id, int serial, const std::string& token, + const std::string& secret); bool fscrypt_fixate_newest_user_key_auth(userid_t user_id); bool fscrypt_unlock_user_key(userid_t user_id, int serial, const std::string& token, diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 78d7ed3..f8ed61c 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -768,6 +768,15 @@ binder::Status VoldNativeService::addUserKeyAuth(int32_t userId, int32_t userSer return translateBool(fscrypt_add_user_key_auth(userId, userSerial, token, secret)); } +binder::Status VoldNativeService::clearUserKeyAuth(int32_t userId, int32_t userSerial, + const std::string& token, + const std::string& secret) { + ENFORCE_SYSTEM_OR_ROOT; + ACQUIRE_CRYPT_LOCK; + + return translateBool(fscrypt_clear_user_key_auth(userId, userSerial, token, secret)); +} + binder::Status VoldNativeService::fixateNewestUserKeyAuth(int32_t userId) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; diff --git a/VoldNativeService.h b/VoldNativeService.h index 5753b0b..2967fae 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -114,6 +114,8 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status addUserKeyAuth(int32_t userId, int32_t userSerial, const std::string& token, const std::string& secret); + binder::Status clearUserKeyAuth(int32_t userId, int32_t userSerial, const std::string& token, + const std::string& secret); binder::Status fixateNewestUserKeyAuth(int32_t userId); binder::Status unlockUserKey(int32_t userId, int32_t userSerial, const std::string& token, diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index cec38c5..e7a44bc 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -92,6 +92,8 @@ interface IVold { void addUserKeyAuth(int userId, int userSerial, @utf8InCpp String token, @utf8InCpp String secret); + void clearUserKeyAuth(int userId, int userSerial, @utf8InCpp String token, + @utf8InCpp String secret); void fixateNewestUserKeyAuth(int userId); void unlockUserKey(int userId, int userSerial, @utf8InCpp String token, From 53d16d39dd9ec7095b9fb635de3811764db08a7e Mon Sep 17 00:00:00 2001 From: Zim Date: Fri, 17 Jan 2020 01:21:24 +0000 Subject: [PATCH 041/112] Always symlink self/primary to /storage/emulated This allows readlink(2) of /sdcard paths to work correctly and return /storage/emulated/ instead of /mnt/user//emulated/ Test: readlink /sdcard -> /storage/emulated/0 Bug: 135341433 Change-Id: I2cfa9cede02a93024e41d90f17c926a69ec6e052 --- Utils.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index a798b27..a66e33c 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1056,7 +1056,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, return -1; } linkpath += "/primary"; - Symlink(fuse_path + "/" + std::to_string(user_id), linkpath); + Symlink("/storage/emulated/" + std::to_string(user_id), linkpath); std::string pass_through_linkpath(StringPrintf("/mnt/pass_through/%d/self", user_id)); result = PrepareDir(pass_through_linkpath, 0755, AID_ROOT, AID_ROOT); @@ -1065,7 +1065,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, return -1; } pass_through_linkpath += "/primary"; - Symlink(pass_through_path + "/" + std::to_string(user_id), pass_through_linkpath); + Symlink("/storage/emulated/" + std::to_string(user_id), pass_through_linkpath); } // Open fuse fd. From ae8f06fe1ccaf0b5894751843efc62f88899c4e0 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Thu, 16 Jan 2020 13:21:42 -0700 Subject: [PATCH 042/112] Update vold to use KM4.1 This CL updates vold to use the Keymaster 4.1 interface, but does not yet call any of the new methods. Test: Boot the device Change-Id: I4574a2f6eead3b71d1e89488b496b734694620c7 --- Android.bp | 4 ++++ KeyStorage.cpp | 4 ++-- Keymaster.cpp | 4 ++-- Keymaster.h | 17 ++++++++++++++--- 4 files changed, 22 insertions(+), 7 deletions(-) diff --git a/Android.bp b/Android.bp index e1877b9..b84cc5f 100644 --- a/Android.bp +++ b/Android.bp @@ -44,6 +44,7 @@ cc_defaults { shared_libs: [ "android.hardware.keymaster@3.0", "android.hardware.keymaster@4.0", + "android.hardware.keymaster@4.1", "android.hardware.boot@1.0", "libbase", "libbinder", @@ -58,6 +59,7 @@ cc_defaults { "libincfs", "libhidlbase", "libkeymaster4support", + "libkeymaster4_1support", "libkeyutils", "liblog", "liblogwrap", @@ -232,10 +234,12 @@ cc_binary { "android.hardware.keymaster@3.0", "android.hardware.keymaster@4.0", + "android.hardware.keymaster@4.1", "libhardware", "libhardware_legacy", "libhidlbase", "libkeymaster4support", + "libkeymaster4_1support", "libutils", ], } diff --git a/KeyStorage.cpp b/KeyStorage.cpp index d5ac7d0..dbf190d 100644 --- a/KeyStorage.cpp +++ b/KeyStorage.cpp @@ -43,8 +43,8 @@ #include #include -#include -#include +#include +#include extern "C" { diff --git a/Keymaster.cpp b/Keymaster.cpp index aad4387..a3853f9 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -17,8 +17,8 @@ #include "Keymaster.h" #include -#include -#include +#include +#include namespace android { namespace vold { diff --git a/Keymaster.h b/Keymaster.h index 9a0616d..049a741 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -24,13 +24,24 @@ #include #include -#include -#include +#include +#include namespace android { namespace vold { -namespace km = ::android::hardware::keymaster::V4_0; +namespace km { + +using namespace ::android::hardware::keymaster::V4_1; + +// Surprisingly -- to me, at least -- this is totally fine. You can re-define symbols that were +// brought in via a using directive (the "using namespace") above. In general this seems like a +// dangerous thing to rely on, but in this case its implications are simple and straightforward: +// km::ErrorCode refers to the 4.0 ErrorCode, though we pull everything else from 4.1. +using ErrorCode = ::android::hardware::keymaster::V4_0::ErrorCode; + +} // namespace km + using KmDevice = km::support::Keymaster; // C++ wrappers to the Keymaster hidl interface. From 1242be866cb2974842d56f8247c6d3f087996747 Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 22 Jan 2020 18:22:29 +0000 Subject: [PATCH 043/112] Harden /mnt/{user,installer} permission bits These paths previously had 0755 permission bits (/mnt/installer got its bits from the /mnt/user bind mount). With such permissive bits, an unauthorized app can access a file using the /mnt/installer path for instance even if access via /storage would have been restricted. In init.rc we create /mnt/user with 0755 initially, this is to keep /sdcard working without FUSE. When mounting a FUSE filesystem, we enusure in vold that /mnt/user is changed to 0700 Bug: 135341433 Test: adb shell ls -d /mnt/{user, installer} Change-Id: Id387e34c5fd257858861246ad51486892653fb3a --- Utils.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index a66e33c..202b98d 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1017,13 +1017,20 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, std::string pass_through_path( StringPrintf("%s/%s", pre_pass_through_path.c_str(), relative_upper_path.c_str())); - // Create directories. + // Ensure that /mnt/user is 0700. With FUSE, apps don't need access to /mnt/user paths directly. + // Without FUSE however, apps need /mnt/user access so /mnt/user in init.rc is 0755 until here + auto result = PrepareDir("/mnt/user", 0700, AID_ROOT, AID_ROOT); + if (result != android::OK) { + PLOG(ERROR) << "Failed to prepare directory /mnt/user"; + return -1; + } + // Shell is neither AID_ROOT nor AID_EVERYBODY. Since it equally needs 'execute' access to // /mnt/user/0 to 'adb shell ls /sdcard' for instance, we set the uid bit of /mnt/user/0 to // AID_SHELL. This gives shell access along with apps running as group everybody (user 0 apps) // These bits should be consistent with what is set in zygote in // com_android_internal_os_Zygote#MountEmulatedStorage on volume bind mount during app fork - auto result = PrepareDir(pre_fuse_path, 0710, user_id ? AID_ROOT : AID_SHELL, + result = PrepareDir(pre_fuse_path, 0710, user_id ? AID_ROOT : AID_SHELL, multiuser_get_uid(user_id, AID_EVERYBODY)); if (result != android::OK) { PLOG(ERROR) << "Failed to prepare directory " << pre_fuse_path; From fb42bc41eb2e0ccc38dfe0cf0adf88dccc40c24a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 16 Jan 2020 01:25:27 +0100 Subject: [PATCH 044/112] Add setProjectQuotaId to vold. To allow vold to set project IDs. Bug: 146419093 Test: manual Change-Id: Ibaf1908e0d35b15d9fd71a5b9c113f0f0c054f54 --- Utils.cpp | 19 +++++++++++++++++++ Utils.h | 1 + 2 files changed, 20 insertions(+) diff --git a/Utils.cpp b/Utils.cpp index 202b98d..67e92c9 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -115,6 +115,25 @@ status_t DestroyDeviceNode(const std::string& path) { } } +int SetQuotaProjectId(std::string path, long projectId) { + struct fsxattr fsx; + + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC))); + if (fd == -1) { + PLOG(ERROR) << "Failed to open " << path << " to set project id."; + return -1; + } + + int ret = ioctl(fd, FS_IOC_FSGETXATTR, &fsx); + if (ret == -1) { + PLOG(ERROR) << "Failed to get extended attributes for " << path << " to get project id."; + return ret; + } + + fsx.fsx_projid = projectId; + return ioctl(fd, FS_IOC_FSSETXATTR, &fsx); +} + int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) { int ret = 0; if (!StartsWith(path, root)) { diff --git a/Utils.h b/Utils.h index 056a635..42e8b4e 100644 --- a/Utils.h +++ b/Utils.h @@ -48,6 +48,7 @@ extern bool sSleepOnUnmount; status_t CreateDeviceNode(const std::string& path, dev_t dev); status_t DestroyDeviceNode(const std::string& path); +int SetQuotaProjectId(std::string path, long projectId); /* * Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'. * 'path' must start with 'root' From c9a2be4e3fb102bfb56f6384121d01b674b4f375 Mon Sep 17 00:00:00 2001 From: Zim Date: Fri, 24 Jan 2020 22:03:02 +0000 Subject: [PATCH 045/112] Allow external_storage or media_rw gid access /mnt/media_rw PublicVolumes are mounted on /mnt/media_rw/. Two categories of apps need access to the mounts. Fortunately, they need access in mutually exclusive scenarios. 1. The FUSE daemon needs access when serving content from app requests on /storage/. 2. File managers (MANAGE_EXTERNAL_STORAGE permission) need access to ureliable (USB OTG) volumes that are only available on the /mnt/media_rw paths, i.e, they are not bind mounted into /storage for apps. Additionally, we want to ensure that file managers cannot access /mnt/media_rw when there's a stacked FUSE volume on it. To do this, we selectively change the mount gid of the /mnt/media_rw/ path: -media_rw if it's a reliable volume, ie there's a stacked FUSE volume -external_storage if it's an unreliable volume. This ensures that file managers with their external_storage gid can access unreliable volumes from /mnt/media_rw and cannot interfere with the FUSE daemon when it's a reliable volume. Test: adb shell sm set-force-adoptable [on|off] to set reliable or unreliable volumes && mounting public volumes shows the correct ACL on /mnt/media_rw/ Bug: 144914977 Change-Id: Iecf1a422d39e5137105b5a4946704858ce902a8a --- model/PublicVolume.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index b246c95..a0b3227 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -141,13 +141,14 @@ status_t PublicVolume::doMount() { } if (mFsType == "vfat") { - if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_MEDIA_RW, AID_MEDIA_RW, 0007, - true)) { + if (vfat::Mount(mDevPath, mRawPath, false, false, false, AID_ROOT, + (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007, true)) { PLOG(ERROR) << getId() << " failed to mount " << mDevPath; return -EIO; } } else if (mFsType == "exfat") { - if (exfat::Mount(mDevPath, mRawPath, AID_MEDIA_RW, AID_MEDIA_RW, 0007)) { + if (exfat::Mount(mDevPath, mRawPath, AID_ROOT, + (isVisible ? AID_MEDIA_RW : AID_EXTERNAL_STORAGE), 0007)) { PLOG(ERROR) << getId() << " failed to mount " << mDevPath; return -EIO; } From 0a7e9925a617dc4a309e3a6a5de268f7a577eb57 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 24 Jan 2020 16:17:32 +0100 Subject: [PATCH 046/112] Automatically use correct lower paths for setupAppDir. When we're asked to create an app directory, find the corresponding volume, and use the raw path of that volume to create the directory. This ensures this will continue working on devices that don't have sdcardfs. Bug: 146419093 Test: manual test on cuttlefish Change-Id: I91d735c1adbcca171e5af73aca0abd7ef396d0b7 --- VolumeManager.cpp | 39 +++++++++++++++++++++++++++++++++++---- VolumeManager.h | 18 ++++++++++++++++++ model/Disk.cpp | 11 +++++++++++ model/Disk.h | 2 ++ 4 files changed, 66 insertions(+), 4 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index d8b1e32..3de89ab 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -830,16 +830,47 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi return -EINVAL; } + // Find the volume it belongs to + auto filter_fn = [&](const VolumeBase& vol) { + if (vol.getState() != VolumeBase::State::kMounted) { + // The volume must be mounted + return false; + } + if ((vol.getMountFlags() & VolumeBase::MountFlags::kVisible) == 0) { + // and visible + return false; + } + if (vol.getInternalPath().empty()) { + return false; + } + if (vol.getMountUserId() != USER_UNKNOWN && + vol.getMountUserId() != multiuser_get_user_id(appUid)) { + // The app dir must be created on a volume with the same user-id + return false; + } + if (!path.empty() && StartsWith(path, vol.getPath())) { + return true; + } + + return false; + }; + auto volume = findVolumeWithFilter(filter_fn); + if (volume == nullptr) { + LOG(ERROR) << "Failed to find mounted volume for " << path; + return -EINVAL; + } // Convert paths to lower filesystem paths to avoid making FUSE requests for these reasons: // 1. A FUSE request from vold puts vold at risk of hanging if the FUSE daemon is down // 2. The FUSE daemon prevents requests on /mnt/user/0/emulated/ and a request // on /storage/emulated/10 means /mnt/user/0/emulated/10 - // TODO(b/146419093): Use lower filesystem paths that don't depend on sdcardfs - const std::string lowerPath = "/mnt/runtime/default/" + path.substr(9); - const std::string lowerAppDirRoot = "/mnt/runtime/default/" + appDirRoot.substr(9); + const std::string lowerPath = + volume->getInternalPath() + path.substr(volume->getPath().length()); + const std::string lowerAppDirRoot = + volume->getInternalPath() + appDirRoot.substr(volume->getPath().length()); // First create the root which holds app dirs, if needed. - int ret = PrepareDirsFromRoot(lowerAppDirRoot, "/mnt/runtime/default/", 0771, AID_MEDIA_RW, AID_MEDIA_RW); + int ret = PrepareDirsFromRoot(lowerAppDirRoot, volume->getInternalPath(), 0771, AID_MEDIA_RW, + AID_MEDIA_RW); if (ret != 0) { return ret; } diff --git a/VolumeManager.h b/VolumeManager.h index cacab85..eb48736 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -83,6 +83,24 @@ class VolumeManager { std::shared_ptr findDisk(const std::string& id); std::shared_ptr findVolume(const std::string& id); + template + std::shared_ptr findVolumeWithFilter(Fn fn) { + for (const auto& vol : mInternalEmulatedVolumes) { + if (fn(*vol)) { + return vol; + } + } + for (const auto& disk : mDisks) { + for (const auto& vol : disk->getVolumes()) { + if (fn(*vol)) { + return vol; + } + } + } + + return nullptr; + } + void listVolumes(android::vold::VolumeBase::Type type, std::list& list) const; const std::set& getStartedUsers() const { return mStartedUsers; } diff --git a/model/Disk.cpp b/model/Disk.cpp index b66c336..f8357a9 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -162,6 +162,17 @@ void Disk::listVolumes(VolumeBase::Type type, std::list& list) cons } } +std::vector> Disk::getVolumes() const { + std::vector> vols; + for (const auto& vol : mVolumes) { + vols.push_back(vol); + auto stackedVolumes = vol->getVolumes(); + vols.insert(vols.end(), stackedVolumes.begin(), stackedVolumes.end()); + } + + return vols; +} + status_t Disk::create() { CHECK(!mCreated); mCreated = true; diff --git a/model/Disk.h b/model/Disk.h index 889e906..d82d141 100644 --- a/model/Disk.h +++ b/model/Disk.h @@ -67,6 +67,8 @@ class Disk { void listVolumes(VolumeBase::Type type, std::list& list) const; + std::vector> getVolumes() const; + status_t create(); status_t destroy(); From 3497cb5be5f9af324a2798eb76a6c17dfdacd78d Mon Sep 17 00:00:00 2001 From: Yurii Zubrytskyi Date: Fri, 10 Jan 2020 11:54:06 -0800 Subject: [PATCH 047/112] Expose new IncFS interface through Vold CL is a part of multi-repository topic and will be merged to AOSP Bug: 146080380 Test: manual Change-Id: I09b33a34ff1ac7f6e415b7bd090c22e7df24d72d --- VoldNativeService.cpp | 26 +++++++++++++------------- VoldNativeService.h | 4 ++-- binder/android/os/IVold.aidl | 4 ++-- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index f8ed61c..67bc939 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -932,26 +932,26 @@ binder::Status VoldNativeService::resetCheckpoint() { return ok(); } -binder::Status VoldNativeService::incFsVersion(int32_t* _aidl_return) { - *_aidl_return = IncFs_Version(); +binder::Status VoldNativeService::incFsEnabled(bool* _aidl_return) { + *_aidl_return = IncFs_IsEnabled(); return ok(); } binder::Status VoldNativeService::mountIncFs( - const std::string& imagePath, const std::string& targetDir, int32_t flags, + const std::string& backingPath, const std::string& targetDir, int32_t flags, ::android::os::incremental::IncrementalFileSystemControlParcel* _aidl_return) { - auto result = IncFs_Mount(imagePath.c_str(), targetDir.c_str(), flags, - INCFS_DEFAULT_READ_TIMEOUT_MS, 0777); - if (result.cmdFd < 0) { - return translate(result.cmdFd); + auto result = IncFs_Mount(backingPath.c_str(), targetDir.c_str(), + {.flags = IncFsMountFlags(flags), + .defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, + .readLogBufferPages = 4}); + if (result.cmd < 0) { + return translate(result.cmd); } - LOG(INFO) << "VoldNativeService::mountIncFs: everything is fine! " << result.cmdFd << "/" - << result.logFd; - using ParcelFileDescriptor = ::android::os::ParcelFileDescriptor; using unique_fd = ::android::base::unique_fd; - _aidl_return->cmd = std::make_unique(unique_fd(result.cmdFd)); - if (result.logFd >= 0) { - _aidl_return->log = std::make_unique(unique_fd(result.logFd)); + _aidl_return->cmd.reset(unique_fd(result.cmd)); + _aidl_return->pendingReads.reset(unique_fd(result.pendingReads)); + if (result.logs >= 0) { + _aidl_return->log.reset(unique_fd(result.logs)); } return ok(); } diff --git a/VoldNativeService.h b/VoldNativeService.h index 2967fae..7de2a67 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -146,9 +146,9 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status supportsFileCheckpoint(bool* _aidl_return); binder::Status resetCheckpoint(); - binder::Status incFsVersion(int32_t* _aidl_return) override; + binder::Status incFsEnabled(bool* _aidl_return) override; binder::Status mountIncFs( - const std::string& imagePath, const std::string& targetDir, int32_t flags, + const std::string& backingPath, const std::string& targetDir, int32_t flags, ::android::os::incremental::IncrementalFileSystemControlParcel* _aidl_return) override; binder::Status unmountIncFs(const std::string& dir) override; binder::Status bindMount(const std::string& sourceDir, const std::string& targetDir) override; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 1819e09..f1e463a 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -130,8 +130,8 @@ interface IVold { FileDescriptor openAppFuseFile(int uid, int mountId, int fileId, int flags); - int incFsVersion(); - IncrementalFileSystemControlParcel mountIncFs(@utf8InCpp String imagePath, @utf8InCpp String targetDir, int flags); + boolean incFsEnabled(); + IncrementalFileSystemControlParcel mountIncFs(@utf8InCpp String backingPath, @utf8InCpp String targetDir, int flags); void unmountIncFs(@utf8InCpp String dir); void bindMount(@utf8InCpp String sourceDir, @utf8InCpp String targetDir); From 4dd47090a5b64796f9b3978d0d11534b5b515335 Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 29 Jan 2020 02:44:46 +0000 Subject: [PATCH 048/112] Allow media_rw access to /mnt/user This allows the FUSE daemon (with media_rw) explicitly use /mnt/user paths for redaction. Test: atest FuseDaemonHostTest#testVfsCacheConsistency Change-Id: If5b5f5aa6a0ce7c8e2fd300ff6146b345b25cf04 --- Utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 67e92c9..4720645 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1038,7 +1038,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, // Ensure that /mnt/user is 0700. With FUSE, apps don't need access to /mnt/user paths directly. // Without FUSE however, apps need /mnt/user access so /mnt/user in init.rc is 0755 until here - auto result = PrepareDir("/mnt/user", 0700, AID_ROOT, AID_ROOT); + auto result = PrepareDir("/mnt/user", 0750, AID_ROOT, AID_MEDIA_RW); if (result != android::OK) { PLOG(ERROR) << "Failed to prepare directory /mnt/user"; return -1; From 26eec7049ba73d0522ae966027224748857654cd Mon Sep 17 00:00:00 2001 From: Zim Date: Fri, 31 Jan 2020 16:00:58 +0000 Subject: [PATCH 049/112] Harden /mnt/pass_through paths Even though /mnt/pass_through itself is 700 root root, the paths under it are quite permissive. Now, change them from 755 to 710 root media_rw since the FUSE daemon is the only one that should access it and it has media_rw gid Test: manual Bug: 135341433 Change-Id: I743c014f2c0273c68a1cead7f4331b55a3abcb4e --- Utils.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 4720645..3915667 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1062,13 +1062,13 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, return -1; } - result = PrepareDir(pre_pass_through_path, 0755, AID_ROOT, AID_ROOT); + result = PrepareDir(pre_pass_through_path, 0710, AID_ROOT, AID_MEDIA_RW); if (result != android::OK) { PLOG(ERROR) << "Failed to prepare directory " << pre_pass_through_path; return -1; } - result = PrepareDir(pass_through_path, 0755, AID_ROOT, AID_ROOT); + result = PrepareDir(pass_through_path, 0710, AID_ROOT, AID_MEDIA_RW); if (result != android::OK) { PLOG(ERROR) << "Failed to prepare directory " << pass_through_path; return -1; @@ -1085,7 +1085,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, Symlink("/storage/emulated/" + std::to_string(user_id), linkpath); std::string pass_through_linkpath(StringPrintf("/mnt/pass_through/%d/self", user_id)); - result = PrepareDir(pass_through_linkpath, 0755, AID_ROOT, AID_ROOT); + result = PrepareDir(pass_through_linkpath, 0710, AID_ROOT, AID_MEDIA_RW); if (result != android::OK) { PLOG(ERROR) << "Failed to prepare directory " << pass_through_linkpath; return -1; From 62a4b279ab7ccff78e0c2a23456160b2ac272e06 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 31 Jan 2020 15:23:09 +0100 Subject: [PATCH 050/112] Setup Android/, Android/data and Android/obb dirs correctly. Normally sdcardfs takes care of setting up these directories on-demand, for example when an app requests its private data directory to be created. On devices without sdcardfs however, we ourselves need to make sure to setup the UID/GID of these directories correctly. Introduce a new PrepareAndroidDirs() function which sets the dirs up correctly. On devices without sdcardfs, that means: Path UID GID mode /Android media_rw media_rw 771 /Android/data media_rw ext_data_rw 771 /Android/obb media_rw ext_obb_rw 771 Bug: 146419093 Test: wipe Android/, reboot, with and without sdcardfs, verify contents Change-Id: I3a879089422c7fc449b6a3e6f1c4b386b86687a4 --- Utils.cpp | 28 ++++++++++++++++++++++- Utils.h | 10 ++++++++- VolumeManager.cpp | 48 +++++++++++++++++++++++++++++++++++----- model/EmulatedVolume.cpp | 34 ++++++++++++++++------------ model/EmulatedVolume.h | 1 + model/VolumeBase.cpp | 5 +++++ model/VolumeBase.h | 2 ++ 7 files changed, 106 insertions(+), 22 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 3915667..be4d293 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -134,7 +134,7 @@ int SetQuotaProjectId(std::string path, long projectId) { return ioctl(fd, FS_IOC_FSSETXATTR, &fsx); } -int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) { +int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) { int ret = 0; if (!StartsWith(path, root)) { return -1; @@ -1164,5 +1164,31 @@ status_t UnmountUserFuse(userid_t user_id, const std::string& absolute_lower_pat return result; } +status_t PrepareAndroidDirs(const std::string& volumeRoot) { + std::string androidDir = volumeRoot + kAndroidDir; + std::string androidDataDir = volumeRoot + kAppDataDir; + std::string androidObbDir = volumeRoot + kAppObbDir; + + bool useSdcardFs = IsFilesystemSupported("sdcardfs"); + + if (fs_prepare_dir(androidDir.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { + PLOG(ERROR) << "Failed to create " << androidDir; + return -errno; + } + + gid_t dataGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_DATA_RW; + if (fs_prepare_dir(androidDataDir.c_str(), 0771, AID_MEDIA_RW, dataGid) != 0) { + PLOG(ERROR) << "Failed to create " << androidDataDir; + return -errno; + } + + gid_t obbGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_OBB_RW; + if (fs_prepare_dir(androidObbDir.c_str(), 0771, AID_MEDIA_RW, obbGid) != 0) { + PLOG(ERROR) << "Failed to create " << androidObbDir; + return -errno; + } + + return OK; +} } // namespace vold } // namespace android diff --git a/Utils.h b/Utils.h index 42e8b4e..ec42f39 100644 --- a/Utils.h +++ b/Utils.h @@ -36,6 +36,11 @@ namespace vold { static const char* kPropFuse = "persist.sys.fuse"; +static const char* kAndroidDir = "/Android/"; +static const char* kAppDataDir = "/Android/data/"; +static const char* kAppMediaDir = "/Android/media/"; +static const char* kAppObbDir = "/Android/obb/"; + /* SELinux contexts used depending on the block device type */ extern security_context_t sBlkidContext; extern security_context_t sBlkidUntrustedContext; @@ -52,8 +57,10 @@ int SetQuotaProjectId(std::string path, long projectId); /* * Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'. * 'path' must start with 'root' + * ONLY for use with app-specific data directories on external storage! + * (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.) */ -int PrepareDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid); +int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid); /* fs_prepare_dir wrapper that creates with SELinux context */ status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid); @@ -164,6 +171,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, status_t UnmountUserFuse(userid_t userId, const std::string& absolute_lower_path, const std::string& relative_upper_path); +status_t PrepareAndroidDirs(const std::string& volumeRoot); } // namespace vold } // namespace android diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 3de89ab..e6d593a 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -81,7 +81,9 @@ using android::vold::BindMount; using android::vold::CreateDir; using android::vold::DeleteDirContents; using android::vold::DeleteDirContentsAndDir; -using android::vold::PrepareDirsFromRoot; +using android::vold::IsFilesystemSupported; +using android::vold::PrepareAndroidDirs; +using android::vold::PrepareAppDirsFromRoot; using android::vold::PrivateVolume; using android::vold::Symlink; using android::vold::Unlink; @@ -822,6 +824,29 @@ int VolumeManager::unmountAll() { return 0; } +static gid_t getAppDirGid(const std::string& appDir) { + // Create app-specific dirs with the correct UID/GID + gid_t gid = AID_MEDIA_RW; + if (!IsFilesystemSupported("sdcardfs")) { + if (appDir == android::vold::kAppDataDir) { + gid = AID_EXT_DATA_RW; + } else if (appDir == android::vold::kAppObbDir) { + gid = AID_EXT_OBB_RW; + } else if (appDir == android::vold::kAppMediaDir) { + gid = AID_MEDIA_RW; + } else { + gid = AID_MEDIA_RW; + } + } + + return gid; +} + +static bool isValidAppDirRoot(const std::string& appDirRoot) { + return appDirRoot == android::vold::kAppDataDir || appDirRoot == android::vold::kAppMediaDir || + appDirRoot == android::vold::kAppObbDir; +} + int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot, int32_t appUid) { // Only offer to create directories for paths managed by vold @@ -868,14 +893,25 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi const std::string lowerAppDirRoot = volume->getInternalPath() + appDirRoot.substr(volume->getPath().length()); - // First create the root which holds app dirs, if needed. - int ret = PrepareDirsFromRoot(lowerAppDirRoot, volume->getInternalPath(), 0771, AID_MEDIA_RW, - AID_MEDIA_RW); + // Do some sanity checking on the app dir (relative from root) + const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0 + + // eg, if lowerAppDirRoot = /data/media/0/Android/data, this is /Android/data + const std::string relativeAppRoot = lowerAppDirRoot.substr(volumeRoot.length()); + if (!isValidAppDirRoot(relativeAppRoot)) { + LOG(ERROR) << path << " is not a valid application directory."; + return -EINVAL; + } + + // Make sure the Android/ directories exist and are setup correctly + int ret = PrepareAndroidDirs(volumeRoot); if (ret != 0) { + LOG(ERROR) << "Failed to prepare Android/ directories."; return ret; } - // Then, create app-specific dirs with the correct UID/GID - return PrepareDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, AID_MEDIA_RW); + + gid_t gid = getAppDirGid(relativeAppRoot); + return PrepareAppDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, gid); } int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 082dea5..8f8c87a 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -73,17 +73,8 @@ std::string EmulatedVolume::getLabel() { } } -// Creates a bind mount from source to target, creating the source (!) directory -// if not yet present. +// Creates a bind mount from source to target static status_t doFuseBindMount(const std::string& source, const std::string& target) { - if (access(source.c_str(), F_OK) != 0) { - // Android path may not exist yet if users has just been created; create it on - // the lower fs. - if (fs_prepare_dir(source.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { - PLOG(ERROR) << "Failed to create " << source; - return -errno; - } - } LOG(INFO) << "Bind mounting " << source << " on " << target; auto status = BindMount(source, target); if (status != OK) { @@ -232,11 +223,19 @@ status_t EmulatedVolume::doMount() { LOG(INFO) << "Mounting emulated fuse volume"; android::base::unique_fd fd; int user_id = getMountUserId(); - int result = MountUserFuse(user_id, getInternalPath(), label, &fd); + auto volumeRoot = getRootPath(); - if (result != 0) { + // Make sure Android/ dirs exist for bind mounting + status_t res = PrepareAndroidDirs(volumeRoot); + if (res != OK) { + LOG(ERROR) << "Failed to prepare Android/ directories"; + return res; + } + + res = MountUserFuse(user_id, getInternalPath(), label, &fd); + if (res != 0) { PLOG(ERROR) << "Failed to mount emulated fuse volume"; - return -result; + return res; } mFuseMounted = true; @@ -252,7 +251,7 @@ status_t EmulatedVolume::doMount() { } // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path. - status_t res = mountFuseBindMounts(); + res = mountFuseBindMounts(); if (res != OK) { fd.reset(); doUnmount(); @@ -317,5 +316,12 @@ status_t EmulatedVolume::doUnmount() { return OK; } +std::string EmulatedVolume::getRootPath() const { + int user_id = getMountUserId(); + std::string volumeRoot = StringPrintf("%s/%d", getInternalPath().c_str(), user_id); + + return volumeRoot; +} + } // namespace vold } // namespace android diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index 4f76a60..3f1b2e3 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -40,6 +40,7 @@ class EmulatedVolume : public VolumeBase { explicit EmulatedVolume(const std::string& rawPath, int userId); EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, int userId); virtual ~EmulatedVolume(); + std::string getRootPath() const override; protected: status_t doMount() override; diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index 636c065..687d4f7 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -274,6 +274,11 @@ status_t VolumeBase::doFormat(const std::string& fsType) { return -ENOTSUP; } +std::string VolumeBase::getRootPath() const { + // Usually the same as the internal path, except for emulated volumes. + return getInternalPath(); +} + std::ostream& VolumeBase::operator<<(std::ostream& stream) const { return stream << " VolumeBase{id=" << mId << ",mountFlags=" << mMountFlags << ",mountUserId=" << mMountUserId << "}"; diff --git a/model/VolumeBase.h b/model/VolumeBase.h index 1d88d1b..078bb0c 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -110,6 +110,8 @@ class VolumeBase { status_t unmount(); status_t format(const std::string& fsType); + virtual std::string getRootPath() const; + std::ostream& operator<<(std::ostream& stream) const; protected: From ba9868bd783b1c515a76f382bd5622f84187234f Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 31 Jan 2020 15:49:24 +0100 Subject: [PATCH 051/112] Set correct quota project ID on application directories. Use PrepareAppDirsFromRoot() to setup the quota project ID on application-specific directories correctly. App directories use AID_EXT_GID_START + their application ID offset, whereas cache directories use AID_CACHE_GID_START. This is consistent with the GIDs sdcardfs used to label these directories with. Bug: 146419093 Test: verified project IDs with lsattr -p Change-Id: Idca8a30d185012efb0d19ceb9b346b9a4de34f18 --- Utils.cpp | 20 ++++++++++++++++++++ Utils.h | 3 ++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index be4d293..dc1c593 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -54,6 +54,7 @@ #endif using namespace std::chrono_literals; +using android::base::EndsWith; using android::base::ReadFileToString; using android::base::StartsWith; using android::base::StringPrintf; @@ -136,9 +137,13 @@ int SetQuotaProjectId(std::string path, long projectId) { int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) { int ret = 0; + bool isCacheDir = false; if (!StartsWith(path, root)) { return -1; } + // Cache directories (eg "/storage/emulated/Android/data/com.foo/cache/") need special treatment + isCacheDir = EndsWith(root, "/Android/data/") && EndsWith(path, "cache/"); + std::string to_create_from_root = path.substr(root.length()); size_t pos = 0; @@ -150,6 +155,21 @@ int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_ if (ret) { break; } + if (!IsFilesystemSupported("sdcardfs")) { + long projectId; + // All app-specific directories share the same project-ID, except + // the cache directory + if (isCacheDir && component == "cache") { + // Note that this also matches paths like: + // /Android/data/com.foo/bar/cache/ + // This is currently safe because we're never asked to create + // such directories. + projectId = uid - AID_APP_START + AID_CACHE_GID_START; + } else { + projectId = uid - AID_APP_START + AID_EXT_GID_START; + } + ret = SetQuotaProjectId(root, projectId); + } } return ret; diff --git a/Utils.h b/Utils.h index ec42f39..90ae8c6 100644 --- a/Utils.h +++ b/Utils.h @@ -56,7 +56,8 @@ status_t DestroyDeviceNode(const std::string& path); int SetQuotaProjectId(std::string path, long projectId); /* * Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'. - * 'path' must start with 'root' + * 'path' must start with 'root'. Sets up quota project IDs correctly. + * * ONLY for use with app-specific data directories on external storage! * (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.) */ From 5fe1b163304423d66f8b9b452dd77e7bad369963 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 6 Feb 2020 18:57:47 +0100 Subject: [PATCH 052/112] Add SetQuotaInherit API. This allows setting the "inherit project ID" flags on directories; in our case, we want to set this on the root of the lower filesystem, eg "/data/media/0". Bug: 146419093 Test: manual invocation works Change-Id: Ic74588fd972d464e7021bef953da0e5aaafc4286 --- Utils.cpp | 28 +++++++++++++++++++++++++++- Utils.h | 3 ++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index dc1c593..d5e0ca8 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -116,7 +116,33 @@ status_t DestroyDeviceNode(const std::string& path) { } } -int SetQuotaProjectId(std::string path, long projectId) { +int SetQuotaInherit(const std::string& path) { + unsigned long flags; + + android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC))); + if (fd == -1) { + PLOG(ERROR) << "Failed to open " << path << " to set project id inheritance."; + return -1; + } + + int ret = ioctl(fd, FS_IOC_GETFLAGS, &flags); + if (ret == -1) { + PLOG(ERROR) << "Failed to get flags for " << path << " to set project id inheritance."; + return ret; + } + + flags |= FS_PROJINHERIT_FL; + + ret = ioctl(fd, FS_IOC_SETFLAGS, &flags); + if (ret == -1) { + PLOG(ERROR) << "Failed to set flags for " << path << " to set project id inheritance."; + return ret; + } + + return 0; +} + +int SetQuotaProjectId(const std::string& path, long projectId) { struct fsxattr fsx; android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC))); diff --git a/Utils.h b/Utils.h index 90ae8c6..b35250d 100644 --- a/Utils.h +++ b/Utils.h @@ -53,7 +53,8 @@ extern bool sSleepOnUnmount; status_t CreateDeviceNode(const std::string& path, dev_t dev); status_t DestroyDeviceNode(const std::string& path); -int SetQuotaProjectId(std::string path, long projectId); +int SetQuotaInherit(const std::string& path); +int SetQuotaProjectId(const std::string& path, long projectId); /* * Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'. * 'path' must start with 'root'. Sets up quota project IDs correctly. From a13d81bbf58fbaa4b4912f57c35da7e2195a7132 Mon Sep 17 00:00:00 2001 From: Zim Date: Fri, 7 Feb 2020 16:39:31 +0000 Subject: [PATCH 053/112] Create Android/media dirs I3a879089422c7fc449b6a3e6f1c4b386b86687a4 enforces some gids on the Android/ dirs but left out Android/media. We now create it Test: atest FuseDaemonHostTest#testListFilesFromExternalMediaDirectory Bug: 149072341 Change-Id: I260c414906cd491a6bdd83522ff45f8663e15604 --- Utils.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Utils.cpp b/Utils.cpp index dc1c593..5dde4b0 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1188,6 +1188,7 @@ status_t PrepareAndroidDirs(const std::string& volumeRoot) { std::string androidDir = volumeRoot + kAndroidDir; std::string androidDataDir = volumeRoot + kAppDataDir; std::string androidObbDir = volumeRoot + kAppObbDir; + std::string androidMediaDir = volumeRoot + kAppMediaDir; bool useSdcardFs = IsFilesystemSupported("sdcardfs"); @@ -1208,6 +1209,11 @@ status_t PrepareAndroidDirs(const std::string& volumeRoot) { return -errno; } + if (fs_prepare_dir(androidMediaDir.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { + PLOG(ERROR) << "Failed to create " << androidMediaDir; + return -errno; + } + return OK; } } // namespace vold From b77ad3a4ccdca0a7cb81602a6c1dd235ec7b9ed2 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 10 Feb 2020 08:57:30 +0100 Subject: [PATCH 054/112] Add TEST_MAPPING for vold. Start with FuseDaemonHostTest and AdoptableHostTest, since these heavily rely on functionality implemented in FUSE to work correctly. Bug: 149095627 Test: run atest in system/vold Change-Id: Ia583505aae260584897b0ea80c419b0e34f04735 --- TEST_MAPPING | 10 ++++++++++ 1 file changed, 10 insertions(+) create mode 100644 TEST_MAPPING diff --git a/TEST_MAPPING b/TEST_MAPPING new file mode 100644 index 0000000..e1f3653 --- /dev/null +++ b/TEST_MAPPING @@ -0,0 +1,10 @@ +{ + "presubmit": [ + { + "name": "FuseDaemonHostTest" + }, + { + "name": "AdoptableHostTest" + } + ] +} From 04bb17f11237f5d960ffba66d0c0ea4ff5070f7b Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 10 Feb 2020 23:48:11 +0100 Subject: [PATCH 055/112] Use a regex to create application directories. A regex allows us to be more specific in what kind of directories we accept here, which in turn makes it easier to correctly create them. Bug: 146419093 Test: atest FuseDaemonHostTest Change-Id: Icb8911f6516eab81b9bbd567c7287be9f605e8b0 --- Utils.cpp | 109 ++++++++++++++++++++++++++++++++-------------- Utils.h | 11 ++--- VolumeManager.cpp | 38 ++-------------- 3 files changed, 82 insertions(+), 76 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index b2a1992..04a61d0 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #ifndef UMOUNT_NOFOLLOW @@ -74,6 +75,11 @@ static const char* kKeyPath = "/data/misc/vold"; static const char* kProcFilesystems = "/proc/filesystems"; +static const char* kAndroidDir = "/Android/"; +static const char* kAppDataDir = "/Android/data/"; +static const char* kAppMediaDir = "/Android/media/"; +static const char* kAppObbDir = "/Android/obb/"; + // Lock used to protect process-level SELinux changes from racing with each // other between multiple threads. static std::mutex kSecurityLock; @@ -161,46 +167,83 @@ int SetQuotaProjectId(const std::string& path, long projectId) { return ioctl(fd, FS_IOC_FSSETXATTR, &fsx); } -int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid) { - int ret = 0; - bool isCacheDir = false; - if (!StartsWith(path, root)) { - return -1; +int PrepareDirWithProjectId(const std::string& path, mode_t mode, uid_t uid, gid_t gid, + long projectId) { + int ret = fs_prepare_dir(path.c_str(), mode, uid, gid); + + if (ret != 0) { + return ret; } - // Cache directories (eg "/storage/emulated/Android/data/com.foo/cache/") need special treatment - isCacheDir = EndsWith(root, "/Android/data/") && EndsWith(path, "cache/"); - std::string to_create_from_root = path.substr(root.length()); - - size_t pos = 0; - while ((pos = to_create_from_root.find('/')) != std::string::npos) { - auto component = to_create_from_root.substr(0, pos); - to_create_from_root.erase(0, pos + 1); - root = root + component + "/"; - ret = fs_prepare_dir(root.c_str(), mode, uid, gid); - if (ret) { - break; - } - if (!IsFilesystemSupported("sdcardfs")) { - long projectId; - // All app-specific directories share the same project-ID, except - // the cache directory - if (isCacheDir && component == "cache") { - // Note that this also matches paths like: - // /Android/data/com.foo/bar/cache/ - // This is currently safe because we're never asked to create - // such directories. - projectId = uid - AID_APP_START + AID_CACHE_GID_START; - } else { - projectId = uid - AID_APP_START + AID_EXT_GID_START; - } - ret = SetQuotaProjectId(root, projectId); - } + if (!IsFilesystemSupported("sdcardfs")) { + ret = SetQuotaProjectId(path, projectId); } return ret; } +static gid_t getAppDirGid(const std::string& appDir) { + gid_t gid = AID_MEDIA_RW; + if (!IsFilesystemSupported("sdcardfs")) { + if (appDir == android::vold::kAppDataDir) { + gid = AID_EXT_DATA_RW; + } else if (appDir == android::vold::kAppObbDir) { + gid = AID_EXT_OBB_RW; + } else if (appDir == android::vold::kAppMediaDir) { + gid = AID_MEDIA_RW; + } else { + gid = AID_MEDIA_RW; + } + } + + return gid; +} + +int PrepareAppDirFromRoot(std::string path, int appUid) { + int ret = 0; + // Extract various parts of the path to setup correctly + // Sample path: + // /data/media/0/Android/data/com.foo/files + // [1]: path in which to create app-specific dir, eg. /data/media/0/Android/data/ + // [2]: the part of [1] starting from /Android, eg. /Android/data/ + // [3]: the package name part of the path, eg. com.foo + // [4]: the directory to create within [3], eg files + std::regex re("(^/.*(/Android/(?:data|media|obb|sandbox)/))([^/]+)/([^/]+)?/?"); + + std::smatch match; + bool is_match = regex_match(path, match, re); + + if (!is_match) { + LOG(ERROR) << "Invalid application directory: " << path; + return -EINVAL; + } + + uid_t uid = appUid; + gid_t gid = getAppDirGid(match.str(2)); + // mode = 770, plus sticky bit on directory to inherit GID when apps + // create subdirs + mode_t mode = S_IRWXU | S_IRWXG | S_ISGID; + long projectId = uid - AID_APP_START + AID_EXT_GID_START; + + // First, create the package-path + std::string package_path = match.str(1) + match.str(3); + ret = PrepareDirWithProjectId(package_path, mode, uid, gid, projectId); + if (ret) { + return ret; + } + + // Next, create the directory within the package, if needed + if (match.size() <= 4) { + return OK; + } + + if (match.str(4) == "cache") { + // All dirs use the "app" project ID, except for the cache dir + projectId = uid - AID_APP_START + AID_CACHE_GID_START; + } + return PrepareDirWithProjectId(path.c_str(), mode, uid, gid, projectId); +} + status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { std::lock_guard lock(kSecurityLock); const char* cpath = path.c_str(); diff --git a/Utils.h b/Utils.h index b35250d..a7dda7a 100644 --- a/Utils.h +++ b/Utils.h @@ -36,11 +36,6 @@ namespace vold { static const char* kPropFuse = "persist.sys.fuse"; -static const char* kAndroidDir = "/Android/"; -static const char* kAppDataDir = "/Android/data/"; -static const char* kAppMediaDir = "/Android/media/"; -static const char* kAppObbDir = "/Android/obb/"; - /* SELinux contexts used depending on the block device type */ extern security_context_t sBlkidContext; extern security_context_t sBlkidUntrustedContext; @@ -56,13 +51,13 @@ status_t DestroyDeviceNode(const std::string& path); int SetQuotaInherit(const std::string& path); int SetQuotaProjectId(const std::string& path, long projectId); /* - * Recursively calls fs_prepare_dir() on all components in 'path', starting at 'root'. - * 'path' must start with 'root'. Sets up quota project IDs correctly. + * Creates and sets up an application-specific path on external + * storage with the correct ACL and project ID (if needed). * * ONLY for use with app-specific data directories on external storage! * (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.) */ -int PrepareAppDirsFromRoot(std::string path, std::string root, mode_t mode, uid_t uid, gid_t gid); +int PrepareAppDirFromRoot(std::string path, int appUid); /* fs_prepare_dir wrapper that creates with SELinux context */ status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 4427c9b..c141d2a 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -82,7 +82,7 @@ using android::vold::DeleteDirContents; using android::vold::DeleteDirContentsAndDir; using android::vold::IsFilesystemSupported; using android::vold::PrepareAndroidDirs; -using android::vold::PrepareAppDirsFromRoot; +using android::vold::PrepareAppDirFromRoot; using android::vold::PrivateVolume; using android::vold::Symlink; using android::vold::Unlink; @@ -823,29 +823,6 @@ int VolumeManager::unmountAll() { return 0; } -static gid_t getAppDirGid(const std::string& appDir) { - // Create app-specific dirs with the correct UID/GID - gid_t gid = AID_MEDIA_RW; - if (!IsFilesystemSupported("sdcardfs")) { - if (appDir == android::vold::kAppDataDir) { - gid = AID_EXT_DATA_RW; - } else if (appDir == android::vold::kAppObbDir) { - gid = AID_EXT_OBB_RW; - } else if (appDir == android::vold::kAppMediaDir) { - gid = AID_MEDIA_RW; - } else { - gid = AID_MEDIA_RW; - } - } - - return gid; -} - -static bool isValidAppDirRoot(const std::string& appDirRoot) { - return appDirRoot == android::vold::kAppDataDir || appDirRoot == android::vold::kAppMediaDir || - appDirRoot == android::vold::kAppObbDir; -} - int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot, int32_t appUid) { // Only offer to create directories for paths managed by vold @@ -889,19 +866,10 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi // on /storage/emulated/10 means /mnt/user/0/emulated/10 const std::string lowerPath = volume->getInternalPath() + path.substr(volume->getPath().length()); - const std::string lowerAppDirRoot = - volume->getInternalPath() + appDirRoot.substr(volume->getPath().length()); // Do some sanity checking on the app dir (relative from root) const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0 - // eg, if lowerAppDirRoot = /data/media/0/Android/data, this is /Android/data - const std::string relativeAppRoot = lowerAppDirRoot.substr(volumeRoot.length()); - if (!isValidAppDirRoot(relativeAppRoot)) { - LOG(ERROR) << path << " is not a valid application directory."; - return -EINVAL; - } - // Make sure the Android/ directories exist and are setup correctly int ret = PrepareAndroidDirs(volumeRoot); if (ret != 0) { @@ -909,8 +877,8 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi return ret; } - gid_t gid = getAppDirGid(relativeAppRoot); - return PrepareAppDirsFromRoot(lowerPath, lowerAppDirRoot, 0770, appUid, gid); + // Finally, create the app paths we need + return PrepareAppDirFromRoot(lowerPath, appUid); } int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, From 82e90de23d0ee47e785307e77c5ab0ba9a4de26f Mon Sep 17 00:00:00 2001 From: Risan Date: Tue, 4 Feb 2020 16:07:21 +0900 Subject: [PATCH 056/112] Add disk for StubVolume StubVolume is a volume type for ARC++ external storage. Named StubVolume because it is managed from outside Android (not through Android kernel). Previously, StubVolume is a diskless volume. However, as mentioned in jsharkey@ email, a disk is needed for StubVolume to hold "kInternal" (external storage type that is "external" from Android perspective, but is "internal" to the device. For example shared directory from ChromeOS to Android) and "kIndexable" (whether or not a disk should be indexed by MediaStore). The addition of disk means we could expose the createStubVolume API to add a disk flags, which is also introduced in this CL. Both kInternal and kIndexable will be introduced in separate CL. Bug: 132796154 Test: Mount/unmount ARC++ removable device in ChromeOS. Change-Id: I8b77fa1cf50ab38a2892272154dafdb78f079378 --- VoldNativeService.cpp | 13 +++++++---- VoldNativeService.h | 3 ++- VolumeManager.cpp | 44 ++++++++++++++++-------------------- VolumeManager.h | 5 ++-- binder/android/os/IVold.aidl | 2 +- model/Disk.cpp | 19 ++++++++++++++++ model/Disk.h | 8 +++++++ model/StubVolume.cpp | 6 +++-- model/StubVolume.h | 2 +- 9 files changed, 64 insertions(+), 38 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 3643c74..d648ebc 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -488,9 +488,12 @@ binder::Status VoldNativeService::destroyObb(const std::string& volId) { return translate(VolumeManager::Instance()->destroyObb(volId)); } -binder::Status VoldNativeService::createStubVolume( - const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, - const std::string& fsUuid, const std::string& fsLabel, std::string* _aidl_return) { +binder::Status VoldNativeService::createStubVolume(const std::string& sourcePath, + const std::string& mountPath, + const std::string& fsType, + const std::string& fsUuid, + const std::string& fsLabel, int32_t flags, + std::string* _aidl_return) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(sourcePath); CHECK_ARGUMENT_PATH(mountPath); @@ -499,8 +502,8 @@ binder::Status VoldNativeService::createStubVolume( // is quite meaningless. ACQUIRE_LOCK; - return translate(VolumeManager::Instance()->createStubVolume(sourcePath, mountPath, fsType, - fsUuid, fsLabel, _aidl_return)); + return translate(VolumeManager::Instance()->createStubVolume( + sourcePath, mountPath, fsType, fsUuid, fsLabel, flags, _aidl_return)); } binder::Status VoldNativeService::destroyStubVolume(const std::string& volId) { diff --git a/VoldNativeService.h b/VoldNativeService.h index 7de2a67..a276de3 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -74,7 +74,8 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status createStubVolume(const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, const std::string& fsUuid, - const std::string& fsLabel, std::string* _aidl_return); + const std::string& fsLabel, int32_t flags, + std::string* _aidl_return); binder::Status destroyStubVolume(const std::string& volId); binder::Status fstrim(int32_t fstrimFlags, diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 4427c9b..7be5e4f 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -114,7 +114,7 @@ VolumeManager* VolumeManager::Instance() { VolumeManager::VolumeManager() { mDebug = false; mNextObbId = 0; - mNextStubVolumeId = 0; + mNextStubId = 0; // For security reasons, assume that a secure keyguard is // showing until we hear otherwise mSecureKeyguardShowing = true; @@ -340,11 +340,6 @@ std::shared_ptr VolumeManager::findVolume(const std:: return vol; } } - for (const auto& vol : mStubVolumes) { - if (vol->getId() == id) { - return vol; - } - } for (const auto& vol : mObbVolumes) { if (vol->getId() == id) { return vol; @@ -767,7 +762,6 @@ int VolumeManager::shutdown() { } mInternalEmulatedVolumes.clear(); - mStubVolumes.clear(); mDisks.clear(); mPendingDisks.clear(); android::vold::sSleepOnUnmount = true; @@ -782,9 +776,6 @@ int VolumeManager::unmountAll() { for (const auto& vol : mInternalEmulatedVolumes) { vol->unmount(); } - for (const auto& stub : mStubVolumes) { - stub->unmount(); - } for (const auto& disk : mDisks) { disk->unmountAll(); } @@ -941,27 +932,30 @@ int VolumeManager::destroyObb(const std::string& volId) { int VolumeManager::createStubVolume(const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, const std::string& fsUuid, - const std::string& fsLabel, std::string* outVolId) { - int id = mNextStubVolumeId++; - auto vol = std::shared_ptr( - new android::vold::StubVolume(id, sourcePath, mountPath, fsType, fsUuid, fsLabel)); - vol->create(); + const std::string& fsLabel, int32_t flags __unused, + std::string* outVolId) { + dev_t stubId = --mNextStubId; + auto vol = std::shared_ptr( + new android::vold::StubVolume(stubId, sourcePath, mountPath, fsType, fsUuid, fsLabel)); - mStubVolumes.push_back(vol); + // TODO (b/132796154): Passed each supported flags explicitly here. + // StubDisk doesn't have device node corresponds to it. So, a fake device + // number is used. The supported flags will be infered from the + // currently-unused flags parameter. + auto disk = std::shared_ptr( + new android::vold::Disk("stub", stubId, "stub", android::vold::Disk::Flags::kStub)); + disk->initializePartition(vol); + handleDiskAdded(disk); *outVolId = vol->getId(); return android::OK; } int VolumeManager::destroyStubVolume(const std::string& volId) { - auto i = mStubVolumes.begin(); - while (i != mStubVolumes.end()) { - if ((*i)->getId() == volId) { - (*i)->destroy(); - i = mStubVolumes.erase(i); - } else { - ++i; - } - } + auto tokens = android::base::Split(volId, ":"); + CHECK(tokens.size() == 2); + dev_t stubId; + CHECK(android::base::ParseUint(tokens[1], &stubId)); + handleDiskRemoved(stubId); return android::OK; } diff --git a/VolumeManager.h b/VolumeManager.h index eb48736..992b6dc 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -163,7 +163,7 @@ class VolumeManager { int createStubVolume(const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, const std::string& fsUuid, - const std::string& fsLabel, std::string* outVolId); + const std::string& fsLabel, int32_t flags, std::string* outVolId); int destroyStubVolume(const std::string& volId); int mountAppFuse(uid_t uid, int mountId, android::base::unique_fd* device_fd); @@ -192,7 +192,6 @@ class VolumeManager { std::list> mDisks; std::list> mPendingDisks; std::list> mObbVolumes; - std::list> mStubVolumes; std::list> mInternalEmulatedVolumes; std::unordered_map mAddedUsers; @@ -205,7 +204,7 @@ class VolumeManager { std::shared_ptr mPrimary; int mNextObbId; - int mNextStubVolumeId; + int mNextStubId; bool mSecureKeyguardShowing; }; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index f1e463a..d4a55c8 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -125,7 +125,7 @@ interface IVold { @utf8InCpp String createStubVolume(@utf8InCpp String sourcePath, @utf8InCpp String mountPath, @utf8InCpp String fsType, - @utf8InCpp String fsUuid, @utf8InCpp String fsLabel); + @utf8InCpp String fsUuid, @utf8InCpp String fsLabel, int flags); void destroyStubVolume(@utf8InCpp String volId); FileDescriptor openAppFuseFile(int uid, int mountId, int fileId, int flags); diff --git a/model/Disk.cpp b/model/Disk.cpp index f8357a9..d08891a 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -180,6 +180,10 @@ status_t Disk::create() { auto listener = VolumeManager::Instance()->getListener(); if (listener) listener->onDiskCreated(getId(), mFlags); + if (isStub()) { + createStubVolume(); + return OK; + } readMetadata(); readPartitions(); return OK; @@ -243,6 +247,15 @@ void Disk::createPrivateVolume(dev_t device, const std::string& partGuid) { vol->create(); } +void Disk::createStubVolume() { + CHECK(mVolumes.size() == 1); + auto listener = VolumeManager::Instance()->getListener(); + if (listener) listener->onDiskMetadataChanged(getId(), mSize, mLabel, mSysPath); + if (listener) listener->onDiskScanned(getId()); + mVolumes[0]->setDiskId(getId()); + mVolumes[0]->create(); +} + void Disk::destroyAllVolumes() { for (const auto& vol : mVolumes) { vol->destroy(); @@ -443,6 +456,12 @@ status_t Disk::readPartitions() { return OK; } +void Disk::initializePartition(std::shared_ptr vol) { + CHECK(isStub()); + CHECK(mVolumes.empty()); + mVolumes.push_back(vol); +} + status_t Disk::unmountAll() { for (const auto& vol : mVolumes) { vol->unmount(); diff --git a/model/Disk.h b/model/Disk.h index d82d141..99c98fc 100644 --- a/model/Disk.h +++ b/model/Disk.h @@ -17,6 +17,7 @@ #ifndef ANDROID_VOLD_DISK_H #define ANDROID_VOLD_DISK_H +#include "StubVolume.h" #include "Utils.h" #include "VolumeBase.h" @@ -52,6 +53,9 @@ class Disk { kUsb = 1 << 3, /* Flag that disk is EMMC internal */ kEmmc = 1 << 4, + /* Flag that disk is Stub disk, i.e., disk that is managed from outside + * Android (e.g., ARC++). */ + kStub = 1 << 5, }; const std::string& getId() const { return mId; } @@ -74,6 +78,7 @@ class Disk { status_t readMetadata(); status_t readPartitions(); + void initializePartition(std::shared_ptr vol); status_t unmountAll(); @@ -109,11 +114,14 @@ class Disk { void createPublicVolume(dev_t device); void createPrivateVolume(dev_t device, const std::string& partGuid); + void createStubVolume(); void destroyAllVolumes(); int getMaxMinors(); + bool isStub() { return mFlags & kStub; } + DISALLOW_COPY_AND_ASSIGN(Disk); }; diff --git a/model/StubVolume.cpp b/model/StubVolume.cpp index edd0861..d2cd8a8 100644 --- a/model/StubVolume.cpp +++ b/model/StubVolume.cpp @@ -16,6 +16,8 @@ #include "StubVolume.h" +#include + #include #include @@ -24,7 +26,7 @@ using android::base::StringPrintf; namespace android { namespace vold { -StubVolume::StubVolume(int id, const std::string& sourcePath, const std::string& mountPath, +StubVolume::StubVolume(dev_t id, const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, const std::string& fsUuid, const std::string& fsLabel) : VolumeBase(Type::kStub), @@ -33,7 +35,7 @@ StubVolume::StubVolume(int id, const std::string& sourcePath, const std::string& mFsType(fsType), mFsUuid(fsUuid), mFsLabel(fsLabel) { - setId(StringPrintf("stub:%d", id)); + setId(StringPrintf("stub:%llu", (unsigned long long)id)); } StubVolume::~StubVolume() {} diff --git a/model/StubVolume.h b/model/StubVolume.h index 538cae9..3697b53 100644 --- a/model/StubVolume.h +++ b/model/StubVolume.h @@ -31,7 +31,7 @@ namespace vold { */ class StubVolume : public VolumeBase { public: - StubVolume(int id, const std::string& sourcePath, const std::string& mountPath, + StubVolume(dev_t id, const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, const std::string& fsUuid, const std::string& fsLabel); virtual ~StubVolume(); From 879fa8015df7092aa8b231fc8a7640b045b44bb5 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 11 Feb 2020 12:37:25 +0100 Subject: [PATCH 057/112] Set default ACL on application-specific directories. On devices without sdcardfs, application-specific directories have a particular GID that ensure some privileged daemons (like installers) are able to write to them. Android applications however run with a umask of 0077, which means that any subdirectory they create within their app-specific directory has mode 700, which in turn prevents things like DownloadManager from working, since it can be asked to download into a subdir of the app's private storage. To prevent this from happening, set a default 770 ACL on the top-level app-specific directory (eg, /data/media/0/Android/data/com.foo); the effect of that default ACL is that all directories that are created within these directories automatically get a 770 mask, regardless of the umask that the process has. Bug: 146419093 Test: atest FuseDaemonHostTest on cf_x86 (without sdcardfs) Change-Id: I3178694e6d25ce3d04a0918ac66862f644635704 --- Utils.cpp | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 04a61d0..6894c6c 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -33,16 +33,18 @@ #include #include #include +#include +#include #include #include #include -#include #include #include #include #include #include #include +#include #include #include @@ -122,6 +124,45 @@ status_t DestroyDeviceNode(const std::string& path) { } } +// Sets a default ACL where the owner and group can read/write/execute. +// Other users aren't allowed anything. +int SetDefault770Acl(const std::string& path, uid_t uid, gid_t gid) { + if (IsFilesystemSupported("sdcardfs")) { + // sdcardfs magically takes care of this + return OK; + } + + static constexpr size_t size = + sizeof(posix_acl_xattr_header) + 3 * sizeof(posix_acl_xattr_entry); + auto buf = std::make_unique(size); + + posix_acl_xattr_header* acl_header = reinterpret_cast(buf.get()); + acl_header->a_version = POSIX_ACL_XATTR_VERSION; + + posix_acl_xattr_entry* entry = + reinterpret_cast(buf.get() + sizeof(posix_acl_xattr_header)); + + entry[0].e_tag = ACL_USER_OBJ; + entry[0].e_perm = ACL_READ | ACL_WRITE | ACL_EXECUTE; + entry[0].e_id = uid; + + entry[1].e_tag = ACL_GROUP_OBJ; + entry[1].e_perm = ACL_READ | ACL_WRITE | ACL_EXECUTE; + entry[1].e_id = gid; + + entry[2].e_tag = ACL_OTHER; + entry[2].e_perm = 0; + entry[2].e_id = 0; + + int ret = setxattr(path.c_str(), XATTR_NAME_POSIX_ACL_DEFAULT, acl_header, size, 0); + + if (ret != 0) { + PLOG(ERROR) << "Failed to set default ACL on " << path; + } + + return ret; +} + int SetQuotaInherit(const std::string& path) { unsigned long flags; @@ -232,6 +273,17 @@ int PrepareAppDirFromRoot(std::string path, int appUid) { return ret; } + // Set the default ACL, to ensure that even if applications run with a + // umask of 0077, new directories within these directories will allow the + // GID specified here to write; this is necessary for apps like installers + // and MTP, that require access here. + // + // See man (5) acl for more details. + ret = SetDefault770Acl(package_path, uid, gid); + if (ret) { + return ret; + } + // Next, create the directory within the package, if needed if (match.size() <= 4) { return OK; From fd9cdbf124cba760f4df0b0977b454048f207e0a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 11 Feb 2020 14:20:29 +0100 Subject: [PATCH 058/112] Set quota project ID and inheritance on top-level storage directory. When creating external storage directories like /data/media/0, make sure we set the quota project ID correctly, and enable project ID inheritance. This ensures that all directories/files under this will be created with the correct project ID and inheritance as well. Bug: 146419093 Test: lsattr -p on /data/media Change-Id: I32bfced0d67eb8c1865897b085324f00c55926a0 --- FsCrypt.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index 1f7faac..4163f4f 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -62,8 +62,11 @@ using android::base::StringPrintf; using android::fs_mgr::GetEntryForMountPoint; using android::vold::BuildDataPath; +using android::vold::IsFilesystemSupported; using android::vold::kEmptyAuthentication; using android::vold::KeyBuffer; +using android::vold::SetQuotaInherit; +using android::vold::SetQuotaProjectId; using android::vold::writeStringToFile; using namespace android::fscrypt; @@ -783,6 +786,14 @@ bool fscrypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ if (!prepare_dir(vendor_ce_path, 0771, AID_ROOT, AID_ROOT)) return false; } if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false; + // Setup quota project ID and inheritance policy + if (!IsFilesystemSupported("sdcardfs")) { + if (SetQuotaInherit(media_ce_path) != 0) return false; + if (SetQuotaProjectId(media_ce_path, multiuser_get_uid(user_id, AID_MEDIA_RW)) != 0) { + return false; + } + } + if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false; if (fscrypt_is_native()) { From 8a68a075a2330ba5eaa62d1b8e7f7ea5d3820f45 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 12 Feb 2020 15:29:02 +0100 Subject: [PATCH 059/112] Remove appDirRoot argument from setupAppDir. This is no longer needed, because vold can deduce this itself now. Bug: 146419093 Test: builds Change-Id: Ib4f4a4109919af683722a63b305b343ef5fe972d --- VoldNativeService.cpp | 6 ++---- VoldNativeService.h | 3 +-- VolumeManager.cpp | 3 +-- VolumeManager.h | 23 +++++++++++++++-------- binder/android/os/IVold.aidl | 2 +- 5 files changed, 20 insertions(+), 17 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 3643c74..dbe1d98 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -458,14 +458,12 @@ binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { return translate(VolumeManager::Instance()->remountUid(uid, remountMode)); } -binder::Status VoldNativeService::setupAppDir(const std::string& path, - const std::string& appDirRoot, int32_t appUid) { +binder::Status VoldNativeService::setupAppDir(const std::string& path, int32_t appUid) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(path); - CHECK_ARGUMENT_PATH(appDirRoot); ACQUIRE_LOCK; - return translate(VolumeManager::Instance()->setupAppDir(path, appDirRoot, appUid)); + return translate(VolumeManager::Instance()->setupAppDir(path, appUid)); } binder::Status VoldNativeService::createObb(const std::string& sourcePath, diff --git a/VoldNativeService.h b/VoldNativeService.h index 7de2a67..36b2717 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -65,8 +65,7 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status remountUid(int32_t uid, int32_t remountMode); - binder::Status setupAppDir(const std::string& path, const std::string& appDirRoot, - int32_t appUid); + binder::Status setupAppDir(const std::string& path, int32_t appUid); binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index c141d2a..9eb7852 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -823,8 +823,7 @@ int VolumeManager::unmountAll() { return 0; } -int VolumeManager::setupAppDir(const std::string& path, const std::string& appDirRoot, - int32_t appUid) { +int VolumeManager::setupAppDir(const std::string& path, int32_t appUid) { // Only offer to create directories for paths managed by vold if (!StartsWith(path, "/storage/")) { LOG(ERROR) << "Failed to find mounted volume for " << path; diff --git a/VolumeManager.h b/VolumeManager.h index eb48736..5a2a481 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -133,20 +133,27 @@ class VolumeManager { /* * Creates a directory 'path' for an application, automatically creating - * directories along the given path if they don't exist yet. 'appDirRoot' - * is the "root" directory for app-specific directories of this kind; - * 'path' must always start with 'appDirRoot'. + * directories along the given path if they don't exist yet. * * Example: * path = /storage/emulated/0/Android/data/com.foo/files/ - * appDirRoot = /storage/emulated/0/Android/data/ * - * This function will set the UID of all app-specific directories below - * 'appDirRoot' to the 'appUid' argument. In the given example, the UID + * This function will first match the first part of the path with the volume + * root of any known volumes; in this case, "/storage/emulated/0" matches + * with the volume root of the emulated volume for user 0. + * + * The subseqent part of the path must start with one of the well-known + * Android/ data directories, /Android/data, /Android/obb or + * /Android/media. + * + * The final part of the path is application specific. This function will + * create all directories, including the application-specific ones, and + * set the UID of all app-specific directories below the well-known data + * directories to the 'appUid' argument. In the given example, the UID * of /storage/emulated/0/Android/data/com.foo and * /storage/emulated/0/Android/data/com.foo/files would be set to 'appUid'. * - * The UID of the parent directories will be set according to the + * The UID/GID of the parent directories will be set according to the * requirements of the underlying filesystem and are of no concern to the * caller. * @@ -155,7 +162,7 @@ class VolumeManager { * and ignored, unless the path ends with "/". Also ensures that path * belongs to a volume managed by vold. */ - int setupAppDir(const std::string& path, const std::string& appDirRoot, int32_t appUid); + int setupAppDir(const std::string& path, int32_t appUid); int createObb(const std::string& path, const std::string& key, int32_t ownerGid, std::string* outVolId); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index f1e463a..29a63af 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -54,7 +54,7 @@ interface IVold { void remountUid(int uid, int remountMode); - void setupAppDir(@utf8InCpp String path, @utf8InCpp String appDirRoot, int appUid); + void setupAppDir(@utf8InCpp String path, int appUid); @utf8InCpp String createObb(@utf8InCpp String sourcePath, @utf8InCpp String sourceKey, int ownerGid); From 724f0092a33e0aafb1fa5c9a37d3bbf844026c4c Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Wed, 12 Feb 2020 07:11:09 -0800 Subject: [PATCH 060/112] Avoid extra string copy We directly pass a reference to our std::string, instead of forcing the creation of a temporary std::string from the result of c_str(). Test: TreeHugger Change-Id: Ibab13f1e1ff43af076df60ae4032bf9dd111dd27 --- Utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 6894c6c..b31008c 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -293,7 +293,7 @@ int PrepareAppDirFromRoot(std::string path, int appUid) { // All dirs use the "app" project ID, except for the cache dir projectId = uid - AID_APP_START + AID_CACHE_GID_START; } - return PrepareDirWithProjectId(path.c_str(), mode, uid, gid, projectId); + return PrepareDirWithProjectId(path, mode, uid, gid, projectId); } status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { From 26ad7b34d1ef287d1c76fa35b1ca880cd1637de4 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 13 Feb 2020 16:20:52 +0100 Subject: [PATCH 061/112] Retry deleting dm devices. For some reason this can be racy; until we understand the root cause, retry to unblock presubmit. Bug: 149396179 Test: atest AdoptableHostTest no longer hangs Change-Id: I3fb4f1d966172bac2f6c52d41c4564f905765212 --- cryptfs.cpp | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/cryptfs.cpp b/cryptfs.cpp index 337bdc2..c06de0a 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -64,6 +64,9 @@ #include #include +#include +#include + extern "C" { #include } @@ -1219,9 +1222,22 @@ static int create_crypto_blk_dev(struct crypt_mnt_ftr* crypt_ftr, const unsigned } static int delete_crypto_blk_dev(const std::string& name) { + bool ret; auto& dm = DeviceMapper::Instance(); - if (!dm.DeleteDevice(name)) { - SLOGE("Cannot remove dm-crypt device %s: %s\n", name.c_str(), strerror(errno)); + // TODO(b/149396179) there appears to be a race somewhere in the system where trying + // to delete the device fails with EBUSY; for now, work around this by retrying. + int tries = 5; + while (tries-- > 0) { + ret = dm.DeleteDevice(name); + if (ret || errno != EBUSY) { + break; + } + SLOGW("DM_DEV Cannot remove dm-crypt device %s: %s, retrying...\n", name.c_str(), + strerror(errno)); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + if (!ret) { + SLOGE("DM_DEV Cannot remove dm-crypt device %s: %s\n", name.c_str(), strerror(errno)); return -1; } return 0; From b5a31c99856875bcc48dc0958d6b83eaf2648a5a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 13 Feb 2020 23:30:38 +0100 Subject: [PATCH 062/112] Stop using a regex for setupAppDir. This was hard to read and understand. Instead, fall back to explicit string operations with more comments on what we're doing and what we're allowing. This also fixes an issue where apps were asking us to create dirs on their behalf that our more than 2 levels deep, eg com.foo/files/downloads ; I thought such paths weren't allowed, but apparently they are (and there's no good reason for us to not set them up correctly). Bug: 149407572 Test: launch opera Change-Id: I7c64831032b66e90960b96e41ee42c7d616a759c --- Utils.cpp | 140 +++++++++++++++++++++++++++------------------- Utils.h | 2 +- VolumeManager.cpp | 12 +--- 3 files changed, 86 insertions(+), 68 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index b31008c..6a67071 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -223,77 +223,103 @@ int PrepareDirWithProjectId(const std::string& path, mode_t mode, uid_t uid, gid return ret; } -static gid_t getAppDirGid(const std::string& appDir) { - gid_t gid = AID_MEDIA_RW; - if (!IsFilesystemSupported("sdcardfs")) { - if (appDir == android::vold::kAppDataDir) { - gid = AID_EXT_DATA_RW; - } else if (appDir == android::vold::kAppObbDir) { - gid = AID_EXT_OBB_RW; - } else if (appDir == android::vold::kAppMediaDir) { - gid = AID_MEDIA_RW; - } else { - gid = AID_MEDIA_RW; - } +int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid) { + long projectId; + size_t pos; + int ret = 0; + + // Make sure the Android/ directories exist and are setup correctly + ret = PrepareAndroidDirs(root); + if (ret != 0) { + LOG(ERROR) << "Failed to prepare Android/ directories."; + return ret; } - return gid; -} + // Now create the application-specific subdir(s) + // path is something like /data/media/0/Android/data/com.foo/files + // First, chop off the volume root, eg /data/media/0 + std::string pathFromRoot = path.substr(root.length()); -int PrepareAppDirFromRoot(std::string path, int appUid) { - int ret = 0; - // Extract various parts of the path to setup correctly - // Sample path: - // /data/media/0/Android/data/com.foo/files - // [1]: path in which to create app-specific dir, eg. /data/media/0/Android/data/ - // [2]: the part of [1] starting from /Android, eg. /Android/data/ - // [3]: the package name part of the path, eg. com.foo - // [4]: the directory to create within [3], eg files - std::regex re("(^/.*(/Android/(?:data|media|obb|sandbox)/))([^/]+)/([^/]+)?/?"); + uid_t uid = appUid; + gid_t gid = AID_MEDIA_RW; + std::string appDir; - std::smatch match; - bool is_match = regex_match(path, match, re); - - if (!is_match) { + // Check that the next part matches one of the allowed Android/ dirs + if (StartsWith(pathFromRoot, kAppDataDir)) { + appDir = kAppDataDir; + if (!IsFilesystemSupported("sdcardfs")) { + gid = AID_EXT_DATA_RW; + } + } else if (StartsWith(pathFromRoot, kAppMediaDir)) { + appDir = kAppMediaDir; + if (!IsFilesystemSupported("sdcardfs")) { + gid = AID_MEDIA_RW; + } + } else if (StartsWith(pathFromRoot, kAppMediaDir)) { + appDir = kAppObbDir; + if (!IsFilesystemSupported("sdcardfs")) { + gid = AID_EXT_OBB_RW; + } + } else { LOG(ERROR) << "Invalid application directory: " << path; return -EINVAL; } - uid_t uid = appUid; - gid_t gid = getAppDirGid(match.str(2)); // mode = 770, plus sticky bit on directory to inherit GID when apps // create subdirs mode_t mode = S_IRWXU | S_IRWXG | S_ISGID; - long projectId = uid - AID_APP_START + AID_EXT_GID_START; + // the project ID for application-specific directories is directly + // derived from their uid - // First, create the package-path - std::string package_path = match.str(1) + match.str(3); - ret = PrepareDirWithProjectId(package_path, mode, uid, gid, projectId); - if (ret) { - return ret; + // Chop off the generic application-specific part, eg /Android/data/ + // this leaves us with something like com.foo/files/ + std::string leftToCreate = pathFromRoot.substr(appDir.length()); + if (!EndsWith(leftToCreate, "/")) { + leftToCreate += "/"; + } + std::string pathToCreate = root + appDir; + int depth = 0; + bool withinCache = false; + while ((pos = leftToCreate.find('/')) != std::string::npos) { + std::string component = leftToCreate.substr(0, pos + 1); + leftToCreate = leftToCreate.erase(0, pos + 1); + pathToCreate = pathToCreate + component; + + if (appDir == kAppDataDir && depth == 1 && component == "cache/") { + // All dirs use the "app" project ID, except for the cache dirs in + // Android/data, eg Android/data/com.foo/cache + // Note that this "sticks" - eg subdirs of this dir need the same + // project ID. + withinCache = true; + } + if (withinCache) { + projectId = uid - AID_APP_START + AID_CACHE_GID_START; + } else { + projectId = uid - AID_APP_START + AID_EXT_GID_START; + } + ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId); + if (ret != 0) { + return ret; + } + + if (depth == 0) { + // Set the default ACL on the top-level application-specific directories, + // to ensure that even if applications run with a umask of 0077, + // new directories within these directories will allow the GID + // specified here to write; this is necessary for apps like + // installers and MTP, that require access here. + // + // See man (5) acl for more details. + ret = SetDefault770Acl(pathToCreate, uid, gid); + if (ret != 0) { + return ret; + } + } + + depth++; } - // Set the default ACL, to ensure that even if applications run with a - // umask of 0077, new directories within these directories will allow the - // GID specified here to write; this is necessary for apps like installers - // and MTP, that require access here. - // - // See man (5) acl for more details. - ret = SetDefault770Acl(package_path, uid, gid); - if (ret) { - return ret; - } - - // Next, create the directory within the package, if needed - if (match.size() <= 4) { - return OK; - } - - if (match.str(4) == "cache") { - // All dirs use the "app" project ID, except for the cache dir - projectId = uid - AID_APP_START + AID_CACHE_GID_START; - } - return PrepareDirWithProjectId(path, mode, uid, gid, projectId); + return OK; } status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { diff --git a/Utils.h b/Utils.h index a7dda7a..54b8dd8 100644 --- a/Utils.h +++ b/Utils.h @@ -57,7 +57,7 @@ int SetQuotaProjectId(const std::string& path, long projectId); * ONLY for use with app-specific data directories on external storage! * (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.) */ -int PrepareAppDirFromRoot(std::string path, int appUid); +int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid); /* fs_prepare_dir wrapper that creates with SELinux context */ status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index c141d2a..67add37 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -867,18 +867,10 @@ int VolumeManager::setupAppDir(const std::string& path, const std::string& appDi const std::string lowerPath = volume->getInternalPath() + path.substr(volume->getPath().length()); - // Do some sanity checking on the app dir (relative from root) const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0 - // Make sure the Android/ directories exist and are setup correctly - int ret = PrepareAndroidDirs(volumeRoot); - if (ret != 0) { - LOG(ERROR) << "Failed to prepare Android/ directories."; - return ret; - } - - // Finally, create the app paths we need - return PrepareAppDirFromRoot(lowerPath, appUid); + // Create the app paths we need from the root + return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid); } int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, From 73a7a85c853368c33d0313bead59c0159adedbd1 Mon Sep 17 00:00:00 2001 From: Risan Date: Fri, 7 Feb 2020 18:03:44 +0900 Subject: [PATCH 063/112] Passed kUsb and kSd flags Initially, we were thinking to pass kInternal for non usb drive/sd card drive (for local external storage like directory shared from ChromeOS). Fortunately, the DocumentsUI logic apparently has TYPE_LOCAL with R.drawable.ic_root_smartphone (that is overlayable) for external storage other than TYPE_USB and TYPE_SD. Therefore, instead of creating a kInternal flags, we can just passed kUsb and kSd and not passing anything for "internal external storage" - which will render ic_root_usb, ic_root_sd, and ic_root_smartphone as icons accordingly. And since ic_root_smartphone is already overlayable, we could overlayed in /vendor - which effectively is what we initially wanted when thinking of introducing kInternal flag. Bug: 132796154 Test: Customize flags in /vendor for different devices and DocumentsUI shows the ic_root_smartphone (which can be overlayed) when kUsb is not passed, and USB icon when kUsb is passed. Change-Id: I55f13e214bbb2aeed96b6950bcf391121174c354 --- VolumeManager.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 0c81cb7..bb62441 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -899,18 +899,19 @@ int VolumeManager::destroyObb(const std::string& volId) { int VolumeManager::createStubVolume(const std::string& sourcePath, const std::string& mountPath, const std::string& fsType, const std::string& fsUuid, - const std::string& fsLabel, int32_t flags __unused, + const std::string& fsLabel, int32_t flags, std::string* outVolId) { dev_t stubId = --mNextStubId; auto vol = std::shared_ptr( new android::vold::StubVolume(stubId, sourcePath, mountPath, fsType, fsUuid, fsLabel)); - // TODO (b/132796154): Passed each supported flags explicitly here. + int32_t passedFlags = android::vold::Disk::Flags::kStub; + passedFlags |= (flags & android::vold::Disk::Flags::kUsb); + passedFlags |= (flags & android::vold::Disk::Flags::kSd); // StubDisk doesn't have device node corresponds to it. So, a fake device - // number is used. The supported flags will be infered from the - // currently-unused flags parameter. + // number is used. auto disk = std::shared_ptr( - new android::vold::Disk("stub", stubId, "stub", android::vold::Disk::Flags::kStub)); + new android::vold::Disk("stub", stubId, "stub", passedFlags)); disk->initializePartition(vol); handleDiskAdded(disk); *outVolId = vol->getId(); From b3d018a62c35d34991332dfaa678d61e97f3e1d2 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Wed, 12 Feb 2020 11:04:05 -0800 Subject: [PATCH 064/112] Refactor key generation to handle both normal and metadata encryption. Bug: 147733587 Test: Treehugger Change-Id: Iee176037dec2621c84da325c2627f988fcebbc8d --- FsCrypt.cpp | 23 +++++++++++++---------- KeyUtil.cpp | 38 ++++++++++++++++++++++++++++---------- KeyUtil.h | 28 +++++++++++++++++++++++----- MetadataCrypt.cpp | 29 +++++++---------------------- cryptfs.cpp | 9 +++++---- cryptfs.h | 4 ++-- model/Disk.cpp | 6 ++++-- 7 files changed, 82 insertions(+), 55 deletions(-) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index 0619fba..141f4c9 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -65,6 +65,9 @@ using android::vold::BuildDataPath; using android::vold::IsFilesystemSupported; using android::vold::kEmptyAuthentication; using android::vold::KeyBuffer; +using android::vold::makeGen; +using android::vold::retrieveKey; +using android::vold::retrieveOrGenerateKey; using android::vold::SetQuotaInherit; using android::vold::SetQuotaProjectId; using android::vold::writeStringToFile; @@ -186,7 +189,7 @@ static bool read_and_fixate_user_ce_key(userid_t user_id, auto const paths = get_ce_key_paths(directory_path); for (auto const ce_key_path : paths) { LOG(DEBUG) << "Trying user CE key " << ce_key_path; - if (android::vold::retrieveKey(ce_key_path, auth, ce_key)) { + if (retrieveKey(ce_key_path, auth, ce_key)) { LOG(DEBUG) << "Successfully retrieved key"; fixate_user_ce_key(directory_path, ce_key_path, paths); return true; @@ -277,8 +280,8 @@ static bool create_and_install_user_keys(userid_t user_id, bool create_ephemeral EncryptionOptions options; if (!get_data_file_encryption_options(&options)) return false; KeyBuffer de_key, ce_key; - if (!generateStorageKey(options, &de_key)) return false; - if (!generateStorageKey(options, &ce_key)) return false; + if (!generateStorageKey(makeGen(options), &de_key)) return false; + if (!generateStorageKey(makeGen(options), &ce_key)) return false; if (create_ephemeral) { // If the key should be created as ephemeral, don't store it. s_ephemeral_users.insert(user_id); @@ -352,7 +355,7 @@ static bool load_all_de_keys() { if (s_de_policies.count(user_id) == 0) { auto key_path = de_dir + "/" + entry->d_name; KeyBuffer de_key; - if (!android::vold::retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false; + if (!retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false; EncryptionPolicy de_policy; if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false; s_de_policies[user_id] = de_policy; @@ -375,8 +378,8 @@ bool fscrypt_initialize_systemwide_keys() { if (!get_data_file_encryption_options(&options)) return false; KeyBuffer device_key; - if (!android::vold::retrieveKey(true, kEmptyAuthentication, device_key_path, device_key_temp, - options, &device_key)) + if (!retrieveOrGenerateKey(device_key_path, device_key_temp, kEmptyAuthentication, + makeGen(options), &device_key)) return false; EncryptionPolicy device_policy; @@ -395,7 +398,7 @@ bool fscrypt_initialize_systemwide_keys() { LOG(INFO) << "Wrote system DE key reference to:" << ref_filename; KeyBuffer per_boot_key; - if (!generateStorageKey(options, &per_boot_key)) return false; + if (!generateStorageKey(makeGen(options), &per_boot_key)) return false; EncryptionPolicy per_boot_policy; if (!install_storage_key(DATA_MNT_POINT, options, per_boot_key, &per_boot_policy)) return false; std::string per_boot_ref_filename = std::string("/data") + fscrypt_key_per_boot_ref; @@ -604,7 +607,7 @@ static bool read_or_create_volkey(const std::string& misc_path, const std::strin EncryptionOptions options; if (!get_volume_file_encryption_options(&options)) return false; KeyBuffer key; - if (!android::vold::retrieveKey(true, auth, key_path, key_path + "_tmp", options, &key)) + if (!retrieveOrGenerateKey(key_path, key_path + "_tmp", auth, makeGen(options), &key)) return false; if (!install_storage_key(BuildDataPath(volume_uuid), options, key, policy)) return false; return true; @@ -623,12 +626,12 @@ static bool fscrypt_rewrap_user_key(userid_t user_id, int serial, auto const directory_path = get_ce_key_directory_path(user_id); KeyBuffer ce_key; std::string ce_key_current_path = get_ce_key_current_path(directory_path); - if (android::vold::retrieveKey(ce_key_current_path, retrieve_auth, &ce_key)) { + if (retrieveKey(ce_key_current_path, retrieve_auth, &ce_key)) { LOG(DEBUG) << "Successfully retrieved key"; // TODO(147732812): Remove this once Locksettingservice is fixed. // Currently it calls fscrypt_clear_user_key_auth with a secret when lockscreen is // changed from swipe to none or vice-versa - } else if (android::vold::retrieveKey(ce_key_current_path, kEmptyAuthentication, &ce_key)) { + } else if (retrieveKey(ce_key_current_path, kEmptyAuthentication, &ce_key)) { LOG(DEBUG) << "Successfully retrieved key with empty auth"; } else { LOG(ERROR) << "Failed to retrieve key for user " << user_id; diff --git a/KeyUtil.cpp b/KeyUtil.cpp index ae4d70b..2e810ff 100644 --- a/KeyUtil.cpp +++ b/KeyUtil.cpp @@ -36,8 +36,20 @@ namespace android { namespace vold { -bool randomKey(KeyBuffer* key) { - *key = KeyBuffer(FSCRYPT_MAX_KEY_SIZE); +const KeyGeneration makeGen(const EncryptionOptions& options) { + return KeyGeneration{FSCRYPT_MAX_KEY_SIZE, true, options.use_hw_wrapped_key}; +} + +const KeyGeneration makeGen(const CryptoType& crypto) { + return KeyGeneration{crypto.get_keysize(), true, false}; +} + +const KeyGeneration neverGen() { + return KeyGeneration{0, false, false}; +} + +static bool randomKey(size_t size, KeyBuffer* key) { + *key = KeyBuffer(size); if (ReadRandomBytes(key->size(), key->data()) != 0) { // TODO status_t plays badly with PLOG, fix it. LOG(ERROR) << "Random read failed"; @@ -46,11 +58,17 @@ bool randomKey(KeyBuffer* key) { return true; } -bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key) { - if (options.use_hw_wrapped_key) { +bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key) { + if (!gen.allow_gen) return false; + if (gen.use_hw_wrapped_key) { + if (gen.keysize != FSCRYPT_MAX_KEY_SIZE) { + LOG(ERROR) << "Cannot generate a wrapped key " << gen.keysize << " bytes long"; + return false; + } return generateWrappedStorageKey(key); + } else { + return randomKey(gen.keysize, key); } - return randomKey(key); } // Return true if the kernel supports the ioctls to add/remove fscrypt keys @@ -315,19 +333,19 @@ bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) { return true; } -bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication, - const std::string& key_path, const std::string& tmp_path, - const EncryptionOptions& options, KeyBuffer* key, bool keepOld) { +bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path, + const KeyAuthentication& key_authentication, const KeyGeneration& gen, + KeyBuffer* key, bool keepOld) { if (pathExists(key_path)) { LOG(DEBUG) << "Key exists, using: " << key_path; if (!retrieveKey(key_path, key_authentication, key, keepOld)) return false; } else { - if (!create_if_absent) { + if (!gen.allow_gen) { LOG(ERROR) << "No key found in " << key_path; return false; } LOG(INFO) << "Creating new key in " << key_path; - if (!generateStorageKey(options, key)) return false; + if (!generateStorageKey(gen, key)) return false; if (!storeKeyAtomically(key_path, tmp_path, key_authentication, *key)) return false; } return true; diff --git a/KeyUtil.h b/KeyUtil.h index 878b4ab..16aaf99 100644 --- a/KeyUtil.h +++ b/KeyUtil.h @@ -17,6 +17,7 @@ #ifndef ANDROID_VOLD_KEYUTIL_H #define ANDROID_VOLD_KEYUTIL_H +#include "CryptoType.h" #include "KeyBuffer.h" #include "KeyStorage.h" @@ -30,9 +31,26 @@ namespace vold { using namespace android::fscrypt; -bool randomKey(KeyBuffer* key); +// Description of how to generate a key when needed. +struct KeyGeneration { + size_t keysize; + bool allow_gen; + bool use_hw_wrapped_key; +}; -bool generateStorageKey(const EncryptionOptions& options, KeyBuffer* key); +// Generate a key as specified in KeyGeneration +bool generateStorageKey(const KeyGeneration& gen, KeyBuffer* key); + +// Returns KeyGeneration suitable for key as described in EncryptionOptions +const KeyGeneration makeGen(const EncryptionOptions& options); + +// Returns KeyGeneration suitable for key as described in CryptoType +const KeyGeneration makeGen(const CryptoType& crypto); + +// Returns a key with allow_gen false so generateStorageKey returns false; +// this is used to indicate to retrieveOrGenerateKey that a key should not +// be generated. +const KeyGeneration neverGen(); bool isFsKeyringSupported(void); @@ -58,9 +76,9 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options, // In the latter case, the caller is responsible for dropping caches. bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy); -bool retrieveKey(bool create_if_absent, const KeyAuthentication& key_authentication, - const std::string& key_path, const std::string& tmp_path, - const EncryptionOptions& options, KeyBuffer* key, bool keepOld = true); +bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path, + const KeyAuthentication& key_authentication, const KeyGeneration& gen, + KeyBuffer* key, bool keepOld = true); } // namespace vold } // namespace android diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 106978e..938ba34 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -129,24 +129,8 @@ static void commit_key(const std::string& dir) { LOG(INFO) << "Old Key deleted: " << dir; } -static bool retrieveMetadataKey(bool create_if_absent, const std::string& key_path, - const std::string& tmp_path, KeyBuffer* key, bool keepOld) { - if (pathExists(key_path)) { - LOG(DEBUG) << "Key exists, using: " << key_path; - if (!retrieveKey(key_path, kEmptyAuthentication, key, keepOld)) return false; - } else { - if (!create_if_absent) { - LOG(ERROR) << "No key found in " << key_path; - return false; - } - LOG(INFO) << "Creating new key in " << key_path; - if (!randomKey(key)) return false; - if (!storeKeyAtomically(key_path, tmp_path, kEmptyAuthentication, *key)) return false; - } - return true; -} - -static bool read_key(const std::string& metadata_key_dir, bool create_if_absent, KeyBuffer* key) { +static bool read_key(const std::string& metadata_key_dir, const KeyGeneration& gen, + KeyBuffer* key) { if (metadata_key_dir.empty()) { LOG(ERROR) << "Failed to get metadata_key_dir"; return false; @@ -168,14 +152,14 @@ static bool read_key(const std::string& metadata_key_dir, bool create_if_absent, Keymaster keymaster; if (pathExists(newKeyPath)) { if (!android::base::ReadFileToString(newKeyPath, &sKey)) - LOG(ERROR) << "Failed to read old key: " << dir; + LOG(ERROR) << "Failed to read incomplete key: " << dir; else if (!keymaster.deleteKey(sKey)) - LOG(ERROR) << "Old key deletion failed, continuing anyway: " << dir; + LOG(ERROR) << "Incomplete key deletion failed, continuing anyway: " << dir; else unlink(newKeyPath.c_str()); } bool needs_cp = cp_needsCheckpoint(); - if (!retrieveMetadataKey(create_if_absent, dir, temp, key, needs_cp)) return false; + if (!retrieveOrGenerateKey(dir, temp, kEmptyAuthentication, gen, key, needs_cp)) return false; if (needs_cp && pathExists(newKeyPath)) std::thread(commit_key, dir).detach(); return true; } @@ -283,8 +267,9 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: return false; } + auto gen = needs_encrypt ? makeGen(cipher) : neverGen(); KeyBuffer key; - if (!read_key(data_rec->metadata_key_dir, needs_encrypt, &key)) return false; + if (!read_key(data_rec->metadata_key_dir, gen, &key)) return false; std::string crypto_blkdev; if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, is_legacy, diff --git a/cryptfs.cpp b/cryptfs.cpp index 530d78e..4487d3b 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -77,6 +77,7 @@ using android::base::StringPrintf; using android::fs_mgr::GetEntryForMountPoint; using android::vold::CryptoType; using android::vold::KeyBuffer; +using android::vold::KeyGeneration; using namespace android::dm; using namespace std::chrono_literals; @@ -323,6 +324,10 @@ static const CryptoType& get_crypto_type() { return crypto_type; } +const KeyGeneration cryptfs_get_keygen() { + return makeGen(get_crypto_type()); +} + /* Should we use keymaster? */ static int keymaster_check_compatibility() { return keymaster_compatibility_cryptfs_scrypt(); @@ -472,10 +477,6 @@ static void get_device_scrypt_params(struct crypt_mnt_ftr* ftr) { ftr->p_factor = pf; } -size_t cryptfs_get_keysize() { - return get_crypto_type().get_keysize(); -} - static uint64_t get_fs_size(const char* dev) { int fd, block_size; struct ext4_super_block sb; diff --git a/cryptfs.h b/cryptfs.h index b34a8d9..872806e 100644 --- a/cryptfs.h +++ b/cryptfs.h @@ -26,6 +26,7 @@ #include #include "KeyBuffer.h" +#include "KeyUtil.h" #define CRYPT_FOOTER_OFFSET 0x4000 @@ -73,7 +74,6 @@ int cryptfs_get_password_type(void); const char* cryptfs_get_password(void); void cryptfs_clear_password(void); int cryptfs_isConvertibleToFBE(void); - -size_t cryptfs_get_keysize(); +const android::vold::KeyGeneration cryptfs_get_keygen(); #endif /* ANDROID_VOLD_CRYPTFS_H */ diff --git a/model/Disk.cpp b/model/Disk.cpp index 7ecc89e..b2ecc50 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -16,6 +16,7 @@ #include "Disk.h" #include "FsCrypt.h" +#include "KeyUtil.h" #include "PrivateVolume.h" #include "PublicVolume.h" #include "Utils.h" @@ -535,11 +536,12 @@ status_t Disk::partitionMixed(int8_t ratio) { return -EIO; } - std::string keyRaw; - if (ReadRandomBytes(cryptfs_get_keysize(), keyRaw) != OK) { + KeyBuffer key; + if (!generateStorageKey(cryptfs_get_keygen(), &key)) { LOG(ERROR) << "Failed to generate key"; return -EIO; } + std::string keyRaw(key.begin(), key.end()); std::string partGuid; StrToHex(partGuidRaw, partGuid); From 9eb436716500d67d2df66409f23e397060618644 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Sat, 15 Feb 2020 01:15:42 +0000 Subject: [PATCH 065/112] Retry deleting dm devices. For some reason this can be racy; until we understand the root cause, retry to unblock AdoptableHostTest. Bug: 149396179 Test: atest AdoptableHostTest no longer hangs Change-Id: I162ff8ad305535e7a4fab3d88f38b687b50cf4a3 --- model/PrivateVolume.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index 9f1f089..75aa938 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -36,6 +36,7 @@ #include #include #include +#include using android::base::StringPrintf; @@ -68,8 +69,19 @@ status_t PrivateVolume::doCreate() { // Recover from stale vold by tearing down any old mappings auto& dm = dm::DeviceMapper::Instance(); - if (!dm.DeleteDeviceIfExists(getId())) { + // TODO(b/149396179) there appears to be a race somewhere in the system where trying + // to delete the device fails with EBUSY; for now, work around this by retrying. + bool ret; + int tries = 10; + while (tries-- > 0) { + ret = dm.DeleteDeviceIfExists(getId()); + if (ret || errno != EBUSY) { + break; + } PLOG(ERROR) << "Cannot remove dm device " << getId(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + if (!ret) { return -EIO; } @@ -86,8 +98,19 @@ status_t PrivateVolume::doCreate() { status_t PrivateVolume::doDestroy() { auto& dm = dm::DeviceMapper::Instance(); - if (!dm.DeleteDevice(getId())) { + // TODO(b/149396179) there appears to be a race somewhere in the system where trying + // to delete the device fails with EBUSY; for now, work around this by retrying. + bool ret; + int tries = 10; + while (tries-- > 0) { + ret = dm.DeleteDevice(getId()); + if (ret || errno != EBUSY) { + break; + } PLOG(ERROR) << "Cannot remove dm device " << getId(); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + } + if (!ret) { return -EIO; } return DestroyDeviceNode(mRawDevPath); From e50ddb786a5f172b24b40a2c67ce9e6bf9a149d8 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Mon, 17 Feb 2020 18:57:01 +0000 Subject: [PATCH 066/112] Fix vold cannot create obb directory Test: setupAppDir works now Change-Id: I4bc67ecb57c30b1d0728580abc738e91f97de722 --- Utils.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Utils.cpp b/Utils.cpp index 6a67071..84bed34 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -255,7 +255,7 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int if (!IsFilesystemSupported("sdcardfs")) { gid = AID_MEDIA_RW; } - } else if (StartsWith(pathFromRoot, kAppMediaDir)) { + } else if (StartsWith(pathFromRoot, kAppObbDir)) { appDir = kAppObbDir; if (!IsFilesystemSupported("sdcardfs")) { gid = AID_EXT_OBB_RW; From 10570c00db9e19bb0caa5012721ece8c3433248f Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 18 Feb 2020 10:41:37 +0100 Subject: [PATCH 067/112] Add sticky dir bit to Android/ dirs. We want subdirectories of Android/data, Android/obb etc. to automatically maintain their group-id. Bug: 146419093 Test: manual inspection of /sdcard/Android Change-Id: I36883febb01aa155dfafb0e86f8b99223cde9815 --- Utils.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 84bed34..feed50f 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1339,24 +1339,26 @@ status_t PrepareAndroidDirs(const std::string& volumeRoot) { bool useSdcardFs = IsFilesystemSupported("sdcardfs"); - if (fs_prepare_dir(androidDir.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { + // mode 0771 + sticky bit for inheriting GIDs + mode_t mode = S_IRWXU | S_IRWXG | S_IXOTH | S_ISGID; + if (fs_prepare_dir(androidDir.c_str(), mode, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { PLOG(ERROR) << "Failed to create " << androidDir; return -errno; } gid_t dataGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_DATA_RW; - if (fs_prepare_dir(androidDataDir.c_str(), 0771, AID_MEDIA_RW, dataGid) != 0) { + if (fs_prepare_dir(androidDataDir.c_str(), mode, AID_MEDIA_RW, dataGid) != 0) { PLOG(ERROR) << "Failed to create " << androidDataDir; return -errno; } gid_t obbGid = useSdcardFs ? AID_MEDIA_RW : AID_EXT_OBB_RW; - if (fs_prepare_dir(androidObbDir.c_str(), 0771, AID_MEDIA_RW, obbGid) != 0) { + if (fs_prepare_dir(androidObbDir.c_str(), mode, AID_MEDIA_RW, obbGid) != 0) { PLOG(ERROR) << "Failed to create " << androidObbDir; return -errno; } - if (fs_prepare_dir(androidMediaDir.c_str(), 0771, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { + if (fs_prepare_dir(androidMediaDir.c_str(), mode, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { PLOG(ERROR) << "Failed to create " << androidMediaDir; return -errno; } From 442bb838286bd47edee68dcdae64edaa5ece55a3 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 18 Feb 2020 13:44:59 +0100 Subject: [PATCH 068/112] Set a default ACL on the top-level OBB directory. Since installers can create directories in Android/obb, make sure those directories end up with the correct ACL bits as well. Bug: 146419093 Test: inspect filesystem manually Change-Id: I211e921197560a40599938463f3171a0ff92d9aa --- Utils.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index feed50f..35839ac 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -124,9 +124,8 @@ status_t DestroyDeviceNode(const std::string& path) { } } -// Sets a default ACL where the owner and group can read/write/execute. -// Other users aren't allowed anything. -int SetDefault770Acl(const std::string& path, uid_t uid, gid_t gid) { +// Sets a default ACL on the directory. +int SetDefaultAcl(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { if (IsFilesystemSupported("sdcardfs")) { // sdcardfs magically takes care of this return OK; @@ -143,15 +142,21 @@ int SetDefault770Acl(const std::string& path, uid_t uid, gid_t gid) { reinterpret_cast(buf.get() + sizeof(posix_acl_xattr_header)); entry[0].e_tag = ACL_USER_OBJ; - entry[0].e_perm = ACL_READ | ACL_WRITE | ACL_EXECUTE; + // The existing mode_t mask has the ACL in the lower 9 bits: + // the lowest 3 for "other", the next 3 the group, the next 3 for the owner + // Use the mode_t masks to get these bits out, and shift them to get the + // correct value per entity. + // + // Eg if mode_t = 0700, rwx for the owner, then & S_IRWXU >> 6 results in 7 + entry[0].e_perm = (mode & S_IRWXU) >> 6; entry[0].e_id = uid; entry[1].e_tag = ACL_GROUP_OBJ; - entry[1].e_perm = ACL_READ | ACL_WRITE | ACL_EXECUTE; + entry[1].e_perm = (mode & S_IRWXG) >> 3; entry[1].e_id = gid; entry[2].e_tag = ACL_OTHER; - entry[2].e_perm = 0; + entry[2].e_perm = mode & S_IRWXO; entry[2].e_id = 0; int ret = setxattr(path.c_str(), XATTR_NAME_POSIX_ACL_DEFAULT, acl_header, size, 0); @@ -310,7 +315,7 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int // installers and MTP, that require access here. // // See man (5) acl for more details. - ret = SetDefault770Acl(pathToCreate, uid, gid); + ret = SetDefaultAcl(pathToCreate, mode, uid, gid); if (ret != 0) { return ret; } @@ -1357,6 +1362,10 @@ status_t PrepareAndroidDirs(const std::string& volumeRoot) { PLOG(ERROR) << "Failed to create " << androidObbDir; return -errno; } + // Some other apps, like installers, have write access to the OBB directory + // to pre-download them. To make sure newly created folders in this directory + // have the right permissions, set a default ACL. + SetDefaultAcl(androidObbDir, mode, AID_MEDIA_RW, obbGid); if (fs_prepare_dir(androidMediaDir.c_str(), mode, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { PLOG(ERROR) << "Failed to create " << androidMediaDir; From 816f4d94f6223cbc00f9d03e95336740dc47a6a5 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 18 Feb 2020 15:06:37 +0100 Subject: [PATCH 069/112] Add fixupAppDir() API. This can be used to fixup application directories in case they have been created by some other entity besides vold; the main use case for this API right now is OBB directories, which can be created by installers outside of vold; on devices without sdcardfs, such directories and the files contained therein are not setup correctly. This API will make sure everything is setup the way it needs to be setup. Bug: 146419093 Test: inspect OBB dir after install Change-Id: I2e35b7ac2992dbb21cc950e53651ffc07cfca907 --- Android.bp | 1 + Utils.cpp | 46 ++++++++++++++++++++++++++++++++++-- Utils.h | 3 ++- VoldNativeService.cpp | 8 +++++++ VoldNativeService.h | 1 + VolumeManager.cpp | 17 +++++++++++-- VolumeManager.h | 13 +++++++++- binder/android/os/IVold.aidl | 1 + 8 files changed, 84 insertions(+), 6 deletions(-) diff --git a/Android.bp b/Android.bp index a420078..676c958 100644 --- a/Android.bp +++ b/Android.bp @@ -167,6 +167,7 @@ cc_library_static { ], whole_static_libs: [ "com.android.sysprop.apex", + "libc++fs" ], } diff --git a/Utils.cpp b/Utils.cpp index 35839ac..9f9b357 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -47,6 +47,7 @@ #include #include +#include #include #include #include @@ -228,7 +229,40 @@ int PrepareDirWithProjectId(const std::string& path, mode_t mode, uid_t uid, gid return ret; } -int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid) { +static int FixupAppDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid, long projectId) { + namespace fs = std::filesystem; + + // Setup the directory itself correctly + int ret = PrepareDirWithProjectId(path, mode, uid, gid, projectId); + if (ret != OK) { + return ret; + } + + // Fixup all of its file entries + for (const auto& itEntry : fs::directory_iterator(path)) { + ret = lchown(itEntry.path().c_str(), uid, gid); + if (ret != 0) { + return ret; + } + + ret = chmod(itEntry.path().c_str(), mode); + if (ret != 0) { + return ret; + } + + if (!IsFilesystemSupported("sdcardfs")) { + ret = SetQuotaProjectId(itEntry.path(), projectId); + if (ret != 0) { + return ret; + } + } + } + + return OK; +} + +int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid, + bool fixupExisting) { long projectId; size_t pos; int ret = 0; @@ -302,7 +336,15 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int } else { projectId = uid - AID_APP_START + AID_EXT_GID_START; } - ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId); + + if (fixupExisting && access(pathToCreate.c_str(), F_OK) == 0) { + // Fixup all files in this existing directory with the correct UID/GID + // and project ID. + ret = FixupAppDir(pathToCreate, mode, uid, gid, projectId); + } else { + ret = PrepareDirWithProjectId(pathToCreate, mode, uid, gid, projectId); + } + if (ret != 0) { return ret; } diff --git a/Utils.h b/Utils.h index 54b8dd8..21abc4d 100644 --- a/Utils.h +++ b/Utils.h @@ -57,7 +57,8 @@ int SetQuotaProjectId(const std::string& path, long projectId); * ONLY for use with app-specific data directories on external storage! * (eg, /Android/data/com.foo, /Android/obb/com.foo, etc.) */ -int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid); +int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appUid, + bool fixupExisting); /* fs_prepare_dir wrapper that creates with SELinux context */ status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 6aa9670..08b4661 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -466,6 +466,14 @@ binder::Status VoldNativeService::setupAppDir(const std::string& path, int32_t a return translate(VolumeManager::Instance()->setupAppDir(path, appUid)); } +binder::Status VoldNativeService::fixupAppDir(const std::string& path, int32_t appUid) { + ENFORCE_SYSTEM_OR_ROOT; + CHECK_ARGUMENT_PATH(path); + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->fixupAppDir(path, appUid)); +} + binder::Status VoldNativeService::createObb(const std::string& sourcePath, const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return) { diff --git a/VoldNativeService.h b/VoldNativeService.h index 6d00d2d..e04c259 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -66,6 +66,7 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status remountUid(int32_t uid, int32_t remountMode); binder::Status setupAppDir(const std::string& path, int32_t appUid); + binder::Status fixupAppDir(const std::string& path, int32_t appUid); binder::Status createObb(const std::string& sourcePath, const std::string& sourceKey, int32_t ownerGid, std::string* _aidl_return); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 6f15846..f7b36bf 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -814,7 +814,7 @@ int VolumeManager::unmountAll() { return 0; } -int VolumeManager::setupAppDir(const std::string& path, int32_t appUid) { +int VolumeManager::setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly) { // Only offer to create directories for paths managed by vold if (!StartsWith(path, "/storage/")) { LOG(ERROR) << "Failed to find mounted volume for " << path; @@ -859,8 +859,21 @@ int VolumeManager::setupAppDir(const std::string& path, int32_t appUid) { const std::string volumeRoot = volume->getRootPath(); // eg /data/media/0 + if (fixupExistingOnly && (access(lowerPath.c_str(), F_OK) != 0)) { + // Nothing to fixup + return OK; + } + // Create the app paths we need from the root - return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid); + return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid, fixupExistingOnly); +} + +int VolumeManager::fixupAppDir(const std::string& path, int32_t appUid) { + if (IsFilesystemSupported("sdcardfs")) { + //sdcardfs magically does this for us + return OK; + } + return setupAppDir(path, appUid, true /* fixupExistingOnly */); } int VolumeManager::createObb(const std::string& sourcePath, const std::string& sourceKey, diff --git a/VolumeManager.h b/VolumeManager.h index 765349d..afea54e 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -157,12 +157,23 @@ class VolumeManager { * requirements of the underlying filesystem and are of no concern to the * caller. * + * If fixupExistingOnly is set, we make sure to fixup any existing dirs and + * files in the passed in path, but only if that path exists; if it doesn't + * exist, this function doesn't create them. + * * Validates that given paths are absolute and that they contain no relative * "." or ".." paths or symlinks. Last path segment is treated as filename * and ignored, unless the path ends with "/". Also ensures that path * belongs to a volume managed by vold. */ - int setupAppDir(const std::string& path, int32_t appUid); + int setupAppDir(const std::string& path, int32_t appUid, bool fixupExistingOnly = false); + + /** + * Fixes up an existing application directory, as if it was created with + * setupAppDir() above. This includes fixing up the UID/GID, permissions and + * project IDs of the contained files and directories. + */ + int fixupAppDir(const std::string& path, int32_t appUid); int createObb(const std::string& path, const std::string& key, int32_t ownerGid, std::string* outVolId); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 78598b3..f1ada6c 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -55,6 +55,7 @@ interface IVold { void remountUid(int uid, int remountMode); void setupAppDir(@utf8InCpp String path, int appUid); + void fixupAppDir(@utf8InCpp String path, int appUid); @utf8InCpp String createObb(@utf8InCpp String sourcePath, @utf8InCpp String sourceKey, int ownerGid); From 07e64a4cea31cf12364e143f674a7c022b6ce8a3 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Tue, 11 Feb 2020 14:31:24 +0000 Subject: [PATCH 070/112] Mount direct boot apps obb dir after fuse is ready. - Remove bind mounting Android/ code as we want to bind mount obb dir for each process instead. - Set property "vold.vold.fuse_running_users" as an array of user id for which fuse is ready to use. - After fuse is ready for a user, fork a background process in vold to bind mount all direct boot apps for that user so its direct boot apps obb dir will be mounted to lower fs for imporoved performance. Bug: 148049767 Bug: 137890172 Test: After flag is enabled, AdoptableHostTest still pass. Change-Id: I90079fbeed1c91f9780ca71e37b0012884680b7c --- Process.cpp | 46 ++++++ Process.h | 1 + Utils.cpp | 51 ++++++ Utils.h | 7 + VolumeManager.cpp | 327 +++++++++++++++++++++++++++++++-------- VolumeManager.h | 9 ++ model/EmulatedVolume.cpp | 58 +++++-- model/EmulatedVolume.h | 3 + 8 files changed, 424 insertions(+), 78 deletions(-) diff --git a/Process.cpp b/Process.cpp index 3d8e3d7..277d6a3 100644 --- a/Process.cpp +++ b/Process.cpp @@ -29,6 +29,7 @@ #include #include +#include #include #include @@ -81,6 +82,51 @@ static bool checkSymlink(const std::string& path, const std::string& prefix) { return false; } +// TODO: Refactor the code with KillProcessesWithOpenFiles(). +int KillProcessesWithMounts(const std::string& prefix, int signal) { + std::unordered_set pids; + + auto proc_d = std::unique_ptr(opendir("/proc"), closedir); + if (!proc_d) { + PLOG(ERROR) << "Failed to open proc"; + return -1; + } + + struct dirent* proc_de; + while ((proc_de = readdir(proc_d.get())) != nullptr) { + // We only care about valid PIDs + pid_t pid; + if (proc_de->d_type != DT_DIR) continue; + if (!android::base::ParseInt(proc_de->d_name, &pid)) continue; + + // Look for references to prefix + std::string mounts_file(StringPrintf("/proc/%d/mounts", pid)); + auto fp = std::unique_ptr( + setmntent(mounts_file.c_str(), "r"), endmntent); + if (!fp) { + PLOG(WARNING) << "Failed to open " << mounts_file; + continue; + } + + // Check if obb directory is mounted, and get all packages of mounted app data directory. + mntent* mentry; + while ((mentry = getmntent(fp.get())) != nullptr) { + if (android::base::StartsWith(mentry->mnt_dir, prefix)) { + pids.insert(pid); + break; + } + } + } + if (signal != 0) { + for (const auto& pid : pids) { + LOG(WARNING) << "Killing pid "<< pid << " with signal " << strsignal(signal) << + " because it has a mount with prefix " << prefix; + kill(pid, signal); + } + } + return pids.size(); +} + int KillProcessesWithOpenFiles(const std::string& prefix, int signal) { std::unordered_set pids; diff --git a/Process.h b/Process.h index 1406782..1c59812 100644 --- a/Process.h +++ b/Process.h @@ -21,6 +21,7 @@ namespace android { namespace vold { int KillProcessesWithOpenFiles(const std::string& path, int signal); +int KillProcessesWithMounts(const std::string& path, int signal); } // namespace vold } // namespace android diff --git a/Utils.cpp b/Utils.cpp index 35839ac..5c58aaf 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -82,6 +82,9 @@ static const char* kAppDataDir = "/Android/data/"; static const char* kAppMediaDir = "/Android/media/"; static const char* kAppObbDir = "/Android/obb/"; +static const char* kMediaProviderCtx = "u:r:mediaprovider:"; +static const char* kMediaProviderAppCtx = "u:r:mediaprovider_app:"; + // Lock used to protect process-level SELinux changes from racing with each // other between multiple threads. static std::mutex kSecurityLock; @@ -382,6 +385,31 @@ status_t ForceUnmount(const std::string& path) { return -errno; } +status_t KillProcessesWithMountPrefix(const std::string& path) { + if (KillProcessesWithMounts(path, SIGINT) == 0) { + return OK; + } + if (sSleepOnUnmount) sleep(5); + + if (KillProcessesWithMounts(path, SIGTERM) == 0) { + return OK; + } + if (sSleepOnUnmount) sleep(5); + + if (KillProcessesWithMounts(path, SIGKILL) == 0) { + return OK; + } + if (sSleepOnUnmount) sleep(5); + + // Send SIGKILL a second time to determine if we've + // actually killed everyone mount + if (KillProcessesWithMounts(path, SIGKILL) == 0) { + return OK; + } + PLOG(ERROR) << "Failed to kill processes using " << path; + return -EBUSY; +} + status_t KillProcessesUsingPath(const std::string& path) { if (KillProcessesWithOpenFiles(path, SIGINT) == 0) { return OK; @@ -839,6 +867,19 @@ uint64_t GetTreeBytes(const std::string& path) { } } +// TODO: Use a better way to determine if it's media provider app. +bool IsFuseDaemon(const pid_t pid) { + auto path = StringPrintf("/proc/%d/mounts", pid); + char* tmp; + if (lgetfilecon(path.c_str(), &tmp) < 0) { + return false; + } + bool result = android::base::StartsWith(tmp, kMediaProviderAppCtx) + || android::base::StartsWith(tmp, kMediaProviderCtx); + freecon(tmp); + return result; +} + bool IsFilesystemSupported(const std::string& fsType) { std::string supported; if (!ReadFileToString(kProcFilesystems, &supported)) { @@ -1198,6 +1239,16 @@ bool writeStringToFile(const std::string& payload, const std::string& filename) return true; } +status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { + if (access(path.c_str(), F_OK) != 0) { + PLOG(WARNING) << "Dir does not exist: " << path; + if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) { + return -errno; + } + } + return OK; +} + status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, const std::string& relative_upper_path, android::base::unique_fd* fuse_fd) { std::string pre_fuse_path(StringPrintf("/mnt/user/%d", user_id)); diff --git a/Utils.h b/Utils.h index 54b8dd8..7cb4437 100644 --- a/Utils.h +++ b/Utils.h @@ -35,6 +35,7 @@ namespace android { namespace vold { static const char* kPropFuse = "persist.sys.fuse"; +static const char* kVoldAppDataIsolationEnabled = "persist.sys.vold_app_data_isolation_enabled"; /* SELinux contexts used depending on the block device type */ extern security_context_t sBlkidContext; @@ -68,6 +69,9 @@ status_t ForceUnmount(const std::string& path); /* Kills any processes using given path */ status_t KillProcessesUsingPath(const std::string& path); +/* Kills any processes using given mount prifix */ +status_t KillProcessesWithMountPrefix(const std::string& path); + /* Creates bind mount from source to target */ status_t BindMount(const std::string& source, const std::string& target); @@ -119,6 +123,7 @@ uint64_t GetFreeBytes(const std::string& path); uint64_t GetTreeBytes(const std::string& path); bool IsFilesystemSupported(const std::string& fsType); +bool IsFuseDaemon(const pid_t pid); /* Wipes contents of block device at given path */ status_t WipeBlockDevice(const std::string& path); @@ -142,6 +147,8 @@ std::string BuildDataUserDePath(const std::string& volumeUuid, userid_t userid); dev_t GetDevice(const std::string& path); +status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid); + status_t RestoreconRecursive(const std::string& path); // TODO: promote to android::base diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 6f15846..9efe01a 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -80,6 +80,7 @@ using android::vold::BindMount; using android::vold::CreateDir; using android::vold::DeleteDirContents; using android::vold::DeleteDirContentsAndDir; +using android::vold::EnsureDirExists; using android::vold::IsFilesystemSupported; using android::vold::PrepareAndroidDirs; using android::vold::PrepareAppDirFromRoot; @@ -104,6 +105,8 @@ static const unsigned int kMajorBlockMmc = 179; static const unsigned int kMajorBlockExperimentalMin = 240; static const unsigned int kMajorBlockExperimentalMax = 254; +using ScanProcCallback = bool(*)(uid_t uid, pid_t pid, int nsFd, const char* name, void* params); + VolumeManager* VolumeManager::sInstance = NULL; VolumeManager* VolumeManager::Instance() { @@ -534,9 +537,9 @@ int VolumeManager::setPrimary(const std::shared_ptr& // 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) { + const char* name) { if (setns(nsFd, CLONE_NEWNS) != 0) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns for %s :%s", de->d_name, + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns for %s :%s", name, strerror(errno)); return false; } @@ -553,59 +556,82 @@ static bool childProcess(const char* storageSource, const char* userSource, int 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)); + storageSource, 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, + "Failed to set MS_SLAVE to /storage for %s :%s", 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)); + userSource, name, strerror(errno)); return false; } return true; } -int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { - if (GetBoolProperty(android::vold::kPropFuse, false)) { - // TODO(135341433): Implement fuse specific logic. - return 0; - } - std::string mode; +// Fork the process and remount storage +bool forkAndRemountChild(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) { + int32_t mountMode = *static_cast(params); + std::string userSource; + std::string storageSource; + pid_t child; + // Need to fix these paths to account for when sdcardfs is gone switch (mountMode) { case VoldNativeService::REMOUNT_MODE_NONE: - mode = "none"; - break; + return true; case VoldNativeService::REMOUNT_MODE_DEFAULT: - mode = "default"; + storageSource = "/mnt/runtime/default"; break; case VoldNativeService::REMOUNT_MODE_READ: - mode = "read"; + storageSource = "/mnt/runtime/read"; break; case VoldNativeService::REMOUNT_MODE_WRITE: case VoldNativeService::REMOUNT_MODE_LEGACY: case VoldNativeService::REMOUNT_MODE_INSTALLER: - mode = "write"; + storageSource = "/mnt/runtime/write"; break; case VoldNativeService::REMOUNT_MODE_FULL: - mode = "full"; + storageSource = "/mnt/runtime/full"; break; case VoldNativeService::REMOUNT_MODE_PASS_THROUGH: - mode = "pass_through"; - break; + return true; default: PLOG(ERROR) << "Unknown mode " << std::to_string(mountMode); - return -1; + return false; } - LOG(DEBUG) << "Remounting " << uid << " as mode " << mode; + LOG(DEBUG) << "Remounting " << uid << " as " << storageSource; + // Fork a child to mount user-specific symlink helper into place + userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid)); + if (!(child = fork())) { + if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, name)) { + _exit(0); + } else { + _exit(1); + } + } + + if (child == -1) { + PLOG(ERROR) << "Failed to fork"; + return false; + } else { + TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0)); + } + return true; +} + +// Helper function to scan all processes in /proc and call the callback if: +// 1). pid belongs to an app process +// 2). If input uid is 0 or it matches the process uid +// 3). If userId is not -1 or userId matches the process userId +bool scanProcProcesses(uid_t uid, userid_t userId, ScanProcCallback callback, void* params) { DIR* dir; struct dirent* de; std::string rootName; @@ -613,24 +639,22 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { int pidFd; int nsFd; struct stat sb; - pid_t child; - std::string userSource; - std::string storageSource; static bool apexUpdatable = android::sysprop::ApexProperties::updatable().value_or(false); if (!(dir = opendir("/proc"))) { - PLOG(ERROR) << "Failed to opendir"; - return -1; + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to opendir"); + return false; } // Figure out root namespace to compare against below if (!android::vold::Readlinkat(dirfd(dir), "1/ns/mnt", &rootName)) { - PLOG(ERROR) << "Failed to read root namespace"; + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to read root namespace"); closedir(dir); - return -1; + return false; } + async_safe_format_log(ANDROID_LOG_INFO, "vold", "Start scanning all processes"); // Poke through all running PIDs look for apps running as UID while ((de = readdir(dir))) { pid_t pid; @@ -645,21 +669,23 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { goto next; } if (fstat(pidFd, &sb) != 0) { - PLOG(WARNING) << "Failed to stat " << de->d_name; + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to stat %s", de->d_name); goto next; } - if (sb.st_uid != uid) { + if (uid != 0 && sb.st_uid != uid) { + goto next; + } + if (userId != static_cast(-1) && multiuser_get_user_id(sb.st_uid) != userId) { goto next; } // Matches so far, but refuse to touch if in root namespace - LOG(DEBUG) << "Found matching PID " << de->d_name; if (!android::vold::Readlinkat(pidFd, "ns/mnt", &pidName)) { - PLOG(WARNING) << "Failed to read namespace for " << de->d_name; + async_safe_format_log(ANDROID_LOG_ERROR, "vold", + "Failed to read namespacefor %s", de->d_name); goto next; } if (rootName == pidName) { - LOG(WARNING) << "Skipping due to root namespace"; goto next; } @@ -674,11 +700,9 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { // non-Java process whose UID is < AID_APP_START. (The UID condition // is required to not filter out child processes spawned by apps.) if (!android::vold::Readlinkat(pidFd, "exe", &exeName)) { - PLOG(WARNING) << "Failed to read exe name for " << de->d_name; goto next; } if (!StartsWith(exeName, "/system/bin/app_process") && sb.st_uid < AID_APP_START) { - LOG(WARNING) << "Skipping due to native system process"; goto next; } } @@ -687,39 +711,13 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { // NOLINTNEXTLINE(android-cloexec-open): Deliberately not O_CLOEXEC nsFd = openat(pidFd, "ns/mnt", O_RDONLY); if (nsFd < 0) { - PLOG(WARNING) << "Failed to open namespace for " << de->d_name; + async_safe_format_log(ANDROID_LOG_ERROR, "vold", + "Failed to open namespace for %s", de->d_name); goto next; } - if (mode == "default") { - storageSource = "/mnt/runtime/default"; - } else if (mode == "read") { - storageSource = "/mnt/runtime/read"; - } else if (mode == "write") { - storageSource = "/mnt/runtime/write"; - } else if (mode == "full") { - storageSource = "/mnt/runtime/full"; - } else { - // Sane default of no storage visible. No need to fork a child - // to remount uid. - goto next; - } - - // Mount user-specific symlink helper into place - userSource = StringPrintf("/mnt/user/%d", multiuser_get_user_id(uid)); - if (!(child = fork())) { - if (childProcess(storageSource.c_str(), userSource.c_str(), nsFd, de)) { - _exit(0); - } else { - _exit(1); - } - } - - if (child == -1) { - PLOG(ERROR) << "Failed to fork"; - goto next; - } else { - TEMP_FAILURE_RETRY(waitpid(child, nullptr, 0)); + if (!callback(sb.st_uid, pid, nsFd, de->d_name, params)) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed in callback"); } next: @@ -727,9 +725,204 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { close(pidFd); } closedir(dir); + async_safe_format_log(ANDROID_LOG_INFO, "vold", "Finished scanning all processes"); + return true; +} + +int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { + if (GetBoolProperty(android::vold::kPropFuse, false)) { + // TODO(135341433): Implement fuse specific logic. + return 0; + } + return scanProcProcesses(uid, static_cast(-1), + forkAndRemountChild, &mountMode) ? 0 : -1; +} + +// Bind mount obb dir for an app if necessary. +// How it works: +// 1). Check if a pid is an app uid and not the FuseDaemon, if not then return. +// 2). Get the mounts for that pid. +// 3). If obb is already mounted then return, otherwise we need to mount obb for this pid. +// 4). Get all packages and uid mounted for jit profile. These packages are all packages with +// same uid or whitelisted apps. +// 5a). If there's no package, it means it's not a process running app data isolation, so +// just bind mount Android/obb dir. +// 5b). Otherwise, for each package, create obb dir if it's not created and bind mount it. +// TODO: Should we get some reliable data from system server instead of scanning /proc ? +static bool bindMountAppObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) { + if (uid < AID_APP_START || uid > AID_APP_END) { + return true; + } + if (android::vold::IsFuseDaemon(pid)) { + return true; + } + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Start mounting obb for uid:%d, pid:%d", uid, + pid); + + userid_t userId = multiuser_get_user_id(uid); + if (setns(nsFd, CLONE_NEWNS) != 0) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns %s", strerror(errno)); + return false; + } + + std::string profiles_path(StringPrintf("/data/misc/profiles/cur/%d/", userId)); + // We search both .../obb and .../obb/$PKG paths here. + std::string obb_path(StringPrintf("/storage/emulated/%d/Android/obb", userId)); + int profiles_path_len = profiles_path.length(); + int obb_path_len = obb_path.length(); + + // TODO: Refactor the code as a util function so we can reuse the mount parsing code. + std::string mounts_file(StringPrintf("/proc/%d/mounts", pid)); + auto fp = std::unique_ptr( + setmntent(mounts_file.c_str(), "r"), endmntent); + if (!fp) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Error opening %s: %s", + mounts_file.c_str(), strerror(errno)); + return false; + } + + // Check if obb directory is mounted, and get all packages of mounted app data directory. + bool obb_mounted = false; + std::vector pkg_name_list; + mntent* mentry; + while ((mentry = getmntent(fp.get())) != nullptr) { + if (strncmp(mentry->mnt_dir, profiles_path.c_str(), profiles_path_len) == 0) { + pkg_name_list.push_back(std::string(mentry->mnt_dir + profiles_path_len)); + } + if (strncmp(mentry->mnt_dir, obb_path.c_str(), obb_path_len) == 0) { + obb_mounted = true; + } + } + + // Obb mounted in zygote already, so skip it + if (obb_mounted) { + return true; + } + + // Ensure obb parent directory exists + std::string obbSource; + if (IsFilesystemSupported("sdcardfs")) { + obbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", userId); + } else { + obbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", userId, userId); + } + std::string obbTarget(StringPrintf("/storage/emulated/%d/Android/obb", userId)); + auto status = EnsureDirExists(obbSource, 0771, AID_MEDIA_RW, AID_MEDIA_RW); + if (status != OK) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to create dir %s %s", + obbSource.c_str(), strerror(-status)); + return false; + } + + // It means app data isolation is not applied to this, so we can just bind the whole obb + // directory instead. + if (pkg_name_list.empty()) { + async_safe_format_log(ANDROID_LOG_INFO, "vold", + "Bind mounting whole obb directory for pid %d", pid); + status = BindMount(obbSource, obbTarget); + if (status != OK) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", + obbSource.c_str(), obbTarget.c_str(), strerror(-status)); + return false; + } + return true; + } + + // Bind mount each app's obb directory + for (const auto& pkg_name : pkg_name_list) { + std::string appObbSource; + if (IsFilesystemSupported("sdcardfs")) { + appObbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s", + userId, pkg_name.c_str()); + } else { + appObbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s", + userId, userId, pkg_name.c_str()); + } + std::string appObbTarget(StringPrintf("/storage/emulated/%d/Android/obb/%s", + userId, pkg_name.c_str())); + + status = EnsureDirExists(appObbSource, 0770, uid, AID_MEDIA_RW); + if (status != OK) { + async_safe_format_log(ANDROID_LOG_INFO, "vold", "Failed to ensure dir %s exists", + appObbSource.c_str()); + continue; + } + async_safe_format_log(ANDROID_LOG_INFO, "vold", + "Bind mounting app obb directory(%s) for pid %d", pkg_name.c_str(), + pid); + status = BindMount(appObbSource, appObbTarget); + if (status != OK) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", + obbSource.c_str(), obbTarget.c_str(), strerror(-status)); + continue; + } + } + return true; +} + +int VolumeManager::remountAppObb(userid_t userId) { + if (!GetBoolProperty(android::vold::kPropFuse, false)) { + return 0; + } + LOG(INFO) << "Start remounting app obb"; + pid_t child; + if (!(child = fork())) { + // Child process + if (daemon(0, 0) == -1) { + PLOG(FATAL) << "Cannot create daemon"; + } + // TODO(149548518): Refactor the code so minimize the work after fork to prevent deadlock. + if (scanProcProcesses(0, userId, bindMountAppObbDir, nullptr)) { + // As some forked zygote processes may not setuid and recognized as an app yet, sleep + // 3s and try again to catch 'em all. + usleep(3 * 1000 * 1000); // 3s + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Retry remounting app obb"); + scanProcProcesses(0, userId, bindMountAppObbDir, nullptr); + _exit(0); + } else { + _exit(1); + } + } + if (child == -1) { + PLOG(ERROR) << "Failed to fork"; + return -1; + } else if (child == 0) { + // Parent + int stat_loc; + for (;;) { + if (waitpid(child, &stat_loc, 0) != -1 || errno != EINTR) { + break; + } + } + } return 0; } +bool VolumeManager::updateFuseMountedProperty() { + if (mFuseMountedUsers.size() == 0) { + android::base::SetProperty("vold.fuse_running_users", ""); + return true; + } + std::stringstream stream; + char const * sep = ""; + for (const auto& userId : mFuseMountedUsers) { + stream << sep; + stream << userId; + sep = ", "; + } + return android::base::SetProperty("vold.fuse_running_users", stream.str()); +} + +bool VolumeManager::addFuseMountedUser(userid_t userId) { + mFuseMountedUsers.insert(userId); + return updateFuseMountedProperty(); +} + +bool VolumeManager::removeFuseMountedUser(userid_t userId) { + mFuseMountedUsers.erase(userId); + return updateFuseMountedProperty(); +} + int VolumeManager::reset() { // Tear down all existing disks/volumes and start from a blank slate so // newly connected framework hears all events. @@ -745,6 +938,8 @@ int VolumeManager::reset() { updateVirtualDisk(); mAddedUsers.clear(); mStartedUsers.clear(); + mFuseMountedUsers.clear(); + updateFuseMountedProperty(); return 0; } @@ -764,6 +959,8 @@ int VolumeManager::shutdown() { mInternalEmulatedVolumes.clear(); mDisks.clear(); mPendingDisks.clear(); + mFuseMountedUsers.clear(); + updateFuseMountedProperty(); android::vold::sSleepOnUnmount = true; return 0; } diff --git a/VolumeManager.h b/VolumeManager.h index 765349d..479d99f 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -118,6 +118,10 @@ class VolumeManager { int setPrimary(const std::shared_ptr& vol); int remountUid(uid_t uid, int32_t remountMode); + int remountAppObb(userid_t userId); + + bool addFuseMountedUser(userid_t userId); + bool removeFuseMountedUser(userid_t userId); /* Reset all internal state, typically during framework boot */ int reset(); @@ -190,6 +194,8 @@ class VolumeManager { void handleDiskChanged(dev_t device); void handleDiskRemoved(dev_t device); + bool updateFuseMountedProperty(); + std::mutex mLock; std::mutex mCryptLock; @@ -213,6 +219,9 @@ class VolumeManager { int mNextObbId; int mNextStubId; bool mSecureKeyguardShowing; + + // Set of all user id that fuse is ready to use. + std::unordered_set mFuseMountedUsers; }; #endif diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 8f8c87a..c2f92e4 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -49,6 +49,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) mLabel = "emulated"; mFuseMounted = false; mUseSdcardFs = IsFilesystemSupported("sdcardfs"); + mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, @@ -59,6 +60,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s mLabel = fsUuid; mFuseMounted = false; mUseSdcardFs = IsFilesystemSupported("sdcardfs"); + mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } EmulatedVolume::~EmulatedVolume() {} @@ -94,14 +96,19 @@ status_t EmulatedVolume::mountFuseBindMounts() { } else { androidSource = StringPrintf("/%s/%d/Android", mRawPath.c_str(), userId); } - std::string androidTarget( - StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); - auto status = doFuseBindMount(androidSource, androidTarget); + status_t status = OK; + // When app data isolation is enabled, obb/ will be mounted per app, otherwise we should + // bind mount the whole Android/ to speed up reading. + if (!mAppDataIsolationEnabled) { + std::string androidTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); + status = doFuseBindMount(androidSource, androidTarget); + } + if (status != OK) { return status; } - // Installers get the same view as all other apps, with the sole exception that the // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires // a special bind mount, since app-private and OBB dirs share the same GID, but we @@ -118,6 +125,19 @@ status_t EmulatedVolume::mountFuseBindMounts() { if (status != OK) { return status; } + + if (mAppDataIsolationEnabled) { + // Starting from now, fuse is running, and zygote will bind app obb data directory + if (!VolumeManager::Instance()->addFuseMountedUser(userId)) { + return UNKNOWN_ERROR; + } + + // As all new processes created by zygote will bind app obb data directory, we just need + // to have a snapshot of all existing processes and see if any existing process needs to + // remount obb data directory. + VolumeManager::Instance()->remountAppObb(userId); + } + return OK; } @@ -135,16 +155,22 @@ status_t EmulatedVolume::unmountFuseBindMounts() { // Intentional continue to try to unmount the other bind mount } } + // When app data isolation is enabled, kill all apps that obb/ is mounted, otherwise we should + // umount the whole Android/ dir. + if (mAppDataIsolationEnabled) { + std::string appObbDir(StringPrintf("%s/%d/Android/obb", getPath().c_str(), userId)); + KillProcessesWithMountPrefix(appObbDir); + } else { + std::string androidTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); - std::string androidTarget( - StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); - - LOG(INFO) << "Unmounting " << androidTarget; - auto status = UnmountTree(androidTarget); - if (status != OK) { - return status; + LOG(INFO) << "Unmounting " << androidTarget; + auto status = UnmountTree(androidTarget); + if (status != OK) { + return status; + } + LOG(INFO) << "Unmounted " << androidTarget; } - LOG(INFO) << "Unmounted " << androidTarget; return OK; } @@ -281,9 +307,15 @@ status_t EmulatedVolume::doUnmount() { if (mFuseMounted) { std::string label = getLabel(); + + // Update fuse mounted record + if (mAppDataIsolationEnabled && + !VolumeManager::Instance()->removeFuseMountedUser(userId)) { + return UNKNOWN_ERROR; + } + // Ignoring unmount return status because we do want to try to unmount // the rest cleanly. - unmountFuseBindMounts(); if (UnmountUserFuse(userId, getInternalPath(), label) != OK) { PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index 3f1b2e3..12d01ec 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -65,6 +65,9 @@ class EmulatedVolume : public VolumeBase { /* Whether to use sdcardfs for this volume */ bool mUseSdcardFs; + /* Whether to use app data isolation is enabled tor this volume */ + bool mAppDataIsolationEnabled; + DISALLOW_COPY_AND_ASSIGN(EmulatedVolume); }; From aee40511ae3082c12ff1ef413dde12b7aba21d4f Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 18 Feb 2020 16:29:25 +0100 Subject: [PATCH 071/112] Switch to new project ID constants. Use new constants, instead of reusing previous sdcardfs values. Bug: 146419093 Test: lsattr -pR Change-Id: I7409d86cac5360e125e843cc79f3c5f41d74dd1e --- FsCrypt.cpp | 4 +++- Utils.cpp | 16 +++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index 141f4c9..8682bdc 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -40,6 +40,7 @@ #include #include +#include #include "android/os/IVold.h" @@ -804,7 +805,8 @@ bool fscrypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ // Setup quota project ID and inheritance policy if (!IsFilesystemSupported("sdcardfs")) { if (SetQuotaInherit(media_ce_path) != 0) return false; - if (SetQuotaProjectId(media_ce_path, multiuser_get_uid(user_id, AID_MEDIA_RW)) != 0) { + if (SetQuotaProjectId(media_ce_path, + multiuser_get_uid(user_id, PROJECT_ID_EXT_DEFAULT)) != 0) { return false; } } diff --git a/Utils.cpp b/Utils.cpp index 9f9b357..0974a0b 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -318,7 +319,13 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int } std::string pathToCreate = root + appDir; int depth = 0; - bool withinCache = false; + // Derive initial project ID + if (appDir == kAppDataDir || appDir == kAppMediaDir) { + projectId = uid - AID_APP_START + PROJECT_ID_EXT_DATA_START; + } else if (appDir == kAppObbDir) { + projectId = uid - AID_APP_START + PROJECT_ID_EXT_OBB_START; + } + while ((pos = leftToCreate.find('/')) != std::string::npos) { std::string component = leftToCreate.substr(0, pos + 1); leftToCreate = leftToCreate.erase(0, pos + 1); @@ -329,12 +336,7 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int // Android/data, eg Android/data/com.foo/cache // Note that this "sticks" - eg subdirs of this dir need the same // project ID. - withinCache = true; - } - if (withinCache) { - projectId = uid - AID_APP_START + AID_CACHE_GID_START; - } else { - projectId = uid - AID_APP_START + AID_EXT_GID_START; + projectId = uid - AID_APP_START + PROJECT_ID_EXT_CACHE_START; } if (fixupExisting && access(pathToCreate.c_str(), F_OK) == 0) { From 4fcb707ecdb0df9111d620f0c0c2aca025c392ff Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Thu, 23 Jan 2020 13:23:26 +0900 Subject: [PATCH 072/112] Use optional for nullable types AIDL generates optional for nullable T types for C++, which is more efficient and idomatic and easy to use. Bug: 144773267 Test: build/flash/boot Merged-In: I98549c8614c9152d5d45e2f1f33f2f3c31a9bbbf Change-Id: I98549c8614c9152d5d45e2f1f33f2f3c31a9bbbf (cherry picked from commit 3ce0ee5363c9325e5c95dadbe24a03d94aedc90e) Exempt-From-Owner-Approval: CP from master --- VoldNativeService.cpp | 4 ++-- VoldNativeService.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 08b4661..788d750 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -811,7 +811,7 @@ binder::Status VoldNativeService::lockUserKey(int32_t userId) { return translateBool(fscrypt_lock_user_key(userId)); } -binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr& uuid, +binder::Status VoldNativeService::prepareUserStorage(const std::optional& uuid, int32_t userId, int32_t userSerial, int32_t flags) { ENFORCE_SYSTEM_OR_ROOT; @@ -823,7 +823,7 @@ binder::Status VoldNativeService::prepareUserStorage(const std::unique_ptr& uuid, +binder::Status VoldNativeService::destroyUserStorage(const std::optional& uuid, int32_t userId, int32_t flags) { ENFORCE_SYSTEM_OR_ROOT; std::string empty_string = ""; diff --git a/VoldNativeService.h b/VoldNativeService.h index e04c259..61f5c3f 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -123,9 +123,9 @@ class VoldNativeService : public BinderService, public os::Bn const std::string& secret); binder::Status lockUserKey(int32_t userId); - binder::Status prepareUserStorage(const std::unique_ptr& uuid, int32_t userId, + binder::Status prepareUserStorage(const std::optional& uuid, int32_t userId, int32_t userSerial, int32_t flags); - binder::Status destroyUserStorage(const std::unique_ptr& uuid, int32_t userId, + binder::Status destroyUserStorage(const std::optional& uuid, int32_t userId, int32_t flags); binder::Status prepareSandboxForApp(const std::string& packageName, int32_t appId, From 1eaea5a6a21a2eb9ec0debb69a8718861e13b4d7 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Thu, 27 Feb 2020 18:21:55 +0000 Subject: [PATCH 073/112] fskeyring & userspace reboot: support DE keys During userspace reboot /data might be unmounted, which means that if device supports filesystem keyring, DE keys will be lost and are needed to be re-installed. Test: adb shell setprop sys.init.userdata_remount.force_umount 1 Test: adb shell svc power reboot userspace Test: atest CtsUserspaceRebootHostSideTestCases Bug: 143970043 Change-Id: I153caa1d7c373b3c906a34f1184c681e52854a9d --- FsCrypt.cpp | 25 ++++++++++--------------- 1 file changed, 10 insertions(+), 15 deletions(-) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index 276444c..d43bc08 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -87,8 +87,6 @@ const std::string prepare_subdirs_path = "/system/bin/vold_prepare_subdirs"; const std::string systemwide_volume_key_dir = std::string() + DATA_MNT_POINT + "/misc/vold/volume_keys"; -bool s_systemwide_keys_initialized = false; - // Some users are ephemeral, don't try to wipe their keys from disk std::set s_ephemeral_users; @@ -363,15 +361,17 @@ static bool load_all_de_keys() { continue; } userid_t user_id = std::stoi(entry->d_name); - if (s_de_policies.count(user_id) == 0) { - auto key_path = de_dir + "/" + entry->d_name; - KeyBuffer de_key; - if (!retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false; - EncryptionPolicy de_policy; - if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false; - s_de_policies[user_id] = de_policy; - LOG(DEBUG) << "Installed de key for user " << user_id; + auto key_path = de_dir + "/" + entry->d_name; + KeyBuffer de_key; + if (!retrieveKey(key_path, kEmptyAuthentication, &de_key)) return false; + EncryptionPolicy de_policy; + if (!install_storage_key(DATA_MNT_POINT, options, de_key, &de_policy)) return false; + auto ret = s_de_policies.insert({user_id, de_policy}); + if (!ret.second && ret.first->second != de_policy) { + LOG(ERROR) << "DE policy for user" << user_id << " changed"; + return false; } + LOG(DEBUG) << "Installed de key for user " << user_id; } // fscrypt:TODO: go through all DE directories, ensure that all user dirs have the // correct policy set on them, and that no rogue ones exist. @@ -381,10 +381,6 @@ static bool load_all_de_keys() { bool fscrypt_initialize_systemwide_keys() { LOG(INFO) << "fscrypt_initialize_systemwide_keys"; - if (s_systemwide_keys_initialized) { - LOG(INFO) << "Already initialized"; - return true; - } EncryptionOptions options; if (!get_data_file_encryption_options(&options)) return false; @@ -418,7 +414,6 @@ bool fscrypt_initialize_systemwide_keys() { LOG(INFO) << "Wrote per boot key reference to:" << per_boot_ref_filename; if (!android::vold::FsyncDirectory(device_key_dir)) return false; - s_systemwide_keys_initialized = true; return true; } From c1e33a3cc979ea2ea4a808f2fd7bfddd53789d1a Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Thu, 20 Feb 2020 16:10:01 +0000 Subject: [PATCH 074/112] Add Android/data mounting along with obb mounting in vold We should mount Android/data also, not only Android/obb. Test: After flag is enabled, AdoptableHostTest still pass. Bug: 148049767 Bug: 150584566 Change-Id: I26dc3756aa5843b85565495e9c2698130113f49a Merged-In: I26dc3756aa5843b85565495e9c2698130113f49a (cherry picked from commit d88e090098d4a95112aecb135d1bcba96150bdd1) --- VolumeManager.cpp | 75 ++++++++++++++++++++++++++++++---------- VolumeManager.h | 2 +- model/EmulatedVolume.cpp | 4 +-- 3 files changed, 59 insertions(+), 22 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 2b6565c..fce977e 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -738,7 +738,7 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { forkAndRemountChild, &mountMode) ? 0 : -1; } -// Bind mount obb dir for an app if necessary. +// Bind mount obb & data dir for an app if necessary. // How it works: // 1). Check if a pid is an app uid and not the FuseDaemon, if not then return. // 2). Get the mounts for that pid. @@ -746,18 +746,18 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { // 4). Get all packages and uid mounted for jit profile. These packages are all packages with // same uid or whitelisted apps. // 5a). If there's no package, it means it's not a process running app data isolation, so -// just bind mount Android/obb dir. +// just bind mount Android/obb & Android/data dir. // 5b). Otherwise, for each package, create obb dir if it's not created and bind mount it. // TODO: Should we get some reliable data from system server instead of scanning /proc ? -static bool bindMountAppObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) { +static bool bindMountAppDataObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) { if (uid < AID_APP_START || uid > AID_APP_END) { return true; } if (android::vold::IsFuseDaemon(pid)) { return true; } - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Start mounting obb for uid:%d, pid:%d", uid, - pid); + async_safe_format_log(ANDROID_LOG_ERROR, "vold", + "Start mounting obb and data for uid:%d, pid:%d", uid, pid); userid_t userId = multiuser_get_user_id(uid); if (setns(nsFd, CLONE_NEWNS) != 0) { @@ -782,6 +782,7 @@ static bool bindMountAppObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, } // Check if obb directory is mounted, and get all packages of mounted app data directory. + // We only need to check obb directory and assume if obb is mounted, data is mounted also. bool obb_mounted = false; std::vector pkg_name_list; mntent* mentry; @@ -799,47 +800,70 @@ static bool bindMountAppObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, return true; } - // Ensure obb parent directory exists - std::string obbSource; + std::string obbSource, dataSource; if (IsFilesystemSupported("sdcardfs")) { obbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", userId); + dataSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/data", userId); } else { obbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", userId, userId); + dataSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/data", userId, userId); } std::string obbTarget(StringPrintf("/storage/emulated/%d/Android/obb", userId)); + std::string dataTarget(StringPrintf("/storage/emulated/%d/Android/data", userId)); + + // TODO: Review if these checks are still necessary auto status = EnsureDirExists(obbSource, 0771, AID_MEDIA_RW, AID_MEDIA_RW); if (status != OK) { async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to create dir %s %s", obbSource.c_str(), strerror(-status)); return false; } + status = EnsureDirExists(dataSource, 0771, AID_MEDIA_RW, AID_MEDIA_RW); + if (status != OK) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to create dir %s %s", + dataSource.c_str(), strerror(-status)); + return false; + } // It means app data isolation is not applied to this, so we can just bind the whole obb // directory instead. if (pkg_name_list.empty()) { async_safe_format_log(ANDROID_LOG_INFO, "vold", - "Bind mounting whole obb directory for pid %d", pid); - status = BindMount(obbSource, obbTarget); - if (status != OK) { + "Bind mounting whole obb and data directory for pid %d", pid); + auto status1 = BindMount(obbSource, obbTarget); + // Still bind mount data even obb fails, just slower to access obb dir + auto status2 = BindMount(dataSource, dataTarget); + if (status1 != OK) { async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", obbSource.c_str(), obbTarget.c_str(), strerror(-status)); return false; } + if (status2 != OK) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", + dataSource.c_str(), dataTarget.c_str(), strerror(-status)); + return false; + } return true; } // Bind mount each app's obb directory for (const auto& pkg_name : pkg_name_list) { - std::string appObbSource; + std::string appObbSource, appDataSource; if (IsFilesystemSupported("sdcardfs")) { appObbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s", userId, pkg_name.c_str()); + appDataSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/data/%s", + userId, pkg_name.c_str()); } else { appObbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s", userId, userId, pkg_name.c_str()); + appDataSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/data/%s", + userId, userId, pkg_name.c_str()); } std::string appObbTarget(StringPrintf("/storage/emulated/%d/Android/obb/%s", userId, pkg_name.c_str())); + std::string appDataTarget(StringPrintf("/storage/emulated/%d/Android/data/%s", + userId, pkg_name.c_str())); status = EnsureDirExists(appObbSource, 0770, uid, AID_MEDIA_RW); if (status != OK) { @@ -847,24 +871,37 @@ static bool bindMountAppObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, appObbSource.c_str()); continue; } - async_safe_format_log(ANDROID_LOG_INFO, "vold", - "Bind mounting app obb directory(%s) for pid %d", pkg_name.c_str(), - pid); - status = BindMount(appObbSource, appObbTarget); + status = EnsureDirExists(appDataSource, 0770, uid, AID_MEDIA_RW); if (status != OK) { + async_safe_format_log(ANDROID_LOG_INFO, "vold", "Failed to ensure dir %s exists", + appDataSource.c_str()); + continue; + } + async_safe_format_log(ANDROID_LOG_INFO, "vold", + "Bind mounting app obb and data directory(%s) for pid %d", + pkg_name.c_str(), pid); + auto status1 = BindMount(appObbSource, appObbTarget); + // Still bind mount data even obb fails, just slower to access obb dir + auto status2 = BindMount(appDataSource, appDataTarget); + if (status1 != OK) { async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", obbSource.c_str(), obbTarget.c_str(), strerror(-status)); continue; } + if (status2 != OK) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", + appDataSource.c_str(), appDataTarget.c_str(), strerror(-status)); + continue; + } } return true; } -int VolumeManager::remountAppObb(userid_t userId) { +int VolumeManager::remountAppStorageDirs(userid_t userId) { if (!GetBoolProperty(android::vold::kPropFuse, false)) { return 0; } - LOG(INFO) << "Start remounting app obb"; + LOG(INFO) << "Start remounting app obb and data"; pid_t child; if (!(child = fork())) { // Child process @@ -872,12 +909,12 @@ int VolumeManager::remountAppObb(userid_t userId) { PLOG(FATAL) << "Cannot create daemon"; } // TODO(149548518): Refactor the code so minimize the work after fork to prevent deadlock. - if (scanProcProcesses(0, userId, bindMountAppObbDir, nullptr)) { + if (scanProcProcesses(0, userId, bindMountAppDataObbDir, nullptr)) { // As some forked zygote processes may not setuid and recognized as an app yet, sleep // 3s and try again to catch 'em all. usleep(3 * 1000 * 1000); // 3s async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Retry remounting app obb"); - scanProcProcesses(0, userId, bindMountAppObbDir, nullptr); + scanProcProcesses(0, userId, bindMountAppDataObbDir, nullptr); _exit(0); } else { _exit(1); diff --git a/VolumeManager.h b/VolumeManager.h index a094eae..bf05dcf 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -118,7 +118,7 @@ class VolumeManager { int setPrimary(const std::shared_ptr& vol); int remountUid(uid_t uid, int32_t remountMode); - int remountAppObb(userid_t userId); + int remountAppStorageDirs(userid_t userId); bool addFuseMountedUser(userid_t userId); bool removeFuseMountedUser(userid_t userId); diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index c2f92e4..1391685 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -127,7 +127,7 @@ status_t EmulatedVolume::mountFuseBindMounts() { } if (mAppDataIsolationEnabled) { - // Starting from now, fuse is running, and zygote will bind app obb data directory + // Starting from now, fuse is running, and zygote will bind app obb & data directory if (!VolumeManager::Instance()->addFuseMountedUser(userId)) { return UNKNOWN_ERROR; } @@ -135,7 +135,7 @@ status_t EmulatedVolume::mountFuseBindMounts() { // As all new processes created by zygote will bind app obb data directory, we just need // to have a snapshot of all existing processes and see if any existing process needs to // remount obb data directory. - VolumeManager::Instance()->remountAppObb(userId); + VolumeManager::Instance()->remountAppStorageDirs(userId); } return OK; From 79b03ff9e6766def10f0596664fa7bd260823433 Mon Sep 17 00:00:00 2001 From: Hyangseok Chae Date: Thu, 27 Feb 2020 18:21:50 +0900 Subject: [PATCH 075/112] umount /data/user/0 before umount /data FDE device has shut down and restart the framework. But restart is not triggered due to umount fail. umount /data fail with "device is busy" It is because bind mount /data/data to /data/user/0 We need umount /data/user/0 before umount /data Bug: 148004718 Test: Flash GSI and check boot with FDE and FBE device. Change-Id: I919f9e31a9d2d745b297a7ab99b399aa9b293b39 Merged-In: I919f9e31a9d2d745b297a7ab99b399aa9b293b39 (cherry picked from commit 3cf3233bac176744d43c682b7f9244db58c3402a) --- cryptfs.cpp | 40 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/cryptfs.cpp b/cryptfs.cpp index 1431459..1ddb34b 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -54,6 +55,7 @@ #include #include #include +#include #include #include #include @@ -1396,8 +1398,46 @@ static int create_encrypted_random_key(const char* passwd, unsigned char* master return encrypt_master_key(passwd, salt, key_buf, master_key, crypt_ftr); } +static void ensure_subdirectory_unmounted(const char *prefix) { + std::vector umount_points; + std::unique_ptr mnts(setmntent("/proc/mounts", "r"), endmntent); + if (!mnts) { + SLOGW("could not read mount files"); + return; + } + + //Find sudirectory mount point + mntent* mentry; + std::string top_directory(prefix); + if (!android::base::EndsWith(prefix, "/")) { + top_directory = top_directory + "/"; + } + while ((mentry = getmntent(mnts.get())) != nullptr) { + if (strcmp(mentry->mnt_dir, top_directory.c_str()) == 0) { + continue; + } + + if (android::base::StartsWith(mentry->mnt_dir, top_directory)) { + SLOGW("found sub-directory mount %s - %s\n", prefix, mentry->mnt_dir); + umount_points.push_back(mentry->mnt_dir); + } + } + + //Sort by path length to umount longest path first + std::sort(std::begin(umount_points), std::end(umount_points), + [](const std::string& s1, const std::string& s2) {return s1.length() > s2.length(); }); + + for (std::string& mount_point : umount_points) { + umount(mount_point.c_str()); + SLOGW("umount sub-directory mount %s\n", mount_point.c_str()); + } +} + static int wait_and_unmount(const char* mountpoint, bool kill) { int i, err, rc; + + // Subdirectory mount will cause a failure of umount. + ensure_subdirectory_unmounted(mountpoint); #define WAIT_UNMOUNT_COUNT 20 /* Now umount the tmpfs filesystem */ From 7de5377c89049a60f5e11a453fa7934359842fca Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 2 Mar 2020 12:57:58 -0800 Subject: [PATCH 076/112] Use the blk_device supplied by vdc encryptFstab fs_mgr may put other dm devices on top of the raw disk, such as for checkpointing, and it hands metadata encryption the uppermost device in vdc. That's what should be encrypted, not the raw disk. Bug: 150354860 Test: Treehugger Merged-In: I279f087b1b7aded40c5a62281154851ce970ba70 Change-Id: I279f087b1b7aded40c5a62281154851ce970ba70 --- MetadataCrypt.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 7891bee..8227e74 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -286,11 +286,6 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: LOG(ERROR) << "Failed to get data_rec for " << mount_point; return false; } - if (blk_device != data_rec->blk_device) { - LOG(ERROR) << "blk_device " << blk_device << " does not match fstab entry " - << data_rec->blk_device << " for " << mount_point; - return false; - } bool is_legacy; if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false; @@ -319,8 +314,7 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: std::string crypto_blkdev; uint64_t nr_sec; - if (!create_crypto_blk_dev(kDmNameUserdata, data_rec->blk_device, key, options, &crypto_blkdev, - &nr_sec)) + if (!create_crypto_blk_dev(kDmNameUserdata, blk_device, key, options, &crypto_blkdev, &nr_sec)) return false; // FIXME handle the corrupt case @@ -341,7 +335,7 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: } LOG(DEBUG) << "Mounting metadata-encrypted filesystem:" << mount_point; - mount_via_fs_mgr(data_rec->mount_point.c_str(), crypto_blkdev.c_str()); + mount_via_fs_mgr(mount_point.c_str(), crypto_blkdev.c_str()); return true; } From 1ee35cf002de9f6aaa6f33e67d882cdbbaa35cc2 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Fri, 28 Feb 2020 19:50:31 +0000 Subject: [PATCH 077/112] fskeyring & userspace reboot: support CE keys During userspace reboot /data might be unmounted & remounted, meaning that CE keys stored in fs-level keyring will be lost. In order to be able to restore them, when installing new key to fs-level keyring, it's also added to session-level keyring with type "fscrypt-provisioning". Then when init_user0 is called during userspace reboot, vold will try to load CE keys from the session-level keyring back into fs-level keyring for all the users that were unlocked before the reboot. If for any user vold fails to install the key, init_user0 will fail and fallback to hard reboot will be triggered. Test: set a pin pattern Test: adb shell setprop sys.init.userdata_remount.force_umount 1 Test: adb shell svc power reboot userspace Test: atest CtsUserspaceRebootHostSideTestCases Bug: 143970043 Change-Id: I37603dc136c7ededc7b0381e4d730cb0ffd912b4 --- FsCrypt.cpp | 18 +++++++ KeyUtil.cpp | 125 ++++++++++++++++++++++++++++++++++++++++++------- KeyUtil.h | 17 +++++-- fscrypt_uapi.h | 10 +++- 4 files changed, 149 insertions(+), 21 deletions(-) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index d43bc08..d8af6f4 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -378,6 +378,17 @@ static bool load_all_de_keys() { return true; } +// Attempt to reinstall CE keys for users that we think are unlocked. +static bool try_reload_ce_keys() { + for (const auto& it : s_ce_policies) { + if (!android::vold::reloadKeyFromSessionKeyring(DATA_MNT_POINT, it.second)) { + LOG(ERROR) << "Failed to load CE key from session keyring for user " << it.first; + return false; + } + } + return true; +} + bool fscrypt_initialize_systemwide_keys() { LOG(INFO) << "fscrypt_initialize_systemwide_keys"; @@ -444,6 +455,13 @@ bool fscrypt_init_user0() { fscrypt_unlock_user_key(0, 0, "!", "!"); } + // In some scenarios (e.g. userspace reboot) we might unmount userdata + // without doing a hard reboot. If CE keys were stored in fs keyring then + // they will be lost after unmount. Attempt to re-install them. + if (fscrypt_is_native() && android::vold::isFsKeyringSupported()) { + if (!try_reload_ce_keys()) return false; + } + return true; } diff --git a/KeyUtil.cpp b/KeyUtil.cpp index 6200c42..3359699 100644 --- a/KeyUtil.cpp +++ b/KeyUtil.cpp @@ -155,7 +155,7 @@ static bool fscryptKeyring(key_serial_t* device_keyring) { return true; } -// Add an encryption key to the legacy global session keyring. +// Add an encryption key of type "logon" to the global session keyring. static bool installKeyLegacy(const KeyBuffer& key, const std::string& raw_ref) { // Place fscrypt_key into automatically zeroing buffer. KeyBuffer fsKeyBuffer(sizeof(fscrypt_key)); @@ -178,6 +178,32 @@ static bool installKeyLegacy(const KeyBuffer& key, const std::string& raw_ref) { return true; } +// Installs fscrypt-provisioning key into session level kernel keyring. +// This allows for the given key to be installed back into filesystem keyring. +// For more context see reloadKeyFromSessionKeyring. +static bool installProvisioningKey(const KeyBuffer& key, const std::string& ref, + const fscrypt_key_specifier& key_spec) { + key_serial_t device_keyring; + if (!fscryptKeyring(&device_keyring)) return false; + + // Place fscrypt_provisioning_key_payload into automatically zeroing buffer. + KeyBuffer buf(sizeof(fscrypt_provisioning_key_payload) + key.size(), 0); + fscrypt_provisioning_key_payload& provisioning_key = + *reinterpret_cast(buf.data()); + memcpy(provisioning_key.raw, key.data(), key.size()); + provisioning_key.type = key_spec.type; + + key_serial_t key_id = add_key("fscrypt-provisioning", ref.c_str(), (void*)&provisioning_key, + buf.size(), device_keyring); + if (key_id == -1) { + PLOG(ERROR) << "Failed to insert fscrypt-provisioning key for " << ref + << " into session keyring"; + return false; + } + LOG(DEBUG) << "Added fscrypt-provisioning key for " << ref << " to session keyring"; + return true; +} + // Build a struct fscrypt_key_specifier for use in the key management ioctls. static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolicy& policy) { switch (policy.options.version) { @@ -205,6 +231,34 @@ static bool buildKeySpecifier(fscrypt_key_specifier* spec, const EncryptionPolic } } +// Installs key into keyring of a filesystem mounted on |mountpoint|. +// +// It's callers responsibility to fill key specifier, and either arg->raw or arg->key_id. +// +// In case arg->key_spec.type equals to FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER +// arg->key_spec.u.identifier will be populated with raw key reference generated +// by kernel. +// +// For documentation on difference between arg->raw and arg->key_id see +// https://www.kernel.org/doc/html/latest/filesystems/fscrypt.html#fs-ioc-add-encryption-key +static bool installFsKeyringKey(const std::string& mountpoint, const EncryptionOptions& options, + fscrypt_add_key_arg* arg) { + if (options.use_hw_wrapped_key) arg->flags |= FSCRYPT_ADD_KEY_FLAG_WRAPPED; + + android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + if (fd == -1) { + PLOG(ERROR) << "Failed to open " << mountpoint << " to install key"; + return false; + } + + if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) { + PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint; + return false; + } + + return true; +} + bool installKey(const std::string& mountpoint, const EncryptionOptions& options, const KeyBuffer& key, EncryptionPolicy* policy) { policy->options = options; @@ -240,33 +294,24 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options, return false; } - if (options.use_hw_wrapped_key) arg->flags |= FSCRYPT_ADD_KEY_FLAG_WRAPPED; - // Provide the raw key. arg->raw_size = key.size(); memcpy(arg->raw, key.data(), key.size()); - android::base::unique_fd fd(open(mountpoint.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); - if (fd == -1) { - PLOG(ERROR) << "Failed to open " << mountpoint << " to install key"; - return false; - } - - if (ioctl(fd, FS_IOC_ADD_ENCRYPTION_KEY, arg) != 0) { - PLOG(ERROR) << "Failed to install fscrypt key to " << mountpoint; - return false; - } + if (!installFsKeyringKey(mountpoint, options, arg)) return false; if (arg->key_spec.type == FSCRYPT_KEY_SPEC_TYPE_IDENTIFIER) { // Retrieve the key identifier that the kernel computed. policy->key_raw_ref = std::string((char*)arg->key_spec.u.identifier, FSCRYPT_KEY_IDENTIFIER_SIZE); } - LOG(DEBUG) << "Installed fscrypt key with ref " << keyrefstring(policy->key_raw_ref) << " to " - << mountpoint; + std::string ref = keyrefstring(policy->key_raw_ref); + LOG(DEBUG) << "Installed fscrypt key with ref " << ref << " to " << mountpoint; + + if (!installProvisioningKey(key, ref, arg->key_spec)) return false; return true; } -// Remove an encryption key from the legacy global session keyring. +// Remove an encryption key of type "logon" from the global session keyring. static bool evictKeyLegacy(const std::string& raw_ref) { key_serial_t device_keyring; if (!fscryptKeyring(&device_keyring)) return false; @@ -289,6 +334,26 @@ static bool evictKeyLegacy(const std::string& raw_ref) { return success; } +static bool evictProvisioningKey(const std::string& ref) { + key_serial_t device_keyring; + if (!fscryptKeyring(&device_keyring)) { + return false; + } + + auto key_serial = keyctl_search(device_keyring, "fscrypt-provisioning", ref.c_str(), 0); + if (key_serial == -1 && errno != ENOKEY) { + PLOG(ERROR) << "Error searching session keyring for fscrypt-provisioning key for " << ref; + return false; + } + + if (key_serial != -1 && keyctl_unlink(key_serial, device_keyring) != 0) { + PLOG(ERROR) << "Failed to unlink fscrypt-provisioning key for " << ref + << " from session keyring"; + return false; + } + return true; +} + bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) { if (policy.options.version == 1 && !isFsKeyringSupported()) { return evictKeyLegacy(policy.key_raw_ref); @@ -322,6 +387,8 @@ bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy) { LOG(ERROR) << "Files still open after removing key with ref " << ref << ". These files were not locked!"; } + + if (!evictProvisioningKey(ref)) return false; return true; } @@ -343,5 +410,31 @@ bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_p return true; } +bool reloadKeyFromSessionKeyring(const std::string& mountpoint, const EncryptionPolicy& policy) { + key_serial_t device_keyring; + if (!fscryptKeyring(&device_keyring)) { + return false; + } + + std::string ref = keyrefstring(policy.key_raw_ref); + auto key_serial = keyctl_search(device_keyring, "fscrypt-provisioning", ref.c_str(), 0); + if (key_serial == -1) { + PLOG(ERROR) << "Failed to find fscrypt-provisioning key for " << ref + << " in session keyring"; + return false; + } + + LOG(DEBUG) << "Installing fscrypt-provisioning key for " << ref << " back into " << mountpoint + << " fs-keyring"; + + struct fscrypt_add_key_arg arg; + memset(&arg, 0, sizeof(arg)); + if (!buildKeySpecifier(&arg.key_spec, policy)) return false; + arg.key_id = key_serial; + if (!installFsKeyringKey(mountpoint, policy.options, &arg)) return false; + + return true; +} + } // namespace vold } // namespace android diff --git a/KeyUtil.h b/KeyUtil.h index dcb1dc7..23278c1 100644 --- a/KeyUtil.h +++ b/KeyUtil.h @@ -51,11 +51,16 @@ bool isFsKeyringSupported(void); // on the specified filesystem using the specified encryption policy version. // // For v1 policies, we use FS_IOC_ADD_ENCRYPTION_KEY if the kernel supports it. -// Otherwise we add the key to the legacy global session keyring. +// Otherwise we add the key to the global session keyring as a "logon" key. // // For v2 policies, we always use FS_IOC_ADD_ENCRYPTION_KEY; it's the only way // the kernel supports. // +// If kernel supports FS_IOC_ADD_ENCRYPTION_KEY, also installs key of +// fscrypt-provisioning type to the global session keyring. This makes it +// possible to unmount and then remount mountpoint without losing the file-based +// key. +// // Returns %true on success, %false on failure. On success also sets *policy // to the EncryptionPolicy used to refer to this key. bool installKey(const std::string& mountpoint, const EncryptionOptions& options, @@ -63,16 +68,20 @@ bool installKey(const std::string& mountpoint, const EncryptionOptions& options, // Evict a file-based encryption key from the kernel. // -// We use FS_IOC_REMOVE_ENCRYPTION_KEY if the kernel supports it. Otherwise we -// remove the key from the legacy global session keyring. +// This undoes the effect of installKey(). // -// In the latter case, the caller is responsible for dropping caches. +// If the kernel doesn't support the filesystem-level keyring, the caller is +// responsible for dropping caches. bool evictKey(const std::string& mountpoint, const EncryptionPolicy& policy); bool retrieveOrGenerateKey(const std::string& key_path, const std::string& tmp_path, const KeyAuthentication& key_authentication, const KeyGeneration& gen, KeyBuffer* key, bool keepOld = true); +// Re-installs a file-based encryption key of fscrypt-provisioning type from the +// global session keyring back into fs keyring of the mountpoint. +bool reloadKeyFromSessionKeyring(const std::string& mountpoint, const EncryptionPolicy& policy); + } // namespace vold } // namespace android diff --git a/fscrypt_uapi.h b/fscrypt_uapi.h index 08592e0..3cda96e 100644 --- a/fscrypt_uapi.h +++ b/fscrypt_uapi.h @@ -9,11 +9,19 @@ struct sys_fscrypt_add_key_arg { struct fscrypt_key_specifier key_spec; __u32 raw_size; - __u32 __reserved[8]; + __u32 key_id; + __u32 __reserved[7]; __u32 flags; __u8 raw[]; }; +struct sys_fscrypt_provisioning_key_payload { + __u32 type; + __u32 __reserved; + __u8 raw[]; +}; + #define fscrypt_add_key_arg sys_fscrypt_add_key_arg +#define fscrypt_provisioning_key_payload sys_fscrypt_provisioning_key_payload #endif //_UAPI_LINUX_FSCRYPT_VOLD_H From 9171fcc9845033748455df1946c3649d9e540f9b Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 11 Mar 2020 11:51:45 +0100 Subject: [PATCH 078/112] Only set quota project ID inheritance on app-private dirs. Previously every directory on external storage had project ID quota inheritance enabled; this means that if any new file/directory is created under such a directory, it will inherit the project ID from the parent. We use a default project ID of 1000 for generic directories, and application-specific project IDs for app-specific directories. MediaProvider is responsible for updating the quota type in the generic directories, as it scans all files there. However, there is a problem with this approach: if you move a file to a directory with project ID inheritance set, and the project ID of that file differs from the project ID of the dir, that results in an EXDEV error, and requires a copy instead. For example, if /sdcard/DCIM/test.jpg has a project ID of 1003 (for images), and you try to move it to /sdcard/Pictures/test.jpg, that would require a copy, because the project ID of /sdcard/Pictures is 1000. While this is not a very common scenario, it's still better to avoid it. Luckily we can - since MediaProvider anyway scans all files, it will set the project ID on individual files correctly - there's no need to inherit them. We then only need to inherit quota in application-specific directories, since in those directories the app can create files itself, and those need to be tagged correctly. This change enables that, by removing quota inheritance setting from the top-level directory, and instead doing it for app-specific directories instead. Bug: 151078664 Test: atest StorageHostTest atest com.android.tests.fused.host.FuseDaemonHostTest#testRenameAndReplaceFile Change-Id: I38a057ec61cb627e39a3ff7ac58c7218dc251bdc --- FsCrypt.cpp | 8 -------- Utils.cpp | 9 +++++++++ 2 files changed, 9 insertions(+), 8 deletions(-) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index d43bc08..f9e60fe 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -807,14 +807,6 @@ bool fscrypt_prepare_user_storage(const std::string& volume_uuid, userid_t user_ if (!prepare_dir(vendor_ce_path, 0771, AID_ROOT, AID_ROOT)) return false; } if (!prepare_dir(media_ce_path, 0770, AID_MEDIA_RW, AID_MEDIA_RW)) return false; - // Setup quota project ID and inheritance policy - if (!IsFilesystemSupported("sdcardfs")) { - if (SetQuotaInherit(media_ce_path) != 0) return false; - if (SetQuotaProjectId(media_ce_path, - multiuser_get_uid(user_id, PROJECT_ID_EXT_DEFAULT)) != 0) { - return false; - } - } if (!prepare_dir(user_ce_path, 0771, AID_SYSTEM, AID_SYSTEM)) return false; diff --git a/Utils.cpp b/Utils.cpp index 82ad1f1..1e20d75 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -366,6 +366,15 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int if (ret != 0) { return ret; } + + if (!IsFilesystemSupported("sdcardfs")) { + // Set project ID inheritance, so that future subdirectories inherit the + // same project ID + ret = SetQuotaInherit(pathToCreate); + if (ret != 0) { + return ret; + } + } } depth++; From 2f1c98324024be74c4e6bfbc179934750f48a493 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 10 Mar 2020 09:28:39 +0100 Subject: [PATCH 079/112] Add quota / casefold options to f2fs if needed. These were only added for ext4. Bug: 150935323 Test: when creating a private f2fs volume, things work as expected. Change-Id: I11ee04bfddecb6c95e223e66c9bf532c425e6fac --- fs/F2fs.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp index 9517dc9..ee39f2b 100644 --- a/fs/F2fs.cpp +++ b/fs/F2fs.cpp @@ -89,6 +89,19 @@ status_t Format(const std::string& source) { cmd.push_back("-O"); cmd.push_back("verity"); + const bool needs_casefold = + android::base::GetBoolProperty("ro.emulated_storage.casefold", false); + const bool needs_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false); + if (needs_projid) { + cmd.push_back("-O"); + cmd.push_back("project_quota,extra_attr"); + } + if (needs_casefold) { + cmd.push_back("-O"); + cmd.push_back("casefold"); + cmd.push_back("-C"); + cmd.push_back("utf8"); + } cmd.push_back(source); return ForkExecvp(cmd); } From 6c695ef1d9359e65e762fd98e534cfd389166f5d Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 11 Mar 2020 15:33:22 +0100 Subject: [PATCH 080/112] Prefer f2fs for virtual (private) storage volumes. Since ext4 currently doesn't have the required kernel patches in place on cuttlefish. Bug: 150935323 Test: sm set-virtual-disk true sm partition disk:7,xyz private inspect mount output Change-Id: Ief5bd9ace9d39bdfbae8d3857044a2143801f6be --- model/PrivateVolume.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index a54b05e..75757f7 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -43,6 +43,7 @@ using android::base::StringPrintf; namespace android { namespace vold { +static const unsigned int kMajorBlockLoop = 7; static const unsigned int kMajorBlockMmc = 179; PrivateVolume::PrivateVolume(dev_t device, const KeyBuffer& keyRaw) @@ -207,7 +208,9 @@ status_t PrivateVolume::doFormat(const std::string& fsType) { if (fsType == "auto") { // For now, assume that all MMC devices are flash-based SD cards, and // give everyone else ext4 because sysfs rotational isn't reliable. - if ((major(mRawDevice) == kMajorBlockMmc) && f2fs::IsSupported()) { + // Additionally, prefer f2fs for loop-bases devices + if ((major(mRawDevice) == kMajorBlockMmc || major(mRawDevice) == kMajorBlockLoop) && + f2fs::IsSupported()) { resolvedFsType = "f2fs"; } else { resolvedFsType = "ext4"; From 6b1225770261cbad5cbf6509a32743691fe40783 Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Fri, 28 Feb 2020 16:30:47 +0000 Subject: [PATCH 081/112] Make storage dirs remount fork() safe Also, use the pids provided by system server to remount all existing processes, so we don't need to do the heavy and unreliable scanning in /proc anymore. Bug: 149548518 Test: atest AdoptableHostTest Change-Id: Ifb5b79a3bc5438f36e0d61ec8aec96bdbc60ca13 --- VoldNativeService.cpp | 8 + VoldNativeService.h | 2 + VolumeManager.cpp | 312 +++++++++++++---------------------- VolumeManager.h | 8 +- binder/android/os/IVold.aidl | 1 + model/EmulatedVolume.cpp | 19 --- model/EmulatedVolume.h | 1 + 7 files changed, 125 insertions(+), 226 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 08b4661..57cee23 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -458,6 +458,14 @@ binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { return translate(VolumeManager::Instance()->remountUid(uid, remountMode)); } +binder::Status VoldNativeService::remountAppStorageDirs(int uid, int pid, + const std::vector& packageNames) { + ENFORCE_SYSTEM_OR_ROOT; + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->remountAppStorageDirs(uid, pid, packageNames)); +} + binder::Status VoldNativeService::setupAppDir(const std::string& path, int32_t appUid) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(path); diff --git a/VoldNativeService.h b/VoldNativeService.h index e04c259..2f4b6eb 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -64,6 +64,8 @@ class VoldNativeService : public BinderService, public os::Bn const android::sp& listener); binder::Status remountUid(int32_t uid, int32_t remountMode); + binder::Status remountAppStorageDirs(int uid, int pid, + const std::vector& packageNames); binder::Status setupAppDir(const std::string& path, int32_t appUid); binder::Status fixupAppDir(const std::string& path, int32_t appUid); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index fce977e..6a40a52 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -738,228 +738,144 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { forkAndRemountChild, &mountMode) ? 0 : -1; } -// Bind mount obb & data dir for an app if necessary. -// How it works: -// 1). Check if a pid is an app uid and not the FuseDaemon, if not then return. -// 2). Get the mounts for that pid. -// 3). If obb is already mounted then return, otherwise we need to mount obb for this pid. -// 4). Get all packages and uid mounted for jit profile. These packages are all packages with -// same uid or whitelisted apps. -// 5a). If there's no package, it means it's not a process running app data isolation, so -// just bind mount Android/obb & Android/data dir. -// 5b). Otherwise, for each package, create obb dir if it's not created and bind mount it. -// TODO: Should we get some reliable data from system server instead of scanning /proc ? -static bool bindMountAppDataObbDir(uid_t uid, pid_t pid, int nsFd, const char* name, void* params) { - if (uid < AID_APP_START || uid > AID_APP_END) { - return true; - } - if (android::vold::IsFuseDaemon(pid)) { - return true; - } - async_safe_format_log(ANDROID_LOG_ERROR, "vold", - "Start mounting obb and data for uid:%d, pid:%d", uid, pid); - userid_t userId = multiuser_get_user_id(uid); +// Set the namespace the app process and remount its storage directories. +static bool remountStorageDirs(int nsFd, const char* sources[], const char* targets[], int size) { + // This code is executed after a fork so it's very important that the set of + // methods we call here is strictly limited. if (setns(nsFd, CLONE_NEWNS) != 0) { async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to setns %s", strerror(errno)); return false; } - std::string profiles_path(StringPrintf("/data/misc/profiles/cur/%d/", userId)); - // We search both .../obb and .../obb/$PKG paths here. - std::string obb_path(StringPrintf("/storage/emulated/%d/Android/obb", userId)); - int profiles_path_len = profiles_path.length(); - int obb_path_len = obb_path.length(); - - // TODO: Refactor the code as a util function so we can reuse the mount parsing code. - std::string mounts_file(StringPrintf("/proc/%d/mounts", pid)); - auto fp = std::unique_ptr( - setmntent(mounts_file.c_str(), "r"), endmntent); - if (!fp) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Error opening %s: %s", - mounts_file.c_str(), strerror(errno)); - return false; - } - - // Check if obb directory is mounted, and get all packages of mounted app data directory. - // We only need to check obb directory and assume if obb is mounted, data is mounted also. - bool obb_mounted = false; - std::vector pkg_name_list; - mntent* mentry; - while ((mentry = getmntent(fp.get())) != nullptr) { - if (strncmp(mentry->mnt_dir, profiles_path.c_str(), profiles_path_len) == 0) { - pkg_name_list.push_back(std::string(mentry->mnt_dir + profiles_path_len)); - } - if (strncmp(mentry->mnt_dir, obb_path.c_str(), obb_path_len) == 0) { - obb_mounted = true; - } - } - - // Obb mounted in zygote already, so skip it - if (obb_mounted) { - return true; - } - - std::string obbSource, dataSource; - if (IsFilesystemSupported("sdcardfs")) { - obbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb", userId); - dataSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/data", userId); - } else { - obbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb", userId, userId); - dataSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/data", userId, userId); - } - std::string obbTarget(StringPrintf("/storage/emulated/%d/Android/obb", userId)); - std::string dataTarget(StringPrintf("/storage/emulated/%d/Android/data", userId)); - - // TODO: Review if these checks are still necessary - auto status = EnsureDirExists(obbSource, 0771, AID_MEDIA_RW, AID_MEDIA_RW); - if (status != OK) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to create dir %s %s", - obbSource.c_str(), strerror(-status)); - return false; - } - status = EnsureDirExists(dataSource, 0771, AID_MEDIA_RW, AID_MEDIA_RW); - if (status != OK) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to create dir %s %s", - dataSource.c_str(), strerror(-status)); - return false; - } - - // It means app data isolation is not applied to this, so we can just bind the whole obb - // directory instead. - if (pkg_name_list.empty()) { - async_safe_format_log(ANDROID_LOG_INFO, "vold", - "Bind mounting whole obb and data directory for pid %d", pid); - auto status1 = BindMount(obbSource, obbTarget); - // Still bind mount data even obb fails, just slower to access obb dir - auto status2 = BindMount(dataSource, dataTarget); - if (status1 != OK) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", - obbSource.c_str(), obbTarget.c_str(), strerror(-status)); + for (int i = 0; i < size; i++) { + if (TEMP_FAILURE_RETRY(mount(sources[i], targets[i], NULL, MS_BIND | MS_REC, NULL)) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s to %s :%s", + sources[i], targets[i], strerror(errno)); return false; } - if (status2 != OK) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", - dataSource.c_str(), dataTarget.c_str(), strerror(-status)); - return false; - } - return true; - } - - // Bind mount each app's obb directory - for (const auto& pkg_name : pkg_name_list) { - std::string appObbSource, appDataSource; - if (IsFilesystemSupported("sdcardfs")) { - appObbSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/obb/%s", - userId, pkg_name.c_str()); - appDataSource = StringPrintf("/mnt/runtime/default/emulated/%d/Android/data/%s", - userId, pkg_name.c_str()); - } else { - appObbSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/obb/%s", - userId, userId, pkg_name.c_str()); - appDataSource = StringPrintf("/mnt/pass_through/%d/emulated/%d/Android/data/%s", - userId, userId, pkg_name.c_str()); - } - std::string appObbTarget(StringPrintf("/storage/emulated/%d/Android/obb/%s", - userId, pkg_name.c_str())); - std::string appDataTarget(StringPrintf("/storage/emulated/%d/Android/data/%s", - userId, pkg_name.c_str())); - - status = EnsureDirExists(appObbSource, 0770, uid, AID_MEDIA_RW); - if (status != OK) { - async_safe_format_log(ANDROID_LOG_INFO, "vold", "Failed to ensure dir %s exists", - appObbSource.c_str()); - continue; - } - status = EnsureDirExists(appDataSource, 0770, uid, AID_MEDIA_RW); - if (status != OK) { - async_safe_format_log(ANDROID_LOG_INFO, "vold", "Failed to ensure dir %s exists", - appDataSource.c_str()); - continue; - } - async_safe_format_log(ANDROID_LOG_INFO, "vold", - "Bind mounting app obb and data directory(%s) for pid %d", - pkg_name.c_str(), pid); - auto status1 = BindMount(appObbSource, appObbTarget); - // Still bind mount data even obb fails, just slower to access obb dir - auto status2 = BindMount(appDataSource, appDataTarget); - if (status1 != OK) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", - obbSource.c_str(), obbTarget.c_str(), strerror(-status)); - continue; - } - if (status2 != OK) { - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s %s %s", - appDataSource.c_str(), appDataTarget.c_str(), strerror(-status)); - continue; - } } return true; } -int VolumeManager::remountAppStorageDirs(userid_t userId) { - if (!GetBoolProperty(android::vold::kPropFuse, false)) { - return 0; +static std::string getStorageDirSrc(userid_t userId, const std::string& dirName, + const std::string& packageName) { + if (IsFilesystemSupported("sdcardfs")) { + return StringPrintf("/mnt/runtime/default/emulated/%d/%s/%s", + userId, dirName.c_str(), packageName.c_str()); + } else { + return StringPrintf("/mnt/pass_through/%d/emulated/%d/%s/%s", + userId, userId, dirName.c_str(), packageName.c_str()); } - LOG(INFO) << "Start remounting app obb and data"; - pid_t child; - if (!(child = fork())) { - // Child process - if (daemon(0, 0) == -1) { - PLOG(FATAL) << "Cannot create daemon"; +} + +static std::string getStorageDirTarget(userid_t userId, std::string dirName, + std::string packageName) { + return StringPrintf("/storage/emulated/%d/%s/%s", + userId, dirName.c_str(), packageName.c_str()); +} + +// Fork the process and remount storage +static bool forkAndRemountStorage(int uid, int pid, const std::vector& packageNames) { + userid_t userId = multiuser_get_user_id(uid); + std::string mnt_path = StringPrintf("/proc/%d/ns/mnt", pid); + android::base::unique_fd nsFd( + TEMP_FAILURE_RETRY(open(mnt_path.c_str(), O_RDONLY | O_CLOEXEC))); + if (nsFd == -1) { + PLOG(ERROR) << "Unable to open " << mnt_path.c_str(); + return false; + } + // Storing both Android/obb and Android/data paths. + int size = packageNames.size() * 2; + + std::unique_ptr sources(new std::string[size]); + std::unique_ptr targets(new std::string[size]); + std::unique_ptr sources_uptr(new const char*[size]); + std::unique_ptr targets_uptr(new const char*[size]); + const char** sources_cstr = sources_uptr.get(); + const char** targets_cstr = targets_uptr.get(); + + for (int i = 0; i < size; i += 2) { + std::string const& packageName = packageNames[i/2]; + sources[i] = getStorageDirSrc(userId, "Android/data", packageName); + targets[i] = getStorageDirTarget(userId, "Android/data", packageName); + sources[i+1] = getStorageDirSrc(userId, "Android/obb", packageName); + targets[i+1] = getStorageDirTarget(userId, "Android/obb", packageName); + + sources_cstr[i] = sources[i].c_str(); + targets_cstr[i] = targets[i].c_str(); + sources_cstr[i+1] = sources[i+1].c_str(); + targets_cstr[i+1] = targets[i+1].c_str(); + } + + for (int i = 0; i < size; i++) { + auto status = EnsureDirExists(sources_cstr[i], 0771, AID_MEDIA_RW, AID_MEDIA_RW); + if (status != OK) { + PLOG(ERROR) << "Failed to create dir: " << sources_cstr[i]; + return false; } - // TODO(149548518): Refactor the code so minimize the work after fork to prevent deadlock. - if (scanProcProcesses(0, userId, bindMountAppDataObbDir, nullptr)) { - // As some forked zygote processes may not setuid and recognized as an app yet, sleep - // 3s and try again to catch 'em all. - usleep(3 * 1000 * 1000); // 3s - async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Retry remounting app obb"); - scanProcProcesses(0, userId, bindMountAppDataObbDir, nullptr); + status = EnsureDirExists(targets_cstr[i], 0771, AID_MEDIA_RW, AID_MEDIA_RW); + if (status != OK) { + PLOG(ERROR) << "Failed to create dir: " << targets_cstr[i]; + return false; + } + } + + pid_t child; + // Fork a child to mount Android/obb android Android/data dirs, as we don't want it to affect + // original vold process mount namespace. + if (!(child = fork())) { + if (remountStorageDirs(nsFd, sources_cstr, targets_cstr, size)) { _exit(0); } else { _exit(1); } } + if (child == -1) { PLOG(ERROR) << "Failed to fork"; - return -1; - } else if (child == 0) { - // Parent - int stat_loc; - for (;;) { - if (waitpid(child, &stat_loc, 0) != -1 || errno != EINTR) { - break; - } + return false; + } else { + int status; + if (TEMP_FAILURE_RETRY(waitpid(child, &status, 0)) == -1) { + PLOG(ERROR) << "Failed to waitpid: " << child; + return false; + } + if (!WIFEXITED(status)) { + PLOG(ERROR) << "Process did not exit normally, status: " << status; + return false; + } + if (WEXITSTATUS(status)) { + PLOG(ERROR) << "Process exited with code: " << WEXITSTATUS(status); + return false; } } + return true; +} + +int VolumeManager::remountAppStorageDirs(int uid, int pid, + const std::vector& packageNames) { + if (!GetBoolProperty(android::vold::kPropFuse, false)) { + return 0; + } + // Only run the remount if fuse is mounted for that user. + userid_t userId = multiuser_get_user_id(uid); + bool fuseMounted = false; + for (auto& vol : mInternalEmulatedVolumes) { + if (vol->getMountUserId() == userId && vol->getState() == VolumeBase::State::kMounted) { + auto* emulatedVol = static_cast(vol.get()); + if (emulatedVol) { + fuseMounted = emulatedVol->isFuseMounted(); + } + break; + } + } + if (fuseMounted) { + forkAndRemountStorage(uid, pid, packageNames); + } return 0; } -bool VolumeManager::updateFuseMountedProperty() { - if (mFuseMountedUsers.size() == 0) { - android::base::SetProperty("vold.fuse_running_users", ""); - return true; - } - std::stringstream stream; - char const * sep = ""; - for (const auto& userId : mFuseMountedUsers) { - stream << sep; - stream << userId; - sep = ", "; - } - return android::base::SetProperty("vold.fuse_running_users", stream.str()); -} - -bool VolumeManager::addFuseMountedUser(userid_t userId) { - mFuseMountedUsers.insert(userId); - return updateFuseMountedProperty(); -} - -bool VolumeManager::removeFuseMountedUser(userid_t userId) { - mFuseMountedUsers.erase(userId); - return updateFuseMountedProperty(); -} - int VolumeManager::reset() { // Tear down all existing disks/volumes and start from a blank slate so // newly connected framework hears all events. @@ -975,8 +891,6 @@ int VolumeManager::reset() { updateVirtualDisk(); mAddedUsers.clear(); mStartedUsers.clear(); - mFuseMountedUsers.clear(); - updateFuseMountedProperty(); return 0; } @@ -996,8 +910,6 @@ int VolumeManager::shutdown() { mInternalEmulatedVolumes.clear(); mDisks.clear(); mPendingDisks.clear(); - mFuseMountedUsers.clear(); - updateFuseMountedProperty(); android::vold::sSleepOnUnmount = true; return 0; } diff --git a/VolumeManager.h b/VolumeManager.h index bf05dcf..b83871e 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -118,10 +118,7 @@ class VolumeManager { int setPrimary(const std::shared_ptr& vol); int remountUid(uid_t uid, int32_t remountMode); - int remountAppStorageDirs(userid_t userId); - - bool addFuseMountedUser(userid_t userId); - bool removeFuseMountedUser(userid_t userId); + int remountAppStorageDirs(int uid, int pid, const std::vector& packageNames); /* Reset all internal state, typically during framework boot */ int reset(); @@ -230,9 +227,6 @@ class VolumeManager { int mNextObbId; int mNextStubId; bool mSecureKeyguardShowing; - - // Set of all user id that fuse is ready to use. - std::unordered_set mFuseMountedUsers; }; #endif diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index f1ada6c..1d5657f 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -53,6 +53,7 @@ interface IVold { IVoldTaskListener listener); void remountUid(int uid, int remountMode); + void remountAppStorageDirs(int uid, int pid, in @utf8InCpp String[] packageNames); void setupAppDir(@utf8InCpp String path, int appUid); void fixupAppDir(@utf8InCpp String path, int appUid); diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 1391685..02d5c37 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -125,19 +125,6 @@ status_t EmulatedVolume::mountFuseBindMounts() { if (status != OK) { return status; } - - if (mAppDataIsolationEnabled) { - // Starting from now, fuse is running, and zygote will bind app obb & data directory - if (!VolumeManager::Instance()->addFuseMountedUser(userId)) { - return UNKNOWN_ERROR; - } - - // As all new processes created by zygote will bind app obb data directory, we just need - // to have a snapshot of all existing processes and see if any existing process needs to - // remount obb data directory. - VolumeManager::Instance()->remountAppStorageDirs(userId); - } - return OK; } @@ -308,12 +295,6 @@ status_t EmulatedVolume::doUnmount() { if (mFuseMounted) { std::string label = getLabel(); - // Update fuse mounted record - if (mAppDataIsolationEnabled && - !VolumeManager::Instance()->removeFuseMountedUser(userId)) { - return UNKNOWN_ERROR; - } - // Ignoring unmount return status because we do want to try to unmount // the rest cleanly. unmountFuseBindMounts(); diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index 12d01ec..b25fb7c 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -41,6 +41,7 @@ class EmulatedVolume : public VolumeBase { EmulatedVolume(const std::string& rawPath, dev_t device, const std::string& fsUuid, int userId); virtual ~EmulatedVolume(); std::string getRootPath() const override; + bool isFuseMounted() const { return mFuseMounted; } protected: status_t doMount() override; From b6488f3f0481e83f0685214b9dfabeef09f43af3 Mon Sep 17 00:00:00 2001 From: Zim Date: Tue, 17 Mar 2020 15:15:42 +0000 Subject: [PATCH 082/112] Fix vold wedge when unmounting Android/ In EmulatedVolume#doMount, if some operations fail, we call EmulatedVolume#doUnmount. During this unmount we try to unmount Android/ causing a FUSE_LOOKUP on the FUSE mount. If the FUSE mount is not up, this can hang. Now we introduce a new state to prevent unmounting Android/ if it wasn't mounted. Test: atest AdoptableHostTest Bug: 151685786 Change-Id: I6246d3910c352034d2a4fb09ad9c1e7fd91cba5e --- model/EmulatedVolume.cpp | 14 ++++++++++++-- model/EmulatedVolume.h | 3 +++ 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 02d5c37..b212c0e 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -48,6 +48,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) mRawPath = rawPath; mLabel = "emulated"; mFuseMounted = false; + mAndroidMounted = false; mUseSdcardFs = IsFilesystemSupported("sdcardfs"); mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } @@ -59,6 +60,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s mRawPath = rawPath; mLabel = fsUuid; mFuseMounted = false; + mAndroidMounted = false; mUseSdcardFs = IsFilesystemSupported("sdcardfs"); mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } @@ -87,6 +89,8 @@ static status_t doFuseBindMount(const std::string& source, const std::string& ta } status_t EmulatedVolume::mountFuseBindMounts() { + CHECK(!mAndroidMounted); + std::string androidSource; std::string label = getLabel(); int userId = getMountUserId(); @@ -109,6 +113,8 @@ status_t EmulatedVolume::mountFuseBindMounts() { if (status != OK) { return status; } + mAndroidMounted = true; + // Installers get the same view as all other apps, with the sole exception that the // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires // a special bind mount, since app-private and OBB dirs share the same GID, but we @@ -129,6 +135,8 @@ status_t EmulatedVolume::mountFuseBindMounts() { } status_t EmulatedVolume::unmountFuseBindMounts() { + CHECK(mAndroidMounted); + std::string label = getLabel(); int userId = getMountUserId(); @@ -158,7 +166,6 @@ status_t EmulatedVolume::unmountFuseBindMounts() { } LOG(INFO) << "Unmounted " << androidTarget; } - return OK; } @@ -297,7 +304,10 @@ status_t EmulatedVolume::doUnmount() { // Ignoring unmount return status because we do want to try to unmount // the rest cleanly. - unmountFuseBindMounts(); + if (mAndroidMounted) { + unmountFuseBindMounts(); + mAndroidMounted = false; + } if (UnmountUserFuse(userId, getInternalPath(), label) != OK) { PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; return -errno; diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index b25fb7c..9bff0ca 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -63,6 +63,9 @@ class EmulatedVolume : public VolumeBase { /* Whether we mounted FUSE for this volume */ bool mFuseMounted; + /* Whether we mounted Android/ for this volume */ + bool mAndroidMounted; + /* Whether to use sdcardfs for this volume */ bool mUseSdcardFs; From 449a7d8ae07787dbed5292e77979e8754978c804 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 16 Mar 2020 14:37:33 +0100 Subject: [PATCH 083/112] Bind mount Android/data and Android/obb individually. Because we want all other paths (in particular Android/media) to go through FUSE. Also use scope_guard to make unwinding some failures easier. Bug: 151272568 Test: atest AdoptableHostTest Change-Id: Ib487b9071b5b212c7bb12ce54f80c96d98acaef5 --- model/EmulatedVolume.cpp | 168 +++++++++++++++++++++++++-------------- model/EmulatedVolume.h | 4 +- 2 files changed, 110 insertions(+), 62 deletions(-) diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index b212c0e..e411b33 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include #include @@ -48,7 +49,6 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) mRawPath = rawPath; mLabel = "emulated"; mFuseMounted = false; - mAndroidMounted = false; mUseSdcardFs = IsFilesystemSupported("sdcardfs"); mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } @@ -60,7 +60,6 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s mRawPath = rawPath; mLabel = fsUuid; mFuseMounted = false; - mAndroidMounted = false; mUseSdcardFs = IsFilesystemSupported("sdcardfs"); mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } @@ -78,22 +77,37 @@ std::string EmulatedVolume::getLabel() { } // Creates a bind mount from source to target -static status_t doFuseBindMount(const std::string& source, const std::string& target) { +static status_t doFuseBindMount(const std::string& source, const std::string& target, + std::list& pathsToUnmount) { LOG(INFO) << "Bind mounting " << source << " on " << target; auto status = BindMount(source, target); if (status != OK) { return status; } LOG(INFO) << "Bind mounted " << source << " on " << target; + pathsToUnmount.push_front(target); return OK; } status_t EmulatedVolume::mountFuseBindMounts() { - CHECK(!mAndroidMounted); - std::string androidSource; std::string label = getLabel(); int userId = getMountUserId(); + std::list pathsToUnmount; + + auto unmounter = [&]() { + LOG(INFO) << "mountFuseBindMounts() unmount scope_guard running"; + for (const auto& path : pathsToUnmount) { + LOG(INFO) << "Unmounting " << path; + auto status = UnmountTree(path); + if (status != OK) { + LOG(INFO) << "Failed to unmount " << path; + } else { + LOG(INFO) << "Unmounted " << path; + } + } + }; + auto unmount_guard = android::base::make_scope_guard(unmounter); if (mUseSdcardFs) { androidSource = StringPrintf("/mnt/runtime/default/%s/%d/Android", label.c_str(), userId); @@ -105,38 +119,43 @@ status_t EmulatedVolume::mountFuseBindMounts() { // When app data isolation is enabled, obb/ will be mounted per app, otherwise we should // bind mount the whole Android/ to speed up reading. if (!mAppDataIsolationEnabled) { - std::string androidTarget( - StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); - status = doFuseBindMount(androidSource, androidTarget); - } + std::string androidDataSource = StringPrintf("%s/data", androidSource.c_str()); + std::string androidDataTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android/data", userId, label.c_str(), userId)); + status = doFuseBindMount(androidDataSource, androidDataTarget, pathsToUnmount); + if (status != OK) { + return status; + } - if (status != OK) { - return status; + std::string androidObbSource = StringPrintf("%s/obb", androidSource.c_str()); + std::string androidObbTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); + status = doFuseBindMount(androidObbSource, androidObbTarget, pathsToUnmount); + if (status != OK) { + return status; + } } - mAndroidMounted = true; // Installers get the same view as all other apps, with the sole exception that the // OBB dirs (Android/obb) are writable to them. On sdcardfs devices, this requires // a special bind mount, since app-private and OBB dirs share the same GID, but we // only want to give access to the latter. - if (!mUseSdcardFs) { - return OK; - } - std::string installerSource( - StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", label.c_str(), userId)); - std::string installerTarget( - StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); + if (mUseSdcardFs) { + std::string installerSource( + StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", label.c_str(), userId)); + std::string installerTarget( + StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); - status = doFuseBindMount(installerSource, installerTarget); - if (status != OK) { - return status; + status = doFuseBindMount(installerSource, installerTarget, pathsToUnmount); + if (status != OK) { + return status; + } } + unmount_guard.Disable(); return OK; } status_t EmulatedVolume::unmountFuseBindMounts() { - CHECK(mAndroidMounted); - std::string label = getLabel(); int userId = getMountUserId(); @@ -156,19 +175,54 @@ status_t EmulatedVolume::unmountFuseBindMounts() { std::string appObbDir(StringPrintf("%s/%d/Android/obb", getPath().c_str(), userId)); KillProcessesWithMountPrefix(appObbDir); } else { - std::string androidTarget( - StringPrintf("/mnt/user/%d/%s/%d/Android", userId, label.c_str(), userId)); + std::string androidDataTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android/data", userId, label.c_str(), userId)); - LOG(INFO) << "Unmounting " << androidTarget; - auto status = UnmountTree(androidTarget); + LOG(INFO) << "Unmounting " << androidDataTarget; + auto status = UnmountTree(androidDataTarget); if (status != OK) { return status; } - LOG(INFO) << "Unmounted " << androidTarget; + LOG(INFO) << "Unmounted " << androidDataTarget; + + std::string androidObbTarget( + StringPrintf("/mnt/user/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); + + LOG(INFO) << "Unmounting " << androidObbTarget; + status = UnmountTree(androidObbTarget); + if (status != OK) { + return status; + } + LOG(INFO) << "Unmounted " << androidObbTarget; } return OK; } +status_t EmulatedVolume::unmountSdcardFs() { + if (!mUseSdcardFs || getMountUserId() != 0) { + // For sdcardfs, only unmount for user 0, since user 0 will always be running + // and the paths don't change for different users. + return OK; + } + + ForceUnmount(mSdcardFsDefault); + ForceUnmount(mSdcardFsRead); + ForceUnmount(mSdcardFsWrite); + ForceUnmount(mSdcardFsFull); + + rmdir(mSdcardFsDefault.c_str()); + rmdir(mSdcardFsRead.c_str()); + rmdir(mSdcardFsWrite.c_str()); + rmdir(mSdcardFsFull.c_str()); + + mSdcardFsDefault.clear(); + mSdcardFsRead.clear(); + mSdcardFsWrite.clear(); + mSdcardFsFull.clear(); + + return OK; +} + status_t EmulatedVolume::doMount() { std::string label = getLabel(); bool isVisible = getMountFlags() & MountFlags::kVisible; @@ -239,7 +293,15 @@ status_t EmulatedVolume::doMount() { TEMP_FAILURE_RETRY(waitpid(sdcardFsPid, nullptr, 0)); sdcardFsPid = 0; } + if (isFuse && isVisible) { + // Make sure we unmount sdcardfs if we bail out with an error below + auto sdcardfs_unmounter = [&]() { + LOG(INFO) << "sdcardfs_unmounter scope_guard running"; + unmountSdcardFs(); + }; + auto sdcardfs_guard = android::base::make_scope_guard(sdcardfs_unmounter); + LOG(INFO) << "Mounting emulated fuse volume"; android::base::unique_fd fd; int user_id = getMountUserId(); @@ -259,13 +321,21 @@ status_t EmulatedVolume::doMount() { } mFuseMounted = true; + auto fuse_unmounter = [&]() { + LOG(INFO) << "fuse_unmounter scope_guard running"; + fd.reset(); + if (UnmountUserFuse(user_id, getInternalPath(), label) != OK) { + PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; + } + mFuseMounted = false; + }; + auto fuse_guard = android::base::make_scope_guard(fuse_unmounter); + auto callback = getMountCallback(); if (callback) { bool is_ready = false; callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready); if (!is_ready) { - fd.reset(); - doUnmount(); return -EIO; } } @@ -273,10 +343,12 @@ status_t EmulatedVolume::doMount() { // Only do the bind-mounts when we know for sure the FUSE daemon can resolve the path. res = mountFuseBindMounts(); if (res != OK) { - fd.reset(); - doUnmount(); + return res; } - return res; + + // All mounts where successful, disable scope guards + sdcardfs_guard.Disable(); + fuse_guard.Disable(); } return OK; @@ -304,10 +376,8 @@ status_t EmulatedVolume::doUnmount() { // Ignoring unmount return status because we do want to try to unmount // the rest cleanly. - if (mAndroidMounted) { - unmountFuseBindMounts(); - mAndroidMounted = false; - } + unmountFuseBindMounts(); + if (UnmountUserFuse(userId, getInternalPath(), label) != OK) { PLOG(INFO) << "UnmountUserFuse failed on emulated fuse volume"; return -errno; @@ -315,28 +385,8 @@ status_t EmulatedVolume::doUnmount() { mFuseMounted = false; } - if (getMountUserId() != 0 || !mUseSdcardFs) { - // For sdcardfs, only unmount for user 0, since user 0 will always be running - // and the paths don't change for different users. - return OK; - } - ForceUnmount(mSdcardFsDefault); - ForceUnmount(mSdcardFsRead); - ForceUnmount(mSdcardFsWrite); - ForceUnmount(mSdcardFsFull); - - rmdir(mSdcardFsDefault.c_str()); - rmdir(mSdcardFsRead.c_str()); - rmdir(mSdcardFsWrite.c_str()); - rmdir(mSdcardFsFull.c_str()); - - mSdcardFsDefault.clear(); - mSdcardFsRead.clear(); - mSdcardFsWrite.clear(); - mSdcardFsFull.clear(); - - return OK; + return unmountSdcardFs(); } std::string EmulatedVolume::getRootPath() const { diff --git a/model/EmulatedVolume.h b/model/EmulatedVolume.h index 9bff0ca..1d2385d 100644 --- a/model/EmulatedVolume.h +++ b/model/EmulatedVolume.h @@ -48,6 +48,7 @@ class EmulatedVolume : public VolumeBase { status_t doUnmount() override; private: + status_t unmountSdcardFs(); status_t mountFuseBindMounts(); status_t unmountFuseBindMounts(); @@ -63,9 +64,6 @@ class EmulatedVolume : public VolumeBase { /* Whether we mounted FUSE for this volume */ bool mFuseMounted; - /* Whether we mounted Android/ for this volume */ - bool mAndroidMounted; - /* Whether to use sdcardfs for this volume */ bool mUseSdcardFs; From 94abae03a97bf67bc2cd04b6a74e07ed08bf30a0 Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Mon, 23 Mar 2020 08:59:12 -0700 Subject: [PATCH 084/112] Record use of metadata encryption in property Bug: 152150018 Test: Cuttlefish with and without keydirectory option Change-Id: I400873ec207cb63f0407fefc83962bb3a927e294 --- MetadataCrypt.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 8227e74..8bc8beb 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -336,6 +336,11 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: LOG(DEBUG) << "Mounting metadata-encrypted filesystem:" << mount_point; mount_via_fs_mgr(mount_point.c_str(), crypto_blkdev.c_str()); + + // Record that there's at least one fstab entry with metadata encryption + if (!android::base::SetProperty("ro.crypto.metadata.enabled", "true")) { + LOG(WARNING) << "failed to set ro.crypto.metadata.enabled"; // This isn't fatal + } return true; } From 131365a3e560224edd48f73ecf45bcc57cad4c6d Mon Sep 17 00:00:00 2001 From: Yurii Zubrytskyi Date: Tue, 24 Mar 2020 23:49:02 -0700 Subject: [PATCH 085/112] [vold] Add argument verification to IncFS methods + Get rid of an extra string copy in path validation function Bug: 152349257 Test: atest vold_tests Change-Id: I03a8cab0dd6abd7d5c9dcbbc2acb651e818e6cd8 --- Android.bp | 1 + VoldNativeService.cpp | 158 +++++++-------------- VoldNativeServiceValidation.cpp | 109 ++++++++++++++ VoldNativeServiceValidation.h | 37 +++++ tests/Android.bp | 2 + tests/VoldNativeServiceValidation_test.cpp | 51 +++++++ 6 files changed, 248 insertions(+), 110 deletions(-) create mode 100644 VoldNativeServiceValidation.cpp create mode 100644 VoldNativeServiceValidation.h create mode 100644 tests/VoldNativeServiceValidation_test.cpp diff --git a/Android.bp b/Android.bp index c2f8936..03dde1e 100644 --- a/Android.bp +++ b/Android.bp @@ -131,6 +131,7 @@ cc_library_static { "ScryptParameters.cpp", "Utils.cpp", "VoldNativeService.cpp", + "VoldNativeServiceValidation.cpp", "VoldUtil.cpp", "VolumeManager.cpp", "cryptfs.cpp", diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 57cee23..5a77a83 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -26,6 +26,7 @@ #include "MetadataCrypt.h" #include "MoveStorage.h" #include "Process.h" +#include "VoldNativeServiceValidation.h" #include "VoldUtil.h" #include "VolumeManager.h" #include "cryptfs.h" @@ -45,6 +46,7 @@ using android::base::StringPrintf; using std::endl; +using namespace std::literals; namespace android { namespace vold { @@ -53,14 +55,6 @@ namespace { constexpr const char* kDump = "android.permission.DUMP"; -static binder::Status ok() { - return binder::Status::ok(); -} - -static binder::Status exception(uint32_t code, const std::string& msg) { - return binder::Status::fromExceptionCode(code, String8(msg.c_str())); -} - static binder::Status error(const std::string& msg) { PLOG(ERROR) << msg; return binder::Status::fromServiceSpecificError(errno, String8(msg.c_str())); @@ -82,77 +76,9 @@ static binder::Status translateBool(bool status) { } } -binder::Status checkPermission(const char* permission) { - pid_t pid; - uid_t uid; - - if (checkCallingPermission(String16(permission), reinterpret_cast(&pid), - reinterpret_cast(&uid))) { - return ok(); - } else { - return exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission)); - } -} - -binder::Status checkUidOrRoot(uid_t expectedUid) { - uid_t uid = IPCThreadState::self()->getCallingUid(); - if (uid == expectedUid || uid == AID_ROOT) { - return ok(); - } else { - return exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d is not expected UID %d", uid, expectedUid)); - } -} - -binder::Status checkArgumentId(const std::string& id) { - if (id.empty()) { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing ID"); - } - for (const char& c : id) { - if (!std::isalnum(c) && c != ':' && c != ',' && c != ';') { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, - StringPrintf("ID %s is malformed", id.c_str())); - } - } - return ok(); -} - -binder::Status checkArgumentPath(const std::string& path) { - if (path.empty()) { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing path"); - } - if (path[0] != '/') { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, - StringPrintf("Path %s is relative", path.c_str())); - } - if ((path + '/').find("/../") != std::string::npos) { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, - StringPrintf("Path %s is shady", path.c_str())); - } - for (const char& c : path) { - if (c == '\0' || c == '\n') { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, - StringPrintf("Path %s is malformed", path.c_str())); - } - } - return ok(); -} - -binder::Status checkArgumentHex(const std::string& hex) { - // Empty hex strings are allowed - for (const char& c : hex) { - if (!std::isxdigit(c) && c != ':' && c != '-') { - return exception(binder::Status::EX_ILLEGAL_ARGUMENT, - StringPrintf("Hex %s is malformed", hex.c_str())); - } - } - return ok(); -} - #define ENFORCE_SYSTEM_OR_ROOT \ { \ - binder::Status status = checkUidOrRoot(AID_SYSTEM); \ + binder::Status status = CheckUidOrRoot(AID_SYSTEM); \ if (!status.isOk()) { \ return status; \ } \ @@ -160,7 +86,7 @@ binder::Status checkArgumentHex(const std::string& hex) { #define CHECK_ARGUMENT_ID(id) \ { \ - binder::Status status = checkArgumentId((id)); \ + binder::Status status = CheckArgumentId((id)); \ if (!status.isOk()) { \ return status; \ } \ @@ -168,7 +94,7 @@ binder::Status checkArgumentHex(const std::string& hex) { #define CHECK_ARGUMENT_PATH(path) \ { \ - binder::Status status = checkArgumentPath((path)); \ + binder::Status status = CheckArgumentPath((path)); \ if (!status.isOk()) { \ return status; \ } \ @@ -176,7 +102,7 @@ binder::Status checkArgumentHex(const std::string& hex) { #define CHECK_ARGUMENT_HEX(hex) \ { \ - binder::Status status = checkArgumentHex((hex)); \ + binder::Status status = CheckArgumentHex((hex)); \ if (!status.isOk()) { \ return status; \ } \ @@ -206,7 +132,7 @@ status_t VoldNativeService::start() { status_t VoldNativeService::dump(int fd, const Vector& /* args */) { auto out = std::fstream(StringPrintf("/proc/self/fd/%d", fd)); - const binder::Status dump_permission = checkPermission(kDump); + const binder::Status dump_permission = CheckPermission(kDump); if (!dump_permission.isOk()) { out << dump_permission.toString8() << endl; return PERMISSION_DENIED; @@ -214,7 +140,6 @@ status_t VoldNativeService::dump(int fd, const Vector& /* args */) { ACQUIRE_LOCK; out << "vold is happy!" << endl; - out.flush(); return NO_ERROR; } @@ -224,7 +149,7 @@ binder::Status VoldNativeService::setListener( ACQUIRE_LOCK; VolumeManager::Instance()->setListener(listener); - return ok(); + return Ok(); } binder::Status VoldNativeService::monitor() { @@ -234,7 +159,7 @@ binder::Status VoldNativeService::monitor() { { ACQUIRE_LOCK; } { ACQUIRE_CRYPT_LOCK; } - return ok(); + return Ok(); } binder::Status VoldNativeService::reset() { @@ -281,12 +206,12 @@ binder::Status VoldNativeService::onUserStopped(int32_t userId) { binder::Status VoldNativeService::addAppIds(const std::vector& packageNames, const std::vector& appIds) { - return ok(); + return Ok(); } binder::Status VoldNativeService::addSandboxIds(const std::vector& appIds, const std::vector& sandboxIds) { - return ok(); + return Ok(); } binder::Status VoldNativeService::onSecureKeyguardStateChanged(bool isShowing) { @@ -403,7 +328,7 @@ static binder::Status pathForVolId(const std::string& volId, std::string* path) return error("Volume " + volId + " missing path"); } } - return ok(); + return Ok(); } binder::Status VoldNativeService::benchmark( @@ -417,7 +342,7 @@ binder::Status VoldNativeService::benchmark( if (!status.isOk()) return status; std::thread([=]() { android::vold::Benchmark(path, listener); }).detach(); - return ok(); + return Ok(); } binder::Status VoldNativeService::checkEncryption(const std::string& volId) { @@ -448,7 +373,7 @@ binder::Status VoldNativeService::moveStorage( } std::thread([=]() { android::vold::MoveStorage(fromVol, toVol, listener); }).detach(); - return ok(); + return Ok(); } binder::Status VoldNativeService::remountUid(int32_t uid, int32_t remountMode) { @@ -534,7 +459,7 @@ binder::Status VoldNativeService::fstrim( ACQUIRE_LOCK; std::thread([=]() { android::vold::Trim(listener); }).detach(); - return ok(); + return Ok(); } binder::Status VoldNativeService::runIdleMaint( @@ -543,7 +468,7 @@ binder::Status VoldNativeService::runIdleMaint( ACQUIRE_LOCK; std::thread([=]() { android::vold::RunIdleMaint(listener); }).detach(); - return ok(); + return Ok(); } binder::Status VoldNativeService::abortIdleMaint( @@ -552,7 +477,7 @@ binder::Status VoldNativeService::abortIdleMaint( ACQUIRE_LOCK; std::thread([=]() { android::vold::AbortIdleMaint(listener); }).detach(); - return ok(); + return Ok(); } binder::Status VoldNativeService::mountAppFuse(int32_t uid, int32_t mountId, @@ -584,7 +509,7 @@ binder::Status VoldNativeService::openAppFuseFile(int32_t uid, int32_t mountId, } *_aidl_return = android::base::unique_fd(fd); - return ok(); + return Ok(); } binder::Status VoldNativeService::fdeCheckPassword(const std::string& password) { @@ -601,7 +526,7 @@ binder::Status VoldNativeService::fdeRestart() { // Spawn as thread so init can issue commands back to vold without // causing deadlock, usually as a result of prep_data_fs. std::thread(&cryptfs_restart).detach(); - return ok(); + return Ok(); } binder::Status VoldNativeService::fdeComplete(int32_t* _aidl_return) { @@ -609,7 +534,7 @@ binder::Status VoldNativeService::fdeComplete(int32_t* _aidl_return) { ACQUIRE_CRYPT_LOCK; *_aidl_return = cryptfs_crypto_complete(); - return ok(); + return Ok(); } static int fdeEnableInternal(int32_t passwordType, const std::string& password, @@ -649,7 +574,7 @@ binder::Status VoldNativeService::fdeEnable(int32_t passwordType, const std::str // Spawn as thread so init can issue commands back to vold without // causing deadlock, usually as a result of prep_data_fs. std::thread(&fdeEnableInternal, passwordType, password, encryptionFlags).detach(); - return ok(); + return Ok(); } binder::Status VoldNativeService::fdeChangePassword(int32_t passwordType, @@ -676,7 +601,7 @@ binder::Status VoldNativeService::fdeGetField(const std::string& key, std::strin return error(StringPrintf("Failed to read field %s", key.c_str())); } else { *_aidl_return = buf; - return ok(); + return Ok(); } } @@ -692,7 +617,7 @@ binder::Status VoldNativeService::fdeGetPasswordType(int32_t* _aidl_return) { ACQUIRE_CRYPT_LOCK; *_aidl_return = cryptfs_get_password_type(); - return ok(); + return Ok(); } binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) { @@ -703,7 +628,7 @@ binder::Status VoldNativeService::fdeGetPassword(std::string* _aidl_return) { if (res != nullptr) { *_aidl_return = res; } - return ok(); + return Ok(); } binder::Status VoldNativeService::fdeClearPassword() { @@ -711,7 +636,7 @@ binder::Status VoldNativeService::fdeClearPassword() { ACQUIRE_CRYPT_LOCK; cryptfs_clear_password(); - return ok(); + return Ok(); } binder::Status VoldNativeService::fbeEnable() { @@ -730,7 +655,7 @@ binder::Status VoldNativeService::mountDefaultEncrypted() { // causing deadlock, usually as a result of prep_data_fs. std::thread(&cryptfs_mount_default_encrypted).detach(); } - return ok(); + return Ok(); } binder::Status VoldNativeService::initUser0() { @@ -745,7 +670,7 @@ binder::Status VoldNativeService::isConvertibleToFbe(bool* _aidl_return) { ACQUIRE_CRYPT_LOCK; *_aidl_return = cryptfs_isConvertibleToFBE() != 0; - return ok(); + return Ok(); } binder::Status VoldNativeService::mountFstab(const std::string& blkDevice, @@ -845,13 +770,13 @@ binder::Status VoldNativeService::destroyUserStorage(const std::unique_ptr= 0) { _aidl_return->log.reset(unique_fd(result.logs)); } - return ok(); + return Ok(); } binder::Status VoldNativeService::unmountIncFs(const std::string& dir) { + ENFORCE_SYSTEM_OR_ROOT; + CHECK_ARGUMENT_PATH(dir); + return translate(IncFs_Unmount(dir.c_str())); } binder::Status VoldNativeService::bindMount(const std::string& sourceDir, const std::string& targetDir) { + ENFORCE_SYSTEM_OR_ROOT; + CHECK_ARGUMENT_PATH(sourceDir); + CHECK_ARGUMENT_PATH(targetDir); + return translate(IncFs_BindMount(sourceDir.c_str(), targetDir.c_str())); } diff --git a/VoldNativeServiceValidation.cpp b/VoldNativeServiceValidation.cpp new file mode 100644 index 0000000..2e21ace --- /dev/null +++ b/VoldNativeServiceValidation.cpp @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "VoldNativeServiceValidation.h" + +#include +#include +#include +#include +#include + +#include +#include + +using android::base::StringPrintf; +using namespace std::literals; + +namespace android::vold { + +binder::Status Ok() { + return binder::Status::ok(); +} + +binder::Status Exception(uint32_t code, const std::string& msg) { + return binder::Status::fromExceptionCode(code, String8(msg.c_str())); +} + +binder::Status CheckPermission(const char* permission) { + pid_t pid; + uid_t uid; + + if (checkCallingPermission(String16(permission), reinterpret_cast(&pid), + reinterpret_cast(&uid))) { + return Ok(); + } else { + return Exception(binder::Status::EX_SECURITY, + StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission)); + } +} + +binder::Status CheckUidOrRoot(uid_t expectedUid) { + uid_t uid = IPCThreadState::self()->getCallingUid(); + if (uid == expectedUid || uid == AID_ROOT) { + return Ok(); + } else { + return Exception(binder::Status::EX_SECURITY, + StringPrintf("UID %d is not expected UID %d", uid, expectedUid)); + } +} + +binder::Status CheckArgumentId(const std::string& id) { + if (id.empty()) { + return Exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing ID"); + } + for (const char& c : id) { + if (!std::isalnum(c) && c != ':' && c != ',' && c != ';') { + return Exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("ID %s is malformed", id.c_str())); + } + } + return Ok(); +} + +binder::Status CheckArgumentPath(const std::string& path) { + if (path.empty()) { + return Exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing path"); + } + if (path[0] != '/') { + return Exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is relative", path.c_str())); + } + if (path.find("/../"sv) != path.npos || android::base::EndsWith(path, "/.."sv)) { + return Exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is shady", path.c_str())); + } + for (const char& c : path) { + if (c == '\0' || c == '\n') { + return Exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Path %s is malformed", path.c_str())); + } + } + return Ok(); +} + +binder::Status CheckArgumentHex(const std::string& hex) { + // Empty hex strings are allowed + for (const char& c : hex) { + if (!std::isxdigit(c) && c != ':' && c != '-') { + return Exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Hex %s is malformed", hex.c_str())); + } + } + return Ok(); +} + +} // namespace android::vold diff --git a/VoldNativeServiceValidation.h b/VoldNativeServiceValidation.h new file mode 100644 index 0000000..d2fc9e0 --- /dev/null +++ b/VoldNativeServiceValidation.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include + +#include +#include + +namespace android::vold { + +binder::Status Ok(); +binder::Status Exception(uint32_t code, const std::string& msg); + +binder::Status CheckPermission(const char* permission); +binder::Status CheckUidOrRoot(uid_t expectedUid); +binder::Status CheckArgumentId(const std::string& id); +binder::Status CheckArgumentPath(const std::string& path); +binder::Status CheckArgumentHex(const std::string& hex); + +} // namespace android::vold diff --git a/tests/Android.bp b/tests/Android.bp index 4731d0a..b90de3a 100644 --- a/tests/Android.bp +++ b/tests/Android.bp @@ -7,7 +7,9 @@ cc_test { srcs: [ "Utils_test.cpp", + "VoldNativeServiceValidation_test.cpp", "cryptfs_test.cpp", ], static_libs: ["libvold"], + shared_libs: ["libbinder"] } diff --git a/tests/VoldNativeServiceValidation_test.cpp b/tests/VoldNativeServiceValidation_test.cpp new file mode 100644 index 0000000..0f87937 --- /dev/null +++ b/tests/VoldNativeServiceValidation_test.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2020 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "../VoldNativeServiceValidation.h" + +#include + +#include + +using namespace std::literals; + +namespace android::vold { + +class VoldServiceValidationTest : public testing::Test {}; + +TEST_F(VoldServiceValidationTest, CheckArgumentPathTest) { + EXPECT_TRUE(CheckArgumentPath("/").isOk()); + EXPECT_TRUE(CheckArgumentPath("/1/2").isOk()); + EXPECT_TRUE(CheckArgumentPath("/1/2/").isOk()); + EXPECT_TRUE(CheckArgumentPath("/1/2/./3").isOk()); + EXPECT_TRUE(CheckArgumentPath("/1/2/./3/.").isOk()); + EXPECT_TRUE(CheckArgumentPath( + "/very long path with some/ spaces and quite/ uncommon names /in\1 it/") + .isOk()); + + EXPECT_FALSE(CheckArgumentPath("").isOk()); + EXPECT_FALSE(CheckArgumentPath("relative/path").isOk()); + EXPECT_FALSE(CheckArgumentPath("../data/..").isOk()); + EXPECT_FALSE(CheckArgumentPath("/../data/..").isOk()); + EXPECT_FALSE(CheckArgumentPath("/data/../system").isOk()); + EXPECT_FALSE(CheckArgumentPath("/data/..trick/../system").isOk()); + EXPECT_FALSE(CheckArgumentPath("/data/..").isOk()); + EXPECT_FALSE(CheckArgumentPath("/data/././../apex").isOk()); + EXPECT_FALSE(CheckArgumentPath(std::string("/data/strange\0one"sv)).isOk()); + EXPECT_FALSE(CheckArgumentPath(std::string("/data/strange\ntwo"sv)).isOk()); +} + +} // namespace android::vold From 01c4e91c09d9781095113c7034f688c1e07db87c Mon Sep 17 00:00:00 2001 From: Songchun Fan Date: Tue, 3 Mar 2020 17:58:20 -0800 Subject: [PATCH 086/112] [vold] update with incfs_ndk.h BUG: 150470163 Test: atest PackageManagerShellCommandIncrementalTest Change-Id: I5166c49cf48f353dab35e385571ada517cb751ac --- VoldNativeService.cpp | 64 ++++++++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 31 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 5a77a83..1beb29c 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -18,6 +18,17 @@ #include "VoldNativeService.h" +#include +#include +#include +#include +#include +#include +#include + +#include +#include + #include "Benchmark.h" #include "CheckEncryption.h" #include "Checkpoint.h" @@ -30,20 +41,8 @@ #include "VoldUtil.h" #include "VolumeManager.h" #include "cryptfs.h" - #include "incfs_ndk.h" -#include -#include - -#include -#include -#include -#include -#include -#include -#include - using android::base::StringPrintf; using std::endl; using namespace std::literals; @@ -144,7 +143,7 @@ status_t VoldNativeService::dump(int fd, const Vector& /* args */) { } binder::Status VoldNativeService::setListener( - const android::sp& listener) { + const android::sp& listener) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; @@ -332,7 +331,7 @@ static binder::Status pathForVolId(const std::string& volId, std::string* path) } binder::Status VoldNativeService::benchmark( - const std::string& volId, const android::sp& listener) { + const std::string& volId, const android::sp& listener) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(volId); ACQUIRE_LOCK; @@ -357,8 +356,8 @@ binder::Status VoldNativeService::checkEncryption(const std::string& volId) { } binder::Status VoldNativeService::moveStorage( - const std::string& fromVolId, const std::string& toVolId, - const android::sp& listener) { + const std::string& fromVolId, const std::string& toVolId, + const android::sp& listener) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_ID(fromVolId); CHECK_ARGUMENT_ID(toVolId); @@ -416,7 +415,7 @@ binder::Status VoldNativeService::createObb(const std::string& sourcePath, ACQUIRE_LOCK; return translate( - VolumeManager::Instance()->createObb(sourcePath, sourceKey, ownerGid, _aidl_return)); + VolumeManager::Instance()->createObb(sourcePath, sourceKey, ownerGid, _aidl_return)); } binder::Status VoldNativeService::destroyObb(const std::string& volId) { @@ -454,7 +453,7 @@ binder::Status VoldNativeService::destroyStubVolume(const std::string& volId) { } binder::Status VoldNativeService::fstrim( - int32_t fstrimFlags, const android::sp& listener) { + int32_t fstrimFlags, const android::sp& listener) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; @@ -463,7 +462,7 @@ binder::Status VoldNativeService::fstrim( } binder::Status VoldNativeService::runIdleMaint( - const android::sp& listener) { + const android::sp& listener) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; @@ -472,7 +471,7 @@ binder::Status VoldNativeService::runIdleMaint( } binder::Status VoldNativeService::abortIdleMaint( - const android::sp& listener) { + const android::sp& listener) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; @@ -689,7 +688,8 @@ binder::Status VoldNativeService::encryptFstab(const std::string& blkDevice, return translateBool(fscrypt_mount_metadata_encrypted(blkDevice, mountPoint, true)); } -binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial, bool ephemeral) { +binder::Status VoldNativeService::createUserKey(int32_t userId, int32_t userSerial, + bool ephemeral) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_CRYPT_LOCK; @@ -890,19 +890,21 @@ binder::Status VoldNativeService::mountIncFs( CHECK_ARGUMENT_PATH(backingPath); CHECK_ARGUMENT_PATH(targetDir); - auto result = IncFs_Mount(backingPath.c_str(), targetDir.c_str(), - {.flags = IncFsMountFlags(flags), - .defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, - .readLogBufferPages = 4}); - if (result.cmd < 0) { - return translate(result.cmd); + auto control = IncFs_Mount(backingPath.c_str(), targetDir.c_str(), + {.flags = IncFsMountFlags(flags), + .defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, + .readLogBufferPages = 4}); + if (control == nullptr) { + return translate(-1); } using unique_fd = ::android::base::unique_fd; - _aidl_return->cmd.reset(unique_fd(result.cmd)); - _aidl_return->pendingReads.reset(unique_fd(result.pendingReads)); - if (result.logs >= 0) { - _aidl_return->log.reset(unique_fd(result.logs)); + _aidl_return->cmd.reset(unique_fd(dup(IncFs_GetControlFd(control, CMD)))); + _aidl_return->pendingReads.reset(unique_fd(dup(IncFs_GetControlFd(control, PENDING_READS)))); + auto logsFd = IncFs_GetControlFd(control, LOGS); + if (logsFd >= 0) { + _aidl_return->log.reset(unique_fd(dup(logsFd))); } + IncFs_DeleteControl(control); return Ok(); } From 91e0bf4998eb3c0f8d3cd05bd7fe369e19279dbb Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Tue, 31 Mar 2020 14:46:25 -0700 Subject: [PATCH 087/112] Checking LOADER_USAGE_STATS before enabling read logs. Bug: b/152633648 Test: atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest Change-Id: I29bf16d06a013566c8dd08e64be2a23ad805e37d --- VoldNativeService.cpp | 26 +++++++++++++++++++++++++- VoldNativeService.h | 3 +++ binder/android/os/IVold.aidl | 1 + 3 files changed, 29 insertions(+), 1 deletion(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 1beb29c..d1d7d86 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -53,6 +53,7 @@ namespace vold { namespace { constexpr const char* kDump = "android.permission.DUMP"; +constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS"; static binder::Status error(const std::string& msg) { PLOG(ERROR) << msg; @@ -893,7 +894,8 @@ binder::Status VoldNativeService::mountIncFs( auto control = IncFs_Mount(backingPath.c_str(), targetDir.c_str(), {.flags = IncFsMountFlags(flags), .defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, - .readLogBufferPages = 4}); + // Mount with read logs disabled. + .readLogBufferPages = 0}); if (control == nullptr) { return translate(-1); } @@ -915,6 +917,28 @@ binder::Status VoldNativeService::unmountIncFs(const std::string& dir) { return translate(IncFs_Unmount(dir.c_str())); } +binder::Status VoldNativeService::setIncFsMountOptions( + const ::android::os::incremental::IncrementalFileSystemControlParcel& control, + bool enableReadLogs) { + auto status = CheckPermission(kDataUsageStats); + if (!status.isOk()) { + return status; + } + + auto incfsControl = IncFs_CreateControl(dup(control.cmd.get()), dup(control.pendingReads.get()), + dup(control.log.get())); + if (auto error = IncFs_SetOptions( + incfsControl, + {.defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, + .readLogBufferPages = enableReadLogs ? INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES : 0}); + error < 0) { + status = binder::Status::fromServiceSpecificError(error); + } + IncFs_DeleteControl(incfsControl); + + return status; +} + binder::Status VoldNativeService::bindMount(const std::string& sourceDir, const std::string& targetDir) { ENFORCE_SYSTEM_OR_ROOT; diff --git a/VoldNativeService.h b/VoldNativeService.h index 2f4b6eb..060d704 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -154,6 +154,9 @@ class VoldNativeService : public BinderService, public os::Bn const std::string& backingPath, const std::string& targetDir, int32_t flags, ::android::os::incremental::IncrementalFileSystemControlParcel* _aidl_return) override; binder::Status unmountIncFs(const std::string& dir) override; + binder::Status setIncFsMountOptions( + const ::android::os::incremental::IncrementalFileSystemControlParcel& control, + bool enableReadLogs) override; binder::Status bindMount(const std::string& sourceDir, const std::string& targetDir) override; }; diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 1d5657f..68e2ba9 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -135,6 +135,7 @@ interface IVold { boolean incFsEnabled(); IncrementalFileSystemControlParcel mountIncFs(@utf8InCpp String backingPath, @utf8InCpp String targetDir, int flags); void unmountIncFs(@utf8InCpp String dir); + void setIncFsMountOptions(in IncrementalFileSystemControlParcel control, boolean enableReadLogs); void bindMount(@utf8InCpp String sourceDir, @utf8InCpp String targetDir); const int ENCRYPTION_FLAG_NO_UI = 4; From 50397a72f13629932423dbd48c554ebec0fa1008 Mon Sep 17 00:00:00 2001 From: Shawn Willden Date: Wed, 1 Apr 2020 10:02:16 -0600 Subject: [PATCH 088/112] Send earlyBootEnded notice to all Keymasters Vold incorrectly sends the earlyBootEnded signal only to the Keymaster instance used for device encryption, but all of them need it. Bug: 152932559 Test: VtsHalKeymasterV4_1TargetTest Change-Id: Id8f01a1dc7d2398395f369c3ea74656a82888829 --- Keymaster.cpp | 20 +++++++++++++------- Keymaster.h | 6 +++--- MetadataCrypt.cpp | 10 +++------- 3 files changed, 19 insertions(+), 17 deletions(-) diff --git a/Keymaster.cpp b/Keymaster.cpp index c3f2912..786cdb5 100644 --- a/Keymaster.cpp +++ b/Keymaster.cpp @@ -229,13 +229,19 @@ bool Keymaster::isSecure() { } void Keymaster::earlyBootEnded() { - auto error = mDevice->earlyBootEnded(); - if (!error.isOk()) { - LOG(ERROR) << "earlyBootEnded failed: " << error.description(); - } - km::V4_1_ErrorCode km_error = error; - if (km_error != km::V4_1_ErrorCode::OK && km_error != km::V4_1_ErrorCode::UNIMPLEMENTED) { - LOG(ERROR) << "Error reporting early boot ending to keymaster: " << int32_t(km_error); + auto devices = KmDevice::enumerateAvailableDevices(); + for (auto& dev : devices) { + auto error = dev->earlyBootEnded(); + if (!error.isOk()) { + LOG(ERROR) << "earlyBootEnded call failed: " << error.description() << " for " + << dev->halVersion().keymasterName; + } + km::V4_1_ErrorCode km_error = error; + if (km_error != km::V4_1_ErrorCode::OK && km_error != km::V4_1_ErrorCode::UNIMPLEMENTED) { + LOG(ERROR) << "Error reporting early boot ending to keymaster: " + << static_cast(km_error) << " for " + << dev->halVersion().keymasterName; + } } } diff --git a/Keymaster.h b/Keymaster.h index 4a9ed02..d9ced91 100644 --- a/Keymaster.h +++ b/Keymaster.h @@ -128,9 +128,9 @@ class Keymaster { km::AuthorizationSet* outParams); bool isSecure(); - // Tell Keymaster that early boot has ended and early boot-only keys can no longer be created or - // used. - void earlyBootEnded(); + // Tell all Keymaster instances that early boot has ended and early boot-only keys can no longer + // be created or used. + static void earlyBootEnded(); private: sp mDevice; diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 8227e74..8659502 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -87,13 +87,9 @@ const KeyGeneration makeGen(const CryptoOptions& options) { } static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) { - // We're about to mount data not verified by verified boot. Tell Keymaster that early boot has - // ended. - // - // TODO(paulcrowley): Make a Keymaster singleton or something, so we don't have to repeatedly - // open and initialize the service. - ::android::vold::Keymaster keymaster; - keymaster.earlyBootEnded(); + // We're about to mount data not verified by verified boot. Tell Keymaster instances that early + // boot has ended. + ::android::vold::Keymaster::earlyBootEnded(); // fs_mgr_do_mount runs fsck. Use setexeccon to run trusted // partitions in the fsck domain. From 75973cb0dde856b8e3a94c808fdfc29d53252c3c Mon Sep 17 00:00:00 2001 From: Linus Tufvesson Date: Mon, 23 Mar 2020 11:59:43 +0000 Subject: [PATCH 089/112] Replace EnsureDirExists with a call to setupAppDir Test: Manually verified ownership of /storage/emulated/0/Android/data on cf_x86_phone-userdebug after enabling feature Bug: 151455752 Change-Id: I75a1e3b769476e56094e41d82e7f8e1a72827ded --- VolumeManager.cpp | 6 ++++-- VolumeManager.h | 2 ++ 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index 6a40a52..e4e5781 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -776,7 +776,8 @@ static std::string getStorageDirTarget(userid_t userId, std::string dirName, } // Fork the process and remount storage -static bool forkAndRemountStorage(int uid, int pid, const std::vector& packageNames) { +bool VolumeManager::forkAndRemountStorage(int uid, int pid, + const std::vector& packageNames) { userid_t userId = multiuser_get_user_id(uid); std::string mnt_path = StringPrintf("/proc/%d/ns/mnt", pid); android::base::unique_fd nsFd( @@ -814,7 +815,8 @@ static bool forkAndRemountStorage(int uid, int pid, const std::vector& packageNames); + static VolumeManager* Instance(); /* From 605a44fe93bd532667b1778a9304d0ecc541b3d8 Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Thu, 2 Apr 2020 15:21:47 -0700 Subject: [PATCH 090/112] Additional operation check when enabling read logs. Vold now does not check caller's permission, but only accepts transactions from system_server. And it's up to system server to do the right thing and check permissions/appops. Bug: b/152633648 Test: atest PackageManagerShellCommandTest PackageManagerShellCommandIncrementalTest Test: adb shell appops set 1000 GET_USAGE_STATS deny Change-Id: Id56c1673b135b72b3ec86e572aa4bcca3afc19ab --- VoldNativeService.cpp | 7 ++----- VoldNativeServiceValidation.cpp | 7 +++---- 2 files changed, 5 insertions(+), 9 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index d1d7d86..0cce561 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -53,7 +53,6 @@ namespace vold { namespace { constexpr const char* kDump = "android.permission.DUMP"; -constexpr const char* kDataUsageStats = "android.permission.LOADER_USAGE_STATS"; static binder::Status error(const std::string& msg) { PLOG(ERROR) << msg; @@ -920,11 +919,9 @@ binder::Status VoldNativeService::unmountIncFs(const std::string& dir) { binder::Status VoldNativeService::setIncFsMountOptions( const ::android::os::incremental::IncrementalFileSystemControlParcel& control, bool enableReadLogs) { - auto status = CheckPermission(kDataUsageStats); - if (!status.isOk()) { - return status; - } + ENFORCE_SYSTEM_OR_ROOT; + auto status = Ok(); auto incfsControl = IncFs_CreateControl(dup(control.cmd.get()), dup(control.pendingReads.get()), dup(control.log.get())); if (auto error = IncFs_SetOptions( diff --git a/VoldNativeServiceValidation.cpp b/VoldNativeServiceValidation.cpp index 2e21ace..ee1e65a 100644 --- a/VoldNativeServiceValidation.cpp +++ b/VoldNativeServiceValidation.cpp @@ -39,11 +39,10 @@ binder::Status Exception(uint32_t code, const std::string& msg) { } binder::Status CheckPermission(const char* permission) { - pid_t pid; - uid_t uid; + int32_t pid; + int32_t uid; - if (checkCallingPermission(String16(permission), reinterpret_cast(&pid), - reinterpret_cast(&uid))) { + if (checkCallingPermission(String16(permission), &pid, &uid)) { return Ok(); } else { return Exception(binder::Status::EX_SECURITY, From 4073c0b5241b635cb59e9e8a75ddcc783b5a99ce Mon Sep 17 00:00:00 2001 From: Paul Crowley Date: Sun, 22 Mar 2020 08:02:06 -0700 Subject: [PATCH 091/112] Choose options format using property To make it easier to support disk formats created using old versions of dm-default-key with new kernels, choose the disk format to use based on options_format_version and first_api_version properties instead of checking the version number of the kernel module. Bug: 150761030 Test: crosshatch and cuttlefish boot normally; cuttlefish fails with "default-key: Not enough arguments" as expected when option is set to 1 Cherry-Picked-From: f56d553babc368e557fe90513e78a5ba06626b0d Merged-In: Ib51071b7c316ce074de72439741087b18335048c Change-Id: Ib51071b7c316ce074de72439741087b18335048c --- MetadataCrypt.cpp | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 8227e74..7b2219b 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -58,7 +58,7 @@ using namespace android::dm; // Parsed from metadata options struct CryptoOptions { struct CryptoType cipher = invalid_crypto_type; - bool is_legacy = false; + bool use_legacy_options_format = false; bool set_dun = true; // Non-legacy driver always sets DUN bool use_hw_wrapped_key = false; }; @@ -211,7 +211,7 @@ static bool create_crypto_blk_dev(const std::string& dm_name, const std::string& auto target = std::make_unique(0, *nr_sec, options.cipher.get_kernel_name(), hex_key, blk_device, 0); - if (options.is_legacy) target->SetIsLegacy(); + if (options.use_legacy_options_format) target->SetUseLegacyOptionsFormat(); if (options.set_dun) target->SetSetDun(); if (options.use_hw_wrapped_key) target->SetWrappedKeyV0(); @@ -287,25 +287,30 @@ bool fscrypt_mount_metadata_encrypted(const std::string& blk_device, const std:: return false; } - bool is_legacy; - if (!DmTargetDefaultKey::IsLegacy(&is_legacy)) return false; + constexpr unsigned int pre_gki_level = 29; + unsigned int options_format_version = android::base::GetUintProperty( + "ro.crypto.dm_default_key.options_format.version", + (GetFirstApiLevel() <= pre_gki_level ? 1 : 2)); CryptoOptions options; - if (is_legacy) { + if (options_format_version == 1) { if (!data_rec->metadata_encryption.empty()) { LOG(ERROR) << "metadata_encryption options cannot be set in legacy mode"; return false; } options.cipher = legacy_aes_256_xts; - options.is_legacy = true; + options.use_legacy_options_format = true; options.set_dun = android::base::GetBoolProperty("ro.crypto.set_dun", false); if (!options.set_dun && data_rec->fs_mgr_flags.checkpoint_blk) { LOG(ERROR) << "Block checkpoints and metadata encryption require ro.crypto.set_dun option"; return false; } - } else { + } else if (options_format_version == 2) { if (!parse_options(data_rec->metadata_encryption, &options)) return false; + } else { + LOG(ERROR) << "Unknown options_format_version: " << options_format_version; + return false; } auto gen = needs_encrypt ? makeGen(options) : neverGen(); From aee6b6fccd82c0eeaf516bc29b1b3ca72e582b12 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 15 Apr 2020 11:42:47 +0200 Subject: [PATCH 092/112] Rename casefold/projectid properties. According to property naming guidelines. Bug: 152170470 Bug: 153525566 Test: N/A Change-Id: Iaebff2a835288839a2faf0edbe0e47ceb96b4458 Merged-In: Iaebff2a835288839a2faf0edbe0e47ceb96b4458 --- fs/Ext4.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/Ext4.cpp b/fs/Ext4.cpp index 8bb930d..6bc7ad2 100644 --- a/fs/Ext4.cpp +++ b/fs/Ext4.cpp @@ -171,8 +171,9 @@ status_t Format(const std::string& source, unsigned long numSectors, const std:: cmd.push_back("-M"); cmd.push_back(target); - bool needs_casefold = android::base::GetBoolProperty("ro.emulated_storage.casefold", false); - bool needs_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false); + bool needs_casefold = + android::base::GetBoolProperty("external_storage.casefold.enabled", false); + bool needs_projid = android::base::GetBoolProperty("external_storage.projid.enabled", false); if (needs_projid) { cmd.push_back("-I"); From e9239f757e079f3d779f3e86c12673a8c358b808 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Thu, 16 Apr 2020 10:16:29 +0200 Subject: [PATCH 093/112] Rename casefold/projectid properties (for f2fs). According to property naming guidelines. Bug: 152170470 Bug: 153525566 Test: N/A Change-Id: Iad1caff6e5cfb7f6a09b77532d64a24de9b0b3c6 --- fs/F2fs.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/fs/F2fs.cpp b/fs/F2fs.cpp index ee39f2b..9b8d2c4 100644 --- a/fs/F2fs.cpp +++ b/fs/F2fs.cpp @@ -90,8 +90,9 @@ status_t Format(const std::string& source) { cmd.push_back("verity"); const bool needs_casefold = - android::base::GetBoolProperty("ro.emulated_storage.casefold", false); - const bool needs_projid = android::base::GetBoolProperty("ro.emulated_storage.projid", false); + android::base::GetBoolProperty("external_storage.casefold.enabled", false); + const bool needs_projid = + android::base::GetBoolProperty("external_storage.projid.enabled", false); if (needs_projid) { cmd.push_back("-O"); cmd.push_back("project_quota,extra_attr"); From bf205ab7d41e04e19fa3e652a5730047716b8b7b Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 20 Apr 2020 15:14:48 +0200 Subject: [PATCH 094/112] Don't do private app-dir permissions/quota on public volumes. While looking at some emulator logs, I noticed that we fail to create dirs like /Android/data/com.foo/cache on public volumes, because we try to chmod it; public volumes go completely through FUSE, even for Android/, and so these operations will fail, because the underlying UID/GID is not setup correctly. Really the only thing we really have to do on public volumes is create the dirs, like we used to do. Bug: 152618535 Test: manually verify cache dirs can be created successfully Change-Id: I66e5d0873f1198123787943b17b468eadf0a853d --- VolumeManager.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index e4e5781..bd11be5 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -1012,6 +1012,12 @@ int VolumeManager::setupAppDir(const std::string& path, int32_t appUid, bool fix return OK; } + if (volume->getType() == VolumeBase::Type::kPublic) { + // On public volumes, we don't need to setup permissions, as everything goes through + // FUSE; just create the dirs and be done with it. + return fs_mkdirs(lowerPath.c_str(), 0700); + } + // Create the app paths we need from the root return PrepareAppDirFromRoot(lowerPath, volumeRoot, appUid, fixupExistingOnly); } From ef63921f81118ea71049f8ff36fa035c54ea5ecd Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Tue, 7 Apr 2020 13:43:20 +0100 Subject: [PATCH 095/112] Bind mount install and android writable DATA and OBB dirs To improvement performance, and also making them able to list the dirs. This should also be fine under b/151055432, as the whole obb directory is mounted, renameTo() from installer to apps should be a move not copy. Bug: 153422990 Bug: 153540919 Test: atest AdoptableHostTest Change-Id: Ia18fd4393db14a0f11d6e5b947dd716515bdeeef --- VolumeManager.cpp | 2 +- model/EmulatedVolume.cpp | 68 ++++++++++++++++++++++++++++++++++++---- 2 files changed, 63 insertions(+), 7 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index e4e5781..eac020f 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -947,7 +947,7 @@ int VolumeManager::unmountAll() { !StartsWith(test, "/mnt/scratch") && #endif !StartsWith(test, "/mnt/vendor") && !StartsWith(test, "/mnt/product") && - !StartsWith(test, "/mnt/installer")) || + !StartsWith(test, "/mnt/installer") && !StartsWith(test, "/mnt/androidwritable")) || StartsWith(test, "/storage/")) { toUnmount.push_front(test); } diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index e411b33..e7cd36e 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -141,12 +141,49 @@ status_t EmulatedVolume::mountFuseBindMounts() { // a special bind mount, since app-private and OBB dirs share the same GID, but we // only want to give access to the latter. if (mUseSdcardFs) { - std::string installerSource( - StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", label.c_str(), userId)); - std::string installerTarget( - StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); + std::string obbSource(StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", + label.c_str(), userId)); + std::string obbInstallerTarget(StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", + userId, label.c_str(), userId)); - status = doFuseBindMount(installerSource, installerTarget, pathsToUnmount); + status = doFuseBindMount(obbSource, obbInstallerTarget, pathsToUnmount); + if (status != OK) { + return status; + } + } else if (mAppDataIsolationEnabled) { + std::string obbSource(StringPrintf("%s/obb", androidSource.c_str())); + std::string obbInstallerTarget(StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", + userId, label.c_str(), userId)); + + status = doFuseBindMount(obbSource, obbInstallerTarget, pathsToUnmount); + if (status != OK) { + return status; + } + } + + // /mnt/androidwriteable is similar to /mnt/installer, but it's for + // MOUNT_EXTERNAL_ANDROID_WRITABLE apps and it can also access DATA (Android/data) dirs. + if (mAppDataIsolationEnabled) { + std::string obbSource = mUseSdcardFs ? + StringPrintf("/mnt/runtime/write/%s/%d/Android/obb", label.c_str(), userId) + : StringPrintf("%s/obb", androidSource.c_str()); + + std::string obbAndroidWritableTarget( + StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/obb", + userId, label.c_str(), userId)); + + status = doFuseBindMount(obbSource, obbAndroidWritableTarget, pathsToUnmount); + if (status != OK) { + return status; + } + + std::string dataSource = mUseSdcardFs ? + StringPrintf("/mnt/runtime/write/%s/%d/Android/data", label.c_str(), userId) + : StringPrintf("%s/data", androidSource.c_str()); + std::string dataTarget(StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/data", + userId, label.c_str(), userId)); + + status = doFuseBindMount(dataSource, dataTarget, pathsToUnmount); if (status != OK) { return status; } @@ -159,7 +196,7 @@ status_t EmulatedVolume::unmountFuseBindMounts() { std::string label = getLabel(); int userId = getMountUserId(); - if (mUseSdcardFs) { + if (mUseSdcardFs || mAppDataIsolationEnabled) { std::string installerTarget( StringPrintf("/mnt/installer/%d/%s/%d/Android/obb", userId, label.c_str(), userId)); LOG(INFO) << "Unmounting " << installerTarget; @@ -169,6 +206,25 @@ status_t EmulatedVolume::unmountFuseBindMounts() { // Intentional continue to try to unmount the other bind mount } } + if (mAppDataIsolationEnabled) { + std::string obbTarget( StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/obb", + userId, label.c_str(), userId)); + LOG(INFO) << "Unmounting " << obbTarget; + auto status = UnmountTree(obbTarget); + if (status != OK) { + LOG(ERROR) << "Failed to unmount " << obbTarget; + // Intentional continue to try to unmount the other bind mount + } + std::string dataTarget(StringPrintf("/mnt/androidwritable/%d/%s/%d/Android/data", + userId, label.c_str(), userId)); + LOG(INFO) << "Unmounting " << dataTarget; + status = UnmountTree(dataTarget); + if (status != OK) { + LOG(ERROR) << "Failed to unmount " << dataTarget; + // Intentional continue to try to unmount the other bind mount + } + } + // When app data isolation is enabled, kill all apps that obb/ is mounted, otherwise we should // umount the whole Android/ dir. if (mAppDataIsolationEnabled) { From 78f806198f85ca37abb617235c89abaca7d1c19c Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Mon, 20 Apr 2020 22:21:49 +0100 Subject: [PATCH 096/112] Introduce ro.crypto.uses_fs_ioc_add_encryption_key property Bug: 154327249 Test: adb shell getprop ro.crypto.uses_fs_ioc_add_encryption_key Test: adb bugreport && checked content contains new property Change-Id: I562df49deffdccdb2cfd657130fc05b24d40a6a6 --- KeyUtil.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/KeyUtil.cpp b/KeyUtil.cpp index 3359699..acc42db 100644 --- a/KeyUtil.cpp +++ b/KeyUtil.cpp @@ -27,6 +27,7 @@ #include #include +#include #include #include @@ -87,6 +88,7 @@ bool isFsKeyringSupported(void) { } LOG(DEBUG) << "Detected support for FS_IOC_ADD_ENCRYPTION_KEY"; supported = true; + android::base::SetProperty("ro.crypto.uses_fs_ioc_add_encryption_key", "true"); } // There's no need to check for FS_IOC_REMOVE_ENCRYPTION_KEY, since it's // guaranteed to be available if FS_IOC_ADD_ENCRYPTION_KEY is. There's From fc7b6697b40076f8fd67f6fbc805812c9fd07369 Mon Sep 17 00:00:00 2001 From: Yurii Zubrytskyi Date: Wed, 22 Apr 2020 23:23:24 -0700 Subject: [PATCH 097/112] [incfs] Use new IncFs_ReleaseControlFds() instead of duping Vold needs to pass / accept IncFs control via Binder, so it neeeds to get and put its internal FDs in and out. Using the new release() function it works without extra fd duping Bug: 153704006 Test: builds & boots Change-Id: I64bc5b1ca9f2c69e34c3a860ed3edbe58bd9ea29 --- VoldNativeService.cpp | 54 ++++++++++++++++++++++--------------------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 0cce561..1020526 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -41,7 +41,7 @@ #include "VoldUtil.h" #include "VolumeManager.h" #include "cryptfs.h" -#include "incfs_ndk.h" +#include "incfs.h" using android::base::StringPrintf; using std::endl; @@ -879,7 +879,7 @@ binder::Status VoldNativeService::resetCheckpoint() { binder::Status VoldNativeService::incFsEnabled(bool* _aidl_return) { ENFORCE_SYSTEM_OR_ROOT; - *_aidl_return = IncFs_IsEnabled(); + *_aidl_return = incfs::enabled(); return Ok(); } @@ -890,22 +890,19 @@ binder::Status VoldNativeService::mountIncFs( CHECK_ARGUMENT_PATH(backingPath); CHECK_ARGUMENT_PATH(targetDir); - auto control = IncFs_Mount(backingPath.c_str(), targetDir.c_str(), - {.flags = IncFsMountFlags(flags), - .defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, - // Mount with read logs disabled. - .readLogBufferPages = 0}); - if (control == nullptr) { - return translate(-1); + auto control = incfs::mount(backingPath, targetDir, + {.flags = IncFsMountFlags(flags), + .defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, + // Mount with read logs disabled. + .readLogBufferPages = 0}); + if (!control) { + return translate(-errno); } - using unique_fd = ::android::base::unique_fd; - _aidl_return->cmd.reset(unique_fd(dup(IncFs_GetControlFd(control, CMD)))); - _aidl_return->pendingReads.reset(unique_fd(dup(IncFs_GetControlFd(control, PENDING_READS)))); - auto logsFd = IncFs_GetControlFd(control, LOGS); - if (logsFd >= 0) { - _aidl_return->log.reset(unique_fd(dup(logsFd))); - } - IncFs_DeleteControl(control); + auto fds = control.releaseFds(); + using android::base::unique_fd; + _aidl_return->cmd.reset(unique_fd(fds[CMD].release())); + _aidl_return->pendingReads.reset(unique_fd(fds[PENDING_READS].release())); + _aidl_return->log.reset(unique_fd(fds[LOGS].release())); return Ok(); } @@ -913,7 +910,7 @@ binder::Status VoldNativeService::unmountIncFs(const std::string& dir) { ENFORCE_SYSTEM_OR_ROOT; CHECK_ARGUMENT_PATH(dir); - return translate(IncFs_Unmount(dir.c_str())); + return translate(incfs::unmount(dir)); } binder::Status VoldNativeService::setIncFsMountOptions( @@ -921,19 +918,24 @@ binder::Status VoldNativeService::setIncFsMountOptions( bool enableReadLogs) { ENFORCE_SYSTEM_OR_ROOT; - auto status = Ok(); - auto incfsControl = IncFs_CreateControl(dup(control.cmd.get()), dup(control.pendingReads.get()), - dup(control.log.get())); - if (auto error = IncFs_SetOptions( + auto incfsControl = + incfs::createControl(control.cmd.get(), control.pendingReads.get(), control.log.get()); + auto cleanupFunc = [](auto incfsControl) { + for (auto& fd : incfsControl->releaseFds()) { + (void)fd.release(); + } + }; + auto cleanup = + std::unique_ptr(&incfsControl, cleanupFunc); + if (auto error = incfs::setOptions( incfsControl, {.defaultReadTimeoutMs = INCFS_DEFAULT_READ_TIMEOUT_MS, .readLogBufferPages = enableReadLogs ? INCFS_DEFAULT_PAGE_READ_BUFFER_PAGES : 0}); error < 0) { - status = binder::Status::fromServiceSpecificError(error); + return binder::Status::fromServiceSpecificError(error); } - IncFs_DeleteControl(incfsControl); - return status; + return Ok(); } binder::Status VoldNativeService::bindMount(const std::string& sourceDir, @@ -942,7 +944,7 @@ binder::Status VoldNativeService::bindMount(const std::string& sourceDir, CHECK_ARGUMENT_PATH(sourceDir); CHECK_ARGUMENT_PATH(targetDir); - return translate(IncFs_BindMount(sourceDir.c_str(), targetDir.c_str())); + return translate(incfs::bindMount(sourceDir, targetDir)); } } // namespace vold From 5ec8658abcb5be66a380190d7e4aa39510f3b1af Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 4 May 2020 14:57:35 +0200 Subject: [PATCH 098/112] Introduce postMount() VolumeBase helper. When we're mounting a private volume, we create stacked emulated volumes on top of it. Due to the ordering there, we would broadcast the emulated volumes being created *before* the "mounted" status update. This in turn could cause us to try and mount these emulated volumes before the underlying private volume is really mounted. This is problematic in particular on devices that support a filesystem keyring, where we need to do some additional setup before the devices can be used. While we could modify StorageManagerService to delay the mount, a safer fix at this stage of the release is to just fix the ordering of these events. To achieve that, add a simple postMount() helper, that is called after a succesful mount. This allows us to setup the volume properly before trying to mount any stacked volumes. Bug: 151079464 Test: atest AdoptableHostTest Change-Id: I2cc4113d4d71d89aa629bb9c0fa9be441355c079 --- model/PrivateVolume.cpp | 6 ++++-- model/PrivateVolume.h | 1 + model/VolumeBase.cpp | 5 +++++ model/VolumeBase.h | 1 + 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index 75757f7..e146633 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -177,6 +177,10 @@ status_t PrivateVolume::doMount() { return -EIO; } + return OK; +} + +void PrivateVolume::doPostMount() { auto vol_manager = VolumeManager::Instance(); std::string mediaPath(mPath + "/media"); @@ -189,8 +193,6 @@ status_t PrivateVolume::doMount() { addVolume(vol); vol->create(); } - - return OK; } status_t PrivateVolume::doUnmount() { diff --git a/model/PrivateVolume.h b/model/PrivateVolume.h index 9780485..607c4d1 100644 --- a/model/PrivateVolume.h +++ b/model/PrivateVolume.h @@ -49,6 +49,7 @@ class PrivateVolume : public VolumeBase { status_t doCreate() override; status_t doDestroy() override; status_t doMount() override; + void doPostMount() override; status_t doUnmount() override; status_t doFormat(const std::string& fsType) override; diff --git a/model/VolumeBase.cpp b/model/VolumeBase.cpp index 687d4f7..27448da 100644 --- a/model/VolumeBase.cpp +++ b/model/VolumeBase.cpp @@ -232,9 +232,14 @@ status_t VolumeBase::mount() { status_t res = doMount(); setState(res == OK ? State::kMounted : State::kUnmountable); + if (res == OK) { + doPostMount(); + } return res; } +void VolumeBase::doPostMount() {} + status_t VolumeBase::unmount() { if (mState != State::kMounted) { LOG(WARNING) << getId() << " unmount requires state mounted"; diff --git a/model/VolumeBase.h b/model/VolumeBase.h index 078bb0c..689750d 100644 --- a/model/VolumeBase.h +++ b/model/VolumeBase.h @@ -120,6 +120,7 @@ class VolumeBase { virtual status_t doCreate(); virtual status_t doDestroy(); virtual status_t doMount() = 0; + virtual void doPostMount(); virtual status_t doUnmount() = 0; virtual status_t doFormat(const std::string& fsType); From e96b34fe822466d4453442f339256e608b4b751c Mon Sep 17 00:00:00 2001 From: Ricky Wai Date: Thu, 7 May 2020 16:01:33 +0100 Subject: [PATCH 099/112] Mount storage Android/data and Android/obb as tmpfs in app namespace So Android/data and Android/obb won't be accessing fuse anymore, and apps should not see other packages as well as it's sandboxed the tmpfs. Bug: 155462341 Test: atest AppDataIsolationTests pass after feature flag is on Change-Id: I5658440772e669c1235d318f708a3d336523754f --- VolumeManager.cpp | 35 ++++++++++++++++++++++++++++++++--- 1 file changed, 32 insertions(+), 3 deletions(-) diff --git a/VolumeManager.cpp b/VolumeManager.cpp index b6edd9e..c0d0e77 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -19,6 +19,7 @@ #include #include #include +#include #include #include #include @@ -739,8 +740,10 @@ int VolumeManager::remountUid(uid_t uid, int32_t mountMode) { } -// Set the namespace the app process and remount its storage directories. -static bool remountStorageDirs(int nsFd, const char* sources[], const char* targets[], int size) { +// In each app's namespace, mount tmpfs on obb and data dir, and bind mount obb and data +// package dirs. +static bool remountStorageDirs(int nsFd, const char* android_data_dir, const char* android_obb_dir, + int uid, const char* sources[], const char* targets[], int size) { // This code is executed after a fork so it's very important that the set of // methods we call here is strictly limited. if (setns(nsFd, CLONE_NEWNS) != 0) { @@ -748,7 +751,27 @@ static bool remountStorageDirs(int nsFd, const char* sources[], const char* targ return false; } + // Mount tmpfs on Android/data and Android/obb + if (TEMP_FAILURE_RETRY(mount("tmpfs", android_data_dir, "tmpfs", + MS_NOSUID | MS_NODEV | MS_NOEXEC, "uid=0,gid=0,mode=0751")) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount tmpfs to %s :%s", + android_data_dir, strerror(errno)); + return false; + } + if (TEMP_FAILURE_RETRY(mount("tmpfs", android_obb_dir, "tmpfs", + MS_NOSUID | MS_NODEV | MS_NOEXEC, "uid=0,gid=0,mode=0751")) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount tmpfs to %s :%s", + android_obb_dir, strerror(errno)); + return false; + } + for (int i = 0; i < size; i++) { + // Create package dir and bind mount it to the actual one. + if (TEMP_FAILURE_RETRY(mkdir(targets[i], 0700)) == -1) { + async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mkdir %s %s", + targets[i], strerror(errno)); + return false; + } if (TEMP_FAILURE_RETRY(mount(sources[i], targets[i], NULL, MS_BIND | MS_REC, NULL)) == -1) { async_safe_format_log(ANDROID_LOG_ERROR, "vold", "Failed to mount %s to %s :%s", sources[i], targets[i], strerror(errno)); @@ -823,11 +846,17 @@ bool VolumeManager::forkAndRemountStorage(int uid, int pid, } } + char android_data_dir[PATH_MAX]; + char android_obb_dir[PATH_MAX]; + snprintf(android_data_dir, PATH_MAX, "/storage/emulated/%d/Android/data", userId); + snprintf(android_obb_dir, PATH_MAX, "/storage/emulated/%d/Android/obb", userId); + pid_t child; // Fork a child to mount Android/obb android Android/data dirs, as we don't want it to affect // original vold process mount namespace. if (!(child = fork())) { - if (remountStorageDirs(nsFd, sources_cstr, targets_cstr, size)) { + if (remountStorageDirs(nsFd, android_data_dir, android_obb_dir, uid, + sources_cstr, targets_cstr, size)) { _exit(0); } else { _exit(1); From 58d40440823c7862c1ca3af482d45ae81b1b2804 Mon Sep 17 00:00:00 2001 From: Satoshi Niwa Date: Tue, 12 May 2020 14:41:40 +0000 Subject: [PATCH 100/112] Revert "ARC++ swap for AppFuseUtil" This reverts commit ab7c958cc5ca32aa4f79a6e1fc5784eb3286e326. Reason for revert: ARC is migrating to ARCVM on R, which doesn't use AppFuse any more. Bug: 110379912 Test: m Change-Id: Icc827c59530274421e4c94789d96fd3d287e591e --- Android.bp | 3 --- 1 file changed, 3 deletions(-) diff --git a/Android.bp b/Android.bp index 03dde1e..b033647 100644 --- a/Android.bp +++ b/Android.bp @@ -151,12 +151,10 @@ cc_library_static { product_variables: { arc: { exclude_srcs: [ - "AppFuseUtil.cpp", "model/ObbVolume.cpp", ], static_libs: [ "arc_services_aidl", - "libarcappfuse", "libarcobbvolume", ], }, @@ -186,7 +184,6 @@ cc_binary { arc: { static_libs: [ "arc_services_aidl", - "libarcappfuse", "libarcobbvolume", ], }, From ff1fc9bc417c8a4b6bffb2b12ab69a705676c17a Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Thu, 14 May 2020 16:35:03 -0700 Subject: [PATCH 101/112] Expand virtio_block check to other virtual devices The Android Emulator isn't the only virtual device the virtio-block detection code is useful for, and those platforms might not set any discriminating properties to indicate that they are virtual. Rework the virtio-block major detection to use /proc/devices instead of hardcoding the assumption that any virtual platform can have virtio-block at any experimental major; the new code permits only the exact experimental major assigned to virtio-block. The new code runs everywhere, but it will only run once and could be expanded later to detect dynamic or experimental majors. Bug: 156286088 Change-Id: Ieae805d08fddd0124a397636f04d99194a9ef7e5 --- Utils.cpp | 36 ++++++++++++++++++++++++++++++++++-- Utils.h | 4 ++-- VolumeManager.cpp | 11 ++++------- model/Disk.cpp | 33 ++------------------------------- 4 files changed, 42 insertions(+), 42 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 1e20d75..b129990 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -77,6 +77,7 @@ bool sSleepOnUnmount = true; static const char* kBlkidPath = "/system/bin/blkid"; static const char* kKeyPath = "/data/misc/vold"; +static const char* kProcDevices = "/proc/devices"; static const char* kProcFilesystems = "/proc/filesystems"; static const char* kAndroidDir = "/Android/"; @@ -1103,8 +1104,39 @@ bool Readlinkat(int dirfd, const std::string& path, std::string* result) { } } -bool IsRunningInEmulator() { - return android::base::GetBoolProperty("ro.kernel.qemu", false); +static unsigned int GetMajorBlockVirtioBlk() { + std::string devices; + if (!ReadFileToString(kProcDevices, &devices)) { + PLOG(ERROR) << "Unable to open /proc/devices"; + return 0; + } + + bool blockSection = false; + for (auto line : android::base::Split(devices, "\n")) { + if (line == "Block devices:") { + blockSection = true; + } else if (line == "Character devices:") { + blockSection = false; + } else if (blockSection) { + auto tokens = android::base::Split(line, " "); + if (tokens.size() == 2 && tokens[1] == "virtblk") { + return std::stoul(tokens[0]); + } + } + } + + return 0; +} + +bool IsVirtioBlkDevice(unsigned int major) { + // Most virtualized platforms expose block devices with the virtio-blk + // block device driver. Unfortunately, this driver does not use a fixed + // major number, but relies on the kernel to assign one from a specific + // range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE" + // per Documentation/devices.txt. This is true even for the latest Linux + // kernel (4.4; see init() in drivers/block/virtio_blk.c). + static unsigned int kMajorBlockVirtioBlk = GetMajorBlockVirtioBlk(); + return kMajorBlockVirtioBlk && major == kMajorBlockVirtioBlk; } static status_t findMountPointsWithPrefix(const std::string& prefix, diff --git a/Utils.h b/Utils.h index 5e6ff1b..e04dcaa 100644 --- a/Utils.h +++ b/Utils.h @@ -155,8 +155,8 @@ status_t RestoreconRecursive(const std::string& path); // TODO: promote to android::base bool Readlinkat(int dirfd, const std::string& path, std::string* result); -/* Checks if Android is running in QEMU */ -bool IsRunningInEmulator(); +// Handles dynamic major assignment for virtio-block +bool IsVirtioBlkDevice(unsigned int major); status_t UnmountTreeWithPrefix(const std::string& prefix); status_t UnmountTree(const std::string& mountPoint); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index c0d0e77..f64f5f6 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -83,6 +83,7 @@ using android::vold::DeleteDirContents; using android::vold::DeleteDirContentsAndDir; using android::vold::EnsureDirExists; using android::vold::IsFilesystemSupported; +using android::vold::IsVirtioBlkDevice; using android::vold::PrepareAndroidDirs; using android::vold::PrepareAppDirFromRoot; using android::vold::PrivateVolume; @@ -103,8 +104,6 @@ static const std::string kEmptyString(""); static const unsigned int kSizeVirtualDisk = 536870912; static const unsigned int kMajorBlockMmc = 179; -static const unsigned int kMajorBlockExperimentalMin = 240; -static const unsigned int kMajorBlockExperimentalMax = 254; using ScanProcCallback = bool(*)(uid_t uid, pid_t pid, int nsFd, const char* name, void* params); @@ -231,12 +230,10 @@ void VolumeManager::handleBlockEvent(NetlinkEvent* evt) { for (const auto& source : mDiskSources) { if (source->matches(eventPath)) { // For now, assume that MMC and virtio-blk (the latter is - // emulator-specific; see Disk.cpp for details) devices are SD, - // and that everything else is USB + // specific to virtual platforms; see Utils.cpp for details) + // devices are SD, and that everything else is USB int flags = source->getFlags(); - if (major == kMajorBlockMmc || (android::vold::IsRunningInEmulator() && - major >= (int)kMajorBlockExperimentalMin && - major <= (int)kMajorBlockExperimentalMax)) { + if (major == kMajorBlockMmc || IsVirtioBlkDevice(major)) { flags |= android::vold::Disk::Flags::kSd; } else { flags |= android::vold::Disk::Flags::kUsb; diff --git a/model/Disk.cpp b/model/Disk.cpp index a4324db..4df4e9d 100644 --- a/model/Disk.cpp +++ b/model/Disk.cpp @@ -73,8 +73,6 @@ static const unsigned int kMajorBlockScsiN = 133; static const unsigned int kMajorBlockScsiO = 134; static const unsigned int kMajorBlockScsiP = 135; static const unsigned int kMajorBlockMmc = 179; -static const unsigned int kMajorBlockExperimentalMin = 240; -static const unsigned int kMajorBlockExperimentalMax = 254; static const unsigned int kMajorBlockDynamicMin = 234; static const unsigned int kMajorBlockDynamicMax = 512; @@ -88,33 +86,6 @@ enum class Table { kGpt, }; -static bool isVirtioBlkDevice(unsigned int major) { - /* - * The new emulator's "ranchu" virtual board no longer includes a goldfish - * MMC-based SD card device; instead, it emulates SD cards with virtio-blk, - * which has been supported by upstream kernel and QEMU for quite a while. - * Unfortunately, the virtio-blk block device driver does not use a fixed - * major number, but relies on the kernel to assign one from a specific - * range of block majors, which are allocated for "LOCAL/EXPERIMENAL USE" - * per Documentation/devices.txt. This is true even for the latest Linux - * kernel (4.4; see init() in drivers/block/virtio_blk.c). - * - * This makes it difficult for vold to detect a virtio-blk based SD card. - * The current solution checks two conditions (both must be met): - * - * a) If the running environment is the emulator; - * b) If the major number is an experimental block device major number (for - * x86/x86_64 3.10 ranchu kernels, virtio-blk always gets major number - * 253, but it is safer to match the range than just one value). - * - * Other conditions could be used, too, e.g. the hardware name should be - * "ranchu", the device's sysfs path should end with "/block/vd[d-z]", etc. - * But just having a) and b) is enough for now. - */ - return IsRunningInEmulator() && major >= kMajorBlockExperimentalMin && - major <= kMajorBlockExperimentalMax; -} - static bool isNvmeBlkDevice(unsigned int major, const std::string& sysPath) { return sysPath.find("nvme") != std::string::npos && major >= kMajorBlockDynamicMin && major <= kMajorBlockDynamicMax; @@ -322,7 +293,7 @@ status_t Disk::readMetadata() { break; } default: { - if (isVirtioBlkDevice(majorId)) { + if (IsVirtioBlkDevice(majorId)) { LOG(DEBUG) << "Recognized experimental block major ID " << majorId << " as virtio-blk (emulator's virtual SD card device)"; mLabel = "Virtual"; @@ -627,7 +598,7 @@ int Disk::getMaxMinors() { return std::stoi(tmp); } default: { - if (isVirtioBlkDevice(majorId)) { + if (IsVirtioBlkDevice(majorId)) { // drivers/block/virtio_blk.c has "#define PART_BITS 4", so max is // 2^4 - 1 = 15 return 15; From c6717310750c1cdd4fbde2479e0966a6c444022f Mon Sep 17 00:00:00 2001 From: Alistair Delva Date: Tue, 19 May 2020 15:49:26 -0700 Subject: [PATCH 102/112] Handle virtio in private fs mapping When the vold core decides if a device is SD or USB, it checks for MMC or virtio, however when the filesystem type is decided, it does not check for virtio, only MMC. This causes virtio SD cards to be formatted with ext4 unconditionally. This fix is independently correct, but it incidentally gets adopted storage working on cuttlefish (and Android Emulator) because f2fs can support fscrypt and casefolding at the same time; ext4 currently cannot. Bug: 156286088 Change-Id: I0b41670d5f76b2506dad437917c2276f8e0aaccf --- model/PrivateVolume.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp index e146633..39a946c 100644 --- a/model/PrivateVolume.cpp +++ b/model/PrivateVolume.cpp @@ -39,6 +39,7 @@ #include using android::base::StringPrintf; +using android::vold::IsVirtioBlkDevice; namespace android { namespace vold { @@ -210,9 +211,10 @@ status_t PrivateVolume::doFormat(const std::string& fsType) { if (fsType == "auto") { // For now, assume that all MMC devices are flash-based SD cards, and // give everyone else ext4 because sysfs rotational isn't reliable. - // Additionally, prefer f2fs for loop-bases devices - if ((major(mRawDevice) == kMajorBlockMmc || major(mRawDevice) == kMajorBlockLoop) && - f2fs::IsSupported()) { + // Additionally, prefer f2fs for loop-based devices + if ((major(mRawDevice) == kMajorBlockMmc || + major(mRawDevice) == kMajorBlockLoop || + IsVirtioBlkDevice(major(mRawDevice))) && f2fs::IsSupported()) { resolvedFsType = "f2fs"; } else { resolvedFsType = "ext4"; From f36bdddc7e5545d361ea8fe16cbac315794874e3 Mon Sep 17 00:00:00 2001 From: Daniel Rosenberg Date: Mon, 11 May 2020 22:58:42 -0700 Subject: [PATCH 103/112] Move enabling sdcardfs behind a property This allows devices that have sdcardfs enabled in the kernel to not use it. When external_storage.sdcardfs.enabled=0, sdcardfs will not be mounted. This is treated as default true to not affect upgrading devices. It does not use the old ro.sys.sdcardfs as that has been repurposed over time and no longer can be relied on to turn off sdcardfs. This is included within emulated_storage.mk Bug: 155222498 Test: mount|grep "type sdcardfs" should find nothing after boot complete if external_storage.sdcardfs.enabled=0 Change-Id: I23d75fb1225aeabbcb1a035ad62fd042b6b3c7b5 --- Utils.cpp | 24 +++++++++++++++--------- Utils.h | 2 ++ VolumeManager.cpp | 5 +++-- model/EmulatedVolume.cpp | 4 ++-- model/PublicVolume.cpp | 2 +- 5 files changed, 23 insertions(+), 14 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index b129990..15a5e49 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -132,7 +132,7 @@ status_t DestroyDeviceNode(const std::string& path) { // Sets a default ACL on the directory. int SetDefaultAcl(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { - if (IsFilesystemSupported("sdcardfs")) { + if (IsSdcardfsUsed()) { // sdcardfs magically takes care of this return OK; } @@ -227,7 +227,7 @@ int PrepareDirWithProjectId(const std::string& path, mode_t mode, uid_t uid, gid return ret; } - if (!IsFilesystemSupported("sdcardfs")) { + if (!IsSdcardfsUsed()) { ret = SetQuotaProjectId(path, projectId); } @@ -255,7 +255,7 @@ static int FixupAppDir(const std::string& path, mode_t mode, uid_t uid, gid_t gi return ret; } - if (!IsFilesystemSupported("sdcardfs")) { + if (!IsSdcardfsUsed()) { ret = SetQuotaProjectId(itEntry.path(), projectId); if (ret != 0) { return ret; @@ -271,6 +271,7 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int long projectId; size_t pos; int ret = 0; + bool sdcardfsSupport = IsSdcardfsUsed(); // Make sure the Android/ directories exist and are setup correctly ret = PrepareAndroidDirs(root); @@ -291,17 +292,17 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int // Check that the next part matches one of the allowed Android/ dirs if (StartsWith(pathFromRoot, kAppDataDir)) { appDir = kAppDataDir; - if (!IsFilesystemSupported("sdcardfs")) { + if (!sdcardfsSupport) { gid = AID_EXT_DATA_RW; } } else if (StartsWith(pathFromRoot, kAppMediaDir)) { appDir = kAppMediaDir; - if (!IsFilesystemSupported("sdcardfs")) { + if (!sdcardfsSupport) { gid = AID_MEDIA_RW; } } else if (StartsWith(pathFromRoot, kAppObbDir)) { appDir = kAppObbDir; - if (!IsFilesystemSupported("sdcardfs")) { + if (!sdcardfsSupport) { gid = AID_EXT_OBB_RW; } } else { @@ -368,7 +369,7 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int return ret; } - if (!IsFilesystemSupported("sdcardfs")) { + if (!sdcardfsSupport) { // Set project ID inheritance, so that future subdirectories inherit the // same project ID ret = SetQuotaInherit(pathToCreate); @@ -943,6 +944,11 @@ bool IsFilesystemSupported(const std::string& fsType) { return supported.find(fsType + "\n") != std::string::npos; } +bool IsSdcardfsUsed() { + return IsFilesystemSupported("sdcardfs") && + base::GetBoolProperty(kExternalStorageSdcardfs, true); +} + status_t WipeBlockDevice(const std::string& path) { status_t res = -1; const char* c_path = path.c_str(); @@ -1426,7 +1432,7 @@ status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, return -errno; } - if (IsFilesystemSupported("sdcardfs")) { + if (IsSdcardfsUsed()) { std::string sdcardfs_path( StringPrintf("/mnt/runtime/full/%s", relative_upper_path.c_str())); @@ -1478,7 +1484,7 @@ status_t PrepareAndroidDirs(const std::string& volumeRoot) { std::string androidObbDir = volumeRoot + kAppObbDir; std::string androidMediaDir = volumeRoot + kAppMediaDir; - bool useSdcardFs = IsFilesystemSupported("sdcardfs"); + bool useSdcardFs = IsSdcardfsUsed(); // mode 0771 + sticky bit for inheriting GIDs mode_t mode = S_IRWXU | S_IRWXG | S_IXOTH | S_ISGID; diff --git a/Utils.h b/Utils.h index e04dcaa..eac3cf4 100644 --- a/Utils.h +++ b/Utils.h @@ -36,6 +36,7 @@ namespace vold { static const char* kPropFuse = "persist.sys.fuse"; static const char* kVoldAppDataIsolationEnabled = "persist.sys.vold_app_data_isolation_enabled"; +static const char* kExternalStorageSdcardfs = "external_storage.sdcardfs.enabled"; /* SELinux contexts used depending on the block device type */ extern security_context_t sBlkidContext; @@ -124,6 +125,7 @@ uint64_t GetFreeBytes(const std::string& path); uint64_t GetTreeBytes(const std::string& path); bool IsFilesystemSupported(const std::string& fsType); +bool IsSdcardfsUsed(); bool IsFuseDaemon(const pid_t pid); /* Wipes contents of block device at given path */ diff --git a/VolumeManager.cpp b/VolumeManager.cpp index f64f5f6..f42f3e7 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -83,6 +83,7 @@ using android::vold::DeleteDirContents; using android::vold::DeleteDirContentsAndDir; using android::vold::EnsureDirExists; using android::vold::IsFilesystemSupported; +using android::vold::IsSdcardfsUsed; using android::vold::IsVirtioBlkDevice; using android::vold::PrepareAndroidDirs; using android::vold::PrepareAppDirFromRoot; @@ -780,7 +781,7 @@ static bool remountStorageDirs(int nsFd, const char* android_data_dir, const cha static std::string getStorageDirSrc(userid_t userId, const std::string& dirName, const std::string& packageName) { - if (IsFilesystemSupported("sdcardfs")) { + if (IsSdcardfsUsed()) { return StringPrintf("/mnt/runtime/default/emulated/%d/%s/%s", userId, dirName.c_str(), packageName.c_str()); } else { @@ -1049,7 +1050,7 @@ int VolumeManager::setupAppDir(const std::string& path, int32_t appUid, bool fix } int VolumeManager::fixupAppDir(const std::string& path, int32_t appUid) { - if (IsFilesystemSupported("sdcardfs")) { + if (IsSdcardfsUsed()) { //sdcardfs magically does this for us return OK; } diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index e7cd36e..bb5aa86 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -49,7 +49,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, int userId) mRawPath = rawPath; mLabel = "emulated"; mFuseMounted = false; - mUseSdcardFs = IsFilesystemSupported("sdcardfs"); + mUseSdcardFs = IsSdcardfsUsed(); mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } @@ -60,7 +60,7 @@ EmulatedVolume::EmulatedVolume(const std::string& rawPath, dev_t device, const s mRawPath = rawPath; mLabel = fsUuid; mFuseMounted = false; - mUseSdcardFs = IsFilesystemSupported("sdcardfs"); + mUseSdcardFs = IsSdcardfsUsed(); mAppDataIsolationEnabled = base::GetBoolProperty(kVoldAppDataIsolationEnabled, false); } diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index a0b3227..6195482 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -51,7 +51,7 @@ PublicVolume::PublicVolume(dev_t device) : VolumeBase(Type::kPublic), mDevice(de setId(StringPrintf("public:%u,%u", major(device), minor(device))); mDevPath = StringPrintf("/dev/block/vold/%s", getId().c_str()); mFuseMounted = false; - mUseSdcardFs = IsFilesystemSupported("sdcardfs"); + mUseSdcardFs = IsSdcardfsUsed(); } PublicVolume::~PublicVolume() {} From 23c0445355e5f46db5fa63e0a86e1cdaf032ea9b Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 29 Apr 2020 07:49:41 +0200 Subject: [PATCH 104/112] vold: Support aborting FUSE connections. This can be done through binder as well as vdc, using 'vdc volume abort_fuse'. Bug: 153411204 Test: adb shell vdc volume abort_fuse Change-Id: I93e46dc1cd361729cc1162c63520cf73152ea409 --- Utils.cpp | 15 +++++++++++++++ Utils.h | 2 ++ VoldNativeService.cpp | 7 +++++++ VoldNativeService.h | 1 + VolumeManager.cpp | 5 +++++ VolumeManager.h | 2 ++ binder/android/os/IVold.aidl | 1 + vdc.cpp | 2 ++ 8 files changed, 35 insertions(+) diff --git a/Utils.cpp b/Utils.cpp index 15a5e49..e3a419f 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1330,6 +1330,21 @@ bool writeStringToFile(const std::string& payload, const std::string& filename) return true; } +status_t AbortFuseConnections() { + namespace fs = std::filesystem; + + for (const auto& itEntry : fs::directory_iterator("/sys/fs/fuse/connections")) { + std::string abortPath = itEntry.path().string() + "/abort"; + LOG(DEBUG) << "Aborting fuse connection entry " << abortPath; + bool ret = writeStringToFile("1", abortPath); + if (!ret) { + LOG(WARNING) << "Failed to write to " << abortPath; + } + } + + return OK; +} + status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { if (access(path.c_str(), F_OK) != 0) { PLOG(WARNING) << "Dir does not exist: " << path; diff --git a/Utils.h b/Utils.h index eac3cf4..c4926e7 100644 --- a/Utils.h +++ b/Utils.h @@ -50,6 +50,8 @@ extern bool sSleepOnUnmount; status_t CreateDeviceNode(const std::string& path, dev_t dev); status_t DestroyDeviceNode(const std::string& path); +status_t AbortFuseConnections(); + int SetQuotaInherit(const std::string& path); int SetQuotaProjectId(const std::string& path, long projectId); /* diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index 1020526..a37ba5a 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -175,6 +175,13 @@ binder::Status VoldNativeService::shutdown() { return translate(VolumeManager::Instance()->shutdown()); } +binder::Status VoldNativeService::abortFuse() { + ENFORCE_SYSTEM_OR_ROOT; + ACQUIRE_LOCK; + + return translate(VolumeManager::Instance()->abortFuse()); +} + binder::Status VoldNativeService::onUserAdded(int32_t userId, int32_t userSerial) { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; diff --git a/VoldNativeService.h b/VoldNativeService.h index 060d704..c7d8849 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -36,6 +36,7 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status monitor(); binder::Status reset(); binder::Status shutdown(); + binder::Status abortFuse(); binder::Status onUserAdded(int32_t userId, int32_t userSerial); binder::Status onUserRemoved(int32_t userId); diff --git a/VolumeManager.cpp b/VolumeManager.cpp index f42f3e7..a543573 100644 --- a/VolumeManager.cpp +++ b/VolumeManager.cpp @@ -905,6 +905,10 @@ int VolumeManager::remountAppStorageDirs(int uid, int pid, return 0; } +int VolumeManager::abortFuse() { + return android::vold::AbortFuseConnections(); +} + int VolumeManager::reset() { // Tear down all existing disks/volumes and start from a blank slate so // newly connected framework hears all events. @@ -940,6 +944,7 @@ int VolumeManager::shutdown() { mDisks.clear(); mPendingDisks.clear(); android::vold::sSleepOnUnmount = true; + return 0; } diff --git a/VolumeManager.h b/VolumeManager.h index a9087fd..3277f75 100644 --- a/VolumeManager.h +++ b/VolumeManager.h @@ -120,6 +120,8 @@ class VolumeManager { int remountUid(uid_t uid, int32_t remountMode); int remountAppStorageDirs(int uid, int pid, const std::vector& packageNames); + /* Aborts all FUSE filesystems, in case the FUSE daemon is no longer up. */ + int abortFuse(); /* Reset all internal state, typically during framework boot */ int reset(); /* Prepare for device shutdown, safely unmounting all devices */ diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 68e2ba9..6d14959 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -25,6 +25,7 @@ import android.os.IVoldTaskListener; interface IVold { void setListener(IVoldListener listener); + void abortFuse(); void monitor(); void reset(); void shutdown(); diff --git a/vdc.cpp b/vdc.cpp index a6a3fb0..c0b798d 100644 --- a/vdc.cpp +++ b/vdc.cpp @@ -99,6 +99,8 @@ int main(int argc, char** argv) { checkStatus(args, vold->fdeEnable(passwordType, "", encryptionFlags)); } else if (args[0] == "cryptfs" && args[1] == "mountdefaultencrypted") { checkStatus(args, vold->mountDefaultEncrypted()); + } else if (args[0] == "volume" && args[1] == "abort_fuse") { + checkStatus(args, vold->abortFuse()); } else if (args[0] == "volume" && args[1] == "shutdown") { checkStatus(args, vold->shutdown()); } else if (args[0] == "volume" && args[1] == "reset") { From de83802e41604e62b0f48b322eb62ca72a86261f Mon Sep 17 00:00:00 2001 From: Abhijeet Kaur Date: Thu, 28 May 2020 18:12:40 +0100 Subject: [PATCH 105/112] FuseDaemonHostTest is migrated to CTS and renamed. FuseDaemonHostTest is migrated to CTS and renamed to CtsScopedStorageHostTest. Bug: 142926859 Test: atest --test-mapping Change-Id: I24c74e20909ccf8868d1487e1cc93f6f2c0108fc --- TEST_MAPPING | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TEST_MAPPING b/TEST_MAPPING index e1f3653..4f62642 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -1,7 +1,7 @@ { "presubmit": [ { - "name": "FuseDaemonHostTest" + "name": "CtsScopedStorageHostTest" }, { "name": "AdoptableHostTest" From 1129b81071f624c638c45aae68f8285b20b151df Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 16 Jun 2020 14:58:52 +0200 Subject: [PATCH 106/112] Add app's own UID to the default ACL. On devices without sdcardfs, /Android/data/com.foo and /Android/obb/com.foo can be written by other processes (eg installers); in those cases, file ownership may be wrong. To ensure that the original app always has access to the files contained in this directory, add a group to the default ACL that matches the UID of the app. Since all apps have their own UID also as their group ID, this ensures that things keep working correctly. Bug: 157530951 Test: atest android.appsecurity.cts.ExternalStorageHostTest#testExternalStorageUnsharedObb Change-Id: I829a2a7c7b578a8328643f38681e68796adcd6b2 Change-Id: Ibbc333fb395507363830dfcf5dc6f1cfd55f008d --- Utils.cpp | 54 ++++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index e3a419f..cc6cb78 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -131,14 +131,15 @@ status_t DestroyDeviceNode(const std::string& path) { } // Sets a default ACL on the directory. -int SetDefaultAcl(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { +int SetDefaultAcl(const std::string& path, mode_t mode, uid_t uid, gid_t gid, + std::vector additionalGids) { if (IsSdcardfsUsed()) { // sdcardfs magically takes care of this return OK; } - static constexpr size_t size = - sizeof(posix_acl_xattr_header) + 3 * sizeof(posix_acl_xattr_entry); + size_t num_entries = 3 + (additionalGids.size() > 0 ? additionalGids.size() + 1 : 0); + size_t size = sizeof(posix_acl_xattr_header) + num_entries * sizeof(posix_acl_xattr_entry); auto buf = std::make_unique(size); posix_acl_xattr_header* acl_header = reinterpret_cast(buf.get()); @@ -147,23 +148,41 @@ int SetDefaultAcl(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { posix_acl_xattr_entry* entry = reinterpret_cast(buf.get() + sizeof(posix_acl_xattr_header)); - entry[0].e_tag = ACL_USER_OBJ; + int tag_index = 0; + + entry[tag_index].e_tag = ACL_USER_OBJ; // The existing mode_t mask has the ACL in the lower 9 bits: // the lowest 3 for "other", the next 3 the group, the next 3 for the owner // Use the mode_t masks to get these bits out, and shift them to get the // correct value per entity. // // Eg if mode_t = 0700, rwx for the owner, then & S_IRWXU >> 6 results in 7 - entry[0].e_perm = (mode & S_IRWXU) >> 6; - entry[0].e_id = uid; + entry[tag_index].e_perm = (mode & S_IRWXU) >> 6; + entry[tag_index].e_id = uid; + tag_index++; - entry[1].e_tag = ACL_GROUP_OBJ; - entry[1].e_perm = (mode & S_IRWXG) >> 3; - entry[1].e_id = gid; + entry[tag_index].e_tag = ACL_GROUP_OBJ; + entry[tag_index].e_perm = (mode & S_IRWXG) >> 3; + entry[tag_index].e_id = gid; + tag_index++; - entry[2].e_tag = ACL_OTHER; - entry[2].e_perm = mode & S_IRWXO; - entry[2].e_id = 0; + if (additionalGids.size() > 0) { + for (gid_t additional_gid : additionalGids) { + entry[tag_index].e_tag = ACL_GROUP; + entry[tag_index].e_perm = (mode & S_IRWXG) >> 3; + entry[tag_index].e_id = additional_gid; + tag_index++; + } + + entry[tag_index].e_tag = ACL_MASK; + entry[tag_index].e_perm = (mode & S_IRWXG) >> 3; + entry[tag_index].e_id = 0; + tag_index++; + } + + entry[tag_index].e_tag = ACL_OTHER; + entry[tag_index].e_perm = mode & S_IRWXO; + entry[tag_index].e_id = 0; int ret = setxattr(path.c_str(), XATTR_NAME_POSIX_ACL_DEFAULT, acl_header, size, 0); @@ -287,6 +306,7 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int uid_t uid = appUid; gid_t gid = AID_MEDIA_RW; + std::vector additionalGids; std::string appDir; // Check that the next part matches one of the allowed Android/ dirs @@ -294,6 +314,10 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appDir = kAppDataDir; if (!sdcardfsSupport) { gid = AID_EXT_DATA_RW; + // Also add the app's own UID as a group; since apps belong to a group + // that matches their UID, this ensures that they will always have access to + // the files created in these dirs, even if they are created by other processes + additionalGids.push_back(uid); } } else if (StartsWith(pathFromRoot, kAppMediaDir)) { appDir = kAppMediaDir; @@ -304,6 +328,8 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int appDir = kAppObbDir; if (!sdcardfsSupport) { gid = AID_EXT_OBB_RW; + // See comments for kAppDataDir above + additionalGids.push_back(uid); } } else { LOG(ERROR) << "Invalid application directory: " << path; @@ -364,7 +390,7 @@ int PrepareAppDirFromRoot(const std::string& path, const std::string& root, int // installers and MTP, that require access here. // // See man (5) acl for more details. - ret = SetDefaultAcl(pathToCreate, mode, uid, gid); + ret = SetDefaultAcl(pathToCreate, mode, uid, gid, additionalGids); if (ret != 0) { return ret; } @@ -1522,7 +1548,7 @@ status_t PrepareAndroidDirs(const std::string& volumeRoot) { // Some other apps, like installers, have write access to the OBB directory // to pre-download them. To make sure newly created folders in this directory // have the right permissions, set a default ACL. - SetDefaultAcl(androidObbDir, mode, AID_MEDIA_RW, obbGid); + SetDefaultAcl(androidObbDir, mode, AID_MEDIA_RW, obbGid, {}); if (fs_prepare_dir(androidMediaDir.c_str(), mode, AID_MEDIA_RW, AID_MEDIA_RW) != 0) { PLOG(ERROR) << "Failed to create " << androidMediaDir; From dcee5c1d213c3f034126ec806966f4e029b81140 Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Fri, 12 Jun 2020 12:59:45 +0100 Subject: [PATCH 107/112] Configure read ahead for fuse mounts For fuse read ahead can be configured by writing a value to the /sys/class/bdi/{MAJOR}:{MINOR}/read_ahead_kb file. There are several different ways of getting {MAJOR}:{MINOR} values of the filesystem: * Look at st_dev of stat("/mnt/user/0/emulated"). * Parse /proc/self/mountinfo. Stat'ing approach is used since it's easier to implement. Bug: 157982297 Test: atest vold_tests Test: adb shell cat /proc/self/mountinfo to get MAJOR:MINOR Test: adb shell cat /sys/class/bdi/{MAJOR}:{MINOR}/read_ahead_kb Test: created public volume, checked it's read_ahead_kb is also 256 Change-Id: Id0c149c4af1ceabf3afc33b4100563a512b38316 --- Utils.cpp | 32 ++++++++++++++++++++++++++++++++ Utils.h | 4 ++++ model/EmulatedVolume.cpp | 2 ++ model/PublicVolume.cpp | 2 ++ 4 files changed, 40 insertions(+) diff --git a/Utils.cpp b/Utils.cpp index e3a419f..af0027f 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -63,6 +63,7 @@ using android::base::EndsWith; using android::base::ReadFileToString; using android::base::StartsWith; using android::base::StringPrintf; +using android::base::unique_fd; namespace android { namespace vold { @@ -92,6 +93,10 @@ static const char* kMediaProviderAppCtx = "u:r:mediaprovider_app:"; // other between multiple threads. static std::mutex kSecurityLock; +std::string GetFuseMountPathForUser(userid_t user_id, const std::string& relative_upper_path) { + return StringPrintf("/mnt/user/%d/%s", user_id, relative_upper_path.c_str()); +} + status_t CreateDeviceNode(const std::string& path, dev_t dev) { std::lock_guard lock(kSecurityLock); const char* cpath = path.c_str(); @@ -1355,6 +1360,33 @@ status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t return OK; } +// Configures read ahead property of the fuse filesystem with the mount point |fuse_mount| by +// writing |read_ahead_kb| to the /sys/class/bdi/MAJOR:MINOR/read_ahead_kb. +void ConfigureReadAheadForFuse(const std::string& fuse_mount, size_t read_ahead_kb) { + LOG(INFO) << "Configuring read_ahead of " << fuse_mount << " fuse filesystem to " + << read_ahead_kb << "kb"; + // First figure out MAJOR:MINOR of fuse_mount. Simplest way is to stat the path. + struct stat info; + if (stat(fuse_mount.c_str(), &info) != 0) { + PLOG(ERROR) << "Failed to stat " << fuse_mount; + return; + } + unsigned int maj = major(info.st_dev); + unsigned int min = minor(info.st_dev); + LOG(INFO) << fuse_mount << " has major:minor " << maj << ":" << min; + // We found major:minor of our filesystem, time to configure read ahead! + std::string read_ahead_file = StringPrintf("/sys/class/bdi/%u:%u/read_ahead_kb", maj, min); + unique_fd fd(TEMP_FAILURE_RETRY(open(read_ahead_file.c_str(), O_WRONLY | O_CLOEXEC))); + if (fd.get() == -1) { + PLOG(ERROR) << "Failed to open " << read_ahead_file; + return; + } + LOG(INFO) << "Writing " << read_ahead_kb << " to " << read_ahead_file; + if (!WriteStringToFd(std::to_string(read_ahead_kb), fd)) { + PLOG(ERROR) << "Failed to write to " << read_ahead_file; + } +} + status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, const std::string& relative_upper_path, android::base::unique_fd* fuse_fd) { std::string pre_fuse_path(StringPrintf("/mnt/user/%d", user_id)); diff --git a/Utils.h b/Utils.h index c4926e7..a1d34b8 100644 --- a/Utils.h +++ b/Utils.h @@ -47,6 +47,8 @@ extern security_context_t sFsckUntrustedContext; // TODO remove this with better solution, b/64143519 extern bool sSleepOnUnmount; +std::string GetFuseMountPathForUser(userid_t user_id, const std::string& relative_upper_path); + status_t CreateDeviceNode(const std::string& path, dev_t dev); status_t DestroyDeviceNode(const std::string& path); @@ -174,6 +176,8 @@ bool FsyncDirectory(const std::string& dirname); bool writeStringToFile(const std::string& payload, const std::string& filename); +void ConfigureReadAheadForFuse(const std::string& fuse_mount, size_t read_ahead_kb); + status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, const std::string& relative_upper_path, android::base::unique_fd* fuse_fd); diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index bb5aa86..26d9582 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -402,6 +402,8 @@ status_t EmulatedVolume::doMount() { return res; } + ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, label), 256u); + // All mounts where successful, disable scope guards sdcardfs_guard.Disable(); fuse_guard.Disable(); diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 6195482..64b5dfa 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -250,6 +250,8 @@ status_t PublicVolume::doMount() { return -EIO; } } + + ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, stableName), 256u); } return OK; From 67f9044ab5b871f36db42e9f863c88b57c30e4a3 Mon Sep 17 00:00:00 2001 From: Paul Lawrence Date: Fri, 12 Jun 2020 08:12:48 -0700 Subject: [PATCH 108/112] Don't call block checkpoint functions above dm-default-key Bug: 156225476 Test: Build for f2fs and ext4 device, make sure checkpoints roll back and commit Merged-In: Ic15fadc67d306463dd0b554f679306d8f9081451 Change-Id: Ic15fadc67d306463dd0b554f679306d8f9081451 --- MetadataCrypt.cpp | 2 +- cryptfs.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp index 0a34007..ca2813d 100644 --- a/MetadataCrypt.cpp +++ b/MetadataCrypt.cpp @@ -99,7 +99,7 @@ static bool mount_via_fs_mgr(const char* mount_point, const char* blk_device) { } auto mount_rc = fs_mgr_do_mount(&fstab_default, const_cast(mount_point), const_cast(blk_device), nullptr, - android::vold::cp_needsCheckpoint()); + android::vold::cp_needsCheckpoint(), true); if (setexeccon(nullptr)) { PLOG(ERROR) << "Failed to clear setexeccon"; return false; diff --git a/cryptfs.cpp b/cryptfs.cpp index 1ddb34b..8b7ac0a 100644 --- a/cryptfs.cpp +++ b/cryptfs.cpp @@ -1625,7 +1625,7 @@ static int cryptfs_restart_internal(int restart_main) { } bool needs_cp = android::vold::cp_needsCheckpoint(); while ((mount_rc = fs_mgr_do_mount(&fstab_default, DATA_MNT_POINT, crypto_blkdev, 0, - needs_cp)) != 0) { + needs_cp, false)) != 0) { if (mount_rc == FS_MGR_DOMNT_BUSY) { /* TODO: invoke something similar to Process::killProcessWithOpenFiles(DATA_MNT_POINT, From 7e07c53aabe79917513808353e8aeac2fbacb5c0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 10 Jun 2020 23:51:17 -0700 Subject: [PATCH 109/112] Add an isCheckpointing() binder call for adb remount. This is needed so "adb remount" can avoid writing to /data during a checkpoint. Bug: 157540389 Test: manual test Change-Id: I33a691da3b99343acfc1e8ddf68a14504c3bfbe1 Merged-In: I33a691da3b99343acfc1e8ddf68a14504c3bfbe1 --- Checkpoint.cpp | 4 ++++ Checkpoint.h | 2 ++ VoldNativeService.cpp | 8 ++++++++ VoldNativeService.h | 1 + binder/android/os/IVold.aidl | 1 + 5 files changed, 16 insertions(+) diff --git a/Checkpoint.cpp b/Checkpoint.cpp index df5fc88..61035e5 100644 --- a/Checkpoint.cpp +++ b/Checkpoint.cpp @@ -294,6 +294,10 @@ bool cp_needsCheckpoint() { return false; } +bool cp_isCheckpointing() { + return isCheckpointing; +} + namespace { const std::string kSleepTimeProp = "ro.sys.cp_msleeptime"; const uint32_t msleeptime_default = 1000; // 1 s diff --git a/Checkpoint.h b/Checkpoint.h index c1fb2b7..6f3acac 100644 --- a/Checkpoint.h +++ b/Checkpoint.h @@ -39,6 +39,8 @@ bool cp_needsRollback(); bool cp_needsCheckpoint(); +bool cp_isCheckpointing(); + android::binder::Status cp_prepareCheckpoint(); android::binder::Status cp_restoreCheckpoint(const std::string& mountPoint, int count = 0); diff --git a/VoldNativeService.cpp b/VoldNativeService.cpp index a37ba5a..0cb86ce 100644 --- a/VoldNativeService.cpp +++ b/VoldNativeService.cpp @@ -809,6 +809,14 @@ binder::Status VoldNativeService::needsCheckpoint(bool* _aidl_return) { return Ok(); } +binder::Status VoldNativeService::isCheckpointing(bool* _aidl_return) { + ENFORCE_SYSTEM_OR_ROOT; + ACQUIRE_LOCK; + + *_aidl_return = cp_isCheckpointing(); + return Ok(); +} + binder::Status VoldNativeService::commitChanges() { ENFORCE_SYSTEM_OR_ROOT; ACQUIRE_LOCK; diff --git a/VoldNativeService.h b/VoldNativeService.h index c7d8849..013d1c2 100644 --- a/VoldNativeService.h +++ b/VoldNativeService.h @@ -139,6 +139,7 @@ class VoldNativeService : public BinderService, public os::Bn binder::Status startCheckpoint(int32_t retry); binder::Status needsCheckpoint(bool* _aidl_return); binder::Status needsRollback(bool* _aidl_return); + binder::Status isCheckpointing(bool* _aidl_return); binder::Status commitChanges(); binder::Status prepareCheckpoint(); binder::Status restoreCheckpoint(const std::string& mountPoint); diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl index 6d14959..54b86d0 100644 --- a/binder/android/os/IVold.aidl +++ b/binder/android/os/IVold.aidl @@ -115,6 +115,7 @@ interface IVold { void startCheckpoint(int retry); boolean needsCheckpoint(); boolean needsRollback(); + boolean isCheckpointing(); void abortChanges(in @utf8InCpp String device, boolean retry); void commitChanges(); void prepareCheckpoint(); From f71707916fdf11715bde10a7b76e92426ea1f32f Mon Sep 17 00:00:00 2001 From: Zim Date: Wed, 17 Jun 2020 14:56:10 +0100 Subject: [PATCH 110/112] Unmount public volume if FUSE mount fails Sometimes, during early boot, a public volume may be created before the user is unlocked and the mount may fail. This mount failure does not revert the lower fs mounts (sdcardfs and vfat). Subsequent mount attempts will then fail because we'd attempt to mount vfat on already mounted /mnt/media_rw/ Bug: 158489548 Test: Resilient to an artificial sleep in StorageManagerService#completeUnlockUser to delay user unlock longer than public volume mount Change-Id: I9a1574596434a2eb6b2553c0c9220c2118c7e4fd --- model/PublicVolume.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 64b5dfa..9ca782b 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -238,6 +238,7 @@ status_t PublicVolume::doMount() { if (result != 0) { LOG(ERROR) << "Failed to mount public fuse volume"; + doUnmount(); return -result; } @@ -247,6 +248,8 @@ status_t PublicVolume::doMount() { bool is_ready = false; callback->onVolumeChecking(std::move(fd), getPath(), getInternalPath(), &is_ready); if (!is_ready) { + LOG(ERROR) << "Failed to complete public volume mount"; + doUnmount(); return -EIO; } } From a485006ab147695fa28ec20c11ffef4f018253a3 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Mon, 29 Jun 2020 11:53:34 +0200 Subject: [PATCH 111/112] Configure backing device max_ratio for FUSE filesystems. By default FUSE filesystems have a max_ratio of 1%, meaning only 1% of dirty pages on the system can belong to a FUSE filesystem before we start writing back pages (and throttling, if writeback can't keep up). This limit is useful for untrusted filesystems, but in our case, we trust the FUSE filesystem. Since FUSE writes result in writes to the lower filesystem, FUSE should take at most 50%. Let's start with changing max_ratio to 40%, to avoid needless throttling. Bug: 159254170 Bug: 159770752 Test: inspect /sys/class/bdi manually after boot Change-Id: I467e3770fc4afba0a08fa480c0b86aa054c8b875 --- Utils.cpp | 50 ++++++++++++++++++++++++++++++++-------- Utils.h | 2 ++ model/EmulatedVolume.cpp | 21 +++++++++++++++++ model/PublicVolume.cpp | 3 +++ 4 files changed, 67 insertions(+), 9 deletions(-) diff --git a/Utils.cpp b/Utils.cpp index 6208efd..a9b7440 100644 --- a/Utils.cpp +++ b/Utils.cpp @@ -1386,22 +1386,54 @@ status_t EnsureDirExists(const std::string& path, mode_t mode, uid_t uid, gid_t return OK; } +// Gets the sysfs path for parameters of the backing device info (bdi) +static std::string getBdiPathForMount(const std::string& mount) { + // First figure out MAJOR:MINOR of mount. Simplest way is to stat the path. + struct stat info; + if (stat(mount.c_str(), &info) != 0) { + PLOG(ERROR) << "Failed to stat " << mount; + return ""; + } + unsigned int maj = major(info.st_dev); + unsigned int min = minor(info.st_dev); + + return StringPrintf("/sys/class/bdi/%u:%u", maj, min); +} + +// Configures max_ratio for the FUSE filesystem. +void ConfigureMaxDirtyRatioForFuse(const std::string& fuse_mount, unsigned int max_ratio) { + LOG(INFO) << "Configuring max_ratio of " << fuse_mount << " fuse filesystem to " << max_ratio; + if (max_ratio > 100) { + LOG(ERROR) << "Invalid max_ratio: " << max_ratio; + return; + } + std::string fuseBdiPath = getBdiPathForMount(fuse_mount); + if (fuseBdiPath == "") { + return; + } + std::string max_ratio_file = StringPrintf("%s/max_ratio", fuseBdiPath.c_str()); + unique_fd fd(TEMP_FAILURE_RETRY(open(max_ratio_file.c_str(), O_WRONLY | O_CLOEXEC))); + if (fd.get() == -1) { + PLOG(ERROR) << "Failed to open " << max_ratio_file; + return; + } + LOG(INFO) << "Writing " << max_ratio << " to " << max_ratio_file; + if (!WriteStringToFd(std::to_string(max_ratio), fd)) { + PLOG(ERROR) << "Failed to write to " << max_ratio_file; + } +} + // Configures read ahead property of the fuse filesystem with the mount point |fuse_mount| by // writing |read_ahead_kb| to the /sys/class/bdi/MAJOR:MINOR/read_ahead_kb. void ConfigureReadAheadForFuse(const std::string& fuse_mount, size_t read_ahead_kb) { LOG(INFO) << "Configuring read_ahead of " << fuse_mount << " fuse filesystem to " << read_ahead_kb << "kb"; - // First figure out MAJOR:MINOR of fuse_mount. Simplest way is to stat the path. - struct stat info; - if (stat(fuse_mount.c_str(), &info) != 0) { - PLOG(ERROR) << "Failed to stat " << fuse_mount; + std::string fuseBdiPath = getBdiPathForMount(fuse_mount); + if (fuseBdiPath == "") { return; } - unsigned int maj = major(info.st_dev); - unsigned int min = minor(info.st_dev); - LOG(INFO) << fuse_mount << " has major:minor " << maj << ":" << min; - // We found major:minor of our filesystem, time to configure read ahead! - std::string read_ahead_file = StringPrintf("/sys/class/bdi/%u:%u/read_ahead_kb", maj, min); + // We found the bdi path for our filesystem, time to configure read ahead! + std::string read_ahead_file = StringPrintf("%s/read_ahead_kb", fuseBdiPath.c_str()); unique_fd fd(TEMP_FAILURE_RETRY(open(read_ahead_file.c_str(), O_WRONLY | O_CLOEXEC))); if (fd.get() == -1) { PLOG(ERROR) << "Failed to open " << read_ahead_file; diff --git a/Utils.h b/Utils.h index a1d34b8..04cbac4 100644 --- a/Utils.h +++ b/Utils.h @@ -176,6 +176,8 @@ bool FsyncDirectory(const std::string& dirname); bool writeStringToFile(const std::string& payload, const std::string& filename); +void ConfigureMaxDirtyRatioForFuse(const std::string& fuse_mount, unsigned int max_ratio); + void ConfigureReadAheadForFuse(const std::string& fuse_mount, size_t read_ahead_kb); status_t MountUserFuse(userid_t user_id, const std::string& absolute_lower_path, diff --git a/model/EmulatedVolume.cpp b/model/EmulatedVolume.cpp index 26d9582..db93bc2 100644 --- a/model/EmulatedVolume.cpp +++ b/model/EmulatedVolume.cpp @@ -404,6 +404,27 @@ status_t EmulatedVolume::doMount() { ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, label), 256u); + // By default, FUSE has a max_dirty ratio of 1%. This means that out of + // all dirty pages in the system, only 1% is allowed to belong to any + // FUSE filesystem. The reason this is in place is that FUSE + // filesystems shouldn't be trusted by default; a FUSE filesystem could + // take up say 100% of dirty pages, and subsequently refuse to write + // them back to storage. The kernel will then apply rate-limiting, and + // block other tasks from writing. For this particular FUSE filesystem + // however, we trust the implementation, because it is a part of the + // Android platform. So use the default ratio of 100%. + // + // The reason we're setting this is that there's a suspicion that the + // kernel starts rate-limiting the FUSE filesystem under extreme + // memory pressure scenarios. While the kernel will only rate limit if + // the writeback can't keep up with the write rate, under extreme + // memory pressure the write rate may dip as well, in which case FUSE + // writes to a 1% max_ratio filesystem are throttled to an extreme amount. + // + // To prevent this, just give FUSE 40% max_ratio, meaning it can take + // up to 40% of all dirty pages in the system. + ConfigureMaxDirtyRatioForFuse(GetFuseMountPathForUser(user_id, label), 40u); + // All mounts where successful, disable scope guards sdcardfs_guard.Disable(); fuse_guard.Disable(); diff --git a/model/PublicVolume.cpp b/model/PublicVolume.cpp index 9ca782b..d40e3e3 100644 --- a/model/PublicVolume.cpp +++ b/model/PublicVolume.cpp @@ -255,6 +255,9 @@ status_t PublicVolume::doMount() { } ConfigureReadAheadForFuse(GetFuseMountPathForUser(user_id, stableName), 256u); + + // See comment in model/EmulatedVolume.cpp + ConfigureMaxDirtyRatioForFuse(GetFuseMountPathForUser(user_id, stableName), 40u); } return OK; From 006eed8e3ad8b38915c55092346fb149298975a0 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Mon, 6 Jul 2020 13:46:38 -0700 Subject: [PATCH 112/112] vold: only allow emmc_optimized on eMMC storage The emmc_optimized encryption flag is specifically designed for the limitations of inline encryption hardware that follows the eMMC standard. It isn't appropriate to use on other types of storage. So, make vold enforce that it's not used on other types of storage. Bug: 160639344 Test: - Enabled emmc_optimized on Cuttlefish and verified it no longer boots - Using a modified version of this change, verified that IsEmmcStorage() works as expected on various devices including Cuttlefish, Cuttlefish booted in GSI image mode, a device with eMMC storage, and a device with UFS storage. - Verified that VtsKernelEncryptionTest still passes Change-Id: Ie27b80658db53b1a4207b3cbb4e309d05130812e Merged-In: Ie27b80658db53b1a4207b3cbb4e309d05130812e --- FsCrypt.cpp | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/FsCrypt.cpp b/FsCrypt.cpp index 4d5cd33..e21524a 100644 --- a/FsCrypt.cpp +++ b/FsCrypt.cpp @@ -52,6 +52,7 @@ #include #include +#include #include #include @@ -60,6 +61,9 @@ #include #include +using android::base::Basename; +using android::base::Realpath; +using android::base::StartsWith; using android::base::StringPrintf; using android::fs_mgr::GetEntryForMountPoint; using android::vold::BuildDataPath; @@ -73,6 +77,7 @@ using android::vold::SetQuotaInherit; using android::vold::SetQuotaProjectId; using android::vold::writeStringToFile; using namespace android::fscrypt; +using namespace android::dm; namespace { @@ -203,6 +208,26 @@ static bool read_and_fixate_user_ce_key(userid_t user_id, return false; } +static bool IsEmmcStorage(const std::string& blk_device) { + // Handle symlinks. + std::string real_path; + if (!Realpath(blk_device, &real_path)) { + real_path = blk_device; + } + + // Handle logical volumes. + auto& dm = DeviceMapper::Instance(); + for (;;) { + auto parent = dm.GetParentBlockDeviceByPath(real_path); + if (!parent.has_value()) break; + real_path = *parent; + } + + // Now we should have the "real" block device. + LOG(DEBUG) << "IsEmmcStorage(): blk_device = " << blk_device << ", real_path=" << real_path; + return StartsWith(Basename(real_path), "mmcblk"); +} + // Retrieve the options to use for encryption policies on the /data filesystem. static bool get_data_file_encryption_options(EncryptionOptions* options) { auto entry = GetEntryForMountPoint(&fstab_default, DATA_MNT_POINT); @@ -215,6 +240,12 @@ static bool get_data_file_encryption_options(EncryptionOptions* options) { << entry->encryption_options; return false; } + if ((options->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) && + !IsEmmcStorage(entry->blk_device)) { + LOG(ERROR) << "The emmc_optimized encryption flag is only allowed on eMMC storage. Remove " + "this flag from the device's fstab"; + return false; + } return true; } @@ -248,6 +279,11 @@ static bool get_volume_file_encryption_options(EncryptionOptions* options) { LOG(ERROR) << "Unable to parse volume encryption options: " << options_string; return false; } + if (options->flags & FSCRYPT_POLICY_FLAG_IV_INO_LBLK_32) { + LOG(ERROR) << "The emmc_optimized encryption flag is only allowed on eMMC storage. Remove " + "this flag from ro.crypto.volume.options"; + return false; + } return true; }