mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-08-15 23:09:05 +00:00
LibGC: Visit the edges of the cells that must survive garbage collection
Previously, we would only keep the cell that must survive alive, but none of it's edges. This cropped up with a GC UAF in must_survive_garbage_collection of WebSocket in .NET's SignalR frontend implementation, where an out-of-scope WebSocket had it's underlying EventTarget properties garbage collected, and must_survive_garbage_collection read from the destroyed EventTarget properties. See: https://github.com/dotnet/aspnetcore/blob/main/src/SignalR/clients/ts/signalr/src/WebSocketTransport.ts#L81 Found on https://www.formula1.com/ during a live session. Co-Authored-By: Tim Flynn <trflynn89@pm.me>
This commit is contained in:
parent
da5d4e9f6a
commit
5146bbe296
Notes:
github-actions[bot]
2025-02-27 19:36:28 +00:00
Author: https://github.com/Lubrsi
Commit: 5146bbe296
Pull-request: https://github.com/LadybirdBrowser/ladybird/pull/3722
3 changed files with 32 additions and 2 deletions
|
@ -430,6 +430,14 @@ void Heap::mark_live_cells(HashMap<Cell*, HeapRoot> const& roots)
|
|||
for (auto& inverse_root : m_uprooted_cells)
|
||||
inverse_root->set_marked(false);
|
||||
|
||||
for_each_block([&](auto& block) {
|
||||
block.template for_each_cell_in_state<Cell::State::Live>([&](Cell* cell) {
|
||||
if (!cell->is_marked() && cell_must_survive_garbage_collection(*cell))
|
||||
cell->visit_edges(visitor);
|
||||
});
|
||||
return IterationDecision::Continue;
|
||||
});
|
||||
|
||||
m_uprooted_cells.clear();
|
||||
}
|
||||
|
||||
|
@ -444,7 +452,7 @@ void Heap::finalize_unmarked_cells()
|
|||
{
|
||||
for_each_block([&](auto& block) {
|
||||
block.template for_each_cell_in_state<Cell::State::Live>([](Cell* cell) {
|
||||
if (!cell->is_marked() && !cell_must_survive_garbage_collection(*cell))
|
||||
if (!cell->is_marked())
|
||||
cell->finalize();
|
||||
});
|
||||
return IterationDecision::Continue;
|
||||
|
@ -466,7 +474,7 @@ void Heap::sweep_dead_cells(bool print_report, Core::ElapsedTimer const& measure
|
|||
bool block_has_live_cells = false;
|
||||
bool block_was_full = block.is_full();
|
||||
block.template for_each_cell_in_state<Cell::State::Live>([&](Cell* cell) {
|
||||
if (!cell->is_marked() && !cell_must_survive_garbage_collection(*cell)) {
|
||||
if (!cell->is_marked()) {
|
||||
dbgln_if(HEAP_DEBUG, " ~ {}", cell);
|
||||
block.deallocate(cell);
|
||||
++collected_cells;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue