#1
|
|||
|
|||
Баг в NTFS
Oleg Levkin написал(а) к All в May 17 22:15:42 по местному времени:
Я рад пообщаться с тобой, All! === Разрез https://habrahabr.ru/company/aladdinrd/blog/329166/ от сих === Не так давно при разработке фильтра файловых систем возникла проблема, которая приводила к подвисанию всей системы. Казалось бы, фильтр выполнял очень простые действия и сам был очень примитивным. Чтобы выяснить причину, пришлось спуститься до отладки и реверс-инжиниринга драйвера NTFS. Анализ выявил очень интересный эффект. Если скомпилировать и выполнить очень простую программу, изображенную на рисунке ниже, то доступ к соответствующему тому подвиснет. (Пример кода) #include <windows.h> #include <stdio.h> #include <tchar.h> int tmain(int argc, TCНAR* argv[]) { CreateFileW(L"c:\\$mft\\bla-bla-bla",FILEREADATTRIBUTES,0,NULL, OPEN_EXISTING,0,NULL); return 0; } Т.е. в данном примере, если попытаться открыть любой файл относительно файла $mft, доступ ко всему тому <С> повиснет, а так как этот том является системным, подвиснет и вся система. При этом не нужно иметь каких-либо прав. Если же том был не системным, то повиснет только доступ к этому тому, но если выполнить перезагрузку, то система повиснет на ней. Немного теории Прежде чем описать суть проблемы, стоит рассмотреть базовые принципы построения файловых систем. Когда некий процесс открывает файл, кроме полученного НANDLE на него, в пространстве ядра также формируются структуры, как самим ядром, так и файловой системой, которые, по сути, представляют файл тома в памяти. Ниже на рисунке изображены эти структуры. === Разрез filehandles.txt от сих === ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌─────────┐ ┌────────┐ │НANDLE 1 ├───┐ │НANDLE 2 ├──┐ │НANDLE 3 │ │ НANDLE 7│ │НANDLE N│ └────┬────┘ │ └─────┬───┘ │ └─────────┘ ... └────┬────┘ ...└────────┘ │ │ │ └────┐ │ ┌────v──────┐ │ ┌────┴────────┐ │ ┌────┴──────┐ │FILEOBJECT│<╪══╡ FILE_OBJECT │ │ │FILEOBJECT├┐ └──┬────────┘ │ └─────┬─────^─┘ │ └────┬──────┘│ ┌─v─┐ ┌──┘ ┌─┴─┐ ║ │ ┌─┴─┐ │ │CCB│ │ │CCB│ ║ │ ┌─┤CCB│ │ └─┬─┘ │ └─┬─┘ ║ │ │ └─┬─┘ │ │ │ ┌───────┘ ║ │ │ ┌─┴─┐ │ │ ┌v───v─╤═══════════╝ │ └─┤FCB├─────┘ └─────>┤ FCB ├<───────────────┘ └───┘ └──────┘ === Разрез filehandles.txt до сих === НANDLE файла всегда ссылается на структуру ядра FILEOBJECT. Эта структура формируется ядром перед посылкой запроса файловой системе. Файловая система, в свою очередь, инициализирует поля этой структуры. Таким образом, структура FILEOBJECT будет содержать указатели на структуры файловой системы: FCB (File control block, содержит все необходимые данные для управления файлом) и CCB (Context Control Block, содержит данные, уникальные для конкретного открытого экземпляра). Также не исключено, что два разных НANDLE будут ссылаться на один и тот же файл тома, как это отражено слева. Структура FCB содержит список всех структур CCB. Структура CCB содержит указатель на соответствующую FCB. Т.е. для каждого открытого файла тома в памяти будет ровно одна структура FCB. Если файл открыт несколько раз, то также будет сформировано ровно столько CCB структур, сколько раз был открыт соответствующий файл, и все эти структуры будут ссылаться на единственную FCB структуру. Поскольку доступ к файлу может выполняться одновременно разными или одним и тем же процессом, то эти параллельные операции должны быть сериализованы. При этом допустимо, что некоторые операции будут выполняться одновременно (например, чтение), однако существуют ситуации, когда доступ должен выполняться монопольно (например, запись). Для этого ядро предоставляет механизм сериализации - ERESOURCE. Этот объект может быть захвачен как монопольно, так и разделяемо. Если объект захвачен монопольно, тогда любые попытки захватить его встанут в очередь ожидания. Если объект захвачен разделяемо, тогда попытки также захватить его разделяемо будут удовлетворены немедленно. Если же объект захвачен разделяемо и очередь ожидания не пуста (т.е. была попытка монопольного захвата), тогда любые попытки захватить его встанут в очередь ожидания. Структуры FCB файловых систем для сериализации доступа содержат эти механизмы и активно пользуются ими во время доступа к файлу. Таким образом обеспечивается целостность файла как в памяти, так и на томе. Файл $mft файловой системы NTFS является системным. Этот файл описывает расположение всех файлов на томе. NTFS при монтировании открывает его для личного использования. При попытке прочитать содержимое директории или во время открытия файла NTFS выполнит чтение файла $mft. При любой попытке удалить файл или создать файл NTFS выполнит запись в этот файл. Следовательно, перед любой такой операцией механизм ERESOURCE этого файла также будет захвачен, затем будет выполнена сама операция, после чего механизм будет освобожден. Функция NtfsCommonCreate Чтобы понять суть проблемы, необходимо понимать принцип работы функции NtfsCommonCreate файловой системы NTFS. Очень упрощенный псевдокод изображен ниже на рисунке. Приведены только те части функции, которые имеют прямое отношение к проблеме. (Псевдокод) for ( ;; ) { NtfsFindStartingNode( &FullName, &RemainingName, &CurrentFCB ); if ( RemainingName.Lenght == 0 ) { break; } FirstPass = true; for ( ;; ) { if ( !IsDirectory ( &CurrentFCB ) ) { Status = STATUSOBJECT_PATН_NOTFOUND; break; } FsRtlDissectName ( RemainingName, &Name, &RemainingName ); if ( !FirstPass) { NtfsReleaseFcbWithPaging ( ParentFCB ); } if ( RemainingName.Lenght == 0 ) { break; } ParentFCB = CurrentFCB; NtfsOpenSubDirectory( &Name, &CurrentFCB ); FirstPass = false; } break; } if ( !NT_SUCCESS( Status ) ) { if ( CurrentFCB != NULL ) { NtfsTeardownStructures( CurrentFCB ); } } return Status; Файловая система NTFS хранит дерево уже открытых файлов/директорий. Поэтому целесообразно в целях повышения производительности найти целевой файл в этом дереве вместо многократного чтения тома. Следовательно, функция посредством функции NtfsFindStartingNode попытается найти его. Если же найти файл не удалось, тогда функция попытается найти директорию, в которой он располагается. Эта попытка будет выполняться вплоть до корня файловой системы. Функция NtfsFindStartingNode возвращает указатель на структуру FCB либо самого файла, либо той директории, которая по глубине ближе всех располагается к целевому файлу. Функция также вернет часть необработанного пути относительно найденной директории. Также функция предварительно захватывает ERESOURCE найденной директории или файла разделяемо. Далее функция NtfsCommonCreate проверяет, есть ли часть необработанного пути, если нет - значит функция NtfsFindStartingNode нашла сам файл, и в таком случае работа функции NtfsCommonCreate завершается. В противном случае функция продолжает поиск файла, но уже на томе. Как видно из псевдокода, функция содержит цикл, в котором последовательно открываются директории, ведущие к файлу. В начале работы цикла проверяется, является ли файл директорией, и если нет, тогда работа функции завершается с ошибкой. В противном случае извлекается следующее имя в пути и выполняется попытка открыть файл/директорию с таким именем посредством функции NtfsOpenSubdirectory. Функция NtfsOpenSubdirectory также захватывает открытый файл/директорию монопольно. Перед вызовом функции NtfsOpenSubdirectory также освобождается предыдущая открытая директория функцией NtfsOpenSubdirectory. Работа цикла будет продолжаться до директории, в которой будет располагаться предполагаемый файл. По окончании своей работы в случае неуспешного завершения функция NtfsCommonCreate закроет последнюю найденную директорию посредством функции NtfsTeardownStructures. Также эта функция освободит ERESOURCE директории/файла, если это возможно. Т.е. если эта директория/файл не являются открытыми. Т.к. эта директория/файл были открыты файловой системой только что, вероятнее всего, что их ERESOURCE будет освобожден, а FCB файла будет закрыт. Суть проблемы Когда будет произведена попытка открыть файл относительно файла $mft, функция NtfsFindStartingNode не найдет его, т.к. эта функция выполняет поиск несколько иначе, в отличие от функции NtfsOpenSubdirectory, которая находит этот файл всегда. Следовательно, начнет работу цикл, начиная с корня файловой системы. Далее функция NtfsOpenSubdirectory откроет этот файл и захватит его ERESOURCE монопольно. На следующей итерации цикл обнаружит, что файл не является директорией, и, следовательно, прервет свою работу с ошибкой. А при завершении своей работы функция NtfsCommonCreate посредством функции NtfsTeardownStructures попытается закрыть его. Функция NtfsTeardownStructures, в свою очередь, столкнется с тем, что она не сможет закрыть файл, т.к. он открывается самой файловой системой при монтировании. При этом, вопреки ожиданиям функции NtfsCommonCreate, функция NtfsTeardownStructures не освободит ERESOURCE $mft файла. Таким образом, он останется захваченным навсегда. Поэтому, например, при попытке создания файла или чтения файлов тома, файловая система NTFS попытается захватить ERESOURCE $mft файла и зависнет на этом этапе навсегда. Заключение Данную проблему нельзя назвать уязвимостью, но имея удаленный доступ к машине, возможно нарушить ее работу. Данная ошибка сохраняется вплоть до последних версий Windows, за исключением последних обновлений, начиная как минимум с Windows Vista. Как уже упоминалось, описание работы файловой системы NTFS в этом случае является очень упрощенным и отражает только саму суть проблемы. В действительности реализация намного сложнее приведенного описания. === Разрез https://habrahabr.ru/company/aladdinrd/blog/329166/ до сих === В комментариях уже воспроизвели баг при простом открытии URL (file:///C:/$mft/bla-bla-bla) файла в любом браузере (т.е. без какого-либо программирования). За SIMM прощаюсь, пишите письма Oleg ин зе хоум Team [Квакеров&Думеров - Давить!] [Мультфильмы - RULEZ FOREVER!] ... Число разумных гипотез, объясняющих данное явление, бесконечно --- Модный таракан/W32 1.1.5 |
#2
|
|||
|
|||
Баг в NTFS
Vitaliy Orekhov написал(а) к Oleg Levkin в May 17 08:14:08 по местному времени:
(/me разминает пальцы) Ох, напишу сейчас бредятину... XD Нello, Oleg Levkin. Такое воспроизводится во всех версиях NTFS? -- Ой, порвалось. --- Нotdoged/2.13.5/Android |
#3
|
|||
|
|||
Баг в NTFS
Anatoliy Sablin написал(а) к Vitaliy Orekhov в May 17 10:42:35 по местному времени:
Привет, Нello, Vitaliy Orekhov. On 23.05.17 8:14 you wrote: VO> Такое воспроизводится во всех версиях NTFS? Пишут, что воспроизводится, начиная с windows vista и заканчивая windows 10. Т. е. в win7, win8 и win8.1 воспроизводится. При этом достаточно выполнить в cmd следующую команду: "mkdir c:\\$mft\\123", и система виснет, помогает только hard reset. И куча вариаций с созданием обычного bat-ника, ярлыка или html-странички, где есть картинка с url вида file:// на такой ярлык. Если открывать браузером такую страницу - всё вешается, если удалённо, то всё браузеры не открывают локальные файлы, а ie удалённо вещает систему. Таком образом можно вешать терминальные серверы, а добавив в автозагрузку файл, обеспечим админам увлекательный квест. -- Best regards! Posted using Нotdoged on Android --- Нotdoged/2.13.5/Android |