diff options
-rw-r--r-- | cmds/installd/InstalldNativeService.cpp | 77 | ||||
-rw-r--r-- | cmds/installd/InstalldNativeService.h | 23 | ||||
-rw-r--r-- | cmds/installd/tests/installd_service_test.cpp | 125 | ||||
-rw-r--r-- | cmds/installd/tests/installd_utils_test.cpp | 34 | ||||
-rw-r--r-- | cmds/installd/utils.cpp | 37 | ||||
-rw-r--r-- | cmds/installd/utils.h | 7 |
6 files changed, 289 insertions, 14 deletions
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 4e3aae4312..7c219449d3 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -18,13 +18,9 @@ #define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER -#include <algorithm> #include <errno.h> -#include <fstream> #include <fts.h> -#include <functional> #include <inttypes.h> -#include <regex> #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -40,6 +36,11 @@ #include <sys/wait.h> #include <sys/xattr.h> #include <unistd.h> +#include <algorithm> +#include <filesystem> +#include <fstream> +#include <functional> +#include <regex> #include <android-base/file.h> #include <android-base/logging.h> @@ -720,6 +721,74 @@ binder::Status InstalldNativeService::createAppDataLocked( return error("Failed to prepare profiles for " + packageName); } } + + { + auto status = createAppDirectoryForSupplementalData(uuid, packageName, userId, appId, + previousAppId, seInfo, flags); + if (!status.isOk()) { + return status; + } + } + + return ok(); +} + +/** + * Responsible for creating /data/user/0/supplemental/<app-name> directory and other + * app level sub directories, such as ./shared + */ +binder::Status InstalldNativeService::createAppDirectoryForSupplementalData( + const std::optional<std::string>& uuid, const std::string& packageName, int32_t userId, + int32_t appId, int32_t previousAppId, const std::string& seInfo, int32_t flags) { + int32_t supplementalUid = multiuser_get_supplemental_uid(userId, appId); + if (supplementalUid == -1) { + // There no valid supplemental process for this app. Skip creation of data directory + return ok(); + } + + // TODO(b/211763739): what if uuid is not nullptr or TEST? + const char* uuid_ = uuid ? uuid->c_str() : nullptr; + + constexpr int storageFlags[2] = {FLAG_STORAGE_CE, FLAG_STORAGE_DE}; + for (int i = 0; i < 2; i++) { + int currentFlag = storageFlags[i]; + if ((flags & currentFlag) == 0) { + continue; + } + bool isCeData = (currentFlag == FLAG_STORAGE_CE); + + // /data/misc_{ce,de}/<user-id>/supplemental directory gets created by vold + // during user creation + + // Prepare the app directory + auto appPath = create_data_misc_supplemental_package_path(uuid_, isCeData, userId, + packageName.c_str()); + if (prepare_app_dir(appPath, 0751, AID_SYSTEM)) { + return error("Failed to prepare " + appPath); + } + + // Now prepare the shared directory which will be accessible by all codes + auto sharedPath = create_data_misc_supplemental_shared_path(uuid_, isCeData, userId, + packageName.c_str()); + + int32_t previousSupplementalUid = multiuser_get_supplemental_uid(userId, previousAppId); + int32_t cacheGid = multiuser_get_cache_gid(userId, appId); + if (cacheGid == -1) { + return exception(binder::Status::EX_ILLEGAL_STATE, + StringPrintf("cacheGid cannot be -1 for supplemental data")); + } + auto status = createAppDataDirs(sharedPath, supplementalUid, &previousSupplementalUid, + cacheGid, seInfo, 0700); + if (!status.isOk()) { + return status; + } + + // TODO(b/211763739): We also need to handle art profile creations + + // TODO(b/211763739): And return the CE inode of the supplemental root directory and + // app directory under it so we can clear contents while CE storage is locked + } + return ok(); } diff --git a/cmds/installd/InstalldNativeService.h b/cmds/installd/InstalldNativeService.h index 96783c3dbb..d4429793c0 100644 --- a/cmds/installd/InstalldNativeService.h +++ b/cmds/installd/InstalldNativeService.h @@ -47,14 +47,9 @@ public: int32_t flags); binder::Status createAppData(const std::optional<std::string>& uuid, - const std::string& packageName, int32_t userId, int32_t flags, int32_t appId, - int32_t previousAppId, const std::string& seInfo, int32_t targetSdkVersion, - int64_t* _aidl_return); - binder::Status createAppDataLocked(const std::optional<std::string>& uuid, - const std::string& packageName, int32_t userId, - int32_t flags, int32_t appId, int32_t previousAppId, - const std::string& seInfo, int32_t targetSdkVersion, - int64_t* _aidl_return); + const std::string& packageName, int32_t userId, int32_t flags, + int32_t appId, int32_t previousAppId, const std::string& seInfo, + int32_t targetSdkVersion, int64_t* _aidl_return); binder::Status createAppData( const android::os::CreateAppDataArgs& args, @@ -202,6 +197,18 @@ private: std::unordered_map<uid_t, int64_t> mCacheQuotas; std::string findDataMediaPath(const std::optional<std::string>& uuid, userid_t userid); + + binder::Status createAppDataLocked(const std::optional<std::string>& uuid, + const std::string& packageName, int32_t userId, + int32_t flags, int32_t appId, int32_t previousAppId, + const std::string& seInfo, int32_t targetSdkVersion, + int64_t* _aidl_return); + + binder::Status createAppDirectoryForSupplementalData(const std::optional<std::string>& uuid, + const std::string& packageName, + int32_t userId, int32_t appId, + int32_t previousAppId, + const std::string& seInfo, int32_t flags); }; } // namespace installd diff --git a/cmds/installd/tests/installd_service_test.cpp b/cmds/installd/tests/installd_service_test.cpp index 9702d42b14..499ba70775 100644 --- a/cmds/installd/tests/installd_service_test.cpp +++ b/cmds/installd/tests/installd_service_test.cpp @@ -74,8 +74,14 @@ std::string get_package_name(uid_t uid) { } namespace installd { -constexpr const char* kTestUuid = "TEST"; -constexpr const char* kTestPath = "/data/local/tmp/user/0"; +static constexpr const char* kTestUuid = "TEST"; +static constexpr const char* kTestPath = "/data/local/tmp/user/0"; +static constexpr const uid_t kSystemUid = 1000; +static constexpr const int32_t kTestUserId = 0; +static constexpr const uid_t kTestAppId = 19999; + +const gid_t kTestAppUid = multiuser_get_uid(kTestUserId, kTestAppId); +const uid_t kTestAppSupplementalUid = multiuser_get_supplemental_uid(kTestUserId, kTestAppId); #define FLAG_FORCE InstalldNativeService::FLAG_FORCE @@ -943,5 +949,120 @@ TEST_F(AppDataSnapshotTest, RestoreAppDataSnapshot_WrongVolumeUuid) { "com.foo", 10000, "", 0, 41, FLAG_STORAGE_DE)); } +class AppSupplementalDataTest : public testing::Test { +public: + void CheckFileAccess(const std::string& path, uid_t uid, mode_t mode) { + const auto fullPath = "/data/local/tmp/" + path; + ASSERT_TRUE(exists(fullPath.c_str())) << "For path: " << fullPath; + struct stat st; + ASSERT_EQ(0, stat(fullPath.c_str(), &st)); + ASSERT_EQ(uid, st.st_uid) << "For path: " << fullPath; + ASSERT_EQ(uid, st.st_gid) << "For path: " << fullPath; + ASSERT_EQ(mode, st.st_mode) << "For path: " << fullPath; + } + + bool exists(const char* path) { return ::access(path, F_OK) == 0; } + + // Creates a default CreateAppDataArgs object + android::os::CreateAppDataArgs createAppDataArgs() { + android::os::CreateAppDataArgs args; + args.uuid = kTestUuid; + args.packageName = "com.foo"; + args.userId = kTestUserId; + args.appId = kTestAppId; + args.seInfo = "default"; + args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE; + return args; + } + +protected: + InstalldNativeService* service; + + virtual void SetUp() { + setenv("ANDROID_LOG_TAGS", "*:v", 1); + android::base::InitLogging(nullptr); + + service = new InstalldNativeService(); + clearAppData(); + ASSERT_TRUE(mkdirs("/data/local/tmp/user/0", 0700)); + ASSERT_TRUE(mkdirs("/data/local/tmp/user_de/0", 0700)); + ASSERT_TRUE(mkdirs("/data/local/tmp/misc_ce/0/supplemental", 0700)); + ASSERT_TRUE(mkdirs("/data/local/tmp/misc_de/0/supplemental", 0700)); + + init_globals_from_data_and_root(); + } + + virtual void TearDown() { + delete service; + clearAppData(); + } + +private: + void clearAppData() { + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true)); + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_ce", true)); + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/misc_de", true)); + ASSERT_EQ(0, delete_dir_contents_and_dir("/data/local/tmp/user_de", true)); + } +}; + +TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData) { + android::os::CreateAppDataResult result; + android::os::CreateAppDataArgs args = createAppDataArgs(); + args.packageName = "com.foo"; + args.flags = FLAG_STORAGE_CE | FLAG_STORAGE_DE; + + // Create the app user data. + ASSERT_BINDER_SUCCESS(service->createAppData(args, &result)); + + CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); + CheckFileAccess("misc_ce/0/supplemental/com.foo/shared", kTestAppSupplementalUid, + S_IFDIR | 0700); + CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); + CheckFileAccess("misc_ce/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); + + CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); + CheckFileAccess("misc_de/0/supplemental/com.foo/shared", kTestAppSupplementalUid, + S_IFDIR | 0700); + CheckFileAccess("misc_de/0/supplemental/com.foo/shared/cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); + CheckFileAccess("misc_de/0/supplemental/com.foo/shared/code_cache", kTestAppSupplementalUid, + S_IFDIR | S_ISGID | 0771); +} + +TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutDeFlag) { + android::os::CreateAppDataResult result; + android::os::CreateAppDataArgs args = createAppDataArgs(); + args.packageName = "com.foo"; + args.flags = FLAG_STORAGE_CE; + + // Create the app user data. + ASSERT_BINDER_SUCCESS(service->createAppData(args, &result)); + + // Only CE paths should exist + CheckFileAccess("misc_ce/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); + + // DE paths should not exist + ASSERT_FALSE(exists("/data/local/tmp/misc_de/0/supplemental/com.foo")); +} + +TEST_F(AppSupplementalDataTest, CreateAppData_CreatesSupplementalAppData_WithoutCeFlag) { + android::os::CreateAppDataResult result; + android::os::CreateAppDataArgs args = createAppDataArgs(); + args.packageName = "com.foo"; + args.flags = FLAG_STORAGE_DE; + + // Create the app user data. + ASSERT_BINDER_SUCCESS(service->createAppData(args, &result)); + + // CE paths should not exist + ASSERT_FALSE(exists("/data/local/tmp/misc_ce/0/supplemental/com.foo")); + + // Only DE paths should exist + CheckFileAccess("misc_de/0/supplemental/com.foo", kSystemUid, S_IFDIR | 0751); +} + } // namespace installd } // namespace android diff --git a/cmds/installd/tests/installd_utils_test.cpp b/cmds/installd/tests/installd_utils_test.cpp index 514b88135a..8d1ccdc5d6 100644 --- a/cmds/installd/tests/installd_utils_test.cpp +++ b/cmds/installd/tests/installd_utils_test.cpp @@ -658,6 +658,40 @@ TEST_F(UtilsTest, TestCreateDirIfNeeded) { ASSERT_NE(0, create_dir_if_needed("/data/local/tmp/user/0/bar/baz", 0700)); } +TEST_F(UtilsTest, TestSupplementalDataPaths) { + // Ce data paths + EXPECT_EQ("/data/misc_ce/0/supplemental", + create_data_misc_supplemental_path(nullptr, /*isCeData=*/true, 0)); + EXPECT_EQ("/data/misc_ce/10/supplemental", + create_data_misc_supplemental_path(nullptr, true, 10)); + + EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, true, 0, "com.foo")); + EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, true, 10, "com.foo")); + + EXPECT_EQ("/data/misc_ce/0/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, true, 0, "com.foo")); + EXPECT_EQ("/data/misc_ce/10/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, true, 10, "com.foo")); + + // De data paths + EXPECT_EQ("/data/misc_de/0/supplemental", + create_data_misc_supplemental_path(nullptr, /*isCeData=*/false, 0)); + EXPECT_EQ("/data/misc_de/10/supplemental", + create_data_misc_supplemental_path(nullptr, false, 10)); + + EXPECT_EQ("/data/misc_de/0/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, false, 0, "com.foo")); + EXPECT_EQ("/data/misc_de/10/supplemental/com.foo", + create_data_misc_supplemental_package_path(nullptr, false, 10, "com.foo")); + + EXPECT_EQ("/data/misc_de/0/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, false, 0, "com.foo")); + EXPECT_EQ("/data/misc_de/10/supplemental/com.foo/shared", + create_data_misc_supplemental_shared_path(nullptr, false, 10, "com.foo")); +} + TEST_F(UtilsTest, WaitChild) { pid_t pid = fork(); if (pid == 0) { diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index f04ee337d9..6650b761e1 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -197,6 +197,43 @@ std::string create_data_user_de_path(const char* volume_uuid, userid_t userid) { return StringPrintf("%s/user_de/%u", data.c_str(), userid); } +/** + * Create the path name where supplemental data for all apps will be stored. + * E.g. /data/misc_ce/0/supplemental + */ +std::string create_data_misc_supplemental_path(const char* uuid, bool isCeData, userid_t user) { + std::string data(create_data_path(uuid)); + if (isCeData) { + return StringPrintf("%s/misc_ce/%d/supplemental", data.c_str(), user); + } else { + return StringPrintf("%s/misc_de/%d/supplemental", data.c_str(), user); + } +} + +/** + * Create the path name where code data for all codes in a particular app will be stored. + * E.g. /data/misc_ce/0/supplemental/<app-name> + */ +std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData, + userid_t user, const char* package_name) { + check_package_name(package_name); + return StringPrintf("%s/%s", + create_data_misc_supplemental_path(volume_uuid, isCeData, user).c_str(), + package_name); +} + +/** + * Create the path name where shared code data for a particular app will be stored. + * E.g. /data/misc_ce/0/supplemental/<app-name>/shared + */ +std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData, + userid_t user, const char* package_name) { + return StringPrintf("%s/shared", + create_data_misc_supplemental_package_path(volume_uuid, isCeData, user, + package_name) + .c_str()); +} + std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user) { return StringPrintf("%s/misc_ce/%u/rollback", create_data_path(volume_uuid).c_str(), user); } diff --git a/cmds/installd/utils.h b/cmds/installd/utils.h index 39738945e4..2d00845c54 100644 --- a/cmds/installd/utils.h +++ b/cmds/installd/utils.h @@ -60,6 +60,13 @@ std::string create_data_user_de_package_path(const char* volume_uuid, std::string create_data_user_ce_package_path_as_user_link( const char* volume_uuid, userid_t userid, const char* package_name); +std::string create_data_misc_supplemental_path(const char* volume_uuid, bool isCeData, + userid_t userid); +std::string create_data_misc_supplemental_package_path(const char* volume_uuid, bool isCeData, + userid_t userid, const char* package_name); +std::string create_data_misc_supplemental_shared_path(const char* volume_uuid, bool isCeData, + userid_t userid, const char* package_name); + std::string create_data_misc_ce_rollback_base_path(const char* volume_uuid, userid_t user); std::string create_data_misc_de_rollback_base_path(const char* volume_uuid, userid_t user); std::string create_data_misc_ce_rollback_path(const char* volume_uuid, userid_t user, |