ApexFile::GetPath() returns realpath
When an APEX file is on a symlink directory (e.g. /system_ext/apex which
actually is /system/system_ext/apex on a device where system_ext is not
a real partition), the apex info constructed by scanning the directory
can be different from apex info re-constructed by reading /proc/mounts.
The latter shows realpath, while the former isn't.
This can make getAllPackages() incorrect. It is a union of the active
apexes gathered from /proc/mounts and factory apexes gathered by
scanning the built-in directories.
Fixing the bug by storing realpath of the apex file to the ApexFile
struct.
Bug: 179211712
Test: ApexTestCases.ApexServiceTest#GetAllPackages
Test: ApexTestCasea.ApexFileTest#GetPathReturnsRealpath
Change-Id: I5da96f78ddb11609c1271edfd1044d1979180b3c
diff --git a/apexd/apex_file.cpp b/apexd/apex_file.cpp
index d65d426..9dfd3f5 100644
--- a/apexd/apex_file.cpp
+++ b/apexd/apex_file.cpp
@@ -157,8 +157,16 @@
return manifest.error();
}
- return ApexFile(path, image_offset, image_size, std::move(*manifest), pubkey,
- fs_type, is_compressed);
+ // b/179211712 the stored path should be the realpath, otherwise the path we
+ // get by scanning the directory would be different from the path we get
+ // by reading /proc/mounts, if the apex file is on a symlink dir.
+ std::string realpath;
+ if (!android::base::Realpath(path, &realpath)) {
+ return ErrnoError() << "can't get realpath of " << path;
+ }
+
+ return ApexFile(realpath, image_offset, image_size, std::move(*manifest),
+ pubkey, fs_type, is_compressed);
}
// AVB-related code.
diff --git a/apexd/apex_file_test.cpp b/apexd/apex_file_test.cpp
index 39d664d..2023646 100644
--- a/apexd/apex_file_test.cpp
+++ b/apexd/apex_file_test.cpp
@@ -293,6 +293,25 @@
ASSERT_FALSE(*exist);
}
+TEST(ApexFileTest, GetPathReturnsRealpath) {
+ const std::string real_path = kTestDataDir + "apex.apexd_test.apex";
+ const std::string symlink_path =
+ kTestDataDir + "apex.apexd_test.symlink.apex";
+
+ // In case the link already exists
+ int ret = unlink(symlink_path.c_str());
+ ASSERT_TRUE(ret == 0 || errno == ENOENT)
+ << "failed to unlink " << symlink_path;
+
+ ret = symlink(real_path.c_str(), symlink_path.c_str());
+ ASSERT_EQ(0, ret) << "failed to create symlink at " << symlink_path;
+
+ // Open with the symlink. Realpath is expected.
+ Result<ApexFile> apex_file = ApexFile::Open(symlink_path);
+ ASSERT_RESULT_OK(apex_file);
+ ASSERT_EQ(real_path, apex_file->GetPath());
+}
+
} // namespace
} // namespace apex
} // namespace android