Skip to content

Commit 397181d

Browse files
authored
[lldb] Fix use after free on ModuleList::RemoveSharedModuleIfOrphaned (#155331)
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.
1 parent 4e6ee0b commit 397181d

File tree

3 files changed

+41
-29
lines changed

3 files changed

+41
-29
lines changed

lldb/include/lldb/Core/ModuleList.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -435,7 +435,7 @@ class ModuleList {
435435

436436
size_t Remove(ModuleList &module_list);
437437

438-
bool RemoveIfOrphaned(const Module *module_ptr);
438+
bool RemoveIfOrphaned(const lldb::ModuleWP module_ptr);
439439

440440
size_t RemoveOrphans(bool mandatory);
441441

@@ -489,7 +489,7 @@ class ModuleList {
489489

490490
static size_t RemoveOrphanSharedModules(bool mandatory);
491491

492-
static bool RemoveSharedModuleIfOrphaned(const Module *module_ptr);
492+
static bool RemoveSharedModuleIfOrphaned(const lldb::ModuleWP module_ptr);
493493

494494
/// Applies 'callback' to each module in this ModuleList.
495495
/// If 'callback' returns false, iteration terminates.
@@ -531,6 +531,9 @@ class ModuleList {
531531

532532
Notifier *m_notifier = nullptr;
533533

534+
/// An orphaned module that lives only in the ModuleList has a count of 1.
535+
static constexpr long kUseCountModuleListOrphaned = 1;
536+
534537
public:
535538
typedef LockingAdaptedIterable<std::recursive_mutex, collection>
536539
ModuleIterable;

lldb/source/Core/ModuleList.cpp

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -349,17 +349,20 @@ bool ModuleList::ReplaceModule(const lldb::ModuleSP &old_module_sp,
349349
return true;
350350
}
351351

352-
bool ModuleList::RemoveIfOrphaned(const Module *module_ptr) {
353-
if (module_ptr) {
352+
bool ModuleList::RemoveIfOrphaned(const ModuleWP module_wp) {
353+
if (auto module_sp = module_wp.lock()) {
354354
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
355355
collection::iterator pos, end = m_modules.end();
356356
for (pos = m_modules.begin(); pos != end; ++pos) {
357-
if (pos->get() == module_ptr) {
358-
if (pos->use_count() == 1) {
357+
if (pos->get() == module_sp.get()) {
358+
// Since module_sp increases the refcount by 1, the use count should be
359+
// the regular use count + 1.
360+
constexpr long kUseCountOrphaned = kUseCountModuleListOrphaned + 1;
361+
if (pos->use_count() == kUseCountOrphaned) {
359362
pos = RemoveImpl(pos);
360363
return true;
361-
} else
362-
return false;
364+
}
365+
return false;
363366
}
364367
}
365368
}
@@ -386,7 +389,7 @@ size_t ModuleList::RemoveOrphans(bool mandatory) {
386389
made_progress = false;
387390
collection::iterator pos = m_modules.begin();
388391
while (pos != m_modules.end()) {
389-
if (pos->use_count() == 1) {
392+
if (pos->use_count() == kUseCountModuleListOrphaned) {
390393
pos = RemoveImpl(pos);
391394
++remove_count;
392395
// We did make progress.
@@ -832,7 +835,7 @@ class SharedModuleList {
832835
if (!module_sp)
833836
return false;
834837
std::lock_guard<std::recursive_mutex> guard(GetMutex());
835-
RemoveFromMap(*module_sp.get());
838+
RemoveFromMap(module_sp);
836839
return m_list.Remove(module_sp, use_notifier);
837840
}
838841

@@ -843,10 +846,10 @@ class SharedModuleList {
843846
ReplaceEquivalentInMap(module_sp);
844847
}
845848

846-
bool RemoveIfOrphaned(const Module *module_ptr) {
849+
bool RemoveIfOrphaned(const ModuleWP module_wp) {
847850
std::lock_guard<std::recursive_mutex> guard(GetMutex());
848-
RemoveFromMap(*module_ptr, /*if_orphaned=*/true);
849-
return m_list.RemoveIfOrphaned(module_ptr);
851+
RemoveFromMap(module_wp, /*if_orphaned=*/true);
852+
return m_list.RemoveIfOrphaned(module_wp);
850853
}
851854

852855
std::recursive_mutex &GetMutex() const { return m_list.GetMutex(); }
@@ -886,16 +889,22 @@ class SharedModuleList {
886889
m_name_to_modules[name].push_back(module_sp);
887890
}
888891

889-
void RemoveFromMap(const Module &module, bool if_orphaned = false) {
890-
ConstString name = module.GetFileSpec().GetFilename();
891-
if (!m_name_to_modules.contains(name))
892-
return;
893-
llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
894-
for (auto *it = vec.begin(); it != vec.end(); ++it) {
895-
if (it->get() == &module) {
896-
if (!if_orphaned || it->use_count() == kUseCountOrphaned) {
897-
vec.erase(it);
898-
break;
892+
void RemoveFromMap(const ModuleWP module_wp, bool if_orphaned = false) {
893+
if (auto module_sp = module_wp.lock()) {
894+
ConstString name = module_sp->GetFileSpec().GetFilename();
895+
if (!m_name_to_modules.contains(name))
896+
return;
897+
llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
898+
for (auto *it = vec.begin(); it != vec.end(); ++it) {
899+
if (it->get() == module_sp.get()) {
900+
// Since module_sp increases the refcount by 1, the use count should
901+
// be the regular use count + 1.
902+
constexpr long kUseCountOrphaned =
903+
kUseCountSharedModuleListOrphaned + 1;
904+
if (!if_orphaned || it->use_count() == kUseCountOrphaned) {
905+
vec.erase(it);
906+
break;
907+
}
899908
}
900909
}
901910
}
@@ -933,7 +942,7 @@ class SharedModuleList {
933942
// remove_if moves the elements that match the condition to the end of the
934943
// container, and returns an iterator to the first element that was moved.
935944
auto *to_remove_start = llvm::remove_if(vec, [](const ModuleSP &module) {
936-
return module.use_count() == kUseCountOrphaned;
945+
return module.use_count() == kUseCountSharedModuleListOrphaned;
937946
});
938947

939948
ModuleList to_remove;
@@ -976,7 +985,7 @@ class SharedModuleList {
976985
llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1>> m_name_to_modules;
977986

978987
/// The use count of a module held only by m_list and m_name_to_modules.
979-
static constexpr long kUseCountOrphaned = 2;
988+
static constexpr long kUseCountSharedModuleListOrphaned = 2;
980989
};
981990

982991
struct SharedModuleListInfo {
@@ -1278,8 +1287,8 @@ bool ModuleList::RemoveSharedModule(lldb::ModuleSP &module_sp) {
12781287
return GetSharedModuleList().Remove(module_sp);
12791288
}
12801289

1281-
bool ModuleList::RemoveSharedModuleIfOrphaned(const Module *module_ptr) {
1282-
return GetSharedModuleList().RemoveIfOrphaned(module_ptr);
1290+
bool ModuleList::RemoveSharedModuleIfOrphaned(const ModuleWP module_wp) {
1291+
return GetSharedModuleList().RemoveIfOrphaned(module_wp);
12831292
}
12841293

12851294
bool ModuleList::LoadScriptingResourcesInTarget(Target *target,

lldb/source/Target/Target.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2567,9 +2567,9 @@ ModuleSP Target::GetOrCreateModule(const ModuleSpec &orig_module_spec,
25672567
m_images.Append(module_sp, notify);
25682568

25692569
for (ModuleSP &old_module_sp : replaced_modules) {
2570-
Module *old_module_ptr = old_module_sp.get();
2570+
auto old_module_wp = old_module_sp->weak_from_this();
25712571
old_module_sp.reset();
2572-
ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr);
2572+
ModuleList::RemoveSharedModuleIfOrphaned(old_module_wp);
25732573
}
25742574
} else
25752575
module_sp.reset();

0 commit comments

Comments
 (0)