Verify the class loader context when loading oat files
Previously, the oat_file_manager would expect and perform validation on a
simple classpath: a list of dex files separated by ':'.
This is no longer enough since the oat file may encode a chain of class
loaders now. The CL moves the validation logic in ClassLoaderContext and
extends it to verify the complete chain of class loaders.
Test: m test-art-host
Bug: 38138251
Change-Id: I8ac9c65db1a14909aaecb04fa7a7115ddedc673f
diff --git a/runtime/class_loader_context.cc b/runtime/class_loader_context.cc
index a6e5c21..678ae8f 100644
--- a/runtime/class_loader_context.cc
+++ b/runtime/class_loader_context.cc
@@ -353,38 +353,6 @@
<< "attempt=" << dex_files_open_attempted_ << ", result=" << dex_files_open_result_;
}
-bool ClassLoaderContext::DecodePathClassLoaderContextFromOatFileKey(
- const std::string& context_spec,
- std::vector<std::string>* out_classpath,
- std::vector<uint32_t>* out_checksums,
- bool* out_is_special_shared_library) {
- ClassLoaderContext context;
- if (!context.Parse(context_spec, /*parse_checksums*/ true)) {
- LOG(ERROR) << "Invalid class loader context: " << context_spec;
- return false;
- }
-
- *out_is_special_shared_library = context.special_shared_library_;
- if (context.special_shared_library_) {
- return true;
- }
-
- if (context.class_loader_chain_.empty()) {
- return true;
- }
-
- // TODO(calin): assert that we only have a PathClassLoader until the logic for
- // checking the context covers all case.
- CHECK_EQ(1u, context.class_loader_chain_.size());
- const ClassLoaderInfo& info = context.class_loader_chain_[0];
- CHECK_EQ(kPathClassLoader, info.type);
- DCHECK_EQ(info.classpath.size(), info.checksums.size());
-
- *out_classpath = info.classpath;
- *out_checksums = info.checksums;
- return true;
-}
-
// Collects the dex files from the give Java dex_file object. Only the dex files with
// at least 1 class are collected. If a null java_dex_file is passed this method does nothing.
static bool CollectDexFilesFromJavaDexFile(ObjPtr<mirror::Object> java_dex_file,
@@ -583,6 +551,8 @@
std::unique_ptr<ClassLoaderContext> ClassLoaderContext::CreateContextForClassLoader(
jobject class_loader,
jobjectArray dex_elements) {
+ CHECK(class_loader != nullptr);
+
ScopedObjectAccess soa(Thread::Current());
StackHandleScope<2> hs(soa.Self());
Handle<mirror::ClassLoader> h_class_loader =
@@ -590,8 +560,6 @@
Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements =
hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Object>>(dex_elements));
- CHECK(h_class_loader != nullptr);
-
std::unique_ptr<ClassLoaderContext> result(new ClassLoaderContext(/*owns_the_dex_files*/ false));
if (result->AddInfoToContextFromClassLoader(soa, h_class_loader, h_dex_elements)) {
return result;
@@ -600,5 +568,60 @@
}
}
+bool ClassLoaderContext::VerifyClassLoaderContextMatch(const std::string& context_spec) {
+ ClassLoaderContext expected_context;
+ if (!expected_context.Parse(context_spec, /*parse_checksums*/ true)) {
+ LOG(WARNING) << "Invalid class loader context: " << context_spec;
+ return false;
+ }
+
+ if (expected_context.special_shared_library_) {
+ return true;
+ }
+
+ if (expected_context.class_loader_chain_.size() != class_loader_chain_.size()) {
+ LOG(WARNING) << "ClassLoaderContext size mismatch. expected="
+ << expected_context.class_loader_chain_.size()
+ << ", actual=" << class_loader_chain_.size();
+ return false;
+ }
+
+ for (size_t i = 0; i < class_loader_chain_.size(); i++) {
+ const ClassLoaderInfo& info = class_loader_chain_[i];
+ const ClassLoaderInfo& expected_info = expected_context.class_loader_chain_[i];
+ if (info.type != expected_info.type) {
+ LOG(WARNING) << "ClassLoaderContext type mismatch for position " << i
+ << ". expected=" << GetClassLoaderTypeName(expected_info.type)
+ << ", found=" << GetClassLoaderTypeName(info.type);
+ return false;
+ }
+ if (info.classpath.size() != expected_info.classpath.size()) {
+ LOG(WARNING) << "ClassLoaderContext classpath size mismatch for position " << i
+ << ". expected=" << expected_info.classpath.size()
+ << ", found=" << info.classpath.size();
+ return false;
+ }
+
+ DCHECK_EQ(info.classpath.size(), info.checksums.size());
+ DCHECK_EQ(expected_info.classpath.size(), expected_info.checksums.size());
+
+ for (size_t k = 0; k < info.classpath.size(); k++) {
+ if (info.classpath[k] != expected_info.classpath[k]) {
+ LOG(WARNING) << "ClassLoaderContext classpath element mismatch for position " << i
+ << ". expected=" << expected_info.classpath[k]
+ << ", found=" << info.classpath[k];
+ return false;
+ }
+ if (info.checksums[k] != expected_info.checksums[k]) {
+ LOG(WARNING) << "ClassLoaderContext classpath element checksum mismatch for position " << i
+ << ". expected=" << expected_info.checksums[k]
+ << ", found=" << info.checksums[k];
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
} // namespace art