From 038a19ba97a7bce6e40597cbff70a2e22c3d3c13 Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Wed, 9 Feb 2022 19:51:52 -0800 Subject: More robust app data and user data removal. 1. rename the folder, so any new files will end up in the renamed folder. this also greatly reduces chances that app will be able to create new files. 2. delete the renamed folder 3. provide an api to cleanup renamed/deleted folders on system startup Bug: 162757029 Test: atest installd_service_test installd_cache_test installd_utils_test installd_dexopt_test installd_otapreopt_test installd_file_test Change-Id: If1c209d49675f7fa9df60b6136588e3b0a7786e5 --- cmds/installd/utils.cpp | 88 ++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 87 insertions(+), 1 deletion(-) (limited to 'cmds/installd/utils.cpp') diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 0f8a732345..a4a21b720c 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -22,9 +22,10 @@ #include #include #include +#include #include #include -#include +#include #include #include @@ -47,6 +48,7 @@ #define DEBUG_XATTRS 0 +using android::base::Dirname; using android::base::EndsWith; using android::base::Fdopendir; using android::base::StringPrintf; @@ -55,6 +57,10 @@ using android::base::unique_fd; namespace android { namespace installd { +using namespace std::literals; + +static constexpr auto deletedSuffix = "==deleted=="sv; + /** * Check that given string is valid filename, and that it attempts no * parent or child directory traversal. @@ -595,6 +601,86 @@ int delete_dir_contents(const char *pathname, return res; } +static std::string make_unique_name(std::string_view suffix) { + static constexpr auto uuidStringSize = 36; + + uuid_t guid; + uuid_generate(guid); + + std::string name; + const auto suffixSize = suffix.size(); + name.reserve(uuidStringSize + suffixSize); + + name.resize(uuidStringSize); + uuid_unparse(guid, name.data()); + name.append(suffix); + + return name; +} + +static int rename_delete_dir_contents(const std::string& pathname, + int (*exclusion_predicate)(const char*, const int), + bool ignore_if_missing) { + auto temp_dir_name = make_unique_name(deletedSuffix); + auto temp_dir_path = + base::StringPrintf("%s/%s", Dirname(pathname).c_str(), temp_dir_name.c_str()); + + if (::rename(pathname.c_str(), temp_dir_path.c_str())) { + if (ignore_if_missing && (errno == ENOENT)) { + return 0; + } + ALOGE("Couldn't rename %s -> %s: %s \n", pathname.c_str(), temp_dir_path.c_str(), + strerror(errno)); + return -errno; + } + + return delete_dir_contents(temp_dir_path.c_str(), 1, exclusion_predicate, ignore_if_missing); +} + +bool is_renamed_deleted_dir(std::string_view path) { + return path.ends_with(deletedSuffix); +} + +int rename_delete_dir_contents_and_dir(const std::string& pathname, bool ignore_if_missing) { + return rename_delete_dir_contents(pathname, nullptr, ignore_if_missing); +} + +static auto open_dir(const char* dir) { + struct DirCloser { + void operator()(DIR* d) const noexcept { ::closedir(d); } + }; + return std::unique_ptr(::opendir(dir)); +} + +void find_and_delete_renamed_deleted_dirs_under_path(const std::string& pathname) { + auto dir = open_dir(pathname.c_str()); + if (!dir) { + return; + } + int dfd = dirfd(dir.get()); + if (dfd < 0) { + ALOGE("Couldn't dirfd %s: %s\n", pathname.c_str(), strerror(errno)); + return; + } + + struct dirent* de; + while ((de = readdir(dir.get()))) { + if (de->d_type != DT_DIR) { + continue; + } + const char* name = de->d_name; + if (is_renamed_deleted_dir({name})) { + LOG(INFO) << "Deleting renamed data directory: " << name; + // Deleting the content. + delete_dir_contents_fd(dfd, name); + // Deleting the directory + if (unlinkat(dfd, name, AT_REMOVEDIR) < 0) { + ALOGE("Couldn't unlinkat %s: %s\n", name, strerror(errno)); + } + } + } +} + int delete_dir_contents_fd(int dfd, const char *name) { int fd, res; -- cgit v1.2.3-59-g8ed1b