Ensure necessary external storage dirs while creating sandboxes.
Bug: 124058579
Test: manual
Test: atest cts/hostsidetests/appsecurity/src/android/appsecurity/cts/ExternalStorageHostTest.java
Test: atest cts/tests/app/src/android/app/cts/DownloadManagerTest.java
Test: atest cts/tests/tests/provider/src/android/provider/cts/MediaStore*
Change-Id: I0e62de38e9ceff80df75e253443af69d4391a49e
diff --git a/Utils.cpp b/Utils.cpp
index 656d706..aa2288b 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -222,6 +222,26 @@
return OK;
}
+status_t CreateDir(const std::string& dir, mode_t mode) {
+ struct stat sb;
+ if (TEMP_FAILURE_RETRY(stat(dir.c_str(), &sb)) == 0) {
+ if (S_ISDIR(sb.st_mode)) {
+ return OK;
+ } else if (TEMP_FAILURE_RETRY(unlink(dir.c_str())) == -1) {
+ PLOG(ERROR) << "Failed to unlink " << dir;
+ return -errno;
+ }
+ } else if (errno != ENOENT) {
+ PLOG(ERROR) << "Failed to stat " << dir;
+ return -errno;
+ }
+ if (TEMP_FAILURE_RETRY(mkdir(dir.c_str(), mode)) == -1) {
+ PLOG(ERROR) << "Failed to mkdir " << dir;
+ return -errno;
+ }
+ return OK;
+}
+
bool FindValue(const std::string& raw, const std::string& key, std::string* value) {
auto qual = key + "=\"";
size_t start = 0;
diff --git a/Utils.h b/Utils.h
index 574bcd4..9a1fa09 100644
--- a/Utils.h
+++ b/Utils.h
@@ -63,6 +63,9 @@
/** Calls unlink(2) at linkpath */
status_t Unlink(const std::string& linkpath);
+/** Creates the given directory if it is not already available */
+status_t CreateDir(const std::string& dir, mode_t mode);
+
bool FindValue(const std::string& raw, const std::string& key, std::string* value);
/* Reads filesystem metadata from device at path */
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index db098e3..7b08858 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -68,12 +68,14 @@
#include "model/ObbVolume.h"
#include "model/StubVolume.h"
+using android::OK;
using android::base::GetBoolProperty;
using android::base::StartsWith;
using android::base::StringAppendF;
using android::base::StringPrintf;
using android::base::unique_fd;
using android::vold::BindMount;
+using android::vold::CreateDir;
using android::vold::DeleteDirContentsAndDir;
using android::vold::Symlink;
using android::vold::Unlink;
@@ -384,8 +386,14 @@
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);
}
@@ -531,6 +539,9 @@
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;
}
@@ -540,6 +551,9 @@
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");
@@ -608,6 +622,8 @@
int VolumeManager::prepareSandboxes(userid_t userId, const std::vector<std::string>& packageNames,
const std::vector<std::string>& visibleVolLabels) {
+ prepareSandboxTargets(userId, packageNames, visibleVolLabels);
+
if (visibleVolLabels.empty()) {
return 0;
}
@@ -616,8 +632,7 @@
bool isVolPrimaryEmulated = (volumeLabel == mPrimary->getLabel() && mPrimary->isEmulated());
if (isVolPrimaryEmulated) {
StringAppendF(&volumeRoot, "/%d", userId);
- if (fs_prepare_dir(volumeRoot.c_str(), 0755, AID_ROOT, AID_ROOT) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << volumeRoot;
+ if (CreateDir(volumeRoot, 0755) < 0) {
return -errno;
}
}
@@ -627,73 +642,127 @@
if (sandboxRoot.empty()) {
return -errno;
}
-
- if (!createPkgSpecificDirRoots(volumeRoot)) {
- return -errno;
- }
-
- std::string mntTargetRoot = StringPrintf("/mnt/user/%d", userId);
- if (fs_prepare_dir(mntTargetRoot.c_str(), 0751, AID_ROOT, AID_ROOT) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << mntTargetRoot;
- return -errno;
- }
- mntTargetRoot.append("/package");
- if (fs_prepare_dir(mntTargetRoot.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << mntTargetRoot;
- return -errno;
- }
-
- for (auto& packageName : packageNames) {
- const auto& it = mAppIds.find(packageName);
- if (it == mAppIds.end()) {
- PLOG(ERROR) << "appId is not available for " << packageName;
- continue;
- }
- appid_t appId = it->second;
- std::string sandboxId = mSandboxIds[appId];
- uid_t uid = multiuser_get_uid(userId, appId);
-
- // [1] Create /mnt/runtime/write/emulated/0/Android/sandbox/<sandboxId>
- // [2] Create /mnt/user/0/package/<packageName>/emulated/0
- std::string pkgSandboxSourceDir = prepareSandboxSource(uid, sandboxId, sandboxRoot);
- if (pkgSandboxSourceDir.empty()) {
- return -errno;
- }
- std::string pkgSandboxTargetDir = prepareSandboxTarget(
- packageName, uid, volumeLabel, mntTargetRoot, isVolPrimaryEmulated);
- if (pkgSandboxTargetDir.empty()) {
- return -errno;
- }
-
- // Create Android/{data,media,obb}/<packageName> segments at
- // [1] /mnt/runtime/write/emulated/0/ and
- // [2] /mnt/runtime/write/emulated/0/Android/sandbox/<sandboxId>/emulated/0/
- if (!createPkgSpecificDirs(packageName, uid, volumeRoot, pkgSandboxSourceDir)) {
- return -errno;
- }
-
- if (volumeLabel == mPrimary->getLabel()) {
- // [1] Create /mnt/user/0/package/<packageName>/self/
- // Link [1] to /storage/emulated/0
- std::string pkgPrimaryTargetDir =
- StringPrintf("%s/%s/self", mntTargetRoot.c_str(), packageName.c_str());
- if (fs_prepare_dir(pkgPrimaryTargetDir.c_str(), 0755, uid, uid) != 0) {
- PLOG(ERROR) << "Failed to fs_prepare_dir on " << pkgPrimaryTargetDir;
- return -errno;
- }
- StringAppendF(&pkgPrimaryTargetDir, "/primary");
- std::string primarySource(mPrimary->getPath());
- if (isVolPrimaryEmulated) {
- StringAppendF(&primarySource, "/%d", userId);
- }
- Symlink(primarySource, pkgPrimaryTargetDir);
- }
- }
}
mountPkgSpecificDirsForRunningProcs(userId, packageNames, visibleVolLabels, -1);
return 0;
}
+int VolumeManager::prepareSandboxTargets(userid_t userId,
+ const std::vector<std::string>& packageNames,
+ const std::vector<std::string>& 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 %s" << mntTargetRoot;
+ return -errno;
+ }
+ StringAppendF(&mntTargetRoot, "/package");
+ if (fs_prepare_dir(mntTargetRoot.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
+ PLOG(ERROR) << "Failed to fs_prepare_dir %s" << mntTargetRoot;
+ return -errno;
+ }
+
+ const unique_fd dfd(open(mntTargetRoot.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (dfd.get() < 0) {
+ PLOG(ERROR) << "Failed to open " << mntTargetRoot;
+ return -errno;
+ }
+ for (auto& package : packageNames) {
+ const auto& it = mAppIds.find(package);
+ if (it == mAppIds.end()) {
+ PLOG(ERROR) << "appId is not available for " << package;
+ continue;
+ }
+ appid_t appId = it->second;
+ uid_t uid = multiuser_get_uid(userId, appId);
+
+ if (TEMP_FAILURE_RETRY(faccessat(dfd.get(), package.c_str(), F_OK, 0)) == 0) {
+ continue;
+ } else if (errno != ENOENT) {
+ PLOG(ERROR) << "Failed to faccessat " << mntTargetRoot << "/" << package;
+ }
+ if (TEMP_FAILURE_RETRY(mkdirat(dfd.get(), package.c_str(), 0755)) == -1) {
+ PLOG(ERROR) << "Failed to mkdirat " << mntTargetRoot << "/" << package;
+ return -errno;
+ }
+ if (TEMP_FAILURE_RETRY(fchownat(dfd.get(), package.c_str(), uid, uid, 0)) == -1) {
+ PLOG(ERROR) << "Failed to fchownat " << mntTargetRoot << "/" << package;
+ return -errno;
+ }
+ }
+ std::string pkgPrimarySource(kEmptyString);
+ if (mPrimary) {
+ StringAppendF(&pkgPrimarySource, "%s", mPrimary->getPath().c_str());
+ if (mPrimary->isEmulated()) {
+ StringAppendF(&pkgPrimarySource, "/%d", userId);
+ }
+ }
+ for (auto& package : packageNames) {
+ const auto& it = mAppIds.find(package);
+ if (it == mAppIds.end()) {
+ PLOG(ERROR) << "appId is not available for " << package;
+ continue;
+ }
+ appid_t appId = it->second;
+ uid_t uid = multiuser_get_uid(userId, appId);
+
+ std::string pkgMountTarget = StringPrintf("%s/%s", mntTargetRoot.c_str(), package.c_str());
+ const unique_fd packageFd(
+ openat(dfd.get(), package.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC));
+ if (packageFd.get() < 0) {
+ PLOG(ERROR) << "Failed to openat " << mntTargetRoot << "/" << package;
+ return -errno;
+ }
+ for (auto& volumeLabel : visibleVolLabels) {
+ if (TEMP_FAILURE_RETRY(faccessat(packageFd.get(), volumeLabel.c_str(), F_OK, 0)) == 0) {
+ continue;
+ } else if (errno != ENOENT) {
+ PLOG(ERROR) << "Failed to faccessat " << pkgMountTarget << "/" << volumeLabel;
+ }
+ if (TEMP_FAILURE_RETRY(mkdirat(packageFd.get(), volumeLabel.c_str(), 0755)) == -1) {
+ PLOG(ERROR) << "Failed to mkdirat " << pkgMountTarget << "/" << volumeLabel;
+ return -errno;
+ }
+ if (TEMP_FAILURE_RETRY(fchownat(packageFd.get(), volumeLabel.c_str(), uid, uid, 0)) ==
+ -1) {
+ PLOG(ERROR) << "Failed to fchownat " << pkgMountTarget << "/" << volumeLabel;
+ return -errno;
+ }
+
+ if (mPrimary && volumeLabel == mPrimary->getLabel() && mPrimary->isEmulated()) {
+ std::string path =
+ StringPrintf("%s/%s/%d", pkgMountTarget.c_str(), volumeLabel.c_str(), userId);
+ if (TEMP_FAILURE_RETRY(mkdir(path.c_str(), 0755)) == -1 && errno != EEXIST) {
+ PLOG(ERROR) << "Failed to mkdir " << path;
+ return -errno;
+ }
+ if (TEMP_FAILURE_RETRY(chown(path.c_str(), uid, uid)) == -1) {
+ PLOG(ERROR) << "Failed to chown " << path;
+ }
+ }
+ }
+ if (TEMP_FAILURE_RETRY(faccessat(packageFd.get(), "self", F_OK, 0)) == -1) {
+ if (errno == ENOENT) {
+ if (TEMP_FAILURE_RETRY(mkdirat(packageFd.get(), "self", 0755)) == -1) {
+ PLOG(ERROR) << "Failed to mkdirat " << pkgMountTarget << "/self";
+ return -errno;
+ }
+ if (TEMP_FAILURE_RETRY(fchownat(packageFd.get(), "self", uid, uid, 0)) == -1) {
+ PLOG(ERROR) << "Failed to fchownat " << pkgMountTarget << "/self";
+ return -errno;
+ }
+ } else {
+ PLOG(ERROR) << "Failed to faccessat " << pkgMountTarget << "/self";
+ return -errno;
+ }
+ }
+ std::string pkgPrimaryTarget = StringPrintf("%s/self/primary", pkgMountTarget.c_str());
+ if (mPrimary && Symlink(pkgPrimarySource, pkgPrimaryTarget) < 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);
@@ -704,78 +773,22 @@
continue;
}
StringAppendF(&path, "/%s", subDir.c_str());
- if (fs_prepare_dir(path.c_str(), mode, uid, gid) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << path;
+ if (CreateDir(path, mode) < 0) {
return kEmptyString;
}
}
return path;
}
-std::string VolumeManager::prepareSandboxSource(uid_t uid, const std::string& sandboxId,
- const std::string& sandboxRootDir) {
- std::string sandboxSourceDir(sandboxRootDir);
- StringAppendF(&sandboxSourceDir, "/%s", sandboxId.c_str());
- if (fs_prepare_dir(sandboxSourceDir.c_str(), 0755, uid, uid) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << sandboxSourceDir;
- return kEmptyString;
- }
- return sandboxSourceDir;
-}
-
-std::string VolumeManager::prepareSandboxTarget(const std::string& packageName, uid_t uid,
- const std::string& volumeLabel,
- const std::string& mntTargetRootDir,
- bool isUserDependent) {
- std::string segment;
- if (isUserDependent) {
- segment = StringPrintf("%s/%s/%d/", packageName.c_str(), volumeLabel.c_str(),
- multiuser_get_user_id(uid));
- } else {
- segment = StringPrintf("%s/%s/", packageName.c_str(), volumeLabel.c_str());
- }
- return prepareSubDirs(mntTargetRootDir, segment.c_str(), 0755, uid, uid);
-}
-
-std::string VolumeManager::preparePkgDataSource(const std::string& packageName, uid_t uid,
- const std::string& dataRootDir) {
- std::string dataSourceDir = StringPrintf("%s/%s", dataRootDir.c_str(), packageName.c_str());
- if (fs_prepare_dir(dataSourceDir.c_str(), 0755, uid, uid) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << dataSourceDir;
- return kEmptyString;
- }
- return dataSourceDir;
-}
-
bool VolumeManager::createPkgSpecificDirRoots(const std::string& volumeRoot) {
std::string volumeAndroidRoot = StringPrintf("%s/Android", volumeRoot.c_str());
- if (fs_prepare_dir(volumeAndroidRoot.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << volumeAndroidRoot;
+ if (CreateDir(volumeAndroidRoot, 0700) < 0) {
return false;
}
std::array<std::string, 3> dirs = {"data", "media", "obb"};
for (auto& dir : dirs) {
std::string path = StringPrintf("%s/%s", volumeAndroidRoot.c_str(), dir.c_str());
- if (fs_prepare_dir(path.c_str(), 0700, AID_ROOT, AID_ROOT) != 0) {
- PLOG(ERROR) << "fs_prepare_dir failed on " << path;
- return false;
- }
- }
- return true;
-}
-
-bool VolumeManager::createPkgSpecificDirs(const std::string& packageName, uid_t uid,
- const std::string& volumeRoot,
- const std::string& sandboxDirRoot) {
- std::array<std::string, 3> dirs = {"data", "media", "obb"};
- for (auto& dir : dirs) {
- std::string sourceDir = StringPrintf("%s/Android/%s", volumeRoot.c_str(), dir.c_str());
- if (prepareSubDirs(sourceDir, packageName, 0755, uid, uid).empty()) {
- return false;
- }
- std::string sandboxSegment =
- StringPrintf("Android/%s/%s/", dir.c_str(), packageName.c_str());
- if (prepareSubDirs(sandboxDirRoot, sandboxSegment, 0755, uid, uid).empty()) {
+ if (CreateDir(path, 0700) < 0) {
return false;
}
}
diff --git a/VolumeManager.h b/VolumeManager.h
index 7d299a1..e369f68 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -152,23 +152,16 @@
int prepareSandboxes(userid_t userId, const std::vector<std::string>& packageNames,
const std::vector<std::string>& visibleVolLabels);
+ int prepareSandboxTargets(userid_t userId, const std::vector<std::string>& packageNames,
+ const std::vector<std::string>& visibleVolLabels);
int mountPkgSpecificDirsForRunningProcs(userid_t userId,
const std::vector<std::string>& packageNames,
const std::vector<std::string>& visibleVolLabels,
int remountMode);
int destroySandboxesForVol(android::vold::VolumeBase* vol, userid_t userId);
- std::string prepareSandboxSource(uid_t uid, const std::string& sandboxId,
- const std::string& sandboxRootDir);
- std::string prepareSandboxTarget(const std::string& packageName, uid_t uid,
- const std::string& volumeLabel,
- const std::string& mntTargetRootDir, bool isUserDependent);
- std::string preparePkgDataSource(const std::string& packageName, uid_t uid,
- const std::string& dataRootDir);
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);
- bool createPkgSpecificDirs(const std::string& packageName, uid_t uid,
- const std::string& volumeRoot, const std::string& sandboxDirRoot);
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,