diff options
author | 2019-03-08 14:59:41 +0000 | |
---|---|---|
committer | 2019-03-14 14:34:20 +0000 | |
commit | a5c3a808020d81447bc19d07a99288e9d28a6e6c (patch) | |
tree | 83a9b1eac0a7209e6e407c0462d0b1ba8f95f62c /runtime/hidden_api_test.cc | |
parent | 98fb083a30e9b37685f943e2923e65e60e0a0971 (diff) |
hiddenapi domain: Use oat dex file location if available
To determine the caller and callee domains of a hidden API access check,
the logic will test the dex location against several known system
locations. However, DexFile instances backed by an OatFile have relative
dex locations to avoid need to rewrite the .oat file when moving files
between folders. The canonical dex location is stored in the OatDexFile
instead.
Because the OatDexFile data structure is not available in libdexfile,
move the domain resolution logic to hidden_api.cc and resolve when dex
files is first registered with the class linker.
Test: m test-art-gtest
Test: camera does not crash
Bug: 126901248
Bug: 127852529
Change-Id: Id494b1c47a2199c227dec046174e08320b9cbc3b
Diffstat (limited to 'runtime/hidden_api_test.cc')
-rw-r--r-- | runtime/hidden_api_test.cc | 210 |
1 files changed, 210 insertions, 0 deletions
diff --git a/runtime/hidden_api_test.cc b/runtime/hidden_api_test.cc index cfc3b07300..be6407963b 100644 --- a/runtime/hidden_api_test.cc +++ b/runtime/hidden_api_test.cc @@ -16,10 +16,15 @@ #include "hidden_api.h" +#include <fstream> + +#include "base/file_utils.h" #include "base/sdk_version.h" +#include "base/stl_util.h" #include "common_runtime_test.h" #include "jni/jni_internal.h" #include "proxy_test.h" +#include "well_known_classes.h" namespace art { @@ -375,4 +380,209 @@ TEST_F(HiddenApiTest, CheckMemberSignatureForProxyClass) { ASSERT_EQ("L$Proxy1234;->interfaces:[Ljava/lang/Class;", ss_field.str()); } +static bool Copy(const std::string& src, const std::string& dst, /*out*/ std::string* error_msg) { + std::ifstream src_stream(src, std::ios::binary); + std::ofstream dst_stream(dst, std::ios::binary); + dst_stream << src_stream.rdbuf(); + src_stream.close(); + dst_stream.close(); + if (src_stream.good() && dst_stream.good()) { + return true; + } else { + *error_msg = "Copy " + src + " => " + dst + " (src_good=" + + (src_stream.good() ? "true" : "false") + ", dst_good=" + + (dst_stream.good() ? "true" : "false") + ")"; + return false; + } +} + +static bool LoadDexFiles(const std::string& path, + ScopedObjectAccess& soa, + /* out */ std::vector<std::unique_ptr<const DexFile>>* dex_files, + /* out */ ObjPtr<mirror::ClassLoader>* class_loader, + /* out */ std::string* error_msg) REQUIRES_SHARED(Locks::mutator_lock_) { + if (!ArtDexFileLoader().Open(path.c_str(), + path, + /* verify= */ true, + /* verify_checksum= */ true, + error_msg, + dex_files)) { + return false; + } + + ClassLinker* const linker = Runtime::Current()->GetClassLinker(); + + StackHandleScope<2> hs(soa.Self()); + Handle<mirror::Class> h_class = hs.NewHandle(soa.Decode<mirror::Class>( + WellKnownClasses::dalvik_system_PathClassLoader)); + Handle<mirror::ClassLoader> h_loader = hs.NewHandle(linker->CreateWellKnownClassLoader( + soa.Self(), + MakeNonOwningPointerVector(*dex_files), + h_class, + /* parent_loader= */ ScopedNullHandle<mirror::ClassLoader>(), + /* shared_libraries= */ ScopedNullHandle<mirror::ObjectArray<mirror::ClassLoader>>())); + for (const auto& dex_file : *dex_files) { + linker->RegisterDexFile(*dex_file.get(), h_loader.Get()); + } + + *class_loader = h_loader.Get(); + return true; +} + +static bool CheckAllDexFilesInDomain(ObjPtr<mirror::ClassLoader> loader, + const std::vector<std::unique_ptr<const DexFile>>& dex_files, + hiddenapi::Domain expected_domain) + REQUIRES_SHARED(Locks::mutator_lock_) { + for (const auto& dex_file : dex_files) { + hiddenapi::AccessContext context(loader, dex_file.get()); + if (context.GetDomain() != expected_domain) { + LOG(ERROR) << dex_file->GetLocation() << ": access context domain does not match " + << "(expected=" << static_cast<uint32_t>(expected_domain) + << ", actual=" << static_cast<uint32_t>(context.GetDomain()) << ")"; + return false; + } + if (dex_file->GetHiddenapiDomain() != expected_domain) { + LOG(ERROR) << dex_file->GetLocation() << ": dex file domain does not match " + << "(expected=" << static_cast<uint32_t>(expected_domain) + << ", actual=" << static_cast<uint32_t>(dex_file->GetHiddenapiDomain()) << ")"; + return false; + } + } + + return true; +} + +TEST_F(HiddenApiTest, DexDomain_DataDir) { + // Load file from a non-system directory and check that it is not flagged as framework. + std::string data_location_path = android_data_ + "/foo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(data_location_path.c_str())); + + ScopedObjectAccess soa(Thread::Current()); + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + ObjPtr<mirror::ClassLoader> class_loader; + + ASSERT_TRUE(Copy(GetTestDexFileName("Main"), data_location_path, &error_msg)) << error_msg; + ASSERT_TRUE(LoadDexFiles(data_location_path, soa, &dex_files, &class_loader, &error_msg)) + << error_msg; + ASSERT_GE(dex_files.size(), 1u); + ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication)); + + dex_files.clear(); + ASSERT_EQ(0, remove(data_location_path.c_str())); +} + +TEST_F(HiddenApiTest, DexDomain_SystemDir) { + // Load file from a system, non-framework directory and check that it is not flagged as framework. + std::string system_location_path = GetAndroidRoot() + "/foo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(system_location_path.c_str())); + + ScopedObjectAccess soa(Thread::Current()); + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + ObjPtr<mirror::ClassLoader> class_loader; + + ASSERT_TRUE(Copy(GetTestDexFileName("Main"), system_location_path, &error_msg)) << error_msg; + ASSERT_TRUE(LoadDexFiles(system_location_path, soa, &dex_files, &class_loader, &error_msg)) + << error_msg; + ASSERT_GE(dex_files.size(), 1u); + ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication)); + + dex_files.clear(); + ASSERT_EQ(0, remove(system_location_path.c_str())); +} + +TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir) { + // Load file from a system/framework directory and check that it is flagged as a framework dex. + std::string system_framework_location_path = GetAndroidRoot() + "/framework/foo.jar"; + ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_location_path.c_str())); + + ScopedObjectAccess soa(Thread::Current()); + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + ObjPtr<mirror::ClassLoader> class_loader; + + ASSERT_TRUE(Copy(GetTestDexFileName("Main"), system_framework_location_path, &error_msg)) + << error_msg; + ASSERT_TRUE(LoadDexFiles(system_framework_location_path, + soa, + &dex_files, + &class_loader, + &error_msg)) << error_msg; + ASSERT_GE(dex_files.size(), 1u); + ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kPlatform)); + + dex_files.clear(); + ASSERT_EQ(0, remove(system_framework_location_path.c_str())); +} + +TEST_F(HiddenApiTest, DexDomain_DataDir_MultiDex) { + // Load multidex file from a non-system directory and check that it is not flagged as framework. + std::string data_multi_location_path = android_data_ + "/multifoo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(data_multi_location_path.c_str())); + + ScopedObjectAccess soa(Thread::Current()); + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + ObjPtr<mirror::ClassLoader> class_loader; + + ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"), data_multi_location_path, &error_msg)) + << error_msg; + ASSERT_TRUE(LoadDexFiles(data_multi_location_path, soa, &dex_files, &class_loader, &error_msg)) + << error_msg; + ASSERT_GE(dex_files.size(), 1u); + ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication)); + + dex_files.clear(); + ASSERT_EQ(0, remove(data_multi_location_path.c_str())); +} + +TEST_F(HiddenApiTest, DexDomain_SystemDir_MultiDex) { + // Load multidex file from a system, non-framework directory and check that it is not flagged + // as framework. + std::string system_multi_location_path = GetAndroidRoot() + "/multifoo.jar"; + ASSERT_FALSE(LocationIsOnSystemFramework(system_multi_location_path.c_str())); + + ScopedObjectAccess soa(Thread::Current()); + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + ObjPtr<mirror::ClassLoader> class_loader; + + ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"), system_multi_location_path, &error_msg)) + << error_msg; + ASSERT_TRUE(LoadDexFiles(system_multi_location_path, soa, &dex_files, &class_loader, &error_msg)) + << error_msg; + ASSERT_GT(dex_files.size(), 1u); + ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kApplication)); + + dex_files.clear(); + ASSERT_EQ(0, remove(system_multi_location_path.c_str())); +} + +TEST_F(HiddenApiTest, DexDomain_SystemFrameworkDir_MultiDex) { + // Load multidex file from a system/framework directory and check that it is flagged as a + // framework dex. + std::string system_framework_multi_location_path = GetAndroidRoot() + "/framework/multifoo.jar"; + ASSERT_TRUE(LocationIsOnSystemFramework(system_framework_multi_location_path.c_str())); + + ScopedObjectAccess soa(Thread::Current()); + std::vector<std::unique_ptr<const DexFile>> dex_files; + std::string error_msg; + ObjPtr<mirror::ClassLoader> class_loader; + + ASSERT_TRUE(Copy(GetTestDexFileName("MultiDex"), + system_framework_multi_location_path, + &error_msg)) << error_msg; + ASSERT_TRUE(LoadDexFiles(system_framework_multi_location_path, + soa, + &dex_files, + &class_loader, + &error_msg)) << error_msg; + ASSERT_GT(dex_files.size(), 1u); + ASSERT_TRUE(CheckAllDexFilesInDomain(class_loader, dex_files, hiddenapi::Domain::kPlatform)); + + dex_files.clear(); + ASSERT_EQ(0, remove(system_framework_multi_location_path.c_str())); +} + } // namespace art |