Загрузчик клянётся, что DLL закреплена, но память с её кодом исчезла

Windows показывала combase.dll как загруженную и закреплённую, хотя байты с функцией CoTaskMemFree уже освободили. Вызов привёл к падению, а виноватым назначили shell32 — за труп, который освободил кто-то другой.

Вкратце

Реймонд Чен загнал 100 свежих крэш-дампов одной сторонней программы в сводную таблицу. На вид это были четыре разных бага: 11 переполнений стека в shell32, 23 нарушения доступа в неизвестном компоненте, ещё переполнения в ctxapclient64. А причина у всех одна.

У инженера, который воспроизводит баги Windows под виртуализацией, был вопрос острее самого диагноза: какой уровень поддержки нужен, чтобы легендарный Чен вообще взглянул на твои дампы?

Падение, которое оказалось четырьмя падениями в одном плаще

Обложка книги Реймонда Чена «The Old New Thing»
Обложка книги Реймонда Чена «The Old New Thing»

Расследование Реймонда Чена начинается с переполнения стека, которое дампы повесили на shell32.dll: рекурсивная петля из RtlLookupFunctionEntry и KiUserExceptionDispatch повторяется сотни раз, пока стек не кончается. Исходное исключение приводит к combase!CoTaskMemFree и строке, которая превращает рядовой баг в загадку: «Память, содержащая функцию CoTaskMemFree, освобождена».

Загрузчик по-прежнему числил combase.dll загруженной со счётчиком 0xFFFFFFFF — закреплённой, не подлежащей выгрузке. Таблица страниц с этим не соглашалась. Кто-то вызвал VirtualFree на памяти под модулем, который загрузчик считал постоянным, поэтому обычный учёт через FreeLibrary так и не отработал. При завершении процесса shell32 первой обратилась в мёртвый модуль — так она и оказалась с орудием убийства в руках.

Чтобы оценить масштаб, Чен собрал 100 свежих падений этой программы в сводную таблицу. Сигнатуры разлетелись: 11 переполнений стека в shell32, 23 нарушения доступа в неизвестном компоненте, ещё переполнения в ctxapclient64. Он называет это разбрызгиванием по корзинам — одна первопричина раскидывает падения по множеству разных корзин. В сумме 46% падений восходят к одной и той же самовольной принудительной выгрузке. Первая часть кончается без названного виновника: «Хорошая новость для команды shell32: они ни при чём, они жертва. Плохая: мы не знаем, кто виновник».

Тред спорит, кому достаётся Чен, а не о том, что он нашёл

Те в треде, кто сам выпускал код на C++, узнали эту картину раньше технической развязки.

«Хорошая новость для команды shell32: они ни при чём, они жертва. Плохая: мы не знаем, кто виновник. История разработки софта во все времена». — бывший программист на C++ и руководитель проектов

Один читатель прикинул, что разбрызгивание по корзинам означает для разбора инцидентов: один дефект раздувается в четыре непохожих друг на друга отчёта о падении.

«Это случай разбрызгивания по корзинам, когда одна базовая причина порождает большое число разных типов падений». — комментатор, который сам пересчитал распределение

Но громче всего звучал не баг. Звучала зависть к доступу. Инженер, который заводит баги Windows из виртуализированных стендов, спросил то, о чём думало большинство:

«Какая политика поддержки MSFT нужна, чтобы легендарный Реймонд Чен взглянул на проблему? …Заставить их вообще обратить внимание — это борьба в гору». — разработчик, который сообщает о багах Windows под виртуализацией

Одна деталь успокоила скептиков, а не наоборот: Чен получил эти 100 дампов потому, что сторонний конвейер отчётов о падениях реально доставил Microsoft пригодную телеметрию, как заметил читатель, считавший это показухой. Нерешённое — не механизм. Даже доказав невиновность shell32, дампы не говорят, какой модуль вызвал VirtualFree на combase. Первая часть опознаёт труп и снимает обвинение с не того подозреваемого; настоящего убийцу оставили на продолжение, которое один читатель уже откопал в треде.

Получайте такие разборы каждый день

Главные истории Hacker News — на email, в Telegram или RSS.

Следующая новость · 27 из 34 Читать дальше
🚀Tech

Гигабайт памяти снова стоит как в 2010-м: откат на 16 лет назад

График Стэнфорда показывает самую низкую цену за гигабайт памяти с 1957 по 2026 год в логарифмической шкале. Всплеск у правого края стирает больше десятилетия прогресса: по цене за гигабайт DDR5 сегодня стоит примерно там же, где DDR3 в 2010-м.

★ 194 · 💬 74 · dam.stanford.edu · 3 мин