Skip to content

Commit 84d4435

Browse files
committed
[lldb] Fix use after free on ModuleList::RemoveSharedModuleIfOrphaned (llvm#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. (cherry picked from commit 397181d)
1 parent 7398869 commit 84d4435

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
@@ -477,7 +477,7 @@ class ModuleList {
477477

478478
size_t Remove(ModuleList &module_list);
479479

480-
bool RemoveIfOrphaned(const Module *module_ptr);
480+
bool RemoveIfOrphaned(const lldb::ModuleWP module_ptr);
481481

482482
size_t RemoveOrphans(bool mandatory);
483483

@@ -531,7 +531,7 @@ class ModuleList {
531531

532532
static size_t RemoveOrphanSharedModules(bool mandatory);
533533

534-
static bool RemoveSharedModuleIfOrphaned(const Module *module_ptr);
534+
static bool RemoveSharedModuleIfOrphaned(const lldb::ModuleWP module_ptr);
535535

536536
/// Applies 'callback' to each module in this ModuleList.
537537
/// If 'callback' returns false, iteration terminates.
@@ -575,6 +575,9 @@ class ModuleList {
575575

576576
Notifier *m_notifier = nullptr;
577577

578+
/// An orphaned module that lives only in the ModuleList has a count of 1.
579+
static constexpr long kUseCountModuleListOrphaned = 1;
580+
578581
public:
579582
typedef LockingAdaptedIterable<std::recursive_mutex, collection>
580583
ModuleIterable;

lldb/source/Core/ModuleList.cpp

Lines changed: 34 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -503,17 +503,20 @@ bool ModuleList::ReplaceModule(const lldb::ModuleSP &old_module_sp,
503503
return true;
504504
}
505505

506-
bool ModuleList::RemoveIfOrphaned(const Module *module_ptr) {
507-
if (module_ptr) {
506+
bool ModuleList::RemoveIfOrphaned(const ModuleWP module_wp) {
507+
if (auto module_sp = module_wp.lock()) {
508508
std::lock_guard<std::recursive_mutex> guard(m_modules_mutex);
509509
collection::iterator pos, end = m_modules.end();
510510
for (pos = m_modules.begin(); pos != end; ++pos) {
511-
if (pos->get() == module_ptr) {
512-
if (pos->use_count() == 1) {
511+
if (pos->get() == module_sp.get()) {
512+
// Since module_sp increases the refcount by 1, the use count should be
513+
// the regular use count + 1.
514+
constexpr long kUseCountOrphaned = kUseCountModuleListOrphaned + 1;
515+
if (pos->use_count() == kUseCountOrphaned) {
513516
pos = RemoveImpl(pos);
514517
return true;
515-
} else
516-
return false;
518+
}
519+
return false;
517520
}
518521
}
519522
}
@@ -540,7 +543,7 @@ size_t ModuleList::RemoveOrphans(bool mandatory) {
540543
made_progress = false;
541544
collection::iterator pos = m_modules.begin();
542545
while (pos != m_modules.end()) {
543-
if (pos->use_count() == 1) {
546+
if (pos->use_count() == kUseCountModuleListOrphaned) {
544547
pos = RemoveImpl(pos);
545548
++remove_count;
546549
// We did make progress.
@@ -1094,7 +1097,7 @@ class SharedModuleList {
10941097
if (!module_sp)
10951098
return false;
10961099
std::lock_guard<std::recursive_mutex> guard(GetMutex());
1097-
RemoveFromMap(*module_sp.get());
1100+
RemoveFromMap(module_sp);
10981101
return m_list.Remove(module_sp, use_notifier);
10991102
}
11001103

@@ -1105,10 +1108,10 @@ class SharedModuleList {
11051108
ReplaceEquivalentInMap(module_sp);
11061109
}
11071110

1108-
bool RemoveIfOrphaned(const Module *module_ptr) {
1111+
bool RemoveIfOrphaned(const ModuleWP module_wp) {
11091112
std::lock_guard<std::recursive_mutex> guard(GetMutex());
1110-
RemoveFromMap(*module_ptr, /*if_orphaned=*/true);
1111-
return m_list.RemoveIfOrphaned(module_ptr);
1113+
RemoveFromMap(module_wp, /*if_orphaned=*/true);
1114+
return m_list.RemoveIfOrphaned(module_wp);
11121115
}
11131116

11141117
std::recursive_mutex &GetMutex() const { return m_list.GetMutex(); }
@@ -1148,16 +1151,22 @@ class SharedModuleList {
11481151
m_name_to_modules[name].push_back(module_sp);
11491152
}
11501153

1151-
void RemoveFromMap(const Module &module, bool if_orphaned = false) {
1152-
ConstString name = module.GetFileSpec().GetFilename();
1153-
if (!m_name_to_modules.contains(name))
1154-
return;
1155-
llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
1156-
for (auto *it = vec.begin(); it != vec.end(); ++it) {
1157-
if (it->get() == &module) {
1158-
if (!if_orphaned || it->use_count() == kUseCountOrphaned) {
1159-
vec.erase(it);
1160-
break;
1154+
void RemoveFromMap(const ModuleWP module_wp, bool if_orphaned = false) {
1155+
if (auto module_sp = module_wp.lock()) {
1156+
ConstString name = module_sp->GetFileSpec().GetFilename();
1157+
if (!m_name_to_modules.contains(name))
1158+
return;
1159+
llvm::SmallVectorImpl<ModuleSP> &vec = m_name_to_modules[name];
1160+
for (auto *it = vec.begin(); it != vec.end(); ++it) {
1161+
if (it->get() == module_sp.get()) {
1162+
// Since module_sp increases the refcount by 1, the use count should
1163+
// be the regular use count + 1.
1164+
constexpr long kUseCountOrphaned =
1165+
kUseCountSharedModuleListOrphaned + 1;
1166+
if (!if_orphaned || it->use_count() == kUseCountOrphaned) {
1167+
vec.erase(it);
1168+
break;
1169+
}
11611170
}
11621171
}
11631172
}
@@ -1195,7 +1204,7 @@ class SharedModuleList {
11951204
// remove_if moves the elements that match the condition to the end of the
11961205
// container, and returns an iterator to the first element that was moved.
11971206
auto *to_remove_start = llvm::remove_if(vec, [](const ModuleSP &module) {
1198-
return module.use_count() == kUseCountOrphaned;
1207+
return module.use_count() == kUseCountSharedModuleListOrphaned;
11991208
});
12001209

12011210
ModuleList to_remove;
@@ -1238,7 +1247,7 @@ class SharedModuleList {
12381247
llvm::DenseMap<ConstString, llvm::SmallVector<ModuleSP, 1>> m_name_to_modules;
12391248

12401249
/// The use count of a module held only by m_list and m_name_to_modules.
1241-
static constexpr long kUseCountOrphaned = 2;
1250+
static constexpr long kUseCountSharedModuleListOrphaned = 2;
12421251
};
12431252

12441253
struct SharedModuleListInfo {
@@ -1540,8 +1549,8 @@ bool ModuleList::RemoveSharedModule(lldb::ModuleSP &module_sp) {
15401549
return GetSharedModuleList().Remove(module_sp);
15411550
}
15421551

1543-
bool ModuleList::RemoveSharedModuleIfOrphaned(const Module *module_ptr) {
1544-
return GetSharedModuleList().RemoveIfOrphaned(module_ptr);
1552+
bool ModuleList::RemoveSharedModuleIfOrphaned(const ModuleWP module_wp) {
1553+
return GetSharedModuleList().RemoveIfOrphaned(module_wp);
15451554
}
15461555

15471556
bool ModuleList::LoadScriptingResourcesInTarget(Target *target,

lldb/source/Target/Target.cpp

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

25982598
for (ModuleSP &old_module_sp : replaced_modules) {
2599-
Module *old_module_ptr = old_module_sp.get();
2599+
auto old_module_wp = old_module_sp->weak_from_this();
26002600
old_module_sp.reset();
2601-
ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr);
2601+
ModuleList::RemoveSharedModuleIfOrphaned(old_module_wp);
26022602
}
26032603
} else
26042604
module_sp.reset();

0 commit comments

Comments
 (0)