From df34c626d8a75472d83612879272a6e83e1d19d1 Mon Sep 17 00:00:00 2001 From: Tim Ledbetter Date: Tue, 21 Apr 2026 16:11:52 +0100 Subject: [PATCH] AK: Avoid UAF for consecutive `SinglyLinkedList` removals The iterator returned by SinglyLinkedList::remove() left `m_prev` default-initialized to `nullptr`. If the caller removed another element without first advancing, the previous node's next pointer was left dangling to the freed node. This caused a UAF in FinalizationRegistry's `remove_by_token()` when two consecutive records shared an unregister token. --- AK/SinglyLinkedList.h | 1 + Tests/AK/TestSinglyLinkedList.cpp | 23 +++++++++++++++++++++++ 2 files changed, 24 insertions(+) diff --git a/AK/SinglyLinkedList.h b/AK/SinglyLinkedList.h index f9fb109989..7ce4ec0e4d 100644 --- a/AK/SinglyLinkedList.h +++ b/AK/SinglyLinkedList.h @@ -281,6 +281,7 @@ public: auto* next = node->next; new_iterator.m_node = next; new_iterator.m_next = next ? next->next : nullptr; + new_iterator.m_prev = iterator.m_prev; delete node; return new_iterator; } diff --git a/Tests/AK/TestSinglyLinkedList.cpp b/Tests/AK/TestSinglyLinkedList.cpp index e3b1d7b324..f500fa77b5 100644 --- a/Tests/AK/TestSinglyLinkedList.cpp +++ b/Tests/AK/TestSinglyLinkedList.cpp @@ -204,3 +204,26 @@ TEST_CASE(singly_linked_list_remove_does_not_leave_dangling_iterator) EXPECT(it == list.end()); EXPECT(list.is_empty()); } + +TEST_CASE(singly_linked_list_remove_consecutive_mid_list_nodes) +{ + SinglyLinkedList list; + list.append(1); + list.append(2); + list.append(3); + list.append(4); + + auto it = list.begin(); + ++it; + it = list.remove(it); + EXPECT_EQ(*it, 3); + it = list.remove(it); + EXPECT_EQ(*it, 4); + + it = list.begin(); + EXPECT_EQ(*it, 1); + ++it; + EXPECT_EQ(*it, 4); + ++it; + EXPECT(it == list.end()); +}