Fixup existing profile directories during upgrades

If the profile directory exists we need to fixup the owner and
permissions. The owner of the directory is set to AID_SYSTEM.
This allows the system to access the profiles while restricting the search
capabilities for others.

Test: installd_dexopt_test
Bug: 30934496
Bug: 69678790
Change-Id: I621c95e24cc85a2797724f6ac448c9f8a8d00a53
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index daa744f..04e39f9 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -373,13 +373,22 @@
 
     const std::string ref_profile_path =
             create_primary_reference_profile_package_dir_path(packageName);
-    // dex2oat/profman runs under the shared app gid and it needs to read/write reference
-    // profiles.
-    if (fs_prepare_dir_strict(
-            ref_profile_path.c_str(), 0701, shared_app_gid, shared_app_gid) != 0) {
+
+    // Prepare the reference profile directory. Note that we use the non strict version of
+    // fs_prepare_dir. This will fix the permission and the ownership to the correct values.
+    // This is particularly important given that in O there were some fixes for how the
+    // shared_app_gid is computed.
+    //
+    // Note that by the time we get here we know that we are using a correct uid (otherwise
+    // prepare_app_dir and the above fs_prepare_file_strict which check the uid). So we
+    // are sure that the gid being used belongs to the owning app and not someone else.
+    //
+    // dex2oat/profman runs under the shared app gid and it needs to read/write reference profiles.
+    if (fs_prepare_dir(ref_profile_path.c_str(), 0770, AID_SYSTEM, shared_app_gid) != 0) {
         PLOG(ERROR) << "Failed to prepare " << ref_profile_path;
         return false;
     }
+
     return true;
 }
 
diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp
index ebeae96..05d7b6c 100644
--- a/cmds/installd/tests/installd_dexopt_test.cpp
+++ b/cmds/installd/tests/installd_dexopt_test.cpp
@@ -574,7 +574,39 @@
 
     CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
     CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
-    CheckFileAccess(ref_profile_dir, kTestAppGid, kTestAppGid, 0701 | S_IFDIR);
+    CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
+}
+
+// Verify that the profile directories are fixed up during an upgrade.
+// (The reference profile directory is prepared lazily).
+TEST_F(ProfileTest, ProfileDirOkAfterFixup) {
+    LOG(INFO) << "ProfileDirOkAfterFixup";
+
+    std::string cur_profile_dir = create_primary_current_profile_package_dir_path(
+            kTestUserId, package_name_);
+    std::string cur_profile_file = create_current_profile_path(kTestUserId, package_name_,
+            /*is_secondary_dex*/false);
+    std::string ref_profile_dir = create_primary_reference_profile_package_dir_path(package_name_);
+
+    // Simulate a pre-P setup by changing the owner to kTestAppGid and permissions to 0700.
+    ASSERT_EQ(0, chown(ref_profile_dir.c_str(), kTestAppGid, kTestAppGid));
+    ASSERT_EQ(0, chmod(ref_profile_dir.c_str(), 0700));
+
+    // Run createAppData again which will offer to fix-up the profile directories.
+    ASSERT_TRUE(service_->createAppData(
+            volume_uuid_,
+            package_name_,
+            kTestUserId,
+            kAppDataFlags,
+            kTestAppUid,
+            se_info_,
+            kOSdkVersion,
+            &ce_data_inode_).isOk());
+
+    // Check the file access.
+    CheckFileAccess(cur_profile_dir, kTestAppUid, kTestAppUid, 0700 | S_IFDIR);
+    CheckFileAccess(cur_profile_file, kTestAppUid, kTestAppUid, 0600 | S_IFREG);
+    CheckFileAccess(ref_profile_dir, kSystemUid, kTestAppGid, 0770 | S_IFDIR);
 }
 
 }  // namespace installd