Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d8b4f10b authored by Sudheer Shanka's avatar Sudheer Shanka
Browse files

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
parent 04709759
Loading
Loading
Loading
Loading
+95 −27
Original line number Diff line number Diff line
@@ -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/<package-name>
    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 CreateSubDirs(int dirfd, const std::string& parentDirPath,
                          const std::vector<std::string>& 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)));
        }
    }
}

static void createPkgSpecificDirRoots(const std::string& parentDir,
                                      bool createSandbox,
                                      mode_t mode, uid_t uid, gid_t gid,
static void EnsurePkgSpecificDirs(const std::string& path,
                                  const std::vector<std::string>& packageNames,
                                  bool createSandboxDir,
                                  fail_fn_t fail_fn) {
    std::string androidDir = StringPrintf("%s/Android", parentDir.c_str());
    CreateDir(androidDir, mode, uid, gid, fail_fn);
    std::vector<std::string> dirs = {"data", "media", "obb"};
    if (createSandbox) {
        dirs.push_back("sandbox");
    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)));
        }
    for (auto& dir : dirs) {
        std::string path = StringPrintf("%s/%s", androidDir.c_str(), dir.c_str());
        CreateDir(path, mode, uid, gid, fail_fn);
    }

    std::vector<std::string> 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<std::string>& 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");
                }