summaryrefslogtreecommitdiff
path: root/cmds/installd/utils.cpp
diff options
context:
space:
mode:
author Alex Buynytskyy <alexbuy@google.com> 2022-02-09 19:51:52 -0800
committer Alex Buynytskyy <alexbuy@google.com> 2022-02-12 19:58:37 -0800
commit038a19ba97a7bce6e40597cbff70a2e22c3d3c13 (patch)
tree4414bdedf35476799eff319d03ae476a881af339 /cmds/installd/utils.cpp
parent32ac30f71c2fdec2ae8058e75fee8ca7c86db8cf (diff)
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
Diffstat (limited to 'cmds/installd/utils.cpp')
-rw-r--r--cmds/installd/utils.cpp88
1 files changed, 87 insertions, 1 deletions
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 <stdlib.h>
#include <sys/capability.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include <sys/wait.h>
#include <sys/xattr.h>
-#include <sys/statvfs.h>
+#include <uuid/uuid.h>
#include <android-base/file.h>
#include <android-base/logging.h>
@@ -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<DIR, DirCloser>(::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;