-
Notifications
You must be signed in to change notification settings - Fork 14.9k
[lldb] Fix use after free on ModuleList::RemoveSharedModuleIfOrphaned #155331
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Conversation
This fixes a potential use after free where ModuleList::RemoveSharedModuleIfOrphaned -> SharedModuleList::RemoveIfOrphaned -> SharedModuleList::RemoveFromMap would potentially dereference a freed pointer. This fixes it by not calling ModuleList::RemoveSharedModuleIfOrphaned at all if the pointer was just freed.
@llvm/pr-subscribers-lldb Author: Augusto Noronha (augusto2112) ChangesThis fixes a potential use after free where Full diff: https://github.com/llvm/llvm-project/pull/155331.diff 1 Files Affected:
diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp
index fa98c24606492..d5406d88ec80a 100644
--- a/lldb/source/Target/Target.cpp
+++ b/lldb/source/Target/Target.cpp
@@ -2564,9 +2564,12 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
m_images.Append(module_sp, notify);
for (ModuleSP &old_module_sp : replaced_modules) {
+ auto use_count = old_module_sp.use_count();
Module *old_module_ptr = old_module_sp.get();
old_module_sp.reset();
- ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr);
+ // If the use count was one, this was not in the shared module list.
+ if (use_count > 1)
+ ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr);
}
} else
module_sp.reset();
|
@JDevlieghere @felipepiovezan with the changes I made to SharedModuleList, I accidentally introduced a use after free, since the caller of |
auto use_count = old_module_sp.use_count(); | ||
Module *old_module_ptr = old_module_sp.get(); | ||
old_module_sp.reset(); | ||
ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr); | ||
// If the use count was one, this was not in the shared module list. | ||
if (use_count > 1) | ||
ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why does RemoveSharedModuleIfOrphaned
take a raw pointer and not the ModuleSP
? If it did, then we could just check if the SP is valid (like Remove
does) and avoid yet another place where we check the use count.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I realize that this isn't enough to address the issue. But I think this shows what a bad idea it is to mix raw pointers, shared pointer references and references.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If RemoveSharedModuleIfOrphaned
takes a shared pointer we have to account for the caller also having a shared pointer to decide whether the module is an orphan or not, which would probably be more confusing.
I'm confused where the "free" in this "use-after-free" is actually occurring. |
The caller of Old code:
|
@JDevlieghere @felipepiovezan any suggestions on this, or can I merge it as is? The other way to do this would be to allow already freed pointers, document it, and be careful to never dereference it. That feels weird and wasteful though. I guess a third possibility is add a new function which takes a reference to the shared pointer (haha), have it check the count, free the pointer from shared pointer and remove the orphans if the reference count > 1. |
Can we solve this by handing down a weak pointer to the module? That way we can check if the ref count has hit zero. |
This fixes a potential use after free where
ModuleList::RemoveSharedModuleIfOrphaned ->
SharedModuleList::RemoveIfOrphaned -> SharedModuleList::RemoveFromMap would potentially dereference a freed pointer. This fixes it by not calling ModuleList::RemoveSharedModuleIfOrphaned at all if the pointer was just freed.