Fix use-after-free issue for dexfile
When we open a dex file, class linker will save dex file address in
dex_caches_. Then when GC occurs, the dex file will be freed in
art::DexFile_closeDexFile, but dex file address is still in dex_caches_.
When some tries to iterate over dex_caches_, HWASAN complains.
Therefore remove the dexfile in dex_caches_ when we delete the dex file.
Ignore-AOSP-First: Security fix
Bug: 222166527
Bug: 238962046
Test: manually
Change-Id: I5bb09a906737db986ead9813695918e06ab590c4
(cherry picked from commit 97283036ec6344eba65f28a3c37b2541f674d4a7)
Merged-In: I5bb09a906737db986ead9813695918e06ab590c4
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index c8dbc75..f6f98e6 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -10298,6 +10298,15 @@
UNREACHABLE();
}
+void ClassLinker::RemoveDexFromCaches(const DexFile& dex_file) {
+ ReaderMutexLock mu(Thread::Current(), *Locks::dex_lock_);
+
+ auto it = dex_caches_.find(&dex_file);
+ if (it != dex_caches_.end()) {
+ dex_caches_.erase(it);
+ }
+}
+
// Instantiate ClassLinker::AllocClass.
template ObjPtr<mirror::Class> ClassLinker::AllocClass</* kMovable= */ true>(
Thread* self,
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 3b20c75b..a3a1adf 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -837,6 +837,7 @@
virtual bool DenyAccessBasedOnPublicSdk(const char* type_descriptor) const;
// Enable or disable public sdk checks.
virtual void SetEnablePublicSdkChecks(bool enabled);
+ void RemoveDexFromCaches(const DexFile& dex_file);
protected:
virtual bool InitializeClass(Thread* self,
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index d714206..ecb9010 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -377,6 +377,7 @@
if (!class_linker->IsDexFileRegistered(soa.Self(), *dex_file)) {
// Clear the element in the array so that we can call close again.
long_dex_files->Set(i, 0);
+ class_linker->RemoveDexFromCaches(*dex_file);
delete dex_file;
} else {
all_deleted = false;