From d8b4f10b568ae15974872e6f1efa4e9efeed8f74 Mon Sep 17 00:00:00 2001 From: Sudheer Shanka Date: Tue, 12 Feb 2019 19:01:21 -0800 Subject: [PATCH] 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: I517870b5a0b2df2cd2e068c9a55f0c0c07b74853 --- core/jni/com_android_internal_os_Zygote.cpp | 124 +++++++++++++++----- 1 file changed, 96 insertions(+), 28 deletions(-) diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp index 5cecf66a593c4..c208ce3276c6f 100644 --- a/core/jni/com_android_internal_os_Zygote.cpp +++ b/core/jni/com_android_internal_os_Zygote.cpp @@ -612,7 +612,7 @@ static void CreateDir(const std::string& dir, } } -static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) { +static void CreatePkgSandboxTarget(uid_t uid, const std::string& package_name, fail_fn_t fail_fn) { // Create /mnt/user/0/package/ userid_t user_id = multiuser_get_user_id(uid); std::string pkg_sandbox_dir = StringPrintf("/mnt/user/%d", user_id); @@ -622,7 +622,7 @@ static void CreatePkgSandbox(uid_t uid, const std::string& package_name, fail_fn CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn); StringAppendF(&pkg_sandbox_dir, "/%s", package_name.c_str()); - CreateDir(pkg_sandbox_dir, 0700, AID_ROOT, AID_ROOT, fail_fn); + CreateDir(pkg_sandbox_dir, 0755, uid, uid, fail_fn); } static void BindMount(const std::string& sourceDir, const std::string& targetDir, @@ -642,29 +642,98 @@ static void MountPkgSpecificDir(const std::string& mntSourceRoot, fail_fn_t fail_fn) { std::string mntSourceDir = StringPrintf("%s/Android/%s/%s", mntSourceRoot.c_str(), dirName, packageName.c_str()); - CreateDir(mntSourceDir, 0755, uid, uid, fail_fn); std::string mntTargetDir = StringPrintf("%s/Android/%s/%s", mntTargetRoot.c_str(), dirName, packageName.c_str()); - CreateDir(mntTargetDir, 0755, uid, uid, fail_fn); BindMount(mntSourceDir, mntTargetDir, fail_fn); } - -static void createPkgSpecificDirRoots(const std::string& parentDir, - bool createSandbox, - mode_t mode, uid_t uid, gid_t gid, - fail_fn_t fail_fn) { - std::string androidDir = StringPrintf("%s/Android", parentDir.c_str()); - CreateDir(androidDir, mode, uid, gid, fail_fn); - std::vector dirs = {"data", "media", "obb"}; - if (createSandbox) { - dirs.push_back("sandbox"); +static void CreateSubDirs(int dirfd, const std::string& parentDirPath, + const std::vector& subDirs, + fail_fn_t fail_fn) { + for (auto& dirName : subDirs) { + struct stat sb; + if (TEMP_FAILURE_RETRY(fstatat(dirfd, dirName.c_str(), &sb, 0)) == 0) { + if (S_ISDIR(sb.st_mode)) { + continue; + } else if (TEMP_FAILURE_RETRY(unlinkat(dirfd, dirName.c_str(), 0)) == -1) { + fail_fn(CREATE_ERROR("Failed to unlinkat on %s/%s: %s", + parentDirPath.c_str(), dirName.c_str(), strerror(errno))); + } + } else if (errno != ENOENT) { + fail_fn(CREATE_ERROR("Failed to fstatat on %s/%s: %s", + parentDirPath.c_str(), dirName.c_str(), strerror(errno))); + } + if (TEMP_FAILURE_RETRY(mkdirat(dirfd, dirName.c_str(), 0700)) == -1) { + fail_fn(CREATE_ERROR("Failed to mkdirat on %s/%s: %s", + parentDirPath.c_str(), dirName.c_str(), strerror(errno))); + } } - for (auto& dir : dirs) { - std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str()); - CreateDir(path, mode, uid, gid, fail_fn); +} + +static void EnsurePkgSpecificDirs(const std::string& path, + const std::vector& packageNames, + bool createSandboxDir, + fail_fn_t fail_fn) { + std::string androidDir = StringPrintf("%s/Android", path.c_str()); + android::base::unique_fd androidFd( + open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + if (androidFd.get() < 0) { + if (errno == ENOENT || errno == ENOTDIR) { + if (errno == ENOTDIR && TEMP_FAILURE_RETRY(unlink(androidDir.c_str())) == -1) { + fail_fn(CREATE_ERROR("Failed to unlink %s: %s", + androidDir.c_str(), strerror(errno))); + } + if (TEMP_FAILURE_RETRY(mkdir(androidDir.c_str(), 0700)) == -1) { + fail_fn(CREATE_ERROR("Failed to mkdir %s: %s", + androidDir.c_str(), strerror(errno))); + } + androidFd.reset(open(androidDir.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + } + + if (androidFd.get() < 0) { + fail_fn(CREATE_ERROR("Failed to open %s: %s", androidDir.c_str(), strerror(errno))); + } + } + + std::vector dataMediaObbDirs = {"data", "media", "obb"}; + if (createSandboxDir) { + dataMediaObbDirs.push_back("sandbox"); + } + CreateSubDirs(androidFd.get(), androidDir, dataMediaObbDirs, fail_fn); + if (createSandboxDir) { + dataMediaObbDirs.pop_back(); + } + for (auto& dirName : dataMediaObbDirs) { + std::string dataDir = StringPrintf("%s/%s", androidDir.c_str(), dirName.c_str()); + android::base::unique_fd dataFd( + openat(androidFd, dirName.c_str(), O_RDONLY | O_DIRECTORY | O_CLOEXEC)); + if (dataFd.get() < 0) { + fail_fn(CREATE_ERROR("Failed to openat %s/%s: %s", + androidDir.c_str(), dirName.c_str(), strerror(errno))); + } + CreateSubDirs(dataFd.get(), dataDir, packageNames, fail_fn); + } +} + +static void CreatePkgSandboxSource(const std::string& sandboxSource, fail_fn_t fail_fn) { + + struct stat sb; + if (TEMP_FAILURE_RETRY(stat(sandboxSource.c_str(), &sb)) == 0) { + if (S_ISDIR(sb.st_mode)) { + return; + } else if (TEMP_FAILURE_RETRY(unlink(sandboxSource.c_str())) == -1) { + fail_fn(CREATE_ERROR("Failed to unlink %s: %s", + sandboxSource.c_str(), strerror(errno))); + } + } else if (errno != ENOENT) { + fail_fn(CREATE_ERROR("Failed to stat %s: %s", + sandboxSource.c_str(), strerror(errno))); + } + if (TEMP_FAILURE_RETRY(mkdir(sandboxSource.c_str(), 0700)) == -1) { + fail_fn(CREATE_ERROR("Failed to mkdir %s: %s", + sandboxSource.c_str(), strerror(errno))); } } @@ -680,21 +749,21 @@ static void PreparePkgSpecificDirs(const std::vector& packageNames, StringAppendF(&mntTarget, "/%d", userId); } - if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) < 0) { + if (TEMP_FAILURE_RETRY(access(mntSource.c_str(), F_OK)) == -1) { ALOGE("Can't access %s: %s", mntSource.c_str(), strerror(errno)); continue; } - // Create /mnt/runtime/write/emulated/0/Android/{data,media,obb,sandbox} - createPkgSpecificDirRoots(mntSource, true, 0700, AID_ROOT, AID_ROOT, fail_fn); + // Ensure /mnt/runtime/write/emulated/0/Android/{data,media,obb} + EnsurePkgSpecificDirs(mntSource, packageNames, true, fail_fn); std::string sandboxSource = StringPrintf("%s/Android/sandbox/%s", mntSource.c_str(), sandboxId.c_str()); - CreateDir(sandboxSource, 0755, uid, uid, fail_fn); + CreatePkgSandboxSource(sandboxSource, fail_fn); BindMount(sandboxSource, mntTarget, fail_fn); - // Create /storage/emulated/0/Android/{data,media,obb} - createPkgSpecificDirRoots(mntTarget, false, 0755, uid, uid, fail_fn); + // Ensure /storage/emulated/0/Android/{data,media,obb} + EnsurePkgSpecificDirs(mntTarget, packageNames, false, fail_fn); for (auto& package : packageNames) { MountPkgSpecificDir(mntSource, mntTarget, package, uid, "data", fail_fn); MountPkgSpecificDir(mntSource, mntTarget, package, uid, "media", fail_fn); @@ -775,15 +844,14 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, userid_t user_id = multiuser_get_user_id(uid); std::string pkgSandboxDir = StringPrintf("/mnt/user/%d/package/%s", user_id, package_name.c_str()); - struct stat sb; bool sandboxAlreadyCreated = true; - if (TEMP_FAILURE_RETRY(lstat(pkgSandboxDir.c_str(), &sb)) == -1) { + if (TEMP_FAILURE_RETRY(access(pkgSandboxDir.c_str(), F_OK)) == -1) { if (errno == ENOENT) { ALOGD("Sandbox not yet created for %s", pkgSandboxDir.c_str()); sandboxAlreadyCreated = false; - CreatePkgSandbox(uid, package_name, fail_fn); + CreatePkgSandboxTarget(uid, package_name, fail_fn); } else { - fail_fn(CREATE_ERROR("Failed to lstat %s: %s", + fail_fn(CREATE_ERROR("Failed to access %s: %s", pkgSandboxDir.c_str(), strerror(errno))); } } @@ -794,7 +862,7 @@ static void MountEmulatedStorage(uid_t uid, jint mount_mode, pkgSandboxDir.c_str(), strerror(errno))); } - if (access("/storage/obb_mount", F_OK) == 0) { + if (TEMP_FAILURE_RETRY(access("/storage/obb_mount", F_OK)) == 0) { if (mount_mode != MOUNT_EXTERNAL_INSTALLER) { remove("/storage/obb_mount"); }