Предисловие
Благодарности
ГЛАВА 1 Концепции и инструменты
Версии операционных систем Windows
Базовые концепции и термины
Windows API
Сервисы, функции и процедуры
Процессы, потоки и задания
Виртуальная память
Режим ядра и пользовательский режим
Terminal Services и несколько сеансов
Объекты и описатели
Безопасность
Реестр
Unicode
Изучение внутреннего устройства Windows
Оснастка Performance
Windows Support Tools
Ресурсы Windows
Отладка ядра
Platform Software Development Kit (SDK)
Device Driver Kit (DDK)
Утилиты Sysinternals
Резюме
ГЛАВА 2 Архитектура системы
Требования и цели проекта
Модель операционной системы
Обзор архитектуры
Переносимость
Симметричная многопроцессорная обработка
Масштабируемость
Различия между клиентскими и серверными версиями
Проверочный выпуск
Ключевые компоненты системы
Подсистемы окружения и их DLL
Ntdll.dll
Исполнительная система
Ядро
Уровень абстрагирования от оборудования
Драйверы устройств
Системные процессы
Резюме
ГЛАВА 3 Системные механизмы
Диспетчеризация ловушек
Диспетчеризация прерываний
Диспетчеризация исключений
Диспетчеризация системных сервисов
Диспетчер объектов
Объекты исполнительной системы
Структура объектов
Синхронизация
Синхронизация ядра при высоком IRQL
Синхронизация при низком IRQL
Системные рабочие потоки
Глобальные флаги Windows
LPC
Трассировка событий ядра
Wow64
Системные вызовы
Диспетчеризация исключений
Пользовательские обратные вызовы
Перенаправление файловой системы
Перенаправление реестра и отражение
Запросы управления вводом-выводом
16-разрядные программы установки
Печать
Ограничения
Резюме
ГЛАВА 4 Механизмы управления
Реестр
Просмотр и изменение реестра
Использование реестра
Типы данных в реестре
Логическая структура реестра
Анализ и устранение проблем с реестром
Внутренние механизмы реестра
Сервисы
Сервисные приложения
Учетные записи сервисов
Диспетчер управления сервисами
Запуск сервиса
Ошибки при запуске
Критерии успешной загрузки и последняя удачная конфигурация
Сбои сервисов
Завершение работы сервиса
Разделяемые процессы сервисов
Программы управления сервисами
Windows Management Instrumentation
Архитектура WMI
Провайдеры
CIM и язык Managed Object Format
Пространство имен WMI
Классы сопоставления
Реализация WMI
Защита WMI
Резюме
ГЛАВА 5 Запуск и завершение работы системы
Процесс загрузки
Что предшествует загрузке на платформах x86 и x64
Загрузочный сектор и Ntldr на платформах x86 и x64
Процесс загрузки на платформе IA64
Инициализация ядра и компонентов исполнительной системы
Smss, Csrss и Winlogon
Автоматически запускаемые образы
Анализ проблем при загрузке и запуске системы
Последняя удачная конфигурация
Безопасный режим
Консоль восстановления
Решение распространенных проблем загрузки
Завершение работы системы
Резюме
ГЛАВА 6 Процессы, потоки и задания
Внутреннее устройство процессов
Структуры данных
Переменные ядра
Счетчики производительности
Сопутствующие функции
Что делает функция CreateProcess
Этап 1
Этап 2
Этап 3
Этап 4
Этап 5
Этап 6
Внутреннее устройство потоков
Структуры данных
Переменные ядра
Счетчики производительности
Сопутствующие функции
Рождение потока
Наблюдение за активностью потоков
Планирование потоков
Обзор планирования в Windows
Уровни приоритета
Сопутствующие утилиты
Приоритеты реального времени
Состояния потоков
База данных диспетчера ядра
Квант
Сценарии планирования
Переключение контекста
Поток простоя
Динамическое повышение приоритета
Многопроцессорные системы
Алгоритмы планирования потоков в многопроцессорных системах
Объекты-задания
Резюме
ГЛАВА 7 Управление памятью
Введение в диспетчер памяти
Компоненты диспетчера памяти
Внутренняя синхронизация
Конфигурирование диспетчера памяти
Исследование используемой памяти
Сервисы диспетчера памяти
Большие и малые страницы
Резервирование и передача страниц
Блокировка памяти
Гранулярность выделения памяти
Разделяемая память и проецируемые файлы
Защита памяти
Запрет на выполнение
Копирование при записи
Диспетчер куч
Address Windowing Extensions
Системные пулы памяти
Настройка размеров пулов
Мониторинг использования пулов
Ассоциативные списки
Утилита Driver Verifier
Структуры виртуального адресного пространства
Структуры пользовательского адресного пространства на платформе x86
Структура системного адресного пространства на платформе x86
Пространство сеанса на платформе x86
Системные PTE
Структуры 64-разрядных адресных пространств
Трансляция адресов
Трансляция виртуальных адресов на платформе x86
Ассоциативный буфер трансляции
Physical Address Extension (PAE)
Трансляция виртуальных адресов на платформе IA64
Трансляция виртуальных адресов на платформе x64
Обработка ошибок страниц
Недействительные PTE
Прототипные PTE
Операции ввода-вывода, связанные с подкачкой страниц
Конфликты ошибок страницы
Страничные файлы
Дескрипторы виртуальных адресов
Объекты-разделы
Рабочие наборы
Подкачка по требованию
Средство логической предвыборки
Правила размещения
Управление рабочими наборами
Диспетчер настройки баланса и подсистема загрузки-выгрузки
Системный рабочий набор
База данных PFN
Динамика списков страниц
Подсистема записи модифицированных страниц
Структуры данных PFN
Уведомление о малом или большом объеме памяти
Резюме
ГЛАВА 8 Защита
Классы безопасности
Trusted Computer System Evaluation Criteria
Common Criteria
Компоненты системы защиты
Защита объектов
Проверка прав доступа
Дескрипторы защиты и управление доступом
Права и привилегии учетных записей
Права учетной записи
Привилегии
Суперпривилегии
Аудит безопасности
Вход в систему
Инициализация Winlogon
Этапы входа пользователя
Политики ограниченного использования программ
Резюме
ГЛАВА 9 Подсистема ввода-вывода
Компоненты подсистемы ввода-вывода
Диспетчер ввода-вывода
Типичная обработка ввода-вывода
Драйверы устройств
Типы драйверов устройств
Структура драйвера
Объекты «драйвер» и «устройство»
Открытие устройств
Обработка ввода-вывода
Типы ввода-вывода
Пакеты запроса ввода-вывода
Запрос ввода-вывода к одноуровневому драйверу
Запрос ввода-вывода к многоуровневому драйверу
Порты завершения ввода-вывода
Driver Verifier
Диспетчер Plug and Play (PnP)
Уровень поддержки Plug and Play
Поддержка Plug and Play со стороны драйвера
Загрузка, инициализация и установка драйвера
Установка драйвера
Диспетчер электропитания
Работа диспетчера электропитания
Участие драйверов в управлении электропитанием
Как драйвер управляет электропитанием устройства
Резюме
ГЛАВА 10 Управление внешней памятью
Базовая терминология
Драйверы дисков
Ntldr
Драйвер класса дисков, порти минипорт-драйверы
Объекты «устройство» для дисков
Диспетчер разделов
Управление томами
Базовые диски
Динамические диски
Управление составными томами
Пространство имен томов
Операции ввода-вывода на томах
Служба виртуального диска
Служба теневого копирования тома
Резюме
ГЛАВА 11 Диспетчер кэша
Основные возможности диспетчера кэша
Единый централизованный системный кэш
Диспетчер памяти
Когерентность кэша
Кэширование виртуальных блоков
Кэширование потоков данных
Поддержка восстанавливаемых файловых систем
Управление виртуальной памятью кэша
Размер кэша
LargeSystemCache
Виртуальный размер кэша
Размер рабочего набора кэша
Физический размер кэша
Структуры данных кэша
Общесистемные структуры данных кэша
Структуры данных кэша, индивидуальные для каждого файла
Интерфейсы файловых систем
Копирование данных в кэш и из него
Кэширование с применением интерфейсов проецирования и фиксации
Кэширование с применением прямого доступа к памяти
Быстрый ввод-вывод
Опережающее чтение и отложенная запись
Интеллектуальное опережающее чтение
Кэширование с обратной записью и отложенная запись
Дросселирование записи
Системные потоки
Резюме
ГЛАВА 12 Файловые системы
Файловые системы Windows
CDFS
UDF
FAT12, FAT16 и FAT32
NTFS
Архитектура драйвера файловой системы
Локальные FSD
Удаленные FSD
Работа файловой системы
Драйверы фильтров файловой системы
Анализ проблем в файловой системе
Базовый и расширенный режимы Filemon
Методики анализа проблем с применением Filemon
Цели разработки и особенности NTFS
Требования к файловой системе класса «high end»
Драйвер файловой системы NTFS
Структура NTFS на диске
Тома
Кластеры
Главная таблица файлов
Структура файловых ссылок
Записи о файлах
Имена файлов
Резидентные и нерезидентные атрибуты
Сжатие данных и разреженные файлы
Файл журнала изменений
Индексация
Идентификаторы объектов
Отслеживание квот
Консолидированная защита
Точки повторного разбора
Поддержка восстановления в NTFS
Эволюция архитектуры файловых систем
Протоколирование
Восстановление
Восстановление плохих кластеров в NTFS
Механизм EFS
Первое шифрование файла
Процесс расшифровки
Резервное копирование шифрованных файлов
Резюме
ГЛАВА 13 Поддержка сетей
Сетевая архитектура Windows
Эталонная модель OSI
Сетевые компоненты Windows
Сетевые API
Windows Sockets
Remote Procedure Call (RPC)
API-интерфейсы доступа к Web
Именованные каналы и почтовые ящики
NetBIOS
Другие сетевые API
Поддержка нескольких редиректоров
Маршрутизатор многосетевого доступа
Многосетевой UNC-провайдер
Разрешение имен
DNS
WINS
Драйверы протоколов
Расширения TCP/IP
Драйверы NDIS
Разновидности минипорт-драйверов NDIS
NDIS, ориентированная на логические соединения
Remote NDIS
QoS
Привязка
Многоуровневые сетевые сервисы
Удаленный доступ
Active Directory
Network Load Balancing
Служба репликации файлов
DFS
Резюме
ГЛАВА 14 Анализ аварийного дампа
Почему происходит крах Windows?
«Синий экран»
Файлы аварийного дампа
Генерация аварийного дампа
Windows Error Reporting
Анализ аварийных дампов через Интернет
Базовый анализ аварийных дампов
Notmyfault
Базовый анализ
Детальный анализ
Средства анализа проблем, вызывающих крах
Переполнение буфера и особый пул
Перезапись кода и защита системного кода от записи
Углубленный анализ аварийных дампов
Засорение стека
Зависание или отсутствие отклика системы
Если аварийного дампа нет
Словарь терминов
Предметный указатель
Об авторах
Text
                    
Посвящается Дэйву Катлеру — отцу ядра Windows IW4_Titul_dop.PM6 1 26.10.2007, 12:43
Mark E. Russinovich David A. Solomon Microsoft ® Windows Internals Fourth Edition: ® Windows Server™ 2003, Windows XP, and Windows 2000 IW4_Titul_dop.PM6 2 26.10.2007, 12:43
Марк Руссинович Дэвид Соломон Внутреннее устройство Microsoft Windows : ® ® Windows Server™ 2003, Windows XP и Windows 2000 4е издание МАСТЕРКЛАСС 2008 IW4_Titul_dop.PM6 3 26.10.2007, 12:43
УДК 004.45 ББК 32.973.26–018.2 P89 Руссинович М. и Соломон Д. P89 Внутреннее устройство Microsoft Windows: Windows Server 2003, Windows XP и Windows 2000. Мастеркласс. / Пер. с англ. — 4е изд. — М.: Издатель ство «Русская редакция», 2008. — 992 стр.: ил. ISBN 978-5–7502–0085–6 («Русская редакция») Книга посвящена внутреннему устройству и алгоритмам работы основных компонентов операционной системы Microsoft Windows — Windows Server 2003, Windows XP и Windows 2000 — и файловой системы NTFS. Детально рассмотрены системные механизмы: диспетчеризация ловушек и прерыва ний, DPC, APC, LPC, RPC, синхронизация, системные рабочие потоки, глобаль ные флаги и др. Также описываются все этапы загрузки операционной сис темы и завершения ее работы. В четвертом издании книги больше внимания уделяется глубокому анализу и устранению проблем, изза которых про исходит крах операционной системы или изза которых ее не удается загру зить. Кроме того, рассматриваются детали реализации поддержки аппарат ных платформ AMD x64 и Intel IA64. Книга состоит из 14 глав, словаря тер минов и предметного указателя. Книга предназначена системным админис траторам, разработчикам серьезных приложений и всем, кто хочет понять, как устроена операционная система Windows. Названия всех команд, диалоговых окон и других интерфейсных элементов операционной системы приведены как на английском языке, так и на русском. УДК 004.45 ББК 32.973.26018.2 © 2005-2012, Translation Russian Edition Publishers. Authorized Russian translation of the English edition of Microsoft® Windows® Internals: Microsoft Windows Server™ 2003, Windows XP, and Windows 2000, Fourth Edition, ISBN 9780735619173 © JDavid Solomon, Mark Russinovich. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. © 2005-2012, перевод ООО «Издательство «Русская редакция». Авторизованный перевод с английского на русский язык произведения Microsoft® Windows® Internals: Microsoft Windows Server™ 2003, Windows XP, and Windows 2000, Fourth Edition, ISBN 9780735619173 © JDavid Solomon, Mark Russinovich. Этот перевод оригинального издания публикуется и продается с разрешения O’Reilly Media, Inc., которая владеет или распоряжается всеми правами на его публикацию и продажу. © 2005-2012, оформление и подготовка к изданию, ООО «Издательство «Русская редакция». Microsoft, а также товарные знаки, перечисленные в списке, расположенном по адресу: http://www.microsoft.com/about/legal/en/us/IntellectualProperty/Trademarks/EN-US.aspx являются товарными знаками или охраняемыми товарными знаками корпорации Microsoft в США и/или других странах. Все другие товарные знаки являются собственностью соответствующих фирм. Все названия компаний, организаций и продуктов, а также имена лиц, используемые в примерах, вымышлены и не имеют никакого отношения к реальным компаниям, организациям, продуктам и лицам. IW4_Titul_dop.PM6 4 26.10.2007, 12:43
Оглавление Предыстория Предисловие Благодарности Введение ГЛАВА 1 Концепции и инструменты XIII XVI XVII XIX 1 Версии операционных систем Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Базовые концепции и термины . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Windows API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Сервисы, функции и процедуры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Процессы, потоки и задания . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Виртуальная память . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Режим ядра и пользовательский режим . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 Terminal Services и несколько сеансов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23 Объекты и описатели . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Безопасность . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Реестр . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 26 Unicode . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Изучение внутреннего устройства Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Оснастка Performance . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Windows Support Tools . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Ресурсы Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Отладка ядра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30 Platform Software Development Kit (SDK) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Device Driver Kit (DDK) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Утилиты Sysinternals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 ГЛАВА 2 Архитектура системы 38 Требования и цели проекта . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Модель операционной системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 39 Обзор архитектуры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Переносимость . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Симметричная многопроцессорная обработка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44 Масштабируемость . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 50 Различия между клиентскими и серверными версиями . . . . . . . . . . . . . . . . . . . . . . . 50 Проверочный выпуск . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53 Ключевые компоненты системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Подсистемы окружения и их DLL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57 Ntdll.dll . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 67 Исполнительная система . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68 Ядро . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 Уровень абстрагирования от оборудования . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 Драйверы устройств . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 75 Системные процессы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 80 Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 90
VI Оглавление ГЛАВА 3 Системные механизмы 91 Диспетчеризация ловушек . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Диспетчеризация прерываний . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93 Диспетчеризация исключений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 Диспетчеризация системных сервисов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 128 Диспетчер объектов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 133 Объекты исполнительной системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 136 Структура объектов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 138 Синхронизация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 Синхронизация ядра при высоком IRQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Синхронизация при низком IRQL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 Системные рабочие потоки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 Глобальные флаги Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 LPC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 183 Трассировка событий ядра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Wow64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Системные вызовы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 Диспетчеризация исключений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 191 Пользовательские обратные вызовы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Перенаправление файловой системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Перенаправление реестра и отражение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Запросы управления вводом>выводом . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 16>разрядные программы установки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Печать . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Ограничения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 194 Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 195 ГЛАВА 4 Механизмы управления Реестр . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Просмотр и изменение реестра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Использование реестра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Типы данных в реестре . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Логическая структура реестра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Анализ и устранение проблем с реестром . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Внутренние механизмы реестра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сервисы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сервисные приложения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Учетные записи сервисов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Диспетчер управления сервисами . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Запуск сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ошибки при запуске . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Критерии успешной загрузки и последняя удачная конфигурация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сбои сервисов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Завершение работы сервиса . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Разделяемые процессы сервисов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Программы управления сервисами . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Windows Management Instrumentation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Архитектура WMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Провайдеры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CIM и язык Managed Object Format . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 196 196 196 197 198 199 205 211 227 228 233 239 242 245 246 248 249 250 252 253 254 256 257
Оглавление VII Пространство имен WMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Классы сопоставления . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Реализация WMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Защита WMI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 260 262 264 266 266 ГЛАВА 5 267 Запуск и завершение работы системы Процесс загрузки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Что предшествует загрузке на платформах x86 и x64 . . . . . . . . . . . . . . . . . . . . . . . Загрузочный сектор и Ntldr на платформах x86 и x64 . . . . . . . . . . . . . . . . . . . . . . . Процесс загрузки на платформе IA64 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Инициализация ядра и компонентов исполнительной системы . . . . . . . . . . . Smss, Csrss и Winlogon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Автоматически запускаемые образы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Анализ проблем при загрузке и запуске системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Последняя удачная конфигурация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Безопасный режим . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Консоль восстановления . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Решение распространенных проблем загрузки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Завершение работы системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 267 271 280 282 286 289 290 291 291 296 298 304 306 ГЛАВА 6 307 Процессы, потоки и задания Внутреннее устройство процессов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Переменные ядра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Счетчики производительности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сопутствующие функции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Что делает функция CreateProcess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Этап 1: открытие образа, подлежащего выполнению . . . . . . . . . . . . . . . . . . . . . . . . Этап 2: создание объекта «процесс» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Этап 3: создание первичного потока, его стека и контекста . . . . . . . . . . . . . . . . Этап 4: уведомление подсистемы Windows о новом процессе . . . . . . . . . . . . . . Этап 5: запуск первичного потока . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Этап 6: инициализация в контексте нового процесса . . . . . . . . . . . . . . . . . . . . . . . Внутреннее устройство потоков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Переменные ядра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Счетчики производительности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сопутствующие функции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Рождение потока . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Наблюдение за активностью потоков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Планирование потоков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Обзор планирования в Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Уровни приоритета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сопутствующие утилиты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Приоритеты реального времени . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Состояния потоков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . База данных диспетчера ядра . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Квант . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сценарии планирования . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Переключение контекста . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 307 307 314 315 315 317 319 322 326 327 328 328 331 331 338 338 339 340 341 344 344 346 349 351 352 356 358 362 365
VIII Оглавление Поток простоя . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Динамическое повышение приоритета . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Многопроцессорные системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Алгоритмы планирования потоков в многопроцессорных системах . . . . . Объекты>задания . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 366 366 376 386 389 394 ГЛАВА 7 395 Управление памятью Введение в диспетчер памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Компоненты диспетчера памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Внутренняя синхронизация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Конфигурирование диспетчера памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Исследование используемой памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сервисы диспетчера памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Большие и малые страницы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резервирование и передача страниц . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Блокировка памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Гранулярность выделения памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Разделяемая память и проецируемые файлы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Защита памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Запрет на выполнение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Копирование при записи . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Диспетчер куч . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Address Windowing Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Системные пулы памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Настройка размеров пулов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Мониторинг использования пулов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ассоциативные списки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Утилита Driver Verifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры виртуального адресного пространства . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры пользовательского адресного пространства на платформе x86 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структура системного адресного пространства на платформе x86 . . . . . . . . Пространство сеанса на платформе x86 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Системные PTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры 64>разрядных адресных пространств . . . . . . . . . . . . . . . . . . . . . . . . . . . . Трансляция адресов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Трансляция виртуальных адресов на платформе x86 . . . . . . . . . . . . . . . . . . . . . . . . Ассоциативный буфер трансляции . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Physical Address Extension (PAE) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Трансляция виртуальных адресов на платформе IA64 . . . . . . . . . . . . . . . . . . . . . . . Трансляция виртуальных адресов на платформе x64 . . . . . . . . . . . . . . . . . . . . . . . . Обработка ошибок страниц . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Недействительные PTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Прототипные PTE . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Операции ввода>вывода, связанные с подкачкой страниц . . . . . . . . . . . . . . . . . . Конфликты ошибок страницы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Страничные файлы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Дескрипторы виртуальных адресов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Объекты>разделы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Рабочие наборы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Подкачка по требованию . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 395 396 397 398 398 402 403 404 406 406 407 409 412 415 416 422 424 424 427 432 433 437 440 441 443 446 446 449 449 457 458 460 461 462 464 465 467 468 468 473 475 482 482
Оглавление IX Средство логической предвыборки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Правила размещения . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Управление рабочими наборами . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Диспетчер настройки баланса и подсистема загрузки>выгрузки . . . . . . . . . . . Системный рабочий набор . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . База данных PFN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Динамика списков страниц . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Подсистема записи модифицированных страниц . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры данных PFN . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Уведомление о малом или большом объеме памяти . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 483 487 488 491 492 494 498 500 502 505 509 ГЛАВА 8 510 Защита Классы безопасности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Trusted Computer System Evaluation Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Common Criteria . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Компоненты системы защиты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Защита объектов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Проверка прав доступа . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Дескрипторы защиты и управление доступом . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Права и привилегии учетных записей . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Права учетной записи . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Привилегии . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Суперпривилегии . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Аудит безопасности . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Вход в систему . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Инициализация Winlogon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Этапы входа пользователя . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Политики ограниченного использования программ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 510 510 512 514 518 518 533 544 545 546 552 553 555 557 558 563 565 ГЛАВА 9 566 Подсистема ввода-вывода Компоненты подсистемы ввода>вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Диспетчер ввода>вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Типичная обработка ввода>вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Драйверы устройств . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Типы драйверов устройств . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структура драйвера . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Объекты «драйвер» и «устройство» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Открытие устройств . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Обработка ввода>вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Типы ввода>вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Пакеты запроса ввода>вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Запрос ввода>вывода к одноуровневому драйверу . . . . . . . . . . . . . . . . . . . . . . . . . . . Запрос ввода>вывода к многоуровневому драйверу . . . . . . . . . . . . . . . . . . . . . . . . . . Порты завершения ввода>вывода . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Driver Verifier . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Диспетчер Plug and Play (PnP) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Уровень поддержки Plug and Play . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Поддержка Plug and Play со стороны драйвера . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Загрузка, инициализация и установка драйвера . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Установка драйвера . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 566 568 569 571 571 578 580 585 591 591 595 602 608 615 620 622 623 623 626 635
X Оглавление Диспетчер электропитания . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Работа диспетчера электропитания . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Участие драйверов в управлении электропитанием . . . . . . . . . . . . . . . . . . . . . . . . . Как драйвер управляет электропитанием устройства . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 640 642 643 647 647 ГЛАВА 10 649 Управление внешней памятью Базовая терминология . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Драйверы дисков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Ntldr . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Драйвер класса дисков, порт> и минипорт>драйверы . . . . . . . . . . . . . . . . . . . . . . . . Объекты «устройство» для дисков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Диспетчер разделов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Управление томами . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Базовые диски . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Динамические диски . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Управление составными томами . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Пространство имен томов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Операции ввода>вывода на томах . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Служба виртуального диска . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Служба теневого копирования тома . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 649 650 651 651 655 657 657 659 661 668 674 683 684 686 691 ГЛАВА 11 692 Диспетчер кэша Основные возможности диспетчера кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Единый централизованный системный кэш . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Диспетчер памяти . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Когерентность кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Кэширование виртуальных блоков . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Кэширование потоков данных . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Поддержка восстанавливаемых файловых систем . . . . . . . . . . . . . . . . . . . . . . . . . . . Управление виртуальной памятью кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Размер кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . LargeSystemCache . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Виртуальный размер кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Размер рабочего набора кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Физический размер кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры данных кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Общесистемные структуры данных кэша . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структуры данных кэша, индивидуальные для каждого файла . . . . . . . . . . . . . Интерфейсы файловых систем . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Копирование данных в кэш и из него . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Кэширование с применением интерфейсов проецирования и фиксации . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Кэширование с применением прямого доступа к памяти . . . . . . . . . . . . . . . . . . . Быстрый ввод>вывод . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Опережающее чтение и отложенная запись . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Интеллектуальное опережающее чтение . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Кэширование с обратной записью и отложенная запись . . . . . . . . . . . . . . . . . . . Дросселирование записи . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Системные потоки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 692 693 693 694 695 695 696 697 699 699 701 702 704 707 707 708 713 714 716 718 719 722 722 724 727 729 730
Оглавление ГЛАВА 12 Файловые системы XI 731 Файловые системы Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . CDFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . UDF . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . FAT12, FAT16 и FAT32 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NTFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Архитектура драйвера файловой системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Локальные FSD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Удаленные FSD . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Работа файловой системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Драйверы фильтров файловой системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Анализ проблем в файловой системе . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Базовый и расширенный режимы Filemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Методики анализа проблем с применением Filemon . . . . . . . . . . . . . . . . . . . . . . . . Цели разработки и особенности NTFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Требования к файловой системе класса «high end» . . . . . . . . . . . . . . . . . . . . . . . . . . . Драйвер файловой системы NTFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структура NTFS на диске . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Тома . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Кластеры . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Главная таблица файлов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Структура файловых ссылок . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Записи о файлах . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Имена файлов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резидентные и нерезидентные атрибуты . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сжатие данных и разреженные файлы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Файл журнала изменений . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Индексация . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Идентификаторы объектов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Отслеживание квот . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Консолидированная защита . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Точки повторного разбора . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Поддержка восстановления в NTFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Эволюция архитектуры файловых систем . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Протоколирование . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Восстановление . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Восстановление плохих кластеров в NTFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Механизм EFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Первое шифрование файла . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Процесс расшифровки . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резервное копирование шифрованных файлов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 732 732 732 733 736 737 737 738 742 748 754 755 756 761 761 774 777 777 777 778 785 785 788 790 794 798 799 801 802 802 804 805 805 809 814 818 822 826 831 833 834 ГЛАВА 13 835 Поддержка сетей Сетевая архитектура Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Эталонная модель OSI . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сетевые компоненты Windows . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Сетевые API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Windows Sockets . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Remote Procedure Call (RPC) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . API>интерфейсы доступа к Web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 835 836 837 839 839 847 852
XII Оглавление Именованные каналы и почтовые ящики . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NetBIOS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Другие сетевые API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Поддержка нескольких редиректоров . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Маршрутизатор многосетевого доступа . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Многосетевой UNC>провайдер . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Разрешение имен . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DNS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . WINS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Драйверы протоколов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Расширения TCP/IP . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Драйверы NDIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Разновидности минипорт>драйверов NDIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . NDIS, ориентированная на логические соединения . . . . . . . . . . . . . . . . . . . . . . . . . Remote NDIS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . QoS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Привязка . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Многоуровневые сетевые сервисы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Удаленный доступ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Active Directory . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Network Load Balancing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Служба репликации файлов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . DFS . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Резюме . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 853 861 864 865 866 869 870 871 871 871 875 879 884 885 888 889 890 892 892 892 894 895 896 897 ГЛАВА 14 898 Анализ аварийного дампа Почему происходит крах Windows? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . «Синий экран» . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Файлы аварийного дампа . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Генерация аварийного дампа . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Windows Error Reporting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Анализ аварийных дампов через Интернет . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Базовый анализ аварийных дампов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Notmyfault . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Базовый анализ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Детальный анализ . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Средства анализа проблем, вызывающих крах . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Переполнение буфера и особый пул . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Перезапись кода и защита системного кода от записи . . . . . . . . . . . . . . . . . . . . . . Углубленный анализ аварийных дампов . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Засорение стека . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Зависание или отсутствие отклика системы . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Если аварийного дампа нет . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 898 900 902 905 906 907 908 909 910 912 914 915 917 919 920 921 925 Словарь терминов Предметный указатель Об авторах 927 951 969
Предисловие Microsoft Windows была частью моей жизни целых 14 лет. За это время — от версии к версии — наша операционная система развивалась вширь и вглубь. Сегодня работа над Windows — один из самых важных и сложных проектов в мире. В выпуске Windows участвуют более 5000 инженеров. Среди пользо# вателей Windows есть представители уже почти всех культур, она использу# ется как на крупных предприятиях, так и маленькими детьми. Пользователи Windows постоянно требуют ее совершенствования практически во всех сферах — от эффективной работы на крупнейших серверах до применения в дошкольном обучении. Windows поставляется в самых разных ипоста# сях — от встраиваемых версий и выпусков для медиа#центров до редакций для центров обработки данных. Все эти продукты опираются на одни и те же базовые компоненты Windows, которые развиваются и совершенствуются в каждой новой версии. Это фундаментальная книга о внутреннем устройстве базовых компонен# тов Windows. Если вы хотите как можно быстрее освоить принципы внут# ренней работы Windows, тогда эта книга для вас. Освоение всех частей столь основательного продукта — задача устрашающая. Но если вы начнете с ба# зовых концепций системы, сложить фрагменты головоломки воедино будет гораздо легче. С эволюцией самой Windows развивается и эта книга — сей# час публикуется ее четвертое издание. Мы уже давно используем ее для обу# чения новых сотрудников Microsoft, так что предлагаемые вам материалы проверены на практике. Если вы вроде меня, значит, вам тоже нравится разбираться в том, как уст# роены вещи. Чтение книжек типа «как использовать то#то и то#то» меня ни# когда не удовлетворяло. Когда понимаешь, как именно устроена вещь, пользу# ешься ею гораздо эффективнее и, честно говоря, с бóльшим удовольствием. Если вас интересует Windows «с изнанки», вы выбрали подходящую книгу. Дэвид и Марк проделали превосходную работу, написав книгу о техничес# кой «изнанке» Windows. А инструменты, которые они предлагают вам, — от# личное средство для самостоятельного обучения и диагностики. Прочитав эту книгу, вы будете гораздо лучше понимать, как взаимодействуют между собой различные компоненты и подсистемы, какие усовершенствования внесены в новую версию и как выжать из них максимум возможного. Это был долгий путь — и он все еще продолжается. Так что открывайте книгу, а заодно и капот, под которым бьется сердце одной из самых потря# сающих операционных систем. Джим Олчин, вицепрезидент группы платформ корпорации Microsoft
Благодарности В первую очередь мы хотим особо поблагодарить следующих людей. 쐽 Дэйва Катлера (Dave Cutler), заслуженного старшего инженера и пер вого архитектора Microsoft Windows NT. Дэйв разрешил Дэвиду Соломо ну (David Solomon) доступ к исходному коду и всячески поддерживал его преподавательскую деятельность, посвященную объяснению деталей внутреннего устройства Windows NT, а также его работу над вторым и третьим изданием книги. Помимо рецензирования главы по процессам и потокам, Дэйв ответил на массу вопросов об архитектуре ядра и напи сал об истории создания Windows для нашей книги. 쐽 Джима Олчина (Jim Allchin), нашего главного спонсора, — за предис ловие к этой книге и за отстаивание интересов нашего дела в Microsoft. 쐽 Роба Шорта (Rob Short), вицепрезидента, который позаботился о том, чтобы нам предоставили ресурсы и доступ к нужным людям. Мы также выражаем признательность двум разработчикам из отдела Win dows за подготовку новых материалов, включенных в это издание: 쐽 Адриану Маринеску (Adrian Marinescu), который написал заметно раз росшийся раздел по диспетчеру куч в главе, где рассматривается диспет чер памяти. 쐽 Самеру Арафеху (Samer Arafeh), который предоставил материалы по Wow64. Спасибо нашему старому приятелю, Джеффри Рихтеру (Jeffrey Richter), с которым мы часто вместе обедаем, за врезку «Как насчет .NET и WinFX?» в главе 1 и за постоянное напоминание о том, как мало людей, понастояще му интересующихся тем, о чем мы говорим в своей книге. В этой книге не было бы такой глубины и точности изложения техничес ких сведений без поддержки, замечаний и предложений ключевых членов команды разработчиков Microsoft Windows. Вот эти люди: Murali Brahmadesam Molly Brown Duncan Bryce Daniel Bucherer Neal Christian Neill Clift Mike Danseglio Joseph Davies Cenk Ergan Tom Fout Nar Ganapathy David Golds Robert Gu Jeff Hamblin Pat Hoffer Anthony Jones Tom Jones Joseph Joy Shreeniwas Kelkar Connie La Chasse Mike Lai Paul Leach Gerald Maffeo Aaron Margosis Iain McDonald Kamen Moutafov Adi Oltean Vince Orgovan Daniel Pravat Dragos Sambotin Jon Schwartz Rob Short Paul Sliwowicz Chittur Subbaraman Cristian Teodorescu Andre Vachon Landy Wang Richard Ward Brad Waters Bruce Worthington Mark Zbikowsk Khawar Zuberi
XVIII Благодарности БЕЗОПАСНОСТЬ Были и другие, кто отвечал на наши вопросы в коридорах или кафетери ях, — если мы вас пропустили, пожалуйста, простите нас! Мы также выражаем благодарность Джейми Ханрахан (Jamie Hanrahan) из Azius Developer Training (www.azius.com), которая в соавторстве с Дэвидом под готовила учебный курс по внутренней архитектуре исходной версии Windows. На основе этого курса было написано второе издание этой книги. Джейми, у которой настоящий талант доходчиво объяснять сложнейшие вещи, предоста вила нам отдельные материалы, а также ряд схем и иллюстраций. Спасибо Дэйву Проберту (Dave Probert) за то, что разместил в сети наши черновые материалы для распространения среди рецензентов внутри Microsoft. Благодарим Джонатана Славза (Jonathan Sloves) из AMD, с помощью ко торого нам предоставили тестовые системы AMD64; они очень помогли нам в написании материалов по 64разрядной архитектуре и в переносе ряда утилит Sysinternals на платформу x64. Наконец, мы хотим выразить благодарность следующим сотрудникам Microsoft Press за их вклад в эту книгу. 쐽 Робину Ван!Штеенбергу (Robin van Steenburgh), рецензенту издатель ства, за терпение в работе с нами над этим проектом. 쐽 Салли Стикни (Sally Stickney), которая на первых порах попрежнему была редактором нашего проекта, но потом ее закрутил водоворот адми нистративных дел. Мы очень скучали без вас! 쐽 Валери Вулли (Valerie Woolley), которая приняла бразды правления от Салли и стала нашим новым редактором проекта. Вы замечательная и не такая резкая, как Салли! 쐽 Роджеру Лебланку (Roger LeBlanc), который одолел все главы и сумел сократить в них текст, найти несогласованности и вообще довести нашу рукопись до высоких стандартов Microsoft Press. Дэвид Соломон и Марк Руссинович сентябрь 2004 г.
Г Л А В А 1 Концепции и инструменты В этой главе мы познакомим вас с основными концепциями и терминами операционной системы Microsoft Windows, которые будут использоваться в последующих главах, в том числе с Windows API, процессами, потоками, вир туальной памятью, режимом ядра и пользовательским режимом, объектами, описателями (handles), защитой, реестром. Мы также расскажем об инстру ментах, с помощью которых вы сможете исследовать внутреннее устройство Windows. К ним относятся, например, отладчик ядра, оснастка Performance и важнейшие утилиты с сайта www.sysinternals.com. Кроме того, мы поясним, как пользоваться Windows Device Driver Kit (DDK) и Platform Software Deve lopment Kit (SDK) в качестве источника дополнительной информации о внутреннем устройстве Windows. Вы должны хорошо понимать все, что написано в этой главе, — в осталь ной части книги мы предполагаем именно так. Версии операционных систем Windows Эта книга охватывает три последние версии операционной системы Micro soft Windows, основанные на кодовой базе Windows NT: Windows 2000, Win dows XP (32 и 64разрядные версии) и Windows Server 2003 (32 и 64раз рядные версии). Текст относится ко всем трем версиям, если не оговорено иное. В таблице 11 перечислены выпуски кодовой базы Windows NT, номе ра версий и названия продуктов. Таблица 1-1. Выпуски операционной системы Windows Название продукта Номер версии Windows NT 3.1 3.1 Дата выпуска Июль 1993 г. Windows NT 3.5 3.5 Сентябрь 1994 г. Windows NT 3.51 3.51 Май 1995 г. Windows NT 4.0 4.0 Июль 1996 г. Windows 2000 5.0 Декабрь 1999 г. Windows XP 5.1 Август 2001 г. Windows Server 2003 5.2 Март 2003 г.
2 ГЛ А В А 1 БЕЗОПАСНОСТЬ Windows NT и Windows 95 При первом выпуске Windows NT компания Microsoft дала ясно по нять, что это долгосрочная замена Windows 95 (и ее последующих выпусков — Windows 98 и Windows Millennium Edition). Вот список некоторых архитектурных различий и преимуществ Windows NT (и ее последующих выпусков) над Windows 95 (и ее последующими выпус ками). 쐽 Windows NT поддерживает многопроцессорные системы, а Win dows 95 — нет. 쐽 Файловая система Windows NT поддерживает средства защиты, на пример управление избирательным доступом (discretionary access control). В файловой системе Windows 95 этого нет. 쐽 Windows NT — полностью 32разрядная (а теперь и 64разрядная) операционная система, в ней нет 16разрядного кода, кроме того, который предназначен для выполнения 16разрядных Windows приложений. Windows 95 содержит большой объем старого 16раз рядного кода из предшествующих операционных систем — Win dows 3.1 и MSDOS. 쐽 Windows NT полностью реентерабельна, а многие части Windows 95 нереентерабельны (в основном это касается 16разрядного кода, взятого из Windows 3.1). Большинство функций, связанных с гра фикой и управлением окнами (GDI и USER), включают именно не реентерабельный код. Когда 32разрядное приложение в Windows 95 пытается вызвать системный сервис, реализованный как нере ентерабельный 16разрядный код, оно должно сначала получить общесистемную блокировку (или мьютекс), чтобы предотвратить вход других потоков в нереентерабельную кодовую базу. Еще хуже, что 16разрядное приложение удерживает такую блокировку в те чение всего времени своего выполнения. В итоге, хотя ядро Win dows 95 содержит 32разрядный планировщик с поддержкой мно гопоточности и вытесняющей многозадачности, приложения час то работают как однопоточные изза того, что большая часть сис темы реализована как нереентерабельный код. 쐽 Windows NT позволяет выполнять 16разрядные Windowsприло жения в выделенном адресном пространстве, а Windows 95 всегда выполняет такие приложения в общем адресном пространстве, в котором они могут навредить друг другу и привести к зависанию системы. 쐽 Разделяемая (общая) память процесса в Windows NT видна только тем процессам, которые имеют проекцию на один и тот же блок разделяемой памяти. В Windows 95 вся общая память видна и дос тупна для записи всем процессам. Таким образом, любой процесс
ГЛАВА 9 Концепции и инструменты 3 может чтото записать и повредить какието данные в общей памя ти, используемые другими процессами. 쐽 Некоторые критически важные страницы памяти, занимаемые опе рационной системой Windows 95, доступны для записи из пользо вательского режима, а значит, обычное приложение может повре дить содержимое этих страниц и привести к краху системы. Единственное, что умеет Windows 95 и чего никогда не смогут де лать операционные системы на основе Windows NT, — выполнять все старые программы для MSDOS и Windows 3.1 (а именно программы, требующие прямого доступа к оборудованию), а также 16разрядные драйверы устройств MSDOS. Если одной из основных целей разработ ки Windows 95 была 100%я совместимость с MSDOS и Windows 3.1, то исходной целью разработки Windows NT — возможность выполне ния большинства существующих 16разрядных приложений при ус ловии сохранения целостности и надежности системы. Базовые концепции и термины В книге будут часто встречаться ссылки на концепции и структуры, с кото рыми некоторые читатели, возможно, не знакомы. Здесь мы определимся с используемой в дальнейшем терминологией. Windows API Это системный интерфейс программирования в семействе операционных систем Microsoft Windows, включая Windows 2000, Windows XP, Windows Server 2003, Windows 95, Windows 98, Windows Millennium Edition (Me) и Windows CE. Каждая операционная система реализует разное подмножество Windows API. Windows 95, Windows 98, Windows Me и Windows CE в этой книге не рассматриваются. ПРИМЕЧАНИЕ Windows API описывается в документации Platform Software Development Kit (SDK). (См. раздел «Platform Software Develop ment Kit (SDK)» далее в этой главе.) Эту документацию можно бесплат но просмотреть на сайте msdn.microsoft.com. Она также поставляется с Microsoft Developer Network (MSDN) всех уровней подписки. (MSDN — это программа Microsoft для поддержки разработчиков. Подробности см. на сайте msdn.microsoft.com.) Отличное описание того, как програм мировать с использованием базового Windows API, см. в четвертом из дании книги Джеффри Рихтера (Jeffrey Richter) «Microsoft Windows для профессионалов» (Русская Редакция, 2000). До появления 64разрядных версий Windows XP и Windows Server 2003 интерфейс программирования 32разрядных версий операционных систем Windows назывался Win32 API, чтобы отличать его от исходного 16разряд ного Windows API. В этой книге термин «Windows API» относится к 32разряд
4 ГЛ А В А 1 БЕЗОПАСНОСТЬ ному интерфейсу программирования Windows 2000, а также к 32 и 64раз рядным интерфейсам программирования Windows XP и Windows Server 2003. Windows API включает тысячи вызываемых функций, которые сгруппи рованы в следующие основные категории: 쐽 базовые сервисы (Base Services); 쐽 сервисы компонентов (Component Services); 쐽 сервисы пользовательского интерфейса (User Interface Services); 쐽 сервисы графики и мультимедиа (Graphics and Multimedia Services); 쐽 коммуникационное взаимодействие и совместная работа (Messaging and Collaboration); 쐽 сети (Networking); 쐽 Webсервисы (Web Services). Основное внимание в нашей книге уделяется внутреннему устройству ключевых базовых сервисов, в частности поддержки процессов и потоков (threads), управления памятью, вводавывода и защиты. Как насчет .NET и WinFX? .NET Framework состоит из библиотеки классов, называемой Frame work Class Library (FCL), и общеязыковой исполняющей среды (Com mon Language Runtime, CLR), которая предоставляет среду для выпол нения управляемого кода с такими возможностями, как компиляция по требованию (justintime compilation, JIT compilation), верификация типов, сбор мусора и защита по правам доступа кода (code access secu rity). Благодаря этому CLR создает среду разработки, которая повыша ет продуктивность труда программистов и уменьшает вероятность появления распространенных ошибок программирования. Отличное описание .NET Framework и ее базовой архитектуры см. в книге Джеф фри Рихтера «Программирование на платформе Microsoft .NET Frame work» (Русская Редакция, 2003). CLR реализована как классический COMсервер, код которой хра нится в стандартной Windows DLL пользовательского режима. Факти чески все компоненты .NET Framework реализованы как стандартные Windows DLL пользовательского режима, занимающие уровень поверх неуправляемых функций Windows API. (Никакие компоненты .NET Framework не работают в режиме ядра.) На рис. 11 показаны взаимо связи этих компонентов.
ГЛАВА 9 Рис. 1-1. Концепции и инструменты Взаимосвязи компонентов .NET Framework WinFX — «новый Windows API». Это результат эволюционного раз вития .NET Framework, которая будет поставляться с версией Windows под кодовым названием «Longhorn», следующим выпуском Windows. WinFX также можно установить в Windows XP и Windows Server 2003. WinFX образует фундамент для приложений следующего поколения, создаваемых для операционной системы Windows. История создания Win32 API Интересно, что поначалу Win32 не рассматривался как интерфейс про граммирования для Microsoft Windows NT. Поскольку проект Windows NT начинался как замена OS/2 версии 2, основным интерфейсом програм мирования был 32разрядный OS/2 Presentation Manager API. Однако год спустя на рынке появилась Microsoft Windows 3.0, быстро ставшая очень популярной. В результате Microsoft сменила курс и перенацелила проект Windows NT на будущую замену семейства продуктов Windows, а не OS/2. Вот на этомто перепутье и встал вопрос о создании Windows API — до этого Windows API существовал только как 16разрядный интерфейс. Хотя в Windows API должно было появиться много новых функций, отсутствующих в Windows 3.1, Microsoft решила сделать новый API по возможности совместимым с именами функций, семантикой и типа ми данных в 16разрядном Windows API, чтобы максимально облег чить бремя переноса существующих 16разрядных Windowsприложе ний в Windows NT. Поэтому тот, кто, впервые глядя на Windows API, удивляется, почему многие имена и интерфейсы функций кажутся противоречивыми, должен учитывать, что одной из причин такой противоречивости было стремление сделать Windows API совмести мым со старым 16разрядным Windows API. 5
6 ГЛ А В А 1 БЕЗОПАСНОСТЬ Сервисы, функции и процедуры Несколько терминов в документации Windows для пользователей и програм мистов имеет разный смысл в разных контекстах. Например, понятие «сер вис» (service) может относиться к вызываемой функции операционной сис темы, драйверу устройства или серверному процессу (в последнем случае сервис часто называют службой). Ниже показано, что означают подобные термины в этой книге. 쐽 Функции Windows API Документированные, вызываемые подпрог раммы в Windows API, например CreateProcess, CreateFile и GetMessage. 쐽 Неуправляемые («родные») системные сервисы (или исполняе мые системные сервисы) Недокументированные низкоуровневые сервисы операционной системы, которые можно вызывать в пользова тельском режиме. Так, NtCreateProcess — это внутрисистемный сервис, вы зываемый Windowsфункцией CreateProcess при создании нового процес са. (Определение неуправляемых функций см. в разделе «Диспетчериза ция системных сервисов» главы 3.) 쐽 Функции (или процедуры) ядра Подпрограммы внутри операцион ной системы Windows, которые можно вызывать только в режиме ядра (определение мы дадим чуть позже). Например, ExAllocatePool — проце дура, вызываемая драйверами устройств для выделения памяти из систем ных куч (динамически распределяемых областей памяти) Windows. 쐽 Windowsсервисы Процессы, запускаемые диспетчером управления сервисами в Windows. (Хотя в документации на реестр драйверы уст ройств Windows определяются как сервисы, мы не пользуемся таким тер мином в этой книге.) Например, сервис Task Scheduler выполняется в про цессе пользовательского режима, который поддерживает команду at (ана логичную UNIXкоманде at или cron). 쐽 DLL (динамически подключаемая библиотека) Набор вызывае мых подпрограмм, включенных в один двоичный файл, который прило жения, использующие эти подпрограммы, могут динамически загружать во время своего выполнения. В качестве примера можно привести моду ли Msvcrt.dll (библиотека исполняющей подсистемы C) и Kernel32.dll (одна из библиотек подсистемы Windows API). DLL активно используют ся компонентами и приложениями Windows пользовательского режима. Преимущество DLL над статическими библиотеками в том, что приложе ния могут разделять DLLмодули, а Windows гарантирует, что в памяти будет находиться лишь по одному экземпляру используемых DLL. Процессы, потоки и задания Хотя на первый взгляд кажется, что программа и процесс — понятия прак тически одинаковые, они фундаментально отличаются друг от друга. Про грамма представляет собой статический набор команд, а процесс — это кон тейнер для набора ресурсов, используемых при выполнении экземпляра
ГЛАВА 9 Концепции и инструменты 7 программы. На самом высоком уровне абстракции процесс в Windows вклю чает следующее: 쐽 закрытое виртуальное адресное пространство — диапазон адресов вир туальной памяти, которым может пользоваться процесс; 쐽 исполняемую программу — начальный код и данные, проецируемые на виртуальное адресное пространство процесса; 쐽 список открытых описателей (handles) различных системных ресур сов — семафоров, коммуникационных портов, файлов и других объектов, доступных всем потокам в данном процессе; 쐽 контекст защиты (security context), называемый маркером доступа (ac cess token) и идентифицирующий пользователя, группы безопасности и привилегии, сопоставленные с процессом; 쐽 уникальный идентификатор процесса (во внутрисистемной терминоло гии называемый идентификатором клиента); 쐽 минимум один поток. Каждый процесс также указывает на свой родительский процесс (про цесссоздатель). Однако, если родитель существует, эта информация не об новляется. Поэтому есть вероятность, что некий процесс указывает на уже несуществующего родителя. Это не создает никакой проблемы, поскольку никто не полагается на наличие такой информации. Следующий экспери мент иллюстрирует данный случай. ЭКСПЕРИМЕНТ: просмотр дерева процессов Большинство утилит не отображает такой уникальный атрибут, как идентификатор родительского процесса. Значение этого атрибута можно получить программно или с помощью оснастки Performance, запросив значение счетчика Creating Process ID [Код (ID) создавшего процесса]. Дерево процессов показывается утилитой Tlist.exe (из Win dows Debugging Tools), если вы указываете ключ /t. Вот образец выво да этой команды: C:\>tlist /t System Process (0) System (2) smss.exe (21) csrss.exe (24) winlogon.exe (35) services.exe (41) spoolss.exe (69) llssrv.exe (94) LOCATOR.EXE (96) RpcSs.exe (112) inetinfo.exe (128) lsass.exe (44) nddeagnt.exe (119) см. след. стр.
8 ГЛ А В А 1 БЕЗОПАСНОСТЬ explorer.exe (123) Program Manager OSA.EXE (121) WINWORD.EXE (117) Microsoft Word  msch02(s).doc cmd.exe (72) Command Prompt  tlist /t tlist.EXE (100) Взаимоотношения процессов (дочернийродительский) Tlist пока зывает отступами. Имена процессов, родительские процессы которых на данный момент завершились, выравниваются по левому краю, по тому что установить их родственные связи невозможно — даже если процессыпрапредки еще существуют. Windows сохраняет идентифи катор только родительского процесса, так что проследить его созда теля нельзя. Чтобы убедиться в этом, выполните следующие операции. 1. Откройте окно командной строки. 2. Наберите start cmd для запуска второго окна командной строки. 3. Откройте диспетчер задач. 4. Переключитесь на второе окно командной строки. 5. Введите mspaint для запуска Microsoft Paint. 6. Щелкните второе окно командной строки. 7. Введите exit. (Заметьте, что окно Paint остается.) 8. Переключитесь в диспетчер задач. 9. Откройте его вкладку Applications (Приложения). 10. Щелкните правой кнопкой мыши задачу Command Prompt (Команд ная строка) и выберите Go To Process (Перейти к процессам). 11. Щелкните процесс Cmd.exe, выделенный серым цветом. 12. Щелкнув правой кнопкой мыши, выберите команду End Process Tree (Завершить дерево процессов). 13. В окне Task Manager Warning (Предупреждение диспетчера задач) щелкните кнопку Yes (Да). Первое окно командной строки исчезнет, но вы попрежнему смо жете наблюдать окно Paint, так как оно является внуком первого из завершенных процессов Command Prompt. А поскольку второй (роди тельский процесс Paint) тоже завершен, связь между родителем и вну ком потеряна. Для просмотра (и модификации) процессов и информации, связанной с ними, существует целый набор утилит. Следующие эксперименты демонст рируют, как получить ту или иную информацию о процессе с помощью не которых из этих утилит. Они включаются непосредственно в саму Windows, а также в Windows Support Tools, Windows Debugging Tools, ресурсы Windows и Platform SDK; ряд утилит можно получить с сайта www.sysinternals.com. Многие из этих утилит выводят перекрывающиеся подмножества информа ции о базовых процессах и потоках, иногда идентифицируемые по разным именам.
ГЛАВА 9 Концепции и инструменты 9 Вероятно, наиболее широко применяемая утилита для анализа активно сти процессов — Task Manager (Диспетчер задач). (Любопытно, что в ядре Windows нет такого понятия, как задача, так что Task Manager на самом деле является инструментом для управления процессами.) Следующий экспери мент показывает разницу между тем, что Task Manager перечисляет как при ложения и процессы. ЭКСПЕРИМЕНТ: просмотр информации о процессах через диспетчер задач Диспетчер задач Windows отображает список выполняемых в систе ме процессов. Его можно запустить тремя способами: 1) нажав клави ши Ctrl+Shift+Esc; 2) щелкнув панель задач правой кнопкой мыши и выбрав команду Task Manager (Диспетчер задач); 3) нажав клавиши Ctrl+Alt+Del. После запуска диспетчера задач откройте вкладку Pro cesses (Процессы). Заметьте, что процессы идентифицируются по име ни образа, экземплярами которого они являются. В отличие от неко торых объектов в Windows процессам нельзя присваивать глобальные имена. Для просмотра более подробных сведений выберите из меню View (Вид) команду Select Columns (Выбрать столбцы) и укажите, ка кая дополнительная информация вас интересует. Если вкладка Processes окна диспетчера задач со всей очевидностью показывает список процессов, то содержимое вкладки Applications (Приложения) нуждается в пояснениях. На ней отображается список видимых окон верхнего уровня всех объектов «рабочий стол» интерак тивного объекта WindowStation. (По умолчанию существуют два объек та «рабочий стол», но вы можете создать дополнительные рабочие сто лы через Windowsфункцию CreateDesktop.) Колонка Status (Состоя ние) дает представление о том, находится ли поток — владелец окна в состоянии ожидания Windowsсообщения. «Running» («Выполняет ся») означает, что поток ожидает ввода в окно, а «Not Responding» («Не см. след. стр.
10 ГЛ А В А 1 БЕЗОПАСНОСТЬ отвечает») — что не ожидает (т. е. занят либо ждет завершения опера ции вводавывода или освобождения какоголибо синхронизирующе го объекта). Вкладка Applications позволяет идентифицировать процесс, кото рому принадлежит поток, владеющий какимлибо окном задачи. Для этого щелкните правой кнопкой мыши имя задачи и выберите коман ду Go To Process (Перейти к процессам). Утилита Process Explorer (с сайта www.sysinternals.com) показывает боль ше информации о процессах и потоках, чем любой другой доступный ин струмент; вот почему она используется нами во многих экспериментах, ко торые вы увидите в этой книге. Ниже перечислены некоторые уникальные сведения, выводимые утилитой Process Explorer, и ее возможности: 쐽 полное имя (вместе с путем) выполняемого образа; 쐽 маркер защиты процесса (список групп и привилегий); 쐽 выделение изменений в списке процессов и потоков; 쐽 список сервисов внутри процессов — хостов сервисов с выводом отобра жаемого имени (display name) и описания; 쐽 процессы, которые являются частью задания, и детальные сведения о за даниях; 쐽 процессы, выполняющие .NET/WinFXприложения, и сведения, специ фичные для .NET (например, список доменов приложений и счетчики производительности, относящиеся к CLR); 쐽 время запуска процессов и потоков;
ГЛАВА 9 Концепции и инструменты 11 쐽 полный список файлов, проецируемых в память (не только DLLмодулей); 쐽 возможность приостановки процесса; 쐽 возможность принудительного завершения индивидуальных потоков; 쐽 простота выявления процессов, использующих наибольшую долю про цессорного времени за определенный период. (Оснастка Performance позволяет просматривать процент использования процессора для задан ного набора процессов, но не показывает автоматически процессы, соз данные после начала сеанса мониторинга.) Process Explorer также упрощает доступ к информации, предоставляемой другими утилитами, создавая единую точку ее просмотра: 쐽 дерево процессов с возможностью свертывания отдельных частей этого дерева; 쐽 открытые описатели в процессе без предварительной настройки (утили ты Microsoft для вывода открытых описателей требуют предварительной установки общесистемного флага и перезагрузки); 쐽 список DLL (и файлов, проецируемых в память) в какомлибо процессе; 쐽 активность потоков в какомлибо процессе; 쐽 стеки потоков пользовательского режима (с сопоставлением адресов именам, используя механизм поддержки символов для инструментов от ладки); 쐽 стеки системных потоков режима ядра (с сопоставлением адресов именам, используя механизм поддержки символов для инструментов отладки); 쐽 разница в переключении контекстов (context switch delta) (более нагляд ное представление активности процессора, как поясняется в главе 6); 쐽 лимиты памяти режима ядра (пулов подкачиваемой и неподкачиваемой памяти) (остальные утилиты показывают только текущие размеры). Попробуем провести первый эксперимент с помощью Process Explorer. ЭКСПЕРИМЕНТ: просмотр детальных сведений о процессах с помощью Process Explorer Скачайте последнюю версию Process Explorer с сайта www.sysinter nals.com и запустите ее. При первом запуске вы увидите сообщение о том, что на данный момент символы не сконфигурированы. Когда они корректно сконфигурированы, Process Explorer может обращаться к символьной информации для отображения символьного имени стар товой функции потока и функций в его стеке вызовов (для этого нуж но дважды щелкнуть процесс и выбрать вкладку Threads). Эта инфор мация полезна для идентификации того, что именно делают потоки внутри процесса. Для доступа к символам вы должны установить Debug ging Tools (об этом мы еще поговорим в данной главе). Потом щелк нуть Options, выбрать Configure Symbols и набрать подходящий путь Symbols. Например: см. след. стр.
12 ГЛ А В А 1 БЕЗОПАСНОСТЬ В предыдущем примере для доступа к символам использовался сер вер символов по требованию (ondemand symbol server), а копии фай лов символов хранились на локальном компьютере в папке c:\symbols. Подробнее о конфигурировании сервера символов см. по ссылке http:/ /www.microsoft.com/whdc/ddk/debugging/symbols.mspx. При запуске Process Explorer по умолчанию выводит список про цессов в верхней половине окна, а список открытых описателей для выбранного на данный момент процесса — в нижней половине. Если вы задержите курсор мыши над именем процесса, Process Explorer так же показывает описание образа, название компании и полный путь. Вот как использовать некоторые базовые возможности Process Exp lorer: 1. Отключите нижнюю секцию, сбросив View, Show Lower Pane. (Ниж няя секция может отображать открытые описатели или проециру емые DLL и файлы — об этом речь пойдет в главах 3 и 7.) 2. Обратите внимание на то, что процессы, являющиеся хостами сер висов, по умолчанию выделяются розовым цветом. Ваши собствен ные процессы выделяются синим. (Эти цвета можно настроить.)
ГЛАВА 9 Концепции и инструменты 13 3. Задержите курсор мыши над именем образа и обратите внимание на то, что в подсказке отображается полный путь. 4. Щелкните View, Select Columns и добавьте путь образа. 5. Отсортируйте по колонке процессов и вы увидите, что представле ние в виде дерева исчезло. (Вы можете либо вывести представление в виде дерева, либо сортировать по любой из отображаемых коло нок.) Снова щелкните для сортировки по алфавиту в обратном по рядке (от Z к A). После этого очередной щелчок вернет представ ление в виде дерева. 6. Сбросьте View, Show Processes From All Users для отображения толь ко ваших процессов. 7. Перейдите в Options, Difference Highlight Duration и смените значе ние на 5 секунд. Потом запустите новый процесс (какой угодно) и обратите внимание на то, что этот процесс выделяется зеленым в течение 5 секунд. Закройте новый процесс и заметьте, что этот про цесс выделяется красным в течение 5 секунд, прежде чем исчезнуть из древовидного списка. Эта функция может пригодиться для об наружения создаваемых и завершаемых процессов в системе. 8. Наконец, дважды щелкните какойнибудь процесс и изучите вклад ки, доступные в окне свойств процесса. (Эти вкладки понадобятся нам в дальнейших экспериментах; там же мы поясним, какую ин формацию они сообщают.) Поток (thread) — некая сущность внутри процесса, получающая процес сорное время для выполнения. Без потока программа процесса не может выполняться. Поток включает следующие наиболее важные элементы: 쐽 содержимое набора регистров процессора, отражающих состояние про цессора; 쐽 два стека, один из которых используется потоком при выполнении в ре жиме ядра, а другой — в пользовательском режиме; 쐽 закрытую область памяти, называемую локальной памятью потока (thre adlocal storage, TLS) и используемую подсистемами, библиотеками испол няющих систем (runtime libraries) и DLL; 쐽 уникальный идентификатор потока (во внутрисистемной терминологии также называемый идентификатором клиента: идентификаторы процес сов и потоков генерируются из одного пространства имен и никогда не перекрываются); 쐽 иногда потоки обладают своим контекстом защиты, который обычно используется многопоточными серверными приложениями, подменяю щими контекст защиты обслуживаемых клиентов. Переменные регистры, стеки и локальные области памяти называются контекстом потока. Поскольку эта информация различна на каждой аппа ратной платформе, на которой может работать Windows, соответствующая
14 ГЛ А В А 1 БЕЗОПАСНОСТЬ структура данных специфична для конкретной платформы. Windowsфун кция GetThreadContext предоставляет доступ к этой аппаратнозависимой информации (называемой блоком CONTEXT). Волокна и потоки Волокна (fibers) позволяют приложениям планировать собственные «потоки» выполнения, не используя встроенный механизм планиро вания потоков на основе приоритетов. Волокна часто называют «об легченными» потоками. Они невидимы ядру, так как Kernel32.dll реа лизует их в пользовательском режиме. Для использования волокна нужно вызвать Windowsфункцию ConvertThreadToFiber, которая пре образует поток в волокно. Полученное волокно может создавать до полнительные волокна через функцию CreateFiber (у каждого волок на может быть свой набор волокон). Выполнение волокна (в отличие от потока) не начинается до тех пор, пока оно не будет вручную вы брано вызовом SwitchToFiber. Волокно работает до завершения или до переключения процессора на другое волокно вызовом все той же Swit chToFiber. Подробнее о функциях, связанных с волокнами, см. докумен тацию Platform SDK. Хотя у потоков свой контекст выполнения, каждый поток внутри одного процесса делит его виртуальное адресное пространство (а также остальные ресурсы, принадлежащие процессу). Это означает, что все потоки в процес се могут записывать и считывать содержимое памяти любого из потоков данного процесса. Однако потоки не могут случайно сослаться на адресное пространство другого процесса. Исключение возможно в ситуации, когда тот предоставляет часть своего адресного пространства как раздел общей памяти (shared memory section), в Windows API называемый объектом «про екция файла» (file mapping object), или когда один из процессов имеет пра во на открытие другого процесса и использует функции доступа к памяти между процессами, например ReadProcessMemory и WriteProcessMemory. Кроме закрытого адресного пространства и одного или нескольких пото ков у каждого процесса имеются идентификация защиты и список открытых описателей таких объектов, как файлы и разделы общей памяти, или синхро низирующих объектов вроде мьютексов, событий и семафоров (рис. 12). Каждый процесс обладает контекстом защиты, который хранится в объекте — маркере доступа. Маркер доступа содержит идентификацию за щиты и определяет полномочия данного процесса. По умолчанию у потока нет собственного маркера доступа, но он может получить его, и это позво лит ему подменять контекст защиты другого процесса (в том числе выпол няемого на удаленной системе Windows). Подробнее на эту тему см. главу 8. Дескрипторы виртуальных адресов (virtual address descriptors, VAD) — это структуры данных, используемые диспетчером памяти для учета виртуаль ных адресов, задействованных процессом (см. главу 7).
ГЛАВА 9 Рис. 1-2. Концепции и инструменты 15 Процесс и его ресурсы Windows предоставляет расширение для модели процессов — задания (jobs). Они предназначены в основном для того, чтобы группами процессов можно было оперировать и управлять как единым целым. Объектзадание позволяет устанавливать определенные атрибуты и накладывать ограниче ния на процесс или процессы, сопоставленные с заданием. В этом объекте также хранится информация обо всех процессах, которые были сопостав лены с заданием, но к настоящему времени уже завершены. В какихто от ношениях объектзадание компенсирует отсутствие иерархического дере ва процессов в Windows, а в какихто — даже превосходит по своим возмож ностям дерево процессов UNIX. Более детальное описание внутренней структуры заданий, процессов и потоков, механизмов создания потоков и процессов, а также алгоритмов планирования потоков вы найдете в главе 6. Виртуальная память В Windows реализована система виртуальной памяти, основанная на плос ком (линейном) адресном пространстве. Она создает каждому процессу ил люзию того, что у него есть собственное большое и закрытое адресное про странство. Виртуальная память дает логическое представление, не обязатель но соответствующее структуре физической памяти. В период выполнения диспетчер памяти, используя аппаратную поддержку, транслирует, или про ецирует (maps), виртуальные адреса на физические, по которым реально хранятся данные. Управляя проецированием и защитой страниц памяти, опе рационная система гарантирует, что ни один процесс не помешает другому и не сможет повредить данные самой операционной системы. На рис. 13 показано, как три смежные страницы виртуальной памяти проецируются на три разрозненные страницы физической памяти.
16 Рис. 1-3. ГЛ А В А 1 БЕЗОПАСНОСТЬ Проецирование виртуальной памяти на физическую Поскольку у большинства компьютеров объем физической памяти на много меньше общего объема виртуальной памяти, задействованной выпол няемыми процессами, диспетчер памяти перемещает, или подкачивает (pa ges), часть содержимого памяти на диск. Подкачка данных на диск освобож дает физическую память для других процессов или самой операционной си стемы. Когда поток обращается к странице виртуальной памяти, сброшен ной на диск, диспетчер виртуальной памяти загружает эту информацию с диска обратно в память. Для использования преимуществ подкачки в прило жениях никакого дополнительного кода не требуется, так как диспетчер па мяти опирается на аппаратную поддержку этого механизма. Размер виртуального адресного пространства зависит от конкретной аппаратной платформы. На 32разрядных x86системах теоретический мак симум для общего виртуального адресного пространства составляет 4 Гб. По умолчанию Windows выделяет нижнюю половину этого пространства (в диапазоне адресов от x00000000 до x7FFFFFFF) процессам, а вторую по ловину (в диапазоне адресов от x80000000 до xFFFFFFFF) использует в собст венных целях. Windows 2000 Advanced Server, Windows 2000 Datacenter Ser ver, Windows XP (SP2 и выше) и Windows Server 2003 поддерживают загру зочные параметры /3GB и /USERVA, которые указываются в файле Boot.ini (см. главу 5), что позволяет процессам, выполняющим программы со специ альным флагом в заголовке исполняемого образа, использовать до 3 Гб зак рытого адресного пространства и оставляет операционной системе только 1 Гб. Этот вариант дает возможность приложению вроде сервера базы дан ных хранить в адресном пространстве своего процесса бóльшие порции ба зы данных и тем самым уменьшить частоту проецирования отдельных пред ставлений этой базы. Две структуры виртуальных адресных пространств, поддерживаемые 32разрядной Windows, показаны на рис. 14.
ГЛАВА 9 Рис. 1-4. Концепции и инструменты 17 Структуры адресных пространств для 32-разрядных Windows Хотя три гигабайта лучше двух, этого все равно недостаточно для проеци рования очень больших баз данных. В связи с этим в 32разрядных Windows появился механизм Address Windowing Extension (AWE), который позволяет 32разрядному приложению выделять до 64 Гб физической памяти, а затем проецировать представления (views), или окна (windows), на свое 2гигабайт ное виртуальное адресное пространство. Применение AWE усложняет управ ление проекциями виртуальной памяти на физическую, но снимает пробле му прямого доступа к объему физической памяти, превышающему лимиты 32разрядного адресного пространства процесса. 64разрядная Windows предоставляет процессам гораздо большее адрес ное пространство: 7152 Гб на Itaniumсистемах и 8192 Гб на x64системах. На рис. 15 показана упрощенная схема структур 64разрядных адресных пространств (детали см. в главе 7). Заметьте, что эти размеры отражают не архитектурные лимиты для данных платформ, а ограничения реализации в текущих версиях 64разрядной Windows. Рис. 1-5. Структуры адресных пространств для 64-разрядной Windows Подробнее о реализации диспетчера памяти, в том числе о трансляции адресов и управлении физической памятью в Windows, см. главу 7. Режим ядра и пользовательский режим Для предотвращения доступа приложений к критически важным данным операционной системы и устранения риска их модификации Windows ис пользует два режима доступа к процессору (даже если он поддерживает более двух режимов): пользовательский (user mode) и ядра (kernel mode). Код
18 ГЛ А В А 1 БЕЗОПАСНОСТЬ приложений работает в пользовательском режиме, тогда как код операци онной системы (например, системные сервисы и драйверы устройств) — в режиме ядра. В режиме ядра предоставляется доступ ко всей системной па мяти и разрешается выполнять любые машинные команды процессора. Пре доставляя операционной системе более высокий уровень привилегий, чем прикладным программам, процессор позволяет разработчикам операцион ных систем реализовать такие архитектуры, которые не дают возможности сбойным приложениям нарушать стабильность работы всей системы. ПРИМЕЧАНИЕ В архитектуре процессора Intel x86 определено четы ре уровня привилегий, или колец (rings), предназначенных для защиты кода и данных системы от случайной или умышленной перезаписи ко дом с меньшим уровнем привилегий. Windows использует уровень при вилегий 0 (или кольцо 0) для режима ядра и уровень привилегий 3 (или кольцо 3) для пользовательского режима. Почему Windows использует только два уровня? Дело в том, что на некоторых из ранее поддержи вавшихся аппаратных платформ (например, Compaq Alpha и Silicon Graphics MIPS) реализовано лишь два уровня привилегий. Хотя каждый Windowsпроцесс имеет свою (закрытую) память, код опе рационной системы и драйверы устройств, работающие в режиме ядра, де лят единое виртуальное адресное пространство. Каждая страница в вирту альной памяти помечается тэгом, определяющим, в каком режиме должен работать процессор для чтения и/или записи данной страницы. Страницы в системном пространстве доступны лишь в режиме ядра, а все страницы в пользовательском адресном пространстве — в пользовательском режиме. Страницы только для чтения (например, содержащие лишь исполняемый код) ни в каком режиме для записи недоступны. Windows не предусматривает никакой защиты системной памяти от ком понентов, работающих в режиме ядра. Иначе говоря, код операционной си стемы и драйверов устройств в режиме ядра получает полный доступ к сис темной памяти и может обходить средства защиты Windows для обращения к любым объектам. Поскольку основная часть кода Windows выполняется в режиме ядра, крайне важно, чтобы компоненты, работающие в этом режи ме, были тщательно продуманы и протестированы. Это также подчеркивает, насколько надо быть осторожным при загрузке драйвера устройства от стороннего поставщика: перейдя в режим ядра, он получит полный доступ ко всем данным операционной системы. Такая уяз вимость стала одной из причин, по которым в Windows введен механизм проверки цифровых подписей драйверов, предупреждающий пользователя о попытке установки неавторизованного (неподписанного) драйвера (под робнее на эту тему см. главу 9). Кроме того, механизм Driver Verifier (вери фикатор драйверов) помогает разработчикам драйверов устройств находить в них ошибки (вызывающие, например, утечку памяти или переполнения буферов). Driver Verifier поясняется в главе 7.
ГЛАВА 9 Концепции и инструменты 19 Как вы увидите в главе 2, прикладные программы могут переключаться из пользовательского режима в режим ядра, обращаясь к системному сервису. Например, Windowsфункции ReadFile в ходе своего выполнения приходит ся вызывать внутреннюю подпрограмму Windows — онато и считывает дан ные из файла. Так как эта подпрограмма обращается к внутрисистемным структурам данных, она должна выполняться в режиме ядра. Переключение из пользовательского режима в режим ядра осуществляется специальной командой процессора. Операционная система перехватывает эту команду, обнаруживает запрос системного сервиса, проверяет аргументы, которые поток передал системной функции, и выполняет внутреннюю подпрограм му. Перед возвратом управления пользовательскому потоку процессор пере ключается обратно в пользовательский режим. Благодаря этому операцион ная система защищает себя и свои данные от возможной модификации пользовательскими процессами. ПРИМЕЧАНИЕ Переключение из пользовательского режима в режим ядра (и обратно) не влияет на планирование потока, так как контекст в этом случае не переключается. О диспетчеризации системных сер висов см. главу 3. Так что ситуация, когда пользовательский поток часть своего времени работает в пользовательском режиме, а часть — в режиме ядра, совершенно нормальна. А поскольку подсистема, отвечающая за поддержку графики и окон, функционирует в режиме ядра, то приложения, интенсивно работаю щие с графикой, большую часть времени действуют в режиме ядра, а не в пользовательском режиме. Самый простой способ проверить это — запус тить приложение вроде Microsoft Paint или Microsoft Pinball и с помощью одного из счетчиков оснастки Performance (Производительность), перечис ленных в таблице 12, понаблюдать за показателями времени работы в поль зовательском режиме и в режиме ядра. Таблица 1-2. Счетчики, позволяющие контролировать время работы в различных режимах Объект: счетчик Описание Processor: % Privileged Time (Процессор: % работы в при вилегированном режиме) Процентная доля времени, в течение которого от дельный процессор (или все процессоры) работал в режиме ядра Processor: % User Time (Процессор: % работы в поль зовательском режиме) Процентная доля времени, в течение которого от дельный процессор (или все процессоры) работал в пользовательском режиме Process: % Privileged Time (Процесс: % работы в приви легированном режиме) Процентная доля времени, в течение которого по токи данного процесса выполнялись в режиме ядра Process: % User Time (Процесс: % работы в пользовательском режиме) Процентная доля времени, в течение которого по токи данного процесса выполнялись в пользова тельском режиме см. след. стр.
20 ГЛ А В А 1 Таблица 1-2. БЕЗОПАСНОСТЬ (продолжение) Объект: счетчик Описание Thread: % Privileged Time (Поток: % работы в привиле гированном режиме) Процентная доля времени, в течение которого данный поток выполнялся в режиме ядра Thread: % User Time (Поток: % работы в пользовательском режиме) Процентная доля времени, в течение которого данный поток выполнялся в пользовательском режиме ЭКСПЕРИМЕНТ: наблюдение за активностью потоков с помощью QuickSlice QuickSlice позволяет в динамике наблюдать за соотношением време ни, проведенного каждым процессом в режиме ядра и в пользователь ском режиме. На диаграмме красная часть столбца отражает количе ство процессорного времени в режиме ядра, а синяя — в пользователь ском режиме. (Хотя в книге эти столбцы воспроизведены в чернобе лом цвете, на самом деле они всегда красные и синие.) Сумма всех по казателей, отображаемых столбцами в окне QuickSlice, должна соот ветствовать 100% процессорного времени. Для запуска QuickSlice щел кните кнопку Start (Пуск), выберите команду Run (Выполнить) и вве дите Qslice.exe (в переменной PATH должен быть указан путь к ресур сам Windows). Например, попробуйте запустить такое интенсивно ис пользующее графику приложение, как Paint (Mspaint.exe). Откройте QuickSlice, расположив его окно рядом с окном Paint, и нарисуйте в Paint несколько кривых. В это время вы сможете наблюдать за выпол нением Mspaint.exe в окне QuickSlice, как показано ниже. Чтобы получить дополнительную информацию о потоках процес са, дважды щелкните имя нужного процесса или соответствующий цветной столбик на диаграмме. Вы увидите список потоков этого про цесса и относительное процессорное время, используемое каждым потоком (в рамках процесса, а не всей системы).
ГЛАВА 9 Концепции и инструменты 21 ЭКСПЕРИМЕНТ: режим ядра и пользовательский режим С помощью оснастки Performance вы можете выяснить, сколько време ни ваша система работает в режиме ядра и в пользовательском режиме. 1. Запустите оснастку Performance (Производительность), открыв ме ню Start (Пуск) и последовательно выбрав команды Programs (Про граммы), Administrative Tools (Администрирование), Performance (Производительность). 2. Щелкните на панели инструментов кнопку Add (Добавить) (на этой кнопке изображен большой знак плюс). 3. Выберите в списке объект Processor (Процессор), щелкните счет чик % Privileged Time (% работы в привилегированном режиме) и, удерживая клавишу Ctrl в нажатом состоянии, щелкните счетчик % User Time (% работы в пользовательском режиме). 4. Щелкните кнопку Add (Добавить), а затем Close (Закрыть). 5. Быстро подвигайте мышью. При этом вы должны заметить всплеск на линии % Privileged Time (рис. 16), который отражает время, за траченное на обслуживание прерываний от мыши, и время, пона добившееся подсистеме поддержки окон на отрисовку графики (эта подсистема, как поясняется в главе 2, работает преимуществен но как драйвер устройства в режиме ядра). 6. Закончив, щелкните на панели инструментов кнопку New Counter Set (Новый набор счетчиков) (или просто закройте оснастку). За той же активностью можно понаблюдать через Task Manager (Диспетчер задач). Просто перейдите в нем на вкладку Performance (Быстродействие), а затем выберите из меню View (Вид) команду Show Kernel Times (Вывод времени ядра). Процент загруженности процес сора отражается зеленым цветом, а процент времени работы в режи ме ядра — красным. см. след. стр.
22 ГЛ А В А 1 БЕЗОПАСНОСТЬ Рис. 1-6. Оснастка Performance, показывающая, как распределяется время работы процессора между двумя режимами — пользовательским и ядра Чтобы увидеть, как сама оснастка Performance использует время в двух режимах, запустите ее снова, но добавьте те же счетчики для объекта Process (Процесс). 1. Если вы закрыли оснастку Performance, снова запустите ее. (Если она уже работает, откройте новый экран, щелкнув на панели инст рументов кнопку New Counter Set.) 2. Щелкните кнопку Add на панели инструментов. 3. Выберите в списке объект Process. 4. Выберите счетчики % Privileged Time и % User Time. 5. В списке экземпляров объекта выберите все процессы (кроме про цесса _Total). 6. Щелкните кнопку Add, а затем Close. 7. Быстро подвигайте мышью. 8. Нажмите комбинацию клавиш Ctrl+H для активизации режима вы деления — текущий выбранный счетчик будет выделен белым цве том в Windows 2000 и черным в Windows XP или Windows Server 2003. 9. Прокрутите список всех счетчиков в нижней части окна оснастки, чтобы определить процессы, потоки которых выполнялись при перемещении мыши, и обратите внимание на то, в каком режиме они выполнялись — пользовательском или ядра. Вы должны заметить, как значения счетчиков для процесса оснаст ки Performance — ищите mmc в колонке Instance (Экземпляр) — рез ко увеличиваются при перемещении мыши, поскольку код приложе ния выполняется в пользовательском режиме, а вызываемые им Win dowsфункции — в режиме ядра. Вы также заметите, что при переме щении мыши увеличивается активность работы в режиме ядра пото
ГЛАВА 9 Концепции и инструменты 23 ка процесса csrss. Он представляет поток необработанного ввода (raw input thread) подсистемы Windows, принимающий ввод от клавиату ры и мыши и передающий его процессу, к которому он подключен. (Подробнее о системных потоках см. главу 2.) Наконец, процесс с име нем Idle, потоки которого, как вы убедитесь, тратят почти 100% свое го времени в режиме ядра, на самом деле не является процессом. Это лжепроцесс, используемый для учета тактов процессора в состоянии простоя. Таким образом, когда Windows нечего делать, она предается этому занятию в режиме ядра. Terminal Services и несколько сеансов Terminal Services (службы терминала) обеспечивают в Windows поддержку нескольких интерактивных сеансов пользователей на одной системе. С по мощью Terminal Services удаленный пользователь может установить сеанс на другой машине, зарегистрироваться на ней и запускать приложения на сер вере. Сервер предоставляет клиенту графический пользовательский интер фейс (GUI), а клиент возвращает серверу пользовательский ввод. (Это отли чается от того, как ведет себя X Windows на UNIXсистемах, где разрешает ся выполнять индивидуальные приложения на сервере, а клиенту предостав ляется удаленный дисплей, так как удаленным является весь сеанс пользова теля — не только одно приложение.) Первый сеанс входа на физической консоли компьютера считается кон сольным сеансом, или нулевым сеансом (session zero). Дополнительные се ансы можно создать с помощью программы соединения с удаленным рабо чим столом (Mstsc.exe), а в Windows XP — через механизм быстрого пере ключения пользователей (об этом позже). Возможность создания удаленного сеанса поддерживается Windows 2000 Server, но не Windows 2000 Professional. Windows XP Professional позволяет одному удаленному пользователю подключаться к машине, однако если кто то начинает процедуру входа в консоли, рабочая станция блокируется (т. е. систему можно использовать либо локально, либо удаленно, но не и то, и другое одновременно). Windows 2000 Server и Windows Server 2003 поддерживают два одновремен ных удаленных сеанса. (Это упрощает удаленное управление, например облег чает применение инструментов, требующих от администратора входа на уда ленный компьютер.) Windows 2000 Advanced Server, Datacenter Server и все из дания Windows Server 2003 способны поддерживать более двух сеансов одно временно при условии правильного лицензирования и настройки системы в качестве сервера терминала. Хотя Windows XP Home и Professional не поддерживают несколько удален ных подключений к рабочему столу, они все же поддерживают несколько сеансов, созданных локально через механизм быстрого переключения поль зователей. (Этот механизм отключается в Windows XP Professional, если си стема присоединяется к домену.) Когда пользователь выбирает выключение
24 ГЛ А В А 1 БЕЗОПАСНОСТЬ своего сеанса вместо выхода [например, последовательным выбором Start (Пуск), Log Off (Выход из системы) и Switch User (Смена пользователя) или нажатием клавиши L при одновременном удерживании клавиши Windows], текущий сеанс (т. е. процессы, выполняемые в этом сеансе, и все структуры данных, глобальные для сеанса и описывающие его) остается в системе, а Windows возвращается к основному окну входа. Если в систему входит но вый пользователь, создается новый сеанс. Для приложений, которым нужно знать, выполняются ли они в сеансе сервера терминала, предназначен набор Windows APIфункций, позволяю щих программно распознавать такую ситуацию и контролировать различ ные аспекты служб терминала. (Детали см. в Platform SDK.) В главе 2 кратко описывается, как создаются сеансы, и проводится не сколько экспериментов, показывающих, как просматривать информацию о сеансе с помощью различных инструментов, включая отладчик ядра. В раз деле «Диспетчер объектов» главы 3 поясняется, как создается сеансовый эк земпляр системного пространства имен для объектов и как приложения могут узнавать о других своих экземплярах в той же системе. Наконец, в гла ве 7 рассказывается, как диспетчер памяти настраивает данные, глобальные для сеанса, и управляет ими. Объекты и описатели В операционной системе Windows объект — это единственный экземпляр периода выполнения (runtime instance) статически определенного типа объекта. Тип объекта состоит из общесистемного типа данных, функций, оперирующих экземплярами этого типа данных, и набора атрибутов. Если вы пишете Windowsприложения, вам наверняка знакомы такие объекты, как процесс, поток, файл и событие, — продолжать можно еще долго. Эти объек ты базируются на объектах более низкого уровня, создаваемых и управляе мых Windows. В Windows процесс является экземпляром объекта типа «про цесс», файл — экземпляром объекта типа «файл» и т. д. Атрибут объекта (object attribute) — это поле данных в объекте, частич но определяющее состояние этого объекта. Например, объект типа «про цесс», имеет атрибуты, в число которых входят идентификатор процесса, базовый приоритет и указатель на объект маркера доступа. Методы объекта (средства для манипулирования объектами) обычно считывают или изменя ют какиелибо атрибуты. Так, метод open процесса мог бы принимать иден тификатор процесса и возвращать указатель на этот объект. ПРИМЕЧАНИЕ Не путайте параметр ObjectAttributes, предоставляемый вызывающей программой при создании объекта через Windows API или его родные сервисы, с термином «атрибуты объекта», имеющим более общий смысл. Самое главное различие между объектом и обычной структурой данных заключается в том, что внутренняя структура объекта скрыта. Чтобы полу чить данные из объекта или записать в него какуюто информацию, вы долж
ГЛАВА 9 Концепции и инструменты 25 ны вызвать его сервис. Прямое чтение или изменение данных внутри объек та невозможно. Тем самым реализация объекта отделяется от кода, который просто использует его, а это позволяет менять реализацию объекта, не мо дифицируя остальной код. Объекты очень удобны для поддержки четырех важных функций опера ционной системы: 쐽 присвоения понятных имен системным ресурсам; 쐽 разделения ресурсов и данных между процессами; 쐽 защиты ресурсов от несанкционированного доступа; 쐽 учета ссылок (благодаря этому система узнает, когда объект больше не используется, и автоматически уничтожает его). Не все структуры данных в Windows являются объектами. В объекты по мещаются лишь те данные, которые нужно разделять, защищать, именовать или делать доступными программам пользовательского режима (через сис темные сервисы). Структуры, используемые только одним из компонентов операционной системы для поддержки какихто внутренних функций, к объектам не относятся. Подробнее объекты и их описатели (ссылки на эк земпляр объекта) рассматриваются в главе 3. Безопасность Windows с самого начала разрабатывалась как защищенная система, удовлет воряющая требованиям различных правительственных и промышленных стандартов безопасности, например спецификации Common Criteria for Infor mation Technology Security Evaluation (CCITSE). Подтверждение правитель ством рейтинга безопасности операционной системы позволяет ей конкури ровать в сферах, требующих повышенной защиты. Разумеется, многим из этих требований должна удовлетворять любая многопользовательская система. Базовые возможности защиты в Windows таковы: избирательная защита любых разделяемых системных объектов (файлов, каталогов, процессов, потоков и т. д.), аудит безопасности (для учета пользователей и инициируе мых ими операций), аутентификация паролей при входе и предотвращение доступа одного из пользователей к неинициализированным ресурсам (на пример, к памяти или дисковому пространству), освобожденным другим пользователем. Windows поддерживает два вида контроля доступа к объектам. Первый из них — управление избирательным доступом (discretionary access control) — является механизмом, который как раз и связывается большинством пользо вателей с защитой. Это метод, при котором владельцы объектов (например, файлов или принтеров) разрешают или запрещают доступ к ним для других пользователей. При входе пользователь получает набор удостоверений защи ты (security credentials), или контекст защиты (security context). Когда он пы тается обратиться к объекту, его контекст защиты сверяется со списком управ ления доступом (access control list, ACL) для данного объекта, чтобы опреде лить, имеет ли он разрешение на выполнение запрошенной операции.
26 ГЛ А В А 1 БЕЗОПАСНОСТЬ Второй метод — управление привилегированным доступом (privileged access control) — необходим в тех случаях, когда управления избирательным досту пом недостаточно. Данный метод гарантирует, что пользователь сможет обра титься к защищенным объектам, даже если их владелец недоступен. Например, если какойто сотрудник увольняется из компании, администратору нужно получить доступ к файлам, которые могли быть доступны только бывшему со труднику. В таких случаях Windows позволяет администратору стать владель цем этих файлов и при необходимости управлять правами доступа к ним. Защита пронизывает весь интерфейс Windows API. Подсистема Windows реализует защиту на основе объектов точно так же, как и сама операцион ная система. При первой попытке доступа приложения к общему (разделяе мому) объекту подсистема Windows проверяет, имеет ли это приложение соответствующие права. Если проверка завершается успешно, подсистема Windows разрешает приложению доступ. Подсистема Windows реализует защиту для общих объектов, часть из ко торых построена на основе родных объектов Windows. К Windowsобъектам относятся объекты рабочего стола, меню, окна, файлы, процессы, потоки и ряд синхронизирующих объектов. Детальное описание защиты в Windows см. в главе 8. Реестр Если вы работали хоть с какойнибудь операционной системой Windows, то, вероятно, слышали о реестре или даже просматривали его. Рассказать о внут реннем устройстве Windows, не упоминая реестр, вряд ли возможно, так как это системная база данных с информацией, необходимой для загрузки и конфигурирования системы; в ней содержатся общесистемные параметры, контролирующие работу Windows, база данных защиты и конфигурацион ные настройки, индивидуальные для каждого пользователя. Кроме того, реестр — это окно, через которое можно заглянуть в пере менные системные данные, чтобы, например, выяснить текущее состояние аппаратной части системы (какие драйверы устройств загружены, какие ре сурсы они используют и т. д.) или значения счетчиков производительности Windows. Счетчики производительности, которые на самом деле в реестре не хранятся, доступны через функции реестра (см. главу 4). Хотя у многих пользователей и администраторов Windows никогда не возникает необходимости работать непосредственно с реестром (бóльшую часть параметров можно просматривать или модифицировать с помощью стандартных административных утилит), он все же является источником полезной информации о внутренних структурах данных Windows, так как содержит множество параметров, влияющих на быстродействие и поведе ние системы. (Будьте крайне осторожны, напрямую изменяя параметры ре естра: любые изменения могут отрицательно сказаться на быстродействии или, что гораздо хуже, привести к краху системы.) Ссылки на различные разделы реестра, относящиеся к описываемым ком понентам, будут встречаться на протяжении всей книги. Большинство таких
ГЛАВА 9 Концепции и инструменты 27 разделов находится в ветви HKEY_LOCAL_MACHINE, которую мы сокращенно называем HKLM. Подробнее о реестре и его внутренней структуре см. главу 4. Unicode Windows отличается от большинства других операционных систем тем, что в качестве внутреннего формата для хранения и обработки текстовых строк использует Unicode. Unicode — это стандартная кодировка, которая поддер живает многие известные в мире наборы символов и в которой каждый сим вол представляется 16битным (двухбайтовым) кодом. (Подробнее о Unicode см. www.unicode.org и документацию на компактдисках MSDN Library.) Поскольку многие приложения имеют дело с 8битными (однобайтовы ми) ANSIсимволами, Windowsфункции, принимающие строковые парамет ры, существуют в двух версиях: для Unicode и для ANSI. В Windows 95, Win dows 98 и Windows ME реализована лишь часть Unicodeверсий Windows функций, поэтому приложения, рассчитанные на выполнение как в одной из этих операционных систем, так и в NTподобных Windows, обычно ис пользуют ANSIверсии функций. Если вы вызываете ANSIверсию Windows функции, входные строковые параметры перед обработкой системой пре образуются в Unicode, а выходные — из Unicode в ANSI (перед возвратом приложению). Таким образом при использовании в Windows устаревшего сервиса или фрагмента кода, написанного в расчете на ANSIстроки, эта опе рационная система будет вынуждена преобразовывать ANSIсимволы в Uni code. Однако Windows никогда не преобразует данные внутри файлов — ре шения о том, в какой кодировке хранить текстовую информацию в файлах, принимают лишь сами приложения. В предыдущих версиях Windows ее азиатский и ближневосточный выпус ки представляли собой надмножество базовых американского и европейс кого выпусков, в которые включались дополнительные Windowsфункции для обработки более сложных раскладок клавиатур и принципов ввода тек ста (например, набора текста справа налево). Начиная с Windows 2000, все языковые выпуски содержат одинаковые Windowsфункции. Единая для всех стран двоичная кодовая база Windows способна поддерживать множество языков за счет простого добавления нужных компонентов языковой поддер жки. Используя эти Windowsфункции, разработчики могут создавать уни версальные приложения, способные работать со множеством языков. Изучение внутреннего устройства Windows Хотя большая часть информации, представленная в этой книге, получена при чтении исходного кода Windows и общении с разработчиками, вы не обяза ны принимать все на веру. Многие детали внутреннего устройства Windows можно вытащить на свет с помощью самых разнообразных средств, в том числе поставляемых с Windows, входящих в Windows Support Tools и ресур сы Windows, а также с использованием отладочных средств самой Windows. Чуть позже мы вкратце рассмотрим эти пакеты инструментальных средств.
28 ГЛ А В А 1 БЕЗОПАСНОСТЬ Чтобы упростить вам исследование внутреннего устройства Windows, мы часто даем в книге врезки «Эксперимент» с пошаговыми инструкциями для изучения какоголибо аспекта поведения Windows. (Вы уже видели такие врезки в этой главе.) Советуем проводить эти эксперименты — это позволит увидеть в действии многие вещи, о которых рассказывается в книге. В таблице 13 перечислены все используемые нами инструменты и утилиты. Таблица 1-3. Средства просмотра внутренней информации Windows Утилита Имя образа Источник Startup Programs Viewer AUTORUNS www.sysinternals.com Dependency Walker DEPENDS Support Tools, Platform SDK DLL List LISTDLLS www.sysinternals.com EFS Information Dumper EFSDUMP www.sysinternals.com File Monitor FILEMON www.sysinternals.com Global Flags GFLAGS Support Tools Handle Viewer HANDLE www.sysinternals.com Junction JUNCTION www.sysinternals.com Отладчики ядра WINDBG, KD Средства отладки, Platform SDK, Windows DDK Live Kernel Debugging LIVEKD Ресурсы Windows Object Viewer WINOBJ www.sysinternals.com Open Handles OH Ресурсы Windows Page Fault Monitor PFMON Support Tools, Ресурсы Windows, Platform SDK Pending File Moves PENDMOVES www.sysinternals.com Performance PERFMON.MSC Утилита Windows PipeList PIPELIST www.sysinternals.com Pool Monitor POOLMON Support Tools, Windows DDK Process Explorer PROCEXP www.sysinternals.com Get SID PSGETSID www.sysinternals.com Process Statistics PSTAT Support Tools, Ресурсы Windows, Platform SDK, www.reskit.com Process Viewer PVIEWER (в Support Tools) или PVIEW (в Platform SDK) Support Tools, Platform SDK Quick Slice QSLICE Ресурсы Windows Registry Monitor REGMON www.sysinternals.com Service Control SC Windows XP, Platform SDK, Ресурсы Windows Task (Process) List TLIST Средства отладки Task Manager TASKMGR Утилита Windows TDImon TDIMON www.sysinternals.com
ГЛАВА 9 Концепции и инструменты 29 Оснастка Performance Мы часто ссылаемся на этот инструмент, доступный через папку Administrative Tools (Администрирование) в меню Start (Пуск) или через Control Panel (Па нель управления). Оснастка Performance (Производительность) предназначе на для мониторинга системы, просмотра журналов, в которых регистрируют ся значения счетчиков производительности, и оповещения при достижении заданных пороговых значений тех или иных счетчиков. Говоря об оснастке Performance, мы подразумеваем лишь ее функцию системного мониторинга. Оснастка Performance способна сообщить о том, как работает система, го раздо больше, чем любая другая, отдельно взятая утилита. Она предусматрива ет сотни счетчиков для различных объектов. По каждому счетчику можно по лучить краткое описание. Чтобы увидеть описание, выберите счетчик в окне Add Counters (Добавить счетчики) и щелкните кнопку Explain (Объяснение). Или откройте справочный файл Performance Counter Reference с компактдис ка «Ресурсы Windows». Информацию о том, как интерпретировать показания счетчиков для устранения «узких мест» в системе или для планирования про пускной способности сервера, см. раздел «Performance Monitoring» в книге «Windows 2000 Server Operations Guide» из набора Windows 2000 Server Resource Kit. Для Windows XP и Windows Server 2003 см. документацию Performance Counters Reference в Windows Server 2003 Resource Kit. Заметьте, что все счетчики производительности Windows доступны про граммным путем. Краткое описание соответствующих компонентов см. в разделе «HKEY_PERFORMANCE_DATA» главы 4. Windows Support Tools Windows Support Tools включают около 40 утилит, полезных в администри ровании систем на базе Windows и устранении неполадок в них. Многие из этих утилит раньше были частью ресурсов Windows NT 4. Вы можете установить Support Tools, запустив Setup.exe из папки \Support\ Tools в дистрибутиве любого издания Windows. Support Tools одинаковы в Win dows 2000 Professional, Server, Advanced Server и Datacenter Server, а для Windows XP, равно как и для Windows Server 2003, существует своя версия Support Tools. Ресурсы Windows Ресурсы Windows (Windows Resource Kits) расширяют Support Tools, предла гая дополнительные утилиты для администрирования и поддержки систем. Утилиты Windows Server 2003 Resource Kit можно бесплатно скачать с www.microsoft.com (выполните поиск по ключевым словам «resource kit tools»). Их можно установить в Windows XP или Windows Server 2003. Ресурсы Windows 2000 существуют в двух изданиях: Windows 2000 Pro fessional Resource Kit и Windows 2000 Server Resource Kit* (самая последняя * Последнее издание переведено на русский язык издательством «Русская Редак ция» и выпущено в 2001 г. в виде серии «Ресурсы Microsoft Windows 2000 Server», которая включает 4 книги: «Сети TCP/IP», «Сопровождение сервера», «Распреде ленные системы» и «Межсетевое взаимодействие». — Прим. перев.
30 ГЛ А В А 1 БЕЗОПАСНОСТЬ его версия — Supplement 1). Хотя последний набор представляет собой над множество первого и может быть установлен на системах с Windows 2000 Professional, утилиты, входящие только в Windows 2000 Server Resource Kit, ни в одном из наших экспериментов не используются. В отличие от утилит Windows Server 2003 Resource Kit эти утилиты нельзя скачать бесплатно. Однако Windows 2000 Server Resource Kit поставляется с подписками на MSDN и TechNet. Отладка ядра Отладка ядра подразумевает изучение внутренних структур данных ядра и/ или пошаговый проход по функциям в ядре. Это полезный способ исследо вания внутреннего устройства Windows, потому что он позволяет увидеть внутрисистемную информацию, недоступную при использовании каких либо других способов, и получить более ясное представление о схеме выпол нения кода внутри ядра. Отладку ядра можно проводить с помощью разнообразных утилит: Win dows Debugging Tools от Microsoft, LiveKD от www.sysinternals.com или SoftIce от Compuware NuMega. Прежде чем описывать эти средства, давайте рас смотрим файл, который понадобится при любом виде отладки ядра. Символы для отладки ядра Файлы символов (symbol files) содержат имена функций и переменных. Они генерируются компоновщиком (linker) и используются отладчиками для ссылки и отображения этих имен в сеансе отладки. Эта информация обыч но не хранится в двоичном образе, потому что она не нужна при выполне нии кода. То есть двоичные образы имеют меньший размер и работают бы стрее. Но это означает, что вам нужно позаботиться о том, чтобы у отладчи ка был доступ к файлам символов, сопоставляемым с образами, на которые вы ссылаетесь в сеансе отладки. Для изучения внутренних структур данных ядра Windows (например, списка процессов, блоков потока, списка загруженных драйверов, информа ции об использовании памяти и т. д.) вам понадобятся подходящие файлы символов как минимум для образа ядра, Ntoskrnl.exe. (Подробнее этот файл рассматривается в разделе «Обзор архитектуры» главы 2.) Файлы таблиц сим волов должны соответствовать версии образа. Так, если вы установили Win dows Service Pack или какоето оперативное исправление, то должны полу чить обновленные файлы символов хотя бы для образа ядра; иначе возник нет ошибка изза неправильной контрольной суммы при попытке отладчи ка ядра загрузить их. Хотя можно скачать и установить символы для разных версий Windows, обновленные символы для оперативных исправлений доступны не всегда. Самый простой способ получить подходящую версию символов для отлад ки — обратиться к Microsoftсерверу символов с запросом, в котором исполь зуется специальный синтаксис пути к символам, как в отладчике. Например,
ГЛАВА 9 Концепции и инструменты 31 следующий путь к символам заставляет средства отладки загружать требуе мые символы с Интернетсервера символов и сохранять локальную копию в папке c:\symbols: srv*c:\symbols*http://msdl.microsoft.com/download/symbols Подробные инструкции о том, как пользоваться сервером символов, см. в справочном файле Debugging Tools или на Webстранице www.microsoft. com/whdc/ddk/debugging/symbols.mspx. Windows Debugging Tools Пакет Windows Debugging Tools содержит дополнительные средства отлад ки, применяемые в этой книге для исследования внутреннего устройства Windows. Вы найдете их последние версии по ссылке www.microsoft.com/ whdc/ddk/debugging. Эти средства можно использовать для отладки как про цессов пользовательского режима, так и ядра (см. следующую врезку). ПРИМЕЧАНИЕ Windows Debugging Tools регулярно обновляются и вы пускаются независимо от версий операционной системы Windows, по этому почаще проверяйте наличие новых версий отладочных средств. Отладка в пользовательском режиме Средства отладки можно подключать к процессу пользовательского режима, чтобы исследовать и/или изменять память процесса. Суще ствует два варианта подключения к процессу: 쐽 Invasive (инвазивный) Если не указано иное, то, когда вы под ключаетесь к выполняемому процессу, Windowsфункция DebugAc tiveProcess устанавливает соединение между отладчиком и отлажи ваемым процессом. Это позволяет изучать и/или изменять память процесса, устанавливать точки прерывания (breakpoints) и выпол нять другие отладочные действия. В Windows 2000 при завершении отладчика закрывается и отлаживаемый процесс. Однако в Windows XP отладчик можно отключать, не уничтожая целевой процесс. 쐽 Noninvasive (неинвазивный) В этом случае отладчик просто открывает процесс через функцию OpenProcess. Он не подключает ся к процессу как отладчик. Это позволяет изучать и/или изменять па мять целевого процесса, но не дает возможности устанавливать точ ки прерывания. Преимущество данного варианта в том, что в Windows 2000 можно закрыть отладчик, не завершая целевой процесс. С помощью отладочных средств также можно открывать файлы дампов процессов пользовательского режима. Что представляют со бой эти файлы, поясняется в главе 3 в разделе по диспетчеризации исключений. Microsoft предлагает отладчики ядра в двух версиях: командной строки (Kd.exe) и с графическим пользовательским интерфейсом (Windbg.exe). Оба
32 ГЛ А В А 1 БЕЗОПАСНОСТЬ инструмента предоставляют одинаковый набор команд, так что выбор кон кретной утилиты определяется сугубо личными пристрастиями. С помощью этих средств вы можете вести отладку ядра в трех режимах. 쐽 Откройте файл дампа, полученный в результате краха системы с Windows (подробнее о таких дампах см. главу 14). 쐽 Подключитесь к работающей системе и изучите ее состояние (или по ставьте точки прерывания, если вы отлаживаете код драйвера устройства). Эта операция требует двух компьютеров — целевого и управляющего. Целевой считается отлаживаемая система, а управляющей — та, в которой выполняется отладчик. Целевая система может быть либо локальной (со единенной с управляющей нульмодемным кабелем или по IEEE 1394), либо удаленной (соединенной по модему). Вы должны загрузить целевую систему со спецификатором /DEBUG, или нажать при загрузке клавишу F8 и выбрать Debug Mode, или добавить соответствующую запись в файл Boot.ini. 쐽 В случае Windows XP и Windows Server 2003 подключитесь к локальной системе и изучите ее состояние. Это называется локальной отладкой ядра. Чтобы инициировать такую отладку ядра, выберите в меню File ко манду Kernel Debug, перейдите на вкладку Local и щелкните OK. Пример окна с выводом показан на рис. 17. Некоторые команды отладчика ядра в этом режиме не работают (например, просмотр стеков ядра и создание дампа памяти командой .dump невозможны). Однако вы можете пользо ваться бесплатной утилитой LiveKd с сайта www.sysinternals.com в тех слу чаях, когда родные средства локальной отладки не срабатывают (см. сле дующий раздел). Рис. 1-7. Локальная отладка ядра
ГЛАВА 9 Концепции и инструменты 33 Подключившись в режиме отладки ядра, вы можете использовать одну из многих команд расширения отладчика (команды, которые начинаются с «!») для вывода содержимого внутренних структур данных, например потоков, процессов, пакетов запроса на вводвывод и информации, связанной с уп равлением памятью. Команды отладчика ядра и их вывод будут обсуждаться при рассмотрении соответствующей тематики. А пока добавим, что коман да dt (display type) может форматировать свыше 400 структур ядра благода ря тому, что файлы символов ядра для Windows 2000 Service Pack 3, Windows XP и Windows Server 2003 содержат информацию о типах, которая и позво ляет отладчику форматировать структуры. ЭКСПЕРИМЕНТ: отображение информации о типах для структур ядра Чтобы вывести список структур ядра, чья информация о типах вклю чена в символы ядра, наберите dt nt!_* в отладчике ядра. Пример час ти вывода показан ниже: lkd> dt nt!_* nt!_LIST_ENTRY nt!_LIST_ENTRY nt!_IMAGE_NT_HEADERS nt!_IMAGE_FILE_HEADER nt!_IMAGE_OPTIONAL_HEADER nt!_IMAGE_NT_HEADERS nt!_LARGE_INTEGER Команда dt позволяет искать конкретные структуры по шаблонам. Например, если вы ищете имя структуры для объекта прерывания (in terrupt object), введите dt nt!_*interrupt*: lkd> dt nt!_*interrupt* nt!_KINTERRUPT nt!_KINTERRUPT_MODE После этого с помощью команды dt можно отформатировать эту структуру: lkd> dt nt!_kinterrupt nt!_KINTERRUPT +0x000 Type : +0x002 Size : +0x004 InterruptListEntry +0x00c ServiceRoutine : +0x010 ServiceContext : +0x014 SpinLock : +0x018 TickCount : +0x01c ActualLock : +0x020 DispatchAddress : +0x024 Vector : +0x028 Irql : Int2B Int2B : _LIST_ENTRY Ptr32 Ptr32 Void Uint4B Uint4B Ptr32 Uint4B Ptr32 Uint4B UChar см. след. стр.
34 ГЛ А В А 1 +0x029 +0x02a +0x02b +0x02c +0x02d +0x030 +0x034 +0x038 +0x03c БЕЗОПАСНОСТЬ SynchronizeIrql FloatingSave Connected Number ShareVector Mode ServiceCount DispatchCount DispatchCode : : : : : : : : : UChar UChar UChar Char UChar _KINTERRUPT_MODE Uint4B Uint4B [106] Uint4B Заметьте, что по умолчанию dt не показывает подструктуры (структу ры внутри структур). Для рекурсивного прохода по подструктурам, ис пользуйте ключ –r. Например, указав этот ключ для отображения объек та ядра «прерывание», вы увидите формат структуры _LIST_ENTRY, хра нящейся в поле InterruptListEntry: lkd> dt nt!_kinterrupt –r nt!_KINTERRUPT +0x000 Type : +0x002 Size : +0x004 InterruptListEntry +0x000 Flink +0x000 Flink +0x004 Blink +0x004 Blink +0x000 Flink +0x004 Blink +0x00c ServiceRoutine : Int2B Int2B : : Ptr32 : Ptr32 : Ptr32 : Ptr32 : Ptr32 : Ptr32 Ptr32 _LIST_ENTRY _LIST_ENTRY _LIST_ENTRY _LIST_ENTRY В справочном файле Windows Debugging Tools объясняется, как устанав ливать и использовать отладчики ядра. Дополнительные сведения о приме нении отладчиков ядра, предназначенных в основном разработчикам драй веров устройств, см. в документации Windows DDK. Есть также несколько полезных статей в Knowledge Base по отладчикам ядра. Выполните поиск по ключевому слову «debugref» в Windows Knowledge Base (онлайновой базе данных технических статей) на support.microsoft.com. Утилита LiveKd LiveKd — бесплатная утилита от www.sysinternals.com, которая позволяет ис пользовать стандартные отладчики ядра от Microsoft на «живой» системе — без подключения второго компьютера. Если встроенная поддержка локаль ной отладки ядра действует только в Windows XP и Windows Server 2003, то LiveKd обеспечивает такую отладку в Windows NT 4.0, Windows 2000, Win dows XP и Windows Server 2003. LiveKd запускается точно так же, как Windbg или Kd. Эта утилита переда ет любые указанные параметры командной строки выбранному вами отлад чику. По умолчанию LiveKd запускает отладчик Kd. Для запуска GUIотлад
ГЛАВА 9 Концепции и инструменты 35 чика (Windbg), задайте ключ –w. Чтобы получить подсказку по ключам Live Kd, укажите ключ –?. LiveKd предоставляет отладчику смоделированный файл аварийного дам па (crash dump), поэтому вы можете выполнять в LiveKd любые операции, поддерживаемые для аварийных дампов. Поскольку LiveKd хранит смодели рованный дамп в физической памяти, отладчик ядра может попасть в такую ситуацию, в которой структуры данных находятся в рассогласованном со стоянии в процессе их изменения системой. При каждом запуске отладчик получает снимок состояния системы; если вы хотите обновить этот снимок, выйдите из отладчика (командой q), и LiveKd спросит вас, нужно ли начать сначала. Если отладчик, выводя информацию на экран, вошел в цикл, нажми те клавиши Ctrl+C, чтобы прервать вывод, выйдите из отладчика и запусти те его снова. Если он завис, нажмите клавиши Ctrl+Break, которые заставят завершить процесс отладчика. После этого вам будет предложено снова за пустить отладчик. SoftICE Еще один инструмент, не требующий двух машин для прямой отладки яд ра, — SoftICE, который можно приобрести у Compuware NuMega (www.com puware.com). SoftICE обладает во многом теми же возможностями, что и Win dows Debugging Tools, но поддерживает переход между кодом пользова тельского режима и режима ядра. Он также поддерживает DLLмодули рас ширения ядра Microsoft, поэтому большинство команд, описываемых нами в книге, будут работать и в SoftICE. На рис. 18 показан пользовательский интерфейс SoftICE, появляющийся при нажатии клавиши активизации Soft ICE (по умолчанию — Ctrl+D); этот интерфейс представляет собой окно на рабочем столе системы, в которой он выполняется. Рис. 1-8. Интерфейс SoftICE
36 ГЛ А В А 1 БЕЗОПАСНОСТЬ Platform Software Development Kit (SDK) Platform SDK является частью подписки на MSDN уровня Professional и выше; кроме того, его можно бесплатно скачать с msdn.microsoft.com. В нем содер жатся документация, заголовочные файлы и библиотеки C, необходимые для компиляции и компоновки Windowsприложений. (Microsoft Visual C++ тоже поставляется с этими файлами, но их версии в Platform SDK всегда более новые и соответствуют самым последним версиям операционных систем Windows.) В Platform SDK для нас будут представлять интерес заголовочные файлы Windows API (\Program Files\Microsoft SDK\Include) и несколько ути лит (Pfmon.exe, Pstat.exe, Pview.exe, Vadump.exe и Winobj.exe). Некоторые из них также поставляются с Ресурсами Windows и Support Tools. Наконец, от дельные утилиты поставляются с Platform SDK и MSDN Library как примеры исходного кода. Device Driver Kit (DDK) Windows DDK является частью подписки на MSDN уровня Professional и выше, но в отличие от Platform SDK его нельзя скачать бесплатно (впрочем, можно заказать CDROM за минимальную цену). Документация Windows DDK включается в MSDN Library. Хотя DDK нацелен на разработчиков драйверов устройств, он представ ляет собой богатый источник информации о внутреннем устройстве Win dows. Например, в главе 9 мы даем описание архитектуры подсистемы вво давывода, модели драйверов и структур данных базовых драйверов уст ройств, но не вдаемся в детали соответствующих функций ядра. А в докумен тации Windows DDK исчерпывающе описаны все внутрисистемные функ ции и драйверы устройств. Кроме документации в DDK входят заголовочные файлы, определяющие ключевые внутренние структуры данных, константы и интерфейсы многих внутрисистемных подпрограмм (в частности, обратите внимание на файлы Ntddk.h и Wdm.h). Эти файлы очень полезны в исследовании внутренних структур данных Windows с помощью отладчика ядра, так как мы даем лишь обобщенное описание внутренних структур, а в заголовочных файлах мож но найти все подробности о каждом поле таких структур. В DDK также де тально поясняются некоторые структуры данных (вроде заголовков для дис петчера объектов, блоки ожидания, события, мутанты, семафоры и др.). Поэтому, если вы хотите поглубже покопаться в подсистеме вводавыво да и в модели драйверов, читайте документацию DDK (особенно руководства KernelMode Driver Architecture Design Guide и Reference). Еще один превос ходный источник — книга Уолта Они (Walt Oney) «Programming the Microsoft Windows Driver Model, Second Edition» (Microsoft Press). Утилиты Sysinternals Во многих экспериментах мы используем свободно распространяемые ути литы, которые можно скачать с www.sysinternals.com. Большинство этих ути
ГЛАВА 9 Концепции и инструменты 37 лит написано Марком Руссиновичем, соавтором этой книги. К наиболее по пулярным утилитам относятся Process Explorer, Filemon и Regmon. Многие из этих утилит требуют установки и запуска драйверов устройств, работающих в режиме ядра, а значит, вам понадобятся полномочия администратора. Резюме В этой главе вы познакомились с ключевыми техническими концепциями и терминами Windows, которые будут использоваться во всей книге. Вы так же получили первое представление о многих полезных инструментах, по зволяющих изучать внутренние структуры данных Windows. Теперь вы го товы вместе с нами приступить к исследованию внутреннего устройства системы. Мы начнем с общего обзора архитектуры системы и ее основных компонентов.
Г Л А В А 2 Архитектура системы Теперь, познакомившись с необходимыми терминами, понятиями и инстру ментами, мы можем рассмотреть задачи, которые ставились при разработ ке операционной системы Microsoft Windows. В этой главе описывается об щая архитектура системы: ключевые компоненты, принципы их взаимодей ствия и контекст выполнения. Чтобы получить базовое представление о внутреннем устройстве Windows, давайте сначала обсудим требования и цели, обусловившие структуру и спецификацию этой системы. Требования и цели проекта Характеристики Windows NT в 1989 году определялись следующими требо ваниями. Операционная система должна: 쐽 быть истинно 32разрядной, реентерабельной, поддерживать вытесняю щую многозадачность и работу с виртуальной памятью; 쐽 работать на разных аппаратных платформах; 쐽 хорошо масштабироваться в системах с симметричной мультипроцес сорной обработкой; 쐽 быть распределенной вычислительной платформой, способной высту пать в роли как клиента сети, так и сервера; 쐽 поддерживать большинство существующих 16разрядных приложений MSDOS и Microsoft Windows 3.1; 쐽 отвечать требованиям правительства к соответствию POSIX 1003.1; 쐽 отвечать требованиям правительства и промышленности к безопаснос ти операционных систем; 쐽 обеспечивать простоту адаптации к глобальному рынку за счет поддер жки Unicode. Для создания системы, соответствующей предъявленным требованиям, нужно было принять тысячи решений. Поэтому перед командой разработ чиков Windows NT на начальном этапе проекта были поставлены следующие цели. 쐽 Расширяемость Код должен быть написан так, чтобы системы можно было легко наращивать и модифицировать по мере изменения потреб ностей рынка.
ГЛАВА 9 Архитектура системы 39 쐽 Переносимость Система должна работать на разных аппаратных ар хитектурах и обладать способностью к сравнительно легкому переносу на новые аппаратные архитектуры, если на рынке возникнет такая по требность. 쐽 Отказоустойчивость и надежность Система должна быть защищен ной как от внутренних сбоев, так и от внешних деструктивных действий. У приложений не должно быть возможности нарушить работу операци онной системы или других приложений. 쐽 Совместимость Хотя Windows NT должна расширить существующую технологию, ее пользовательский интерфейс и API должны быть совмес тимы с предыдущими версиями Windows и MSDOS. Она также должна уметь взаимодействовать с другими системами вроде UNIX, OS/2 и NetWare. 쐽 Производительность С учетом ограничений, налагаемых поставлен ными целями, система должна быть максимально быстрой и отзывчивой независимо от аппаратной платформы. По мере изучения деталей внутренней структуры Windows вы увидите, насколько успешно были реализованы все эти требования и цели. Но сна чала мы рассмотрим общую модель Windows и сравним ее с другими совре менными операционными системами. Модель операционной системы В большинстве многопользовательских операционных систем приложения отделены от собственно операционной системы: код ее ядра выполняется в привилегированном режиме процессора (называемом режимом ядра), ко торый обеспечивает доступ к системным данным и оборудованию. Код при ложений выполняется в непривилегированном режиме процессора (назы ваемом пользовательским) с неполным набором интерфейсов, ограничен ным доступом к системным данным и без прямого доступа к оборудованию. Когда программа пользовательского режима вызывает системный сервис, процессор перехватывает вызов и переключает вызывающий поток в режим ядра. По окончании работы системного сервиса операционная система пе реключает контекст потока обратно в пользовательский режим и продолжа ет его выполнение. Windows, как и большинство UNIXсистем, является монолитной опера ционной системой — в том смысле, что бóльшая часть ее кода и драйверов использует одно и то же пространство защищенной памяти режима ядра. Это значит, что любой компонент операционной системы или драйвер уст ройства потенциально способен повредить данные, используемые другими компонентами операционной системы.
40 ГЛ А В А 2 БЕЗОПАСНОСТЬ Основана ли Windows на микроядре? Хотя некоторые объявляют ее таковой, Windows не является операци онной системой на основе микроядра в классическом понимании это го термина. В подобных системах основные компоненты операцион ной системы (диспетчеры памяти, процессов, вводавывода) выполня ются как отдельные процессы в собственных адресных пространствах и представляют собой надстройки над примитивными сервисами мик роядра. Пример современной системы с архитектурой на основе мик роядра — операционная система Mach, разработанная в Carnegie Mel lon University. Она реализует крошечное ядро, которое включает сер висы планирования потоков, передачи сообщений, виртуальной памя ти и драйверов устройств. Все остальное, в том числе разнообразные API, файловые системы и поддержка сетей, работает в пользовательс ком режиме. Однако в коммерческих реализациях на основе микро ядра Mach код файловой системы, поддержки сетей и управления па мятью выполняется в режиме ядра. Причина проста: системы, постро енные строго по принципу микроядра, непрактичны с коммерческой точки зрения изза слишком низкой эффективности. Означает ли тот факт, что большая часть Windows работает в режи ме ядра, ее меньшую надежность в сравнении с операционными сис темами на основе микроядра? Вовсе нет. Рассмотрим следующий сце нарий. Допустим, в коде файловой системы имеется ошибка, которая время от времени приводит к краху системы. Ошибка в коде режима ядра (например, в диспетчере памяти или файловой системы) скорее всего вызовет полный крах традиционной операционной системы. В истинной операционной системе на основе микроядра подобные компоненты выполняются в пользовательском режиме, поэтому тео ретически ошибка приведет лишь к завершению процесса соответ ствующего компонента. Но на практике такая ошибка все равно вызо вет крах системы, так как восстановление после сбоя столь критичес ки важного процесса невозможно. Все эти компоненты операционной системы, конечно, полностью защи щены от сбойных приложений, поскольку такие программы не имеют пря мого доступа к коду и данным привилегированной части операционной системы (хотя и способны вызывать сервисы ядра). Эта защита — одна из причин, по которым Windows заслужила репутацию отказоустойчивой и стабильной операционной системы в качестве сервера приложений и плат формы рабочих станций, обеспечивающей быстродействие основных сис темных сервисов вроде поддержки виртуальной памяти, файлового ввода вывода, работы с сетями и доступа к общим файлам и принтерам. Компоненты Windows режима ядра также построены на принципах объектноориентированного программирования (ООП). Так, для получения информации о какомлибо компоненте они, как правило, не обращаются к его
ГЛАВА 9 Архитектура системы 41 структурам данных. Вместо этого для передачи параметров, доступа к струк турам данных и их изменения используются формальные интерфейсы. Однако, несмотря на широкое использование объектов, представляющих разделяемые системные ресурсы, Windows не является объектноориенти рованной системой в строгом понимании этого термина. Бóльшая часть си стемного кода написана на С в целях переносимости и изза широкой рас пространенности средств разработки на С. В этом языке нет прямой поддер жки конструкций и механизмов ООП вроде динамического связывания ти пов данных, полиморфных функций или наследования классов. Обзор архитектуры Теперь обратимся к ключевым компонентам системы, составляющим ее ар хитектуру. Упрощенная версия этой архитектуры показана на рис. 21. Уч тите, что упрощенная схема не отражает всех деталей архитектуры (напри мер, здесь не показаны уровни сетевых компонентов и различных типов драйверов устройств). Рис. 2-1. Упрощенная схема архитектуры Windows На рис. 21 прежде всего обратите внимание на линию, разделяющую те части Windows, которые выполняются в режиме ядра и в пользовательском режиме. Прямоугольники над этой линией соответствуют процессам пользо вательского режима, а компоненты под ней — сервисам режима ядра. Как говорилось в главе 1, потоки пользовательского режима выполняются в за щищенных адресных пространствах процессов (хотя при выполнении в режиме ядра они получают доступ к системному пространству). Таким об разом, процессы поддержки системы, сервисов, приложений и подсистем окружения имеют свое адресное пространство. Существует четыре типа пользовательских процессов: 쐽 фиксированные процессы поддержки системы (system support proces ses) — например, процесс обработки входа в систему и диспетчер сеан сов, не являющиеся сервисами Windows (т. е. не запускаемые диспетче ром управления сервисами);
42 ГЛ А В А 2 БЕЗОПАСНОСТЬ 쐽 процессы сервисов (service processes) — носители Windowsсервисов вро де Task Scheduler и Spooler. Многие серверные приложения Windows, на пример Microsoft SQL Server и Microsoft Exchange Server, тоже включают компоненты, выполняемые как сервисы; 쐽 пользовательские приложения (user applications) — бывают шести типов: для 32разрядной Windows, 64разрядной Windows, 16разрядной Windows 3.1, 16разрядной MSDOS, 32разрядной POSIX и 32разрядной OS/2; 쐽 подсистемы окружения (environment subsystems) — реализованы как часть поддержки среды операционной системы, предоставляемой поль зователям и программистам. Изначально Windows NT поставлялась с тре мя подсистемами окружения: Windows, POSIX и OS/2. Последняя была изъята в Windows 2000. Что касается Windows XP, то в ней исходно по ставляется только подсистема Windows — улучшенная подсистема POSIX доступна как часть бесплатного продукта Services for UNIX. Обратите внимание на прямоугольник «DLL подсистем», расположенный на рис. 21 под прямоугольниками «процессы сервисов» и «пользовательские приложения». В Windows пользовательские приложения не могут вызывать родные сервисы операционной системы напрямую, вместо этого они рабо тают с одной или несколькими DLL подсистем. Их назначение заключается в трансляции документированных функций в соответствующие внутренние (и обычно недокументированные) вызовы системных сервисов Windows. Трансляция может осуществляться как с помощью сообщения, посылаемо го процессу подсистемы окружения, обслуживающему пользовательское приложение, так и без него. Windows включает следующие компоненты режима ядра. 쐽 Исполнительная система (executive) Windows, содержащая базовые сер висы операционной системы, которые обеспечивают управление памя тью, процессами и потоками, защиту, вводвывод и взаимодействие меж ду процессами. 쐽 Ядро (kernel) Windows, содержащее низкоуровневые функции операци онной системы, которые поддерживают, например, планирование пото ков, диспетчеризацию прерываний и исключений, а также синхрониза цию при использовании нескольких процессоров. Оно также предостав ляет набор процедур и базовых объектов, применяемых исполнительной системой для реализации структур более высокого уровня. 쐽 Драйверы устройств (device drivers), в состав которых входят драйверы аппаратных устройств, транслирующие пользовательские вызовы функ ций вводавывода в запросы, специфичные для конкретного устройства, а также сетевые драйверы и драйверы файловых систем. 쐽 Уровень абстрагирования от оборудования (hardware abstraction layer, HAL), изолирующий ядро, драйверы и исполнительную систему Windows от специфики оборудования на данной аппаратной платформе (напри мер, от различий между материнскими платами).
ГЛАВА 9 Архитектура системы 43 쐽 Подсистема поддержки окон и графики (windowing and graphics system), реализующая функции графического пользовательского интерфейса (GUI), более известные как Windowsфункции модулей USER и GDI. Эти функции обеспечивают поддержку окон, элементов управления пользо вательского интерфейса и отрисовку графики. В таблице 21 перечислены имена файлов основных компонентов Win dows. (Вы должны знать их, потому что в дальнейшем мы будем ссылаться на некоторые системные файлы по именам.) Каждый из этих компонентов подробно рассматривается в этой и последующих главах. Таблица 2-1. Основные системные файлы Windows Имя файла Компоненты Ntoskrnl.exe Исполнительная система и ядро Ntkrnlpa.exe Исполнительная система и ядро с поддержкой механизма (только 32разрядные Physical Address Extension (PAE), позволяющего адресовать системы) 64 Гб физической памяти Hal.dll Уровень абстрагирования от оборудования Win32sk.sys Часть подсистемы Windows, работающая в режиме ядра Ntdll.dll Внутренние функции поддержки и интерфейсы (stubs) диспетчера системных сервисов с функциями исполнитель ной системы Kernel32.dll, Advapi32.dll, User32.dll, Gdi32.dll Основные DLL подсистемы Windows Прежде чем детально рассматривать эти компоненты, давайте проясним, как достигается переносимость Windows между различными аппаратными платформами. Переносимость Windows рассчитана на разные аппаратные платформы, включая как CISC системы Intel, так и RISCсистемы. Windows NT первого выпуска поддержи вала архитектуры x86 и MIPS. Спустя некоторое время была добавлена под держка Alpha AXP производства DEC (DEC была приобретена Compaq, а по зднее произошло слияние компаний Compaq и Hewlett Packard). (Хотя Alpha AXP был 64разрядным процессором, Windows NT работала с ним в 32раз рядном режиме. В ходе разработки Windows 2000 была создана ее 64разряд ная версия специально под Alpha AXP, но в свет она так и не вышла.) В Win dows NT 3.51 ввели поддержку четвертой процессорной архитектуры — Motorola PowerPC. В связи с изменениями на рынке необходимость в под держке MIPS и PowerPC практически отпала еще до начала разработки Win dows 2000. Позднее Compaq отозвала поддержку архитектуры Alpha AXP, и в Windows 2000 осталась поддержка лишь архитектуры x86. В самые после дние выпуски — Windows XP и Windows Server 2003 — добавлена поддерж ка трех семейств 64разрядных процессоров: Intel Itanium IA64, AMD x8664 и Intel 64bit Extension Technology (EM64T) для x86 (эта архитектура совме
44 ГЛ А В А 2 БЕЗОПАСНОСТЬ стима с архитектурой AMD x8664, хотя есть небольшие различия в поддер живаемых командах). Последние два семейства процессоров называются системами с 64!разрядными расширениями и в этой книге обозначаются как x64. (Как 32разрядные приложения выполняются в 64разрядной Windows, объясняется в главе 3.) Переносимость Windows между системами с различной аппаратной ар хитектурой и платформами достигается главным образом двумя способами. 쐽 Windows имеет многоуровневую структуру. Специфичные для архитекту ры процессора или платформы низкоуровневые части системы вынесе ны в отдельные модули. Благодаря этому высокоуровневая часть системы не зависит от специфики архитектур и аппаратных платформ. Ключевые компоненты, обеспечивающие переносимость операционной системы, — ядро (содержится в файле Ntoskrnl.exe) и уровень абстрагирования от оборудования (HAL) (содержится в файле Hal.dll). Функции, специфичные для конкретной архитектуры (переключение контекста потоков, диспет черизация ловушек и др.), реализованы в ядре. Функции, которые могут отличаться на компьютерах с одинаковой архитектурой (например, в сис темах с разными материнскими платами), реализованы в HAL. Еще один компонент, содержащий большую долю кода, специфичного для конкрет ной архитектуры, — диспетчер памяти (memory manager), но если рас сматривать систему в целом, такого кода все равно немного. 쐽 Подавляющее большинство компонентов Windows написано на С и лишь часть из них — на С++. Язык ассемблера применяли только при создании частей системы, напрямую взаимодействующих с системным оборудова нием (например, при написании обработчика ловушек прерываний) или требующих исключительного быстродействия (скажем, при переключе нии контекста). Ассемблерный код имеется не только в ядре и HAL, но и в составе некоторых других частей операционной системы: процедур, реализующих взаимоблокировку, механизма вызова локальных процедур (LPC), части подсистемы Windows, выполняемой в режиме ядра, и даже в некоторых библиотеках пользовательского режима (например, в коде запуска процессов в Ntdll.dll — системной библиотеке, о которой будет рассказано в этой главе несколько позже). Симметричная многопроцессорная обработка Многозадачность (multitasking) — механизм операционной системы, позво ляющий использовать один процессор для выполнения нескольких потоков. Однако истинно одновременное выполнение, например, двух потоков воз можно, только если на компьютере установлено два процессора. При мно гозадачности система лишь создает видимость одновременного выполнения множества потоков, тогда как многопроцессорная система действительно выполняет сразу несколько потоков — по одному на каждом процессоре. Как уже говорилось в начале этой главы, одной из ключевых целей раз работки Windows была поддержка многопроцессорных компьютерных сис
ГЛАВА 9 Архитектура системы 45 тем. Windows является операционной системой, поддерживающей симмет! ричную многопроцессорную обработку (symmetric multiprocessing, SMP). В этой модели нет главного процессора; операционная система, как и пользо вательские потоки, может выполняться на любом процессоре. Кроме того, все процессоры используют одну и ту же память. При асимметричной мно! гопроцессорной обработке (asymmetric multiprocessing, ASMP) система, на против, выбирает один из процессоров для выполнения кода ядра операци онной системы, а другие процессоры выполняют только пользовательский код. Различия между этими двумя моделями показаны на рис. 22. Рис. 2-2. Симметричная и асимметричная многопроцессорная обработка Windows XP и Windows Server 2003 поддерживают два новых типа мно гопроцессорных систем: логические процессоры (hyperthreading) и NUMA (NonUniform Memory Architecture). Об этом кратко рассказывается в абза це ниже. (Полное описание поддержки планирования потоков для таких систем см. в разделе по планированию потоков в главе 6.) Логические процессоры — это технология, созданная Intel; благодаря ей на одном физическом процессоре может быть несколько логических. Каж дый логический процессор имеет свое состояние, но исполняющее ядро (execution engine) и набортный кэш (onboard cache) являются общими. Это позволяет одному из логических процессоров продолжать работу, пока дру гой логический процессор занят (например, обработкой прерывания, кото рая не дает потокам выполняться на этом логическом процессоре). Алгорит мы планирования в Windows XP были оптимизированы под компьютеры с такими процессорами.
46 ГЛ А В А 2 БЕЗОПАСНОСТЬ В NUMAсистемах процессоры группируются в блоки, называемые узла ми (nodes). В каждом узле имеются свои процессоры и память, и он соеди няется с остальными узлами специальной шиной. Windows в NUMAсисте ме попрежнему работает как SMPсистема, в которой все процессоры име ют доступ ко всей памяти, — просто доступ к памяти, локальной для узла, осуществляется быстрее, чем к памяти в других узлах. Система стремится повысить производительность, выделяя потокам время на процессорах, ко торые находятся в том же узле, что и используемая память. Она также пыта ется выделять память в пределах узла, но при необходимости выделяет па мять и из других узлов. Хотя Windows изначально разрабатывалась для поддержки до 32 процес соров, многопроцессорной модели не свойственны никакие внутренние особенности, которые ограничивали бы число используемых процессоров до 32. Просто это число легко представить битовой маской с помощью ма шинного 32разрядного типа данных. И действительно, 64разрядные вер сии Windows поддерживают до 64 процессоров, потому что размер слова на 64разрядных процессорах равен 64 битам. Реальное число поддерживаемых процессоров зависит от конкретного выпуска Windows (см. таблицы 23 и 24). Это число хранится в параметре реестра HKLM\SYSTEM\CurrentControlSet\Control\Session\Manager\Licensed Processors. (Учтите, что модификация этого параметра считается нарушени ем условий лицензионного соглашения на программное обеспечение, да и для увеличения числа поддерживаемых процессоров требуется нечто боль шее, чем простое изменение данного параметра.) Для большей производительности ядро и HAL имеют одно и многопро цессорную версии. В случае Windows 2000 это относится к шести ключевым системным файлам (см. примечание ниже), а в 32разрядных Windows XP и Windows Server 2003 — только к трем (см. таблицу 22). В 64разрядных си стемах Windows ядра PAE нет, поэтому одно и многопроцессорные систе мы отличаются лишь ядром и HAL. Соответствующие файлы выбираются и копируются в локальный каталог \Windows\System32 на этапе установки. Чтобы определить, какие файлы были скопированы, см. файл \Windows\Repair\Setup.log, где перечисляются все файлы, копировавшиеся на локальный системный диск, и каталоги на дистрибутивном носителе, откуда они были взяты.
ГЛАВА 9 Архитектура системы 47 Таблица 2-2. Системные файлы, специфичные для однои многопроцессорных систем Имя файла на системном диске Имя однопроцессорной версии на дистрибутивном носителе Имя многопроцессорной версии на дистрибутивном носителе Ntoskrnl.exe Ntoskrnl.exe Ntkrnlmp.exe Ntkrnlpa.exe (ядро PAE; только 32разрядные системы) Ntkrnlpa.exe в \Windows\ <arch>\Driver.cab Ntkrpamp.exe в \Windows\ <arch>\Driver.cab Hal.dll Зависит от типа системы Зависит от типа системы (см. список HAL в таблице 26) (см. список HAL в таблице 26) Только Windows 2000 Win32k.sys \I386\UNIPROC\Win32k.sys Win32k.sys в \I386\ Driver.cab Ntdll.dll \I386\UNIPROC\Ntdll.dll \I386\Ntdll.dll Kernel32.dll \I386\UNIPROC\Kernel32.dll \I386\Kernel32.dll ПРИМЕЧАНИЕ В папке \I386\UNIPROC в дистрибутиве Windows 2000 находится файл Winsrv.dll. Хотя он помещен в папку UNIPROC, назва ние которой указывает на однопроцессорную версию, на самом деле для одно и многопроцессорных систем существует только одна вер сия этого образа. ЭКСПЕРИМЕНТ: поиск файлов поддержки многопроцессорных систем в Windows 2000 Вы можете убедиться в том, что для многопроцессорной 32разрядной системы Windows 2000 используются другие файлы, просмотрев све дения о драйверах для Computer (Компьютер) в Device Manager (Дис петчер устройств). 1. Откройте окно свойств системы, дважды щелкнув System (Система) в окне Control Panel (Панель управления) или щелкнув правой кнопкой мыши My Computer (Мой компьютер) на рабочем столе и выбрав из контекстного меню команду Properties (Свойства). 2. Перейдите на вкладку Hardware (Оборудование). 3. Щелкните кнопку Device Manager (Диспетчер устройств). 4. Раскройте объект Computer (Компьютер). 5. Дважды щелкните дочерний узел объекта Computer. 6. Откройте вкладку Driver (Драйвер). 7. Щелкните кнопку Driver Details (Сведения о драйверах). В многопроцессорной системе вы должны увидеть диалоговое окно, показанное ниже.
48 ГЛ А В А 2 БЕЗОПАСНОСТЬ Специальные версии этих ключевых системных файлов для однопроцес сорных систем созданы для максимального повышения производительнос ти. Синхронизация работы нескольких процессоров — задача принципиаль но более сложная, и благодаря «однопроцессорным» версиям системных файлов устраняются издержки этой синхронизации, которая в однопроцес сорных системах (а они составляют подавляющее большинство систем под управлением Windows) не нужна. Интересно, что «однопроцессорная» и «многопроцессорная» версии Ntoskrnl создаются за счет условной компиляции одного и того же исходного кода, а «однопроцессорные» версии Ntdll.dll и Kernel32.dll для Windows 2000 требу ют замены машинных x86команд LOCK и UNLOCK, используемых для синх ронизации множества потоков, командой NOP (которая ничего не делает). Остальные системные файлы Windows (включая все утилиты, библиоте ки и драйверы устройств) одинаковы как в многопроцессорных, так и в од нопроцессорных системах. При разработке нового программного обеспе чения — Windowsприложения или драйвера устройства — вы должны учи тывать этот подход и тестировать свое программное обеспечение как в одно, так и в многопроцессорных системах. ЭКСПЕРИМЕНТ: определение текущей версии Ntoskrnl В Windows 2000 и выше нет утилиты, показывающей, с какой версией Ntoskrnl вы работаете. Однако при каждой загрузке в журнале систе мы регистрируется, какая версия ядра запускается — одно или мно гопроцессорная, отладочная или конечная (см. следующую иллюстра цию). Выберите из меню Start (Пуск) команду Programs (Программы), затем Administrative Tools (Администрирование) и Event Viewer (Про смотр событий). Далее выберите System Log (Журнал системы) и дваж ды щелкните запись с кодом события 6009 — она создается при заг рузке системы.
ГЛАВА 9 Архитектура системы 49 Эта запись не содержит сведений о том, загружена ли PAEверсия образа ядра, поддерживающая более 4 Гб физической памяти (Ntkrnlpa.exe). Однако вы можете узнать это, проверив значение пара метра SystemStartOptions в разделе реестра HKLM\SYSTEM\Current ControlSet\Control. Кроме того, при загрузке PAEверсии ядра парамет ру PhysicalAddressExtension в разделе реестра HKLM\SYSTEM\Current ControlSet\Control\Session Manager\Memory Management присваивает ся значение, равное 1. Есть и другой способ определить, установлена ли многопроцессор ная версия Ntoskrnl (или Ntkrnlpa): запустите Windows Explorer (Про водник), в каталоге \Windows\System32 щелкните правой кнопкой мы ши файл Ntoskrnl.exe и выберите из контекстного меню команду Pro см. след. стр.
50 ГЛ А В А 2 БЕЗОПАСНОСТЬ perties (Свойства). Перейдите на вкладку Version (Версия) и выберите свойство Original Filename (Исходное имя файла). Если вы работаете с многопроцессорной версией, то увидите диалоговое окно, показан ное на предыдущей странице. Наконец, просмотрев файл \Windows\Repair\Setup.log, можно точ но выяснить, какие файлы ядра и HAL были выбраны при установке. Масштабируемость Масштабируемость (scalability) — одна из ключевых целей многопроцес сорных систем. Для корректного выполнения в SMPсистемах операционная система должна строго соответствовать определенным требованиям. Решить проблемы конкуренции за ресурсы и другие вопросы в многопроцессорных системах сложнее, чем в однопроцессорных, и это нужно учитывать при разработке системы. Некоторые особенности Windows оказались решающи ми для ее успеха как многопроцессорной операционной системы: 쐽 способность выполнять код операционной системы на любом доступном процессоре и на нескольких процессорах одновременно; 쐽 несколько потоков одного процесса можно параллельно выполнять на разных процессорах; 쐽 тонкая синхронизация внутри ядра (спинблокировки, спинблокировки с очередями и др.; см. главу 3), драйверов устройств и серверных процес сов позволяет выполнять больше компонентов на нескольких процессо рах одновременно; 쐽 механизмы вроде портов завершения вводавывода (см. главу 9), облегча ющие эффективную реализацию многопоточных серверных процессов, хорошо масштабируемых в многопроцессорных системах. Масштабируемость ядра Windows со временем улучшалась. Например, в Windows Server 2003 имеются очереди планирования, индивидуальные для каждого процессора, что дает возможность планировать потоки параллель но на нескольких машинах. О планировании потоков в многопроцессорных системах см. главу 6, а о синхронизации в таких системах — главу 3. Различия между клиентскими и серверными версиями Windows поставляется в клиентских и серверных версиях. В Windows 2000 клиентская версия называется Windows 2000 Professional. Существует также три серверных версии Windows 2000: Windows 2000 Server, Advanced Server и Datacenter Server. У Windows XP шесть клиентских версий: Windows XP Home Edition, Win dows XP Professional, Windows XP Starter Edition, Windows XP Tablet PC Edition, Windows XP Media Center Edition и Windows XP Embedded. Последние три являются надмножествами Windows XP Professional и в книге детально не рассматриваются, так как все они построены на том же базовом коде, что и Windows XP Professional.
ГЛАВА 9 Архитектура системы 51 Windows Server 2003 выпускается в шести разновидностях: Windows Ser ver 2003 Web Edition, Standard Edition, Small Business Server, Storage Server, Enterprise Edition и Datacenter Edition. Эти версии различаются по следующим параметрам: 쐽 числу поддерживаемых процессоров; 쐽 объему поддерживаемой физической памяти; 쐽 возможному количеству одновременных сетевых соединений (например, в клиентской версии допускается максимум 10 одновременных соедине ний со службой доступа к общим файлам и принтерам); 쐽 наличием в выпусках Server сервисов, не входящих в Professional (напри мер, служб каталогов, поддержкой кластеризации и многопользователь ской службы терминала). Эти различия для Windows 2000 суммируются в таблице 23. Та же инфор мация, но применительно к Windows XP и Windows Server 2003 дана в таб лице 24. Детальное сравнение различных выпусков Windows Server 2003 см. по ссылке http://www.microsoft.com/windowsserver2003/evaluation/features/ compareeditions.mspx. Таблица 2-3. Различия между Windows 2000 Professional и Server Выпуск Windows 2000 Professional Windows 2000 Server Windows 2000 Advanced Server Windows 2000 Datacenter Server Число процессоров 2 4 8 32 Объем физической памяти, Гб 4 4 8 64 Таблица 2-4. Различия между Windows XP и Windows Server 2003 Объем физической памяти, Гб (32разрядная Число процессоров (64-разрядная версия) Windows XP 1 Home Edition 4 Неприменимо Неприменимо Неприменимо Windows XP 2 Professional 4 2 Windows Server 2003 Web Edition 2 2 Неприменимо Неприменимо Неприменимо Windows 2 Server 2003 Small Business Server 2 Неприменимо Неприменимо Неприменимо Windows Server 2003 Standard Edition 4 Неприменимо Неприменимо Неприменимо Число процессоров (32-разрядная версия) 4 Объем физической памяти, Гб (версии для для Itanium) 16 Объем физической памяти, Гб (версии для x64) 16 см. след. стр.
52 ГЛ А В А 2 БЕЗОПАСНОСТЬ Таблица 2-4. (окончание) Число процессоров (32-разрядная версия) Объем физической памяти, Гб (32разрядная Число процессоров (64-разрядная версия) Объем физической памяти, Гб (версии для для Itanium) Объем физической памяти, Гб (версии для x64) Windows Server 2003 Enterprise Edition 8 32 8 64 64 Windows Server 2003 Datacenter Edition 32 128 (на x64); 64 (на x86) 64 512 (1024 Гб в SP1) Неприменимо Хотя существует несколько клиентских и серверных выпусков операци онной системы Windows, у них общий набор базовых системных файлов, в том числе: ядро, Ntoskrnl.exe (а также версия PAE, Ntkrnlpa.exe), библиотеки HAL, драйверы, основные системные утилиты и DLL. Эти файлы идентичны для всех выпусков Windows 2000. ПРИМЕЧАНИЕ Windows XP была первым клиентским выпуском кодо вой базы Windows NT, который поставляется без соответствующих серверных версий. Вместо этого разработки продолжались, и пример но год спустя после выхода Windows XP была выпущена Windows Ser ver 2003. Таким образом, базовые системные файлы Windows XP и Windows Server 2003 не идентичны. Однако они не столь значимы (и во многих случаях компоненты не изменялись). Итак, если образ ядра для Windows 2000 Professional и Windows 2000 Server одинаков (и сходен для Windows XP и Windows Server 2003), то как же система определяет, какой именно выпуск загружается? Для этого она про веряет значения параметров ProductType и ProductSuite в разделе реестра HKLM\SYSTEM\CurrentControlSet\Control\ProductOptions. Параметр Product Type используется, чтобы отличить клиентскую систему от серверной (лю бого выпуска). Список допустимых значений этого параметра приведен в таблице 25. Результат проверки помещается в глобальную системную пере менную MmProductType, значение которой может быть запрошено драйве ром устройства через функцию MmIsThisAnNtAsSystem режима ядра, описан ную в документации Windows DDK. Таблица 2-5. Значения параметра реестра ProductType Выпуск Windows Значение ProductType Windows 2000 Professional, Windows XP Professional, Windows XP Home Edition WinNT Windows Server (контроллер домена) LanmanNT Windows Server (только сервер) ServerNT
ГЛАВА 9 Архитектура системы 53 Другой параметр, ProductSuite, позволяет различать серверные версии Windows (Standard, Enterprise, Datacenter Server и др.), а также Windows XP Home от Windows XP Professional. Для проверки текущего выпуска Windows пользовательские программы вызывают Windowsфункцию VerifyVersionInfo, описанную в Platform SDK. Драйверы могут вызвать функцию RtlGetVersion режима ядра, документированную в Windows DDK. Итак, если базовые файлы в целом одинаковы для клиентских и сервер ных версий, то чем же отличается их функционирование? Серверные сис темы оптимизированы для работы в качестве высокопроизводительных сер веров приложений, а клиентские, несмотря на поддержку серверных воз можностей, — для персональных систем. Так, некоторые решения по выде лению ресурсов (например, о числе и размере системных пулов памяти, ко личестве внутрисистемных рабочих потоков и размере системного кэша данных) при загрузке принимаются поразному, в зависимости от типа про дукта. Политика принятия таких решений, как обслуживание диспетчером памяти запросов системы и процессов на выделение памяти, у серверной и клиентской версий тоже различается. В равной мере это относится и к осо бенностям планирования потоков по умолчанию (детали см. в главе 6). Су щественные отличия в функционировании этих двух продуктов будут отме чены в соответствующих главах. Любые материалы в нашей книге, если явно не указано иное, относятся к обеим версиям — клиентской и серверной. Проверочный выпуск Специальная отладочная версия Windows 2000 Professional, Windows XP Professional или Windows Server 2003 называется проверочным выпуском (checked build). Она доступна только подписчикам MSDN уровня Professional (или выше). Проверочный выпуск представляет собой перекомпилирован ный исходный код Windows, для которого флаг «DBG» (заставляющий вклю чать код отладки и трассировки этапа компиляции) был установлен как TRUE. Кроме того, чтобы облегчить восприятие машинного кода, отключа ется обработка двоичных файлов, при которой структура кода оптимизиру ется для большего быстродействия (см. раздел «PerformanceOptimized Code» в справочном файле Debugging Tools). Проверочный выпуск предназначен главным образом разработчикам драйверов устройств, поскольку эта версия выполняет более строгую провер ку ошибок при вызове функций режима ядра драйверами устройств или дру гим системным кодом. Например, если драйвер (или какойто иной код ре жима ядра) неверно вызывает системную функцию, контролирующую пере даваемые параметры, то при обнаружении этой проблемы система останав ливается, предотвращая повреждение структур данных и возможный крах.
54 ГЛ А В А 2 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: определяем, является ли данная система проверочным выпуском Встроенной утилиты, которая позволяла бы увидеть, с каким выпуском вы имеете дело — проверочным или готовым, нет. Однако эта инфор мация доступна через свойство «Debug» WMIкласса (Windows Mana gement Instrumentation) Win32_OperatingSystem. Следующий сценарий на Visual Basic отображает содержимое этого свойства: strComputer = "." Set objWMIService = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\\" & _ strComputer & "\root\cimv2”) Set colOperatingSystems = objWMIService.ExecQuery _ ("SELECT * FROM Win32_OperatingSystem"S) For Each objOperatingSystem in colOperatingSystems Wscript.Echo "Caption: " & objOperatingSystem.Caption Wscript.Echo "Debug: " & objOperatingSystem.Debug Wscript.Echo "Version: " & objOperatingSystem.Version Next Чтобы опробовать его в действии, наберите код этого сценария и сохраните как файл. Вот пример вывода: C:\>cscript osversion.vbs Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 19962001. All rights reserved. Caption: Microsoft Windows XP Professional Debug: False Version: 5.1.2600 Эта система не является проверочным выпуском, так как флаг De bug равен False. Значительная часть дополнительного кода в собранных таким образом двоичных файлах является результатом работы макроса ASSERT, определен ного в заголовочном файле Ntddk.h, который входит в состав DDK. Этот мак рос проверяет некое условие (например, правильность структуры данных или параметра) и, если значение выражения получается равным FALSE, вы зывает функцию RtlAssert режима ядра, которая в свою очередь обращается к DbgPrint, передающей текст отладочного сообщения в буфер отладочных сообщений (debug message buffer). Если отладчик ядра подключен, это сооб щение выводится на экран, а за ним автоматически появляется запрос к пользователю, какое действие следует предпринять (игнорировать, завер шить процесс или поток и т. д.). Если система загружена без отладчика ядра (в отсутствие ключа /DEBUG в файле Boot.ini) и этот отладчик сейчас не подключен, неудачный тест ASSERT вызовет крах системы. Список тестов
ГЛАВА 9 Архитектура системы 55 ASSERT, выполняемых некоторыми вспомогательными процедурами ядра, см. в разделе «Checked Build ASSERTs» документации Windows DDK. ПРИМЕЧАНИЕ Сравнив файл Ntoskrnl.exe с Ntkrnlmp.exe или Ntkrnlpa. exe с Ntkrpamp.exe в проверочной версии системы, вы убедитесь, что они идентичны и являются «многопроцессорными» версиями соответ ствующих файлов. Иначе говоря, в проверочной версии системы нет отладочных вариантов файлов для однопроцессорных систем. Проверочный выпуск также полезен системным администраторам, так как в нем можно включить детальную трассировку для определенных ком понентов. (Подробные инструкции см. в статье 314743 «HOWTO: Enable Verbose Debug Tracing in Various Drivers and Subsystems» в Microsoft Knowledge Base.) Вывод такой трассировки посылается в буфер отладочных сообщений с помощью функции DbgPrint, о которой мы уже упоминали. Для просмот ра отладочных сообщений к целевой системе можно подключить отладчик ядра (что потребует загрузки целевой системы в отладочном режиме), ис пользовать команду !dbgprint в процессе локальной отладки ядра или при менить утилиту Dbgview.exe с сайта www.sysinternals.com. Для использования возможностей отладочной версии операционной си стемы необязательно устанавливать весь проверочный выпуск. Можно про сто скопировать проверочную версию образа ядра (Ntoskrnl.exe) и соответ ствующий HAL (Hal.dll) в обычную систему. Преимущество этого подхода в том, что он позволяет тщательно протестировать драйверы устройств и дру гой код ядра, не устанавливая медленнее работающие версии всех компонен тов системы. О том, как это сделать, см. раздел «Installing Just the Checked Operating System and HAL» в документации Windows DDK. Поскольку Micro soft не поставляет проверочный выпуск Windows 2000 Server, вы можете применить этот способ и получить проверочную версию ядра в системе Windows 2000 Server. Наконец, проверочная версия пригодится и для тестирования кода поль зовательского режима, но только в том смысле, что в проверочной версии системы устанавливаются другие интервалы ожидания (тайминги). (Это свя зано с тем, что в ядре выполняются дополнительные проверки, а сами ком поненты компилируются без оптимизации.) В таких условиях часто проявля ются ошибки, связанные с синхронизацией нескольких потоков приложения. Ключевые компоненты системы Теперь, ознакомившись с высокоуровневой архитектурой Windows, копнем поглубже и рассмотрим роль каждого ключевого компонента системы. На рис. 23 отражена более подробная схема системной архитектуры Windows. Заметьте, что на ней все равно не показаны некоторые компоненты (в част ности, компоненты сетевой поддержки, о которых пойдет речь в главе 13). Основные элементы этой схемы детально описываются в последующих главах. В главе 3 рассказывается об основных механизмах управления,
56 ГЛ А В А 2 БЕЗОПАСНОСТЬ используемых системой (в том числе о диспетчере объектов, прерываниях и т. п.), в главе 5 — о процессах запуска и завершения Windows, а в главе 4 — о таких механизмах управления, как реестр, процессы сервисов и Windows Management Instrumentation (WMI). В остальных главах не менее подробно поясняется внутреннее устройство и функционирование ключевых элемен тов — процессов, потоков, подсистемы управления памятью, защиты, диспет чера вводавывода, диспетчера кэша, файловой системы NTFS, сетевой под держки и др. Рис. 2-3. Архитектура Windows
ГЛАВА 9 Архитектура системы 57 Подсистемы окружения и их DLL Как показано на рис. 23, в Windows имеется три подсистемы окружения: OS/2, POSIX и Windows. Как мы уже говорили, подсистема OS/2 была удалена в Windows 2000. Начиная с Windows XP, базовая подсистема POSIX не постав ляется с Windows, но ее гораздо более совершенную версию можно получить бесплатно как часть продукта Services for UNIX. Подсистема Windows отличается от остальных двух тем, что без нее Win dows работать не может (эта подсистема обрабатывает все, что связано с кла виатурой, мышью и экраном, и нужна даже на серверах в отсутствие интерак тивных пользователей). Фактически остальные две подсистемы запускаются только по требованию, тогда как подсистема Windows работает всегда. Стартовая информация подсистемы хранится в разделе реестра HKLM\ SYSTEM\CurrentControlSet\Control\Session Manager\SubSystems. Значения параметров в этом разделе показаны на рис. 24. Рис. 2-4. Просмотр стартовой информации Windows в Registry Editor Значением параметра Required является список подсистем, загружаемых при запуске системы. Параметр состоит из двух строк: Windows и Debug. В параметре Windows указывается спецификация файла подсистемы Windows, Csrss.exe (аббревиатура от Client/Server RunTime Subsystem; см. примечание ниже). Параметр Debug остается незаполненным (он используется для внут реннего тестирования) и не выполняет никаких функций. Параметр Optional указывает, что подсистемы OS/2 и POSIX запускаются по требованию. Пара метр Kmode содержит имя файла той части подсистемы Windows, которая работает в режиме ядра, — Win32k.sys (об этом файле чуть позже). Подсистемы окружения предоставляют прикладным программам некое подмножество базовых сервисов исполнительной системы Windows. Каждая подсистема обеспечивает доступ к разным подмножествам встроенных сер висов Windows. Это значит, что приложения, созданные для одной подсис темы, могут выполнять операции, невозможные в другой подсистеме. Так, Windowsприложения не могут использовать POSIXфункцию fork. Каждый исполняемый образ (EXE) принадлежит одной — и только од ной — подсистеме. При запуске образа код, отвечающий за создание процес са, получает тип подсистемы, указанный в заголовке образа, и уведомляет со ответствующую подсистему о новом процессе. Тип указывается специфика
58 ГЛ А В А 2 БЕЗОПАСНОСТЬ тором /SUBSYSTEM в команде link в Microsoft Visual C++; его можно просмот реть с помощью утилиты Exetype, входящей в состав ресурсов Windows. ПРИМЕЧАНИЕ Процесс подсистемы Windows назван Csrss.exe пото му, что в Windows NT все подсистемы изначально предполагалось вы полнять как потоки внутри единственного общесистемного процес са. Когда подсистемы POSIX и OS/2 были выделены в собственные про цессы, имя файла процесса подсистемы Windows осталось прежним. Смешивать вызовы функций разных подсистем нельзя. Иными словами, приложения POSIX могут вызывать только сервисы, экспортируемые подсис темой POSIX, а приложения Windows — лишь сервисы, экспортируемые под системой Windows. Как вы еще убедитесь, это ограничение послужило одной из причин, по которой исходная подсистема POSIX, реализующая весьма ограниченный набор функций (только POSIX 1003.1), не стала полез ной средой для переноса в нее UNIXприложений. Мы уже говорили, что пользовательские приложения не могут вызывать системные сервисы Windows напрямую. Вместо этого они обращаются к DLL подсистем. Эти DLL предоставляют документированный интерфейс между программами и вызываемой ими подсистемой. Так, DLL подсистемы Win dows (Kernel32.dll, Advapi32.dll, User32.dll и Gdi32.dll) реализуют функции Windows API. DLL подсистемы POSIX (Psxdll.dll) реализует POSIX API. ЭКСПЕРИМЕНТ: определение типа подсистемы, для которой предназначен исполняемый файл Вы можете определить, для какой подсистемы предназначен исполня емый файл с помощью утилиты Exetype из набора ресурсов Windows или утилиты Dependency Walker (Depends.exe), входящей в состав Win dows Support Tools и Platform SDK. Попробуем, например, выяснить тип подсистемы для двух принципиально разных Windowsобразов: Notepad.exe (простого текстового редактора) и Cmd.exe (поддержки командной строки Windows). C:\>exetype \windows\system32\notepad.exe File “\windows\system32\notepad.exe“ is of the following type: Windows NT 32 bit machine Built for the Intel 80386 processor Runs under the Windows GUI subsystem C:\>exetype \windows\system32\cmd.exe File “\windows\system32\cmd.exe“ is of the following type: Windows NT 32 bit machine Built for the Intel 80386 processor Runs under the Windows characterbased subsystem
ГЛАВА 9 Архитектура системы 59 Это показывает, что Notepad является GUIпрограммой, а Cmd — консольной, или программой текстового режима. Хотя вывод утили ты Exetype сообщает о наличии двух разных подсистем для GUI и кон сольных программ, на самом деле существует лишь одна подсистема Windows. Кроме того, Windows не поддерживает процессор Intel 386 (или 486, если это имеет какоето значение) — текст сообщений, вы водимых программой Exetype, просто не обновили. При вызове приложением одной из функций DLL подсистемы возможно одно из трех. 쐽 Функция полностью реализована в пользовательском режиме внутри DLL подсистемы. Иначе говоря, никаких сообщений процессу подсистемы окружения не посылается, и вызова сервисов исполнительной системы Windows не происходит. После выполнения функции в пользовательском режиме результат возвращается вызвавшей ее программе. Примерами таких функций могут служить GetCurrentProcess (всегда возвращает –1, значение, определенное для ссылки на текущий процесс во всех функци ях, связанных с процессами) и GetCurrentProcessId (идентификатор про цесса не меняется в течение его срока жизни, поэтому его можно полу чить из кэша, что позволяет избежать переключения в режим ядра). 쐽 Функция требует одного или более вызовов исполнительной системы Windows. Например, Windowsфункции ReadFile и WriteFile обращаются к внутренним недокументированным сервисам вводавывода — соответ ственно к NtReadFile и NtWriteFile. 쐽 Функция требует выполнения какихлибо операций в процессе подсис темы окружения (такие процессы, работающие в пользовательском режи ме, отвечают за обслуживание клиентских приложений, выполняемых под их контролем). В этом случае подсистеме окружения выдается кли ентсерверный запрос через сообщение с требованием выполнить какую либо операцию, и DLL подсистемы, прежде чем вернуть управление выз вавшей программе, ждет соответствующего ответа. Некоторые функции вроде CreateProcess и CreateThread могут требовать выполнения как второго, так и третьего пункта. Хотя структура Windows позволяет поддерживать несколько независимых подсистем окружения, с практической точки зрения было бы неудобно вклю чать в состав каждой подсистемы свой код для обработки окон и отображе ния вводавывода. Это привело бы к дублированию системных функций и в конечном счете негативно отразилось бы на объеме и производительности системы. Поскольку главной подсистемой была Windows, разработчики реши ли разместить эти базовые функции именно в ней. Так что другие подсисте мы для отображения вводавывода вызывают соответствующие сервисы Win dows. (Кстати, посмотрев на тип подсистемы в заголовках их файлов, вы убе дитесь, что фактически они являются исполняемыми файлами Windows.) Теперь поближе познакомимся с каждой подсистемой окружения.
60 ГЛ А В А 2 БЕЗОПАСНОСТЬ Подсистема Windows Эта подсистема состоит из следующих основных элементов. 쐽 Процесса подсистемы окружения (Csrss.exe), предоставляющего: 쐽 поддержку консольных (текстовых) окон; 쐽 поддержку создания и удаления процессов и потоков; 쐽 частичную поддержку процессов 16разрядной виртуальной DOSма шины (VDM); 쐽 множество других функций, например GetTempFile, DefineDosDevice, ExitWindowsEx, а также несколько функций поддержки естественных языков. 쐽 Драйвера режима ядра (Win32k.sys), включающего: 쐽 диспетчер окон, который управляет отрисовкой и выводом окон на экран, принимает ввод с клавиатуры, мыши и других устройств, а так же передает пользовательские сообщения приложениям; 쐽 Graphics Device Interface (GDI), который представляет собой библиоте ку функций для устройств графического вывода. В GDI входят функции для манипуляций с графикой и отрисовки линий, текста и фигур. 쐽 DLLмодулей подсистем (Kernel32.dll, Advapi32.dll, User32.dll и Gdi32.dll), транслирующих вызовы документированных функций Windows API в вызовы соответствующих (и в большинстве своем недокументирован ных) сервисов режима ядра из Ntoskrnl.exe и Win32k.sys. 쐽 Драйверов графических устройств, представляющих собой специфичные для конкретного оборудования драйверы графического дисплея, принте ра и минипортдрайверы видеоплат. Для формирования элементов управления пользовательского интерфейса на экране, например окон и кнопок, приложения могут вызывать стандарт ные функции USER. Диспетчер окон передает эти вызовы GDI, а тот — драй верам графических устройств, где они форматируются для дисплея. Драйвер дисплея работает в паре с соответствующим минипортдрайвером видеопла ты, обеспечивая полную поддержку видео. GDI предоставляет набор стандартных функций двухмерной графики, которые позволяют приложениям, не имеющим представления о графичес ких устройствах, обращаться к ним. GDIфункции играют роль посредника между приложениями и драйверами дисплея и принтера. GDI интерпрети рует запросы приложений на вывод графики и посылает соответствующие запросы драйверам. Он также предоставляет приложениям стандартный унифицированный интерфейс для использования самых разнообразных устройств графического вывода. Этот интерфейс обеспечивает независи мость кода приложений от конкретного оборудования и его драйверов. GDI выдает свои запросы с учетом возможностей конкретного устройства, час то разделяя запрос на несколько частей для обработки. Так, некоторые уст ройства сами умеют формировать эллипсы, а другие требуют от GDI интер
ГЛАВА 9 Архитектура системы 61 претировать эллипсы как набор пикселов с определенными координатами. Подробнее об архитектуре подсистемы вывода графики и драйвере дисплея см. раздел «Design Guide» в книге «Graphics Drivers» из Windows DDK. До Windows NT 4 диспетчер окон и графические сервисы были частью процесса подсистемы Windows пользовательского режима. В Windows NT 4 основная часть кода, ответственного за обработку окон и графики, перене сена из контекста процесса подсистемы Windows в набор вызываемых сер висов, выполняемых в режиме ядра (в файл Win32k.sys). Этот перенос был осуществлен в основном для повышения общей производительности систе мы. Отдельный серверный процесс, содержащий графическую подсистему, требовал многочисленных переключений контекста потоков и процессов, что отнимало большое количество тактов процессора и значительные ре сурсы памяти, даже несмотря на высокую оптимизацию исходной архитек туры этой подсистемы. Например, каждый клиентский поток обслуживается парным серверным потоком в процессе подсистемы Windows, ожидающем запросов от клиент ского потока. Для передачи сообщений между потоками используется спе циальный механизм взаимодействия между процессами, так называемый быстрый LPC (fast LPC). В отличие от обычного переключения контекста потоков передача данных между парными потоками через быстрый LPC не вызывает в ядре события перепланирования, что позволяет серверному по току выполняться в течение оставшегося кванта времени клиентского потока (вне очереди, определенной планировщиком). Более того, для быстрой пе редачи больших структур данных, например битовых карт, используются разделяемые буферы памяти, и клиенты получают прямой доступ (только для чтения) к ключевым структурам данных сервера, а это сводит к минимуму необходимость в частом переключении контекста между клиентами и сер вером Windows. GDIоперации выполняются в пакетном режиме. При этом серия графи ческих объектов, запрошенных Windowsприложениями, не обрабатывает ся сервером и не прорисовывается на устройстве вывода до тех пор, пока не будет заполнена вся очередь GDI. Размер очереди можно установить через Windowsфункцию GdiSetBatchLimit. В любой момент все объекты из очере ди можно сбросить вызовом функции GdiFlush. С другой стороны, неизме няемые свойства и структуры данных GDI после получения от процессов подсистемы Windows кэшируются клиентскими процессами для ускорения последующего доступа к ним. Однако, несмотря на такую оптимизацию, общая производительность системы попрежнему не соответствовала требованиям приложений, интен сивно работающих с графикой. Очевидным решением проблемы стал пере вод подсистемы поддержки окон и графики в режим ядра, что позволило избежать потребности в дополнительных потоках и связанных с ними пе реключениями контекста. Кроме того, как только приложения вызывают диспетчер окон и GDI, эти подсистемы теперь получают прямой доступ к
62 ГЛ А В А 2 БЕЗОПАСНОСТЬ компонентам исполнительной системы Windows без перехода из пользова тельского режима в режим ядра и обратно. Прямой доступ особенно важен в случае вызова GDI через видеодрайверы, когда взаимодействие с видеообо рудованием требует высокой пропускной способности. Так что же остается в той части процесса подсистемы Windows, которая работает в пользовательском режиме? Поскольку консольные программы не перерисовывают окна, все операции по отрисовке и обновлению консоль ных и текстовых окон проводятся именно этой частью Windows. Увидеть ее деятельность несложно: просто откройте окно командной строки и перета щите поверх него другое окно. Вы увидите, что процесс подсистемы Win dows начинает расходовать процессорное время, перерисовывая консоль ное окно. Кроме поддержки консольных окон, только небольшая часть Win dowsфункций посылает сообщения процессу подсистемы Windows. К ним относятся функции, отвечающие за создание и завершение процессов и по токов, назначение букв сетевым дискам, создание временных файлов. Как правило, Windowsприложение нечасто переключает (если вообще переклю чает) контекст в процесс подсистемы Windows. Не пострадала ли стабильность Windows от перевода USER и GDI в режим ядра? Некоторые интересуются, не повлияет ли на стабильность системы перевод такой значительной части кода в режим ядра. Но риск сниже ния стабильности системы минимален. Дело в том, что до Windows NT 4 (равно как и в настоящее время) ошибка вроде нарушения доступа (access violation) в процессе подсистемы Windows пользовательского режима (Csrss.exe) приводила к краху системы, потому что процесс подсистемы Windows был и остается жизненно важным для функци онирования всей системы. Поскольку структуры данных, определяю щие окна на экране, содержатся именно в этом процессе, его гибель приводит к уничтожению пользовательского интерфейса. Однако да же при функционировании Windows в качестве сервера без интерак тивных процессов система не могла бы работать без Csrss, поскольку серверные процессы иногда используют оконные сообщения для кон троля внутреннего состояния приложений. Так что в Windows ошиб ки вроде нарушения доступа в том же коде, только выполняемом в ре жиме ядра, просто быстрее приводят к краху — исключения в режиме ядра требуют прекращения работы системы. Правда, теоретически появляется другая опасность. Поскольку этот код выполняется в режиме ядра, ошибка (например, применение не верного указателя) может повредить защищенные структуры данных режима ядра. До Windows NT 4 это могло привести к нарушению дос тупа, так как запись в страницы режима ядра из пользовательского режима не разрешается. Но результатом стал бы крах системы. Теперь же при выполнении кода в режиме ядра запись на какуюлибо страни
ГЛАВА 9 Архитектура системы 63 цу памяти по неверному указателю не обязательно вызовет немедлен ный крах системы. Но, если при этом будут повреждены какието структуры данных, крах скорее всего произойдет. Тем не менее возни кает риск, что изза такого указателя будет повреждена не структура данных, а буфер памяти, и это приведет к возврату пользовательской программе или записи на диск неверных данных. Существует еще одно негативное последствие перевода графичес ких драйверов в режим ядра. Ранее некоторые части графического драйвера выполнялись в Csrss, а остальные части — в режиме ядра. Те перь весь драйвер работает только в режиме ядра. Так как не все драй веры поддерживаемых Windows графических устройств разрабатыва ются Microsoft, она тесно сотрудничает с производителями оборудо вания, чтобы гарантировать разработку ими надежных и эффектив ных драйверов. Все поставляемые с системой драйверы тестируются так же тщательно, как и другие компоненты исполнительной системы. Наконец, важно понимать, что такая схема (при которой подсис тема поддержки окон и графики выполняется в режиме ядра) не явля ется принципиально рискованной. Идентичный подход используется для многих других драйверов устройств (например, сетевых карт и жестких дисков). Все эти драйверы, выполняемые в режиме ядра, ни когда не снижали надежности Windows NT. Некоторые распространяют измышления насчет снижения эффек тивности вытесняющей многозадачности Windows изза перевода диспетчера окон и GDI в режим ядра. Теория, которая стоит за этой точкой зрения, — увеличивается время, затрачиваемое на дополни тельную обработку Windows в режиме ядра. Это мнение возникло в результате ошибочного понимания архитектуры Windows. Действи тельно, во многих других операционных системах, формально под держивающих вытесняющую многозадачность, планировщик никог да не вытесняет потоки, выполняемые в режиме ядра, или вытесняет, но лишь в отдельных ситуациях. Однако в Windows любые потоки, выполняемые в режиме ядра, планируются и вытесняются так же, как и потоки пользовательского режима, — код исполнительной системы полностью реентерабелен. Помимо многих других соображений, это просто необходимо для достижения высокого уровня масштабируемо сти системы на оборудовании с поддержкой SMP. Другое направление спекуляций касалось снижения масштабируе мости SMP в результате уже описанных изменений. Теоретические обоснования были такими: раньше во взаимодействии между прило жением и диспетчером окон или GDI участвовали два потока: один — в приложении и один — в Csrss.exe. Поэтому в SMPсистемах, где эти потоки могут выполняться параллельно, пропускная способность воз растает. Это свидетельствует о непонимании технологий, применяв шихся до Windows NT 4. В большинстве случаев клиентские приложе ния вызывают процесс подсистемы Windows синхронно, т. е. клиент см. след. стр.
64 ГЛ А В А 2 БЕЗОПАСНОСТЬ ский поток полностью блокируется в ожидании обработки вызова сер верным потоком и возобновляется только после этого. Так что ника кой параллелизм в SMPсистемах недостижим. Это явление легко на блюдать в SMPсистемах на примере приложений, интенсивно рабо тающих с графикой. При этом обнаружится, что в двухпроцессорной системе каждый процессор загружен на 50%; также легко заметить единственный поток Csrss, отделенный от потока приложения. Дей ствительно, поскольку два потока тесно взаимодействуют и находят ся в сходном состоянии, для поддержания синхронизации процессо рам приходится постоянно сбрасывать кэш. Именно по этой причи не однопоточные графические приложения в SMPсистемах под уп равлением Windows NT 3.51 обычно выполняются медленнее, чем в однопроцессорных системах. В результате изменений, внесенных в Windows NT 4, удалось повы сить пропускную способность SMPсистем для приложений, интенсив но использующих диспетчер окон и GDI, — особенно когда в прило жении работает более одного потока. При наличии двух потоков при ложения на двухпроцессорной машине под управлением Windows NT 3.51 за процессорное время конкурируют в общей сложности четыре потока (два — в приложении и два — в Csrss). Хотя в каждый момент к выполнению готовы, как правило, лишь два потока, их рассогласован ность ведет к потере локальности ссылок и синхронизации кэша. Это происходит скорее всего изза переключения потоков приложения с одного процессора на другой. В Windows NT 4 каждый из двух пото ков приложения по сути имеет собственный процессор, а механизм автоматической привязки потоков в Windows пытается постоянно вы полнять данный поток на одном и том же процессоре, максимально увеличивая локальность ссылок и сводя к минимуму потребность в синхронизации кэшпамяти индивидуальных процессоров. В заключение отметим, что повышение производительности в ре зультате перевода диспетчера окон и GDI из пользовательского режи ма в режим ядра достигнуто без скольконибудь значимого снижения стабильности и надежности системы — даже в случае нескольких се ансов, созданных в конфигурации с поддержкой Terminal Services. Подсистема POSIX POSIX, название которой представляет собой аббревиатуру от «portable ope rating system interface based on UNIX» (переносимый интерфейс операцион ной системы на основе UNIX), — это совокупность международных стандар тов на интерфейсы операционных систем типа UNIX. Стандарты POSIX сти мулировали производителей поддерживать совместимость реализуемых ими UNIXподобных интерфейсов, тем самым позволяя программистам легко переносить свои приложения между системами.
ГЛАВА 9 Архитектура системы 65 В Windows реализован лишь один из многих стандартов POSIX, а имен но POSIX.1, который официально называется ISO/IEC 99451:1990, или IEEE POSIX стандарта 1003.11990. Этот стандарт изначально был включен в ос новном для соответствия требованиям правительства США, установленным во второй половине 80х годов. В федеральном стандарте Federal Information Processing Standard (FIPS) 1512, разработанном государственным институ том стандартов и технологий (NIST), содержится требование совместимос ти с POSIX 1. Windows NT 3.5, 3.51 и 4 прошли тестирование на соответствие FIPS 1512. Поскольку совместимость с POSIX.1 была одной из обязательных целей, в Windows включена необходимая базовая поддержка подсистемы POSIX.1 — например, функция fork, реализованная в исполнительной системе Windows, и поддержка файловой системой Windows жестких файловых связей (hard file links). Однако POSIX.1 определяет лишь ограниченный набор сервисов (управ ление процессами, взаимодействие между процессами, простой символьный вводвывод и т. д.), и поэтому подсистема POSIX в Windows не является пол ноценной средой программирования. Так как вызов функций из разных под систем Windows невозможен, набор функций, доступный приложениям POSIX по умолчанию, строго ограничен сервисами, определяемыми POSIX.1. Смысл этих ограничений в следующем: приложение POSIX не может создать поток или окно в Windows, а также использовать RPC или сокеты. Для преодоления этого ограничения предназначен продукт Microsoft Windows Services for UNIX, включающий (в версии 3.5) улучшенную подсис тему окружения POSIX, которая предоставляет около 2000 функций UNIX и 300 инструментов и утилит в стиле UNIX. (Детали см. на www.microsoft.com/ windows/sfu/default.asp). Эта улучшенная подсистема POSIX реально помогает переносить UNIX приложения в Windows. Однако, поскольку эти программы все равно связа ны с исполняемыми файлами POSIX, Windowsфункции им недоступны. Что бы UNIXприложения, переносимые в Windows, могли использовать Win dowsфункции, нужно приобрести специальные пакеты для переноса UNIX программ в Windows, подобные продуктам MKS Toolkit, разработанные ком панией Mortice Kern Systems Inc. (www.mkssoftware.com). Тогда UNIXприло жения можно перекомпилировать и заново собрать как исполняемые фай лы Windows и начать постепенный переход на «родные» Windowsфункции. ЭКСПЕРИМЕНТ: наблюдаем старт подсистемы POSIX Подсистема POSIX по умолчанию сконфигурирована на запуск в мо мент начала выполнения приложения POSIX. Таким образом, старт подсистемы POSIX можно наблюдать, запустив какуюнибудь програм му POSIX, например одну из утилит POSIX из Windows Services for UNIX (небольшой набор утилит вы найдете и в каталоге \Apps\POSIX на ком пактдиске ресурсов Windows 2000; они не устанавливаются как часть см. след. стр.
66 ГЛ А В А 2 БЕЗОПАСНОСТЬ ресурсов). Для запуска подсистемы POSIX следуйте инструкциям, при веденным ниже. 1. Откройте окно командной строки. 2. Запустите Process Explorer и убедитесь, что подсистема POSIX еще не запущена (т. е. процесса Psxss.exe в системе нет). Также убедитесь, что Process Explorer отображает список процессов как дерево (на жмите Ctrl+T). 3. Запустите POSIXпрограмму (например C Shell или Korn Shell, по ставляемую с Windows Services for UNIX) или утилиту POSIX из ре сурсов Windows 2000, например \Apps\POSIX\Ls.exe. 4. Вернитесь в Process Explorer и обратите внимание на новый про цесс Psxss.exe, являющийся дочерним процессом Smss.exe (который в зависимости от выбранного интервала подсветки может какоето время оставаться выделенным как новый процесс). Для компиляции и сборки приложения POSIX в Windows нужны заголовочные файлы и библиотеки POSIX из Platform SDK. Исполняе мые файлы POSIX связываются с библиотекой подсистемы POSIX, Psxdll.dll. Поскольку Windows по умолчанию сконфигурирована на запуск подсистемы POSIX только по требованию, при первом запуске приложения POSIX должен запуститься процесс подсистемы POSIX (Psxss.exe). Его выполнение продолжается до перезагрузки системы. (Если вы завершите процесс подсистемы POSIX, запуск приложений POSIX станет невозможен до следующей перезагрузки системы.) При ложение POSIX не выполняется самостоятельно; для него запускается специальный файл поддержки Posix.exe, создающий дочерний про цесс, из которого и запускаются приложения POSIX. Подсистема OS/2 Подсистема окружения OS/2, как и подсистема POSIX, обладает довольно ограниченной функциональностью и поддерживает лишь 16разрядные приложения OS/2 версии 1.2 c символьным или графическим вводомвыво дом. Кроме того, Windows запрещает прикладным программам прямой до ступ к оборудованию и поэтому не поддерживает приложения OS/2, исполь зующие расширенный вводвывод видео или включающие сегменты приви легированного вводавывода, которые пытаются выполнять инструкции IN/ OUT (для доступа к некоторым аппаратным устройствам). Приложения, вы дающие машинные команды CLI/STI, могут работать в Windows, но на вре мя выполнения команды STI все другие приложения OS/2 в системе и пото ки процессов OS/2, выдающих команды CLI, приостанавливаются. Как показано на рис. 25, подсистема OS/2, использующая 32разрядное виртуальное адресное пространство Windows, может предоставить прило жениям OS/2 версии 1.2 до 512 Мб памяти, снимая тем самым исходное ог раничение этой версии на объем адресуемой памяти (до 16 Мб).
ГЛАВА 9 Архитектура системы 67 Мозаичная область (tiled area) — это 512 Мб заранее резервируемого виртуального адресного пространства, откуда передается и куда возвраща ется память, выделяемая под сегменты, которыми пользуются 16разрядные приложения. Для каждого процесса подсистема OS/2 ведет таблицу локаль ных дескрипторов (local descriptor table, LDT), в которой сегменты разделя емой памяти занимают один и тот же LDTслот для всех процессов OS/2. Рис. 2-5. Структура виртуальной памяти подсистемы OS/2 Как будет детально показано в главе 6, потоки являются элементами вы полняемой программы и, как таковые, подлежат планированию (подключе нию к процессору по определенной схеме). В OS/2 всего 64 уровня приори тетов (от 0 до 63), а в Windows — 32 (от 0 до 31). Несмотря на это, 64 уровня приоритетов OS/2 проецируются на динамические приоритеты Windows с 1го по 15й. Потоки OS/2, выполняемые в Windows, никогда не получают приоритеты реального времени (16–31). Как и подсистема POSIX, подсистема OS/2 автоматически запускается при первой активизации OS/2совместимого образа и продолжает выполняться до перезагрузки всей системы. Подробнее о выполнении приложений POSIX и OS/2 в Windows см. главу 6. Ntdll.dll Ntdll.dll — специальная библиотека системной поддержки, нужная в основ ном при использовании DLL подсистем. Она содержит функции двух типов:
68 ГЛ А В А 2 БЕЗОПАСНОСТЬ 쐽 интерфейсы диспетчера системных сервисов (system service dispatch stubs) к сервисам исполнительной системы Windows; 쐽 внутренние функции поддержки, используемые подсистемами, DLL под систем и другими компонентами операционной системы. Первая группа функций предоставляет интерфейс к сервисам исполни тельной системы Windows, которые можно вызывать из пользовательского режима. Таких функций более 200, например NtCreateFile, NtSetEvent и т. д. Как уже говорилось, большинство из них доступно через Windows API (од нако некоторые из них предназначены только для применения внутри са мой операционной системы). Для каждой из этих функций в Ntdll существует точка входа с тем же име нем. Код внутри функции содержит специфичную для конкретной аппарат ной архитектуры команду перехода в режим ядра для вызова диспетчера системных сервисов (о нем рассказывается в главе 3), который после про верки некоторых параметров вызывает уже настоящий сервис режима ядра из Ntoskrnl.exe. Ntdll также включает множество функций поддержки, например загруз чик образов (функции, имена которых начинаются с Ldr), диспетчер куч, функции для взаимодействия с процессом подсистемы Windows (функции, имена которых начинаются с Csr), а также универсальные процедуры биб лиотек периода выполнения (функции, имена которых начинаются с Rtl). Там же находится диспетчер APC (asynchronous procedure call) пользователь ского режима и диспетчер исключений. (Подробнее об APC и исключениях см. главу 3.) Исполнительная система Исполнительная система (executive) находится на верхнем уровне Ntoskrnl.exe (ядро располагается на более низком уровне). В ее состав входят функции следующего типа. 쐽 Экспортируемые функции, доступные для вызова из пользовательского режима. Эти функции называются системными сервисами и экспортиру ются через Ntdll. Большинство сервисов доступно через Windows API или API других подсистем окружения. Однако некоторые из них недоступны через документированные функции (примером могут служить LPC, функ ции запросов вроде NtQueryInformationProcess, специализированные фун кции типа NtCreatePagingFile и т. д.). 쐽 Функции драйверов устройств, вызываемые через функцию DeviceIoCont! rol. Последняя является универсальным интерфейсом от пользовательс кого режима к режиму ядра для вызова функций в драйверах устройств, не связанных с чтением или записью. 쐽 Экспортируемые функции, доступные для вызова только из режима ядра и документированные в Windows DDK или Windows Installable File System (IFS) Kit (см. www.microsoft.com/whdc/ddk/ifskit.default.mspx).
ГЛАВА 9 Архитектура системы 69 쐽 Экспортируемые функции, доступные для вызова только из режима ядра, но не описанные в Windows DDK или IFS Kit (например, функции, кото рые используются видеодрайвером, работающим на этапе загрузки, и чьи имена начинаются с Inbv). 쐽 Функции, определенные как глобальные, но не экспортируемые симво лы. Включают внутренние функции поддержки, вызываемые в Ntoskrnl; их имена начинаются с Iop (функции поддержки диспетчера вводавывода) или с Mi (функции поддержки управления памятью). 쐽 Внутренние функции в какомлибо модуле, не определенные как глобаль ные символы. Исполнительная система состоит из следующих основных компонентов (каждый из них подробно рассматривается в последующих главах книги). 쐽 Диспетчер конфигурации (см. главу 4), отвечающий за реализацию и уп равление системным реестром. 쐽 Диспетчер процессов и потоков (см. главу 6), создающий и завершающий процессы и потоки. Низкоуровневая поддержка процессов и потоков ре ализована в ядре Windows, а исполнительная система дополняет эти низ коуровневые объекты своей семантикой и функциями. 쐽 Монитор состояния защиты (см. главу 8), реализующий политики безо пасности на локальном компьютере. Он охраняет ресурсы операционной системы, осуществляя аудит и контролируя доступ к объектам в период выполнения. 쐽 Диспетчер ввода!вывода (см. главу 9), реализующий аппаратнонезави симый вводвывод и отвечающий за пересылку вводавывода нужным драйверам устройств для дальнейшей обработки. 쐽 Диспетчер Plug and Play (см. главу 9), определяющий, какие драйверы нужны для поддержки конкретного устройства, и загружающий их. Тре бования каждого устройства в аппаратных ресурсах определяются в про цессе перечисления. В зависимости от требований каждого устройства диспетчер PnP распределяет такие ресурсы, как порты вводавывода, IRQ, каналы DMA и области памяти. Он также отвечает за посылку соответству ющих уведомлений об изменениях в аппаратном обеспечении системы (при добавлении или удалении устройств). 쐽 Диспетчер электропитания (см. главу 9), который координирует собы тия, связанные с электропитанием, и генерирует уведомления системы управления электропитанием, посылаемые драйверам. Когда система не занята, диспетчер можно настроить на остановку процессора для сниже ния энергопотребления. Изменение энергопотребления отдельных уст ройств возлагается на их драйверы, но координируется диспетчером электропитания. 쐽 Подпрограммы WDM Windows Management Instrumentation (см. главу 4), позволяющие драйверам публиковать информацию о своих рабочих ха рактеристиках и конфигурации, а также получать команды от службы
70 ГЛ А В А 2 БЕЗОПАСНОСТЬ WMI пользовательского режима. Потребители информации WMI могут находиться как на локальной машине, так и на любом компьютере в сети. 쐽 Диспетчер кэша (см. главу 11), повышающий производительность фай лового вводавывода за счет сохранения в основной памяти дисковых данных, к которым недавно было обращение (это также уменьшает чис ло обращений к диску для записи, поскольку модифицированные данные предварительно накапливаются в памяти в течение определенного пери ода). Как вы увидите, диспетчер кэша выполняет эту задачу, используя поддержку проецируемых файлов со стороны диспетчера памяти. 쐽 Диспетчер памяти (см. главу 7), реализующий виртуальную память — схему управления памятью, позволяющую выделять каждому процессу большое закрытое адресное пространство, объем которого может превы шать доступную физическую память. Диспетчер памяти также обеспечи вает низкоуровневую поддержку диспетчера кэша. 쐽 Средство логической предвыборки (см. главу 7), ускоряющее запуск сис темы и процессов за счет оптимизации загрузки данных, к которым про исходит обращение при запуске системы или процессов. Кроме того, в состав исполнительной системы входят четыре основные группы функций поддержки, используемые вышеперечисленными компо нентами. Примерно треть из них описана в DDK, поскольку драйверы тоже используют их. Вот что представляют собой четыре категории функций под держки. 쐽 Диспетчер объектов — создает, управляет и удаляет объекты и абстракт ные типы данных исполнительной системы, используемые для представ ления таких ресурсов операционной системы, как процессы, потоки и различные синхронизирующие объекты. Подробнее о диспетчере объек тов см. главу 3. 쐽 Механизм LPC (см. главу 3) — передает сообщения между клиентским и серверным процессами на одном компьютере. LPC является гибкой, оп тимизированной версией RPC (remote procedure call), стандартного ме ханизма взаимодействия между клиентскими и серверными процессами через сеть. 쐽 Большой набор стандартных библиотечных функций для обработки строк, арифметических операций, преобразования типов данных и обра ботки структур безопасности. 쐽 Подпрограммы поддержки исполнительной системы, например для вы деления системной памяти (пулов подкачиваемых и неподкачиваемых страниц), доступа к памяти со взаимоблокировкой, а также два специаль ных типа синхронизирующих объектов: ресурс (resource) и быстродей ствующий мьютекс (fast mutex).
ГЛАВА 9 Архитектура системы 71 Ядро Ядро состоит из набора функций в Ntoskrnl.exe, предоставляющих фунда ментальные механизмы (в том числе планирования потоков и синхрониза ции), которые используются компонентами исполнительной системы и низ коуровневыми аппаратнозависимыми средствами поддержки (диспетчери зации прерываний и исключений), различными в каждой процессорной архитектуре. Код ядра написан в основном на С, а ассемблер использовали лишь для решения специфических задач, трудно реализуемых на С. Как и функции поддержки исполнительной системы, упоминавшиеся в предыдущем разделе, часть функций ядра описана в DDK (см. функции, чьи имена начинаются с Ke), поскольку они необходимы для реализации драй веров устройств. Объекты ядра Ядро состоит из низкоуровневых, четко определенных и хорошо предска зуемых примитивов и механизмов операционной системы, позволяющих компонентам исполнительной системы более высокого уровня выполнять свои функции. Ядро отделено от остальной части исполнительной системы; оно реализует системные механизмы и не участвует в принятии решений, связанных с системной политикой. Практически все такие решения, кроме планирования и диспетчеризации потоков, принимаются исполнительной системой. Вне ядра исполнительная система представляет потоки и другие разде ляемые ресурсы в виде объектов. Управление этими объектами требует оп ределенных издержек, так как нужны описатели, позволяющие манипулиро вать объектами, средства защиты и квоты ресурсов, резервируемых при их создании. В ядре можно избежать таких издержек, поскольку оно реализует набор более простых объектов, называемых объектами ядра (kernel objects). Эти объекты позволяют ядру контролировать обработку данных процессо ром и поддерживают объекты исполнительной системы. Большинство объектов уровня исполнительной системы инкапсулирует один или более объектов ядра, включая в себя их атрибуты, определенные ядром. Одна из групп объектов ядра, называемых управляющими (control objects), определяет семантику управления различными функциями операционной системы. В эту группу входят объекты APC, DPC (deferred procedure call) и несколько объектов, используемых диспетчером вводавывода (например, объект прерывания). Другая группа объектов под названием объекты диспетчера (dispatcher objects) реализует средства синхронизации, позволяющие изменять плани рование потоков. В группу таких объектов входят поток ядра (kernel thread), мьютекс (mutex), событие (event), семафор (semaphore), таймер (timer), ожи даемый таймер (waitable timer) и некоторые другие. С помощью функций ядра исполнительная система создает объекты ядра, манипулирует ими и конструирует более сложные объекты, предоставляемые в пользовательском
72 ГЛ А В А 2 БЕЗОПАСНОСТЬ режиме. Объекты подробно рассматриваются в главе 3, а процессы и пото ки — в главе 6. Поддержка оборудования Другая важная задача ядра — абстрагирование или изоляция исполнитель ной системы и драйверов устройств от различий между аппаратными архи тектурами, поддерживаемыми Windows (т. е. различий в обработке преры ваний, диспетчеризации исключений и синхронизации между несколькими процессорами). Архитектура ядра нацелена на максимальное обобщение кода — даже в случае аппаратнозависимых функций. Ядро поддерживает набор семанти чески идентичных и переносимых между архитектурами интерфейсов. Боль шая часть кода, реализующего переносимые интерфейсы, также идентична для разных архитектур. Но одна часть этих интерфейсов поразному реализуется на разных ар хитектурах, а другая включает код, специфичный для конкретной архитек туры. Архитектурнонезависимые интерфейсы могут быть вызваны на лю бой машине, причем семантика интерфейса будет одинаковой — независи мо от специфического кода для той или иной архитектуры. Некоторые ин терфейсы ядра (например, процедуры спинблокировки, описанные в гла ве 3) на самом деле реализуются в HAL (см. следующий раздел), поскольку их реализация может отличаться даже в пределах семейства процессоров с одинаковой архитектурой. В ядре также содержится небольшая порция кода с х86специфичными интерфейсами, необходимыми для поддержки старых программ MSDOS. Эти интерфейсы не являются переносимыми в том смысле, что их нельзя вызывать на машине с другой архитектурой, где они попросту отсутствуют. Этот х86специфичный код, например, поддерживает манипуляции с GDT (global descriptor tables) и LDT (local descriptor tables) — аппаратными сред ствами x86. Другим примером архитектурноспецифичного кода ядра может служить интерфейс, предоставляющий поддержку буфера трансляции и процес сорного кэша. Эта поддержка требует разного кода на разных архитектурах, поскольку кэш в них реализуется различным образом. Еще один пример — переключение контекста. Хотя на высоком уровне для выбора потоков и переключения контекста применяется один и тот же алгоритм (сохраняется контекст предыдущего потока, загружается контекст нового и запускается новый поток), существуют архитектурные различия между его реализациями для разных процессоров. Поскольку контекст опи сывается состоянием процессора (его регистров и т. д.), сохраняемая и заг ружаемая информация зависит от архитектуры. Уровень абстрагирования от оборудования Как отмечалось в начале этой главы, одной из важнейших особенностей архи тектуры Windows является переносимость между различными аппаратными
ГЛАВА 9 Архитектура системы 73 платформами. Ключевой компонент, обеспечивающий такую переносимость, — уровень абстрагирования от оборудования (hardware abstraction layer, HAL). HAL — это загружаемый модуль режима ядра (Hal.dll), предоставляющий низ коуровневый интерфейс с аппаратной платформой, на которой выполняется Windows. Он скрывает от операционной системы специфику конкретной ап паратной платформы, в том числе ее интерфейсов вводавывода, контроллеров прерываний и механизмов взаимодействия между процессорами, т. е. все функ ции, зависимые от архитектуры и от конкретной машины. Когда внутренним компонентам Windows и драйверам устройств нужна платформеннозависимая информация, они обращаются не к самому обо рудованию, а к подпрограммам HAL, что и обеспечивает переносимость этой операционной системы. По этой причине подпрограммы HAL документиро ваны в Windows DDK, где вы найдете более подробные сведения о HAL и о его использовании драйверами. Хотя в Windows имеется несколько модулей HAL (см. таблицу 26), при ус тановке на жесткий диск компьютера копируется только один из них — Hal.dll. (В других операционных системах, например в VMS, нужный модуль HAL вы бирается при загрузке системы.) Поскольку для поддержки разных процессо ров требуются разные модули HAL, системный диск от одной х86установки скорее всего не подойдет для загрузки системы с другим процессором. Таблица 2-6. Список модулей HAL для x86 в \Windows\Driver\Cache\i386\Driver.cab Имя файла HAL Поддерживаемые системы Hal.dll Стандартные персональные компьютеры (ПК) Halacpi.dll ПК с ACPI (Advanced Configuration and Power Interface) Halapic.dll ПК с APIC (Advanced Programmable Interrupt Controller) Halaacpi.dll ПК с APIC и ACPI Halmps.dll Многопроцессорные ПК Halmacpi.dll Многопроцессорные ПК с ACPI Halborg.dll Рабочие станции Silicon Graphics (только для Windows 2000; больше не продаются) Halsp.dll Compaq SystemPro (только для Windows XP) ПРИМЕЧАНИЕ В базовой системе Windows Server 2003 нет HAL, специ фических для конкретных вендоров. ЭКСПЕРИМЕНТ: просмотр базовых HAL, включенных в Windows Для просмотра HAL, включенных в Windows, откройте файл Driver.cab в соответствующем подкаталоге, специфичном для конкретной архи тектуры, в каталоге \Windows\Driver Cache. (Например, для систем x86 имя этого файла — \Windows\Driver Cache\i386\Driver.cab.) Прокрути те список до файлов, начинающихся с «Hal», и вы увидите файлы, пе речисленные в таблице 26.
74 ГЛ А В А 2 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: определяем используемый модуль HAL Определить, какой модуль HAL используется на вашей машине, мож но двумя способами. 1. Откройте файл \Windows\Repair\Setup.log, найдите строку с Hal.dll. Имя файла, стоящее в этой строке после знака равенства, соответ ствует имени модуля HAL, извлеченного из Driver.cab с дистрибу тивного носителя. 2. Откройте Device Manager (Диспетчер устройств): щелкните правой кнопкой мыши значок My Computer (Мой компьютер) на рабочем столе, выберите команду Properties (Свойства), откройте вкладку Hardware (Оборудование) и щелкните кнопку Device Manager (Дис петчер устройств). Проверьте имя «драйвера» для устройства Com puter (Компьютер). ЭКСПЕРИМЕНТ: просмотр зависимостей NTOSKRNL и HAL Вы можете просмотреть взаимосвязи образов ядра и HAL, изучив их таблицы импорта и экспорта с помощью утилиты Dependency Walker (Depends.exe), которая содержится в Windows Support Tools и Platform SDK. Для исследования файла в Dependency Walker откройте его ко мандой Open из меню File. Вот пример вывода этой утилиты при просмотре зависимостей в Ntoskrnl. Обратите внимание, что Ntoskrnl связан с HAL, который в свою оче редь связан с Ntoskrnl (оба используют функции друг у друга). Ntoskrnl также связан с Bootvid.dll, видеодрайвером, используемым для вывода заставки при запуске Windows. В Windows XP и выше вы увидите в списке дополнительную DLL, Kdcom.dll. Она содержит код инфра структуры отладчика ядра, который раньше был частью Ntoskrnl.exe. Подробное описание информации, выводимой Dependency Walker, см. в справочном файле этой утилиты (Depends.hlp).
ГЛАВА 9 Архитектура системы 75 Драйверы устройств Драйверы устройств подробно описываются в главе 9, а здесь мы даем крат кий обзор их типов и поясняем, как перечислить установленные драйверы, загруженные в системе. Драйверы устройств являются загружаемыми модулями режима ядра (как правило, это файлы с расширением .sys); они образуют интерфейс между диспетчером вводавывода и соответствующим оборудованием. Эти драйве ры выполняются в режиме ядра в одном из трех контекстов: 쐽 в контексте пользовательского потока, инициировавшего функцию вво давывода; 쐽 в контексте системного потока режима ядра; 쐽 как результат прерывания (а значит, не в контексте какоголибо процес са или потока, который был текущим на момент прерывания). Как было сказано в предыдущем разделе, в Windows драйверы устройств не управляют оборудованием напрямую — вместо этого они вызывают функ ции HAL. Драйверы, как правило, пишутся на С (иногда на С++), поэтому при правильном использовании процедур HAL они являются переносимыми между поддерживаемыми Windows архитектурами на уровне исходного кода, а на уровне двоичных файлов — внутри семейства с одинаковой архи тектурой. Существует несколько типов драйверов устройств. 쐽 Драйверы аппаратных устройств, которые управляют (через HAL) обо рудованием, записывают на них выводимые данные и получают вводимые данные от физического устройства или из сети. Есть множество типов таких драйверов — драйверы шин, интерфейсов, устройств массовой па мяти и т. д. 쐽 Драйверы файловой системы — это драйверы Windows, принимающие запросы на файловый вводвывод и транслирующие их в запросы ввода вывода для конкретного устройства. 쐽 Драйверы фильтра файловой системы, которые обеспечивают зеркали рование и шифрование дисков, перехват вводавывода и некоторую до полнительную обработку информации перед передачей ее на следующий уровень. 쐽 Сетевые редиректоры и серверы, являющиеся драйверами файловых си стем, которые передают запросы файловой системы на вводвывод дру гим компьютерам в сети и принимают от них аналогичные запросы. 쐽 Драйверы протоколов, реализующие сетевые протоколы вроде TCP/IP, NetBEUI и IPX/SPX. 쐽 Драйверы потоковых фильтров ядра, действующие по цепочке для об работки потоковых данных, например при записи и воспроизведении аудио и видеоинформации. Поскольку установка драйвера устройства — единственный способ добав ления в систему стороннего кода режима ядра, некоторые программисты
76 ГЛ А В А 2 БЕЗОПАСНОСТЬ пишут драйверы просто для того, чтобы получить доступ к внутренним функ циям или структурам данных операционной системы, недоступным из поль зовательского режима (но документированным и поддерживаемым в DDK). Например, многие утилиты с www.sysinternals.com представляют собой ком бинацию GUIприложений Windows с драйверами устройств, используемы ми для сбора сведений о состоянии внутрисистемных структур и вызова функций, доступных только в режиме ядра. Усовершенствования в модели драйверов Windows В Windows 2000 была введена поддержка Plug and Play и энергосберегающих технологий, а также расширена модель драйверов Windows NT, называемая Windows Driver Model (WDM). Windows 2000 и более поздние версии могут работать с унаследованными драйверами Windows NT 4, но, поскольку они не поддерживают Plug and Play и энергосберегающие технологии, функци ональность системы в этом случае будет ограничена. С точки зрения WDM, существует три типа драйверов. 쐽 Драйвер шины (bus driver), обслуживающий контроллер шины, адаптер, мост или любые другие устройства, имеющие дочерние устройства. Драй веры шин нужны для работы системы и в общем случае поставляются Microsoft. Для каждого типа шины (PCI, PCMCIA и USB) в системе имеет ся свой драйвер. Сторонние разработчики создают драйверы для поддерж ки новых шин вроде VMEbus, Multibus и Futurebus. 쐽 Функциональный драйвер (function driver) — основной драйвер устрой ства, предоставляющий его функциональный интерфейс. Обязателен, кроме тех случаев, когда устройство используется без драйверов (т. е. вводвывод осуществляется драйвером шины или драйверами фильтров шины, как в случае SCSI PassThru). Функциональный драйвер по опреде лению обладает наиболее полной информацией о своем устройстве. Обычно только этот драйвер имеет доступ к специфическим регистрам устройства. 쐽 Драйвер фильтра (filter driver), поддерживающий дополнительную функ циональность устройства (или существующего драйвера) или изменяю щий запросы на вводвывод и ответы на них от других драйверов (это часто используется для коррекции устройств, предоставляющих невер ную информацию о своих требованиях к аппаратным ресурсам). Такие драйверы не обязательны, и их может быть несколько. Они могут рабо тать как на более высоком уровне, чем функциональный драйвер или драйвер шины, так и на более низком. Обычно эти драйверы предостав ляются OEMпроизводителями или независимыми поставщиками обору дования (IHV). В среде WDM один драйвер не может контролировать все аспекты уст ройства: драйвер шины информирует диспетчер PnP об устройствах, под ключенных к шине, в то время как функциональный драйвер управляет уст ройством.
ГЛАВА 9 Архитектура системы 77 В большинстве случаев драйвер фильтра более низкого уровня модифи цирует поведение устройства. Например, если устройство сообщает драйве ру своей шины о том, что ему нужно 4 порта вводавывода, тогда как на са мом деле ему требуется 16, драйвер фильтра может перехватить список ап паратных ресурсов, направляемый драйвером шины диспетчеру PnP и ис править число портов. Драйвер фильтра более высокого уровня обычно придает устройству до полнительную функциональность. Так, высокоуровневый драйвер фильтра для клавиатуры может обеспечивать дополнительную защиту. Обработка прерываний описывается в главе 3. Подробнее о диспетчере вво давывода, WDM, Plug and Play и энергосберегающих технологиях см. главу 9. ЭКСПЕРИМЕНТ: просмотр установленных драйверов устройств Чтобы вывести список установленных драйверов, запустите оснастку Computer Management (Управление компьютером). Для этого выбери те из меню Start (Пуск) команду Programs (Программы), затем Admi nistrative Tools (Администрирование) и Computer Management (Управ ление компьютером) или откройте Control Panel (Панель управления) и дважды щелкните значок Computer Management. В окне Computer Management раскройте System Information (Сведения о системе), затем Software Environment (Программная среда) и Drivers (Драйверы). Ниже приведен пример списка драйверов. В этом окне выводится список драйверов, определенных в реест ре, а также их тип и состояние — Running (Работает) или Stopped (Ос тановлена). Драйверы устройств и процессы Windowsсервисов опре деляются в разделе реестра HKLM\SYSTEM\CurrentControlSet\Services. Однако они отличаются по коду типа, например 1 соответствует драй веру режима ядра. (Полный список хранящихся в реестре сведений, которые относятся к драйверам, см. в таблице 47.) Список загруженных в текущий момент драйверов можно просмот реть и с помощью утилиты Drivers (Drivers.exe в ресурсах Windows 2000) или Pstat (Pstat.exe в Windows XP Support Tools, Windows Server 2003 Support Tools, ресурсах Windows 2000 и Platform SDK). Ниже при веден листинг части выходной информации утилиты Drivers. см. след. стр.
78 ГЛ А В А 2 БЕЗОПАСНОСТЬ C:\>drivers ModuleName Code Data Bss Paged Init LinkDate ———————————————————————————————— ntoskrnl.exe 429184 96896 0 775360 138880 Tue Dec 07 18:41:11 1999 hal.dll 25856 6016 0 16160 10240 Tue Nov 02 20:14:22 1999 BOOTVID.DLL 5664 2464 0 0 320 Wed Nov 03 20:24:33 1999 ACPI.sys 92096 8960 0 43488 4448 Wed Nov 10 20:06:04 1999 WMILIB.SYS 512 0 0 1152 192 Sat Sep 25 14:36:47 1999 pci.sys 12704 1536 0 31264 4608 Wed Oct 27 19:11:08 1999 isapnp.sys 14368 832 0 22944 2048 Sat Oct 02 16:00:35 1999 compbatt.sys 2496 0 0 2880 1216 Fri Oct 22 18:32:49 1999 BATTC.SYS 800 0 0 2976 704 Sun Oct 10 19:45:37 1999 intelide.sys 1760 32 0 0 128 Thu Oct 28 19:20:03 1999 PCIIDEX.SYS 4544 480 0 10944 1632 Wed Oct 27 19:02:19 1999 pcmcia.sys 32800 8864 0 23680 6240 Fri Oct 29 19:20:08 1999 ftdisk.sys 4640 32 0 95072 3392 Mon Nov 22 14:36:23 1999 ———————————————————————————————— Total 4363360 580320 0 3251424 432992 Утилита перечисляет все загруженные компоненты режима ядра (Ntoskrnl, HAL и драйверы устройств) и сообщает размеры разделов в каждом образе. Pstat также выводит список загруженных драйверов, но только пос ле списка процессов и потоков в каждом процессе. Она показывает один вид очень важной информации, не сообщаемой утилитой Drivers: адрес загрузки модуля в системном пространстве. Как вы еще увиди те, этот адрес нужен для увязки выполняемых системных потоков с драйвером, в котором они существуют. Недокументированные интерфейсы Просмотр имен экспортируемых или глобальных символов в ключе вых системных файлах (Ntoskrnl.exe, Hal.dll или Ntdll.dll) может ока заться полезным: вы получите представление о том, что умеет делать Windows в сравнении с документированной и поддерживаемой час тью. Конечно, знание имен этих функций еще не означает, что вы смо жете или должны их вызывать. Эти интерфейсы не документированы и могут быть изменены. Мы предлагаем рассмотреть эти функции только для лучшего понимания внутренних функций Windows, а не для обхода поддерживаемых интерфейсов. Например, просмотрев список функций в Ntdll.dll, вы сможете срав нить список всех системных сервисов, которые Windows предостав ляет DLLмодулям подсистем пользовательского режима, с их подмно жеством, предоставляемым каждой подсистемой. Хотя многие из этих функций точно соответствуют документированным и поддерживае мым Windowsфункциям, некоторые из них недоступны через Win dows API (см. статью «Inside the Native API» на www.sysinternals.com).
ГЛАВА 9 Архитектура системы 79 С другой стороны, было бы интересно выяснить, что импортиру ют DLLмодули подсистемы Windows (скажем, Kernel32.dll или Adva pi32.dll) и какие функции они вызывают в Ntdll. Также представляет интерес содержимое Ntoskrnl.exe: хотя в Windows DDK документированы многие экспортируемые подпрограммы, исполь зуемые драйверами режима ядра, немалая их часть не описана. Возмож но, вас заинтересует содержимое таблицы импорта для Ntoskrnl и HAL, где перечислены функции HAL, используемые Ntoskrnl, и наоборот. В таблице 27 приведено большинство общеупотребительных пре фиксов имен функций в компонентах исполнительной системы. В каж дом из таких компонентов также используются слегка модифицирован ные префиксы, обозначающие внутренние функции: либо за первой буквой префикса указывается i (от internal), либо префикс заканчива ется на букву p (от private). Так, Ki относится к внутренним функциям ядра, а Psp — к внутренним функциям поддержки процессов. Таблица 2-7. Общеупотребительные префиксы Префикс Компонент Cc Диспетчер кэша Cm Диспетчер конфигурации Ex Подпрограммы поддержки исполнительной системы FsRtl Библиотека (периода выполнения) драйвера файловой системы Hal HAL Io Диспетчер вводавывода Ke Ядро Lpc LPC Lsa Локальная аутентификация Mm Диспетчер памяти Nt Системные сервисы Windows (большинство из них экспортируется как Windowsфункции) Ob Диспетчер объектов Po Диспетчер электропитания Pp Диспетчер PnP Ps Поддержка процессов Rtl Стандартная библиотека (периода выполнения) Se Защита Wmi Windows Management Instrumentation (Инструментарий управления Windows) Zw Зеркальная точка входа для системных сервисов (имена которых начинаются с Nt), устанавливающих предыдущий режим доступа к ядру. При этом параметры не контролиру ются, так как Ntсервисы проверяют параметры только при переключении из пользовательского режима см. след. стр.
80 ГЛ А В А 2 БЕЗОПАСНОСТЬ Понимая схему именования системных процедур Windows, рас шифровывать имена экспортируемых функций гораздо легче. Общий формат выглядит так: <префикс><операция><объект> где префикс — внутренний компонент, экспортирующий процедуру, операция — название операции, выполняемой над объектом или ре сурсом, а объект — объект, над которым проводится эта операция. Например, ExAllocatePoolWithTag является процедурой поддержки исполнительной системы, которая выделяет память из пула подкачива емых или неподкачиваемых страниц. KeInitializeThread представляет собой процедуру для создания и инициализации объекта ядра «поток». Системные процессы В каждой системе Windows выполняются перечисленные ниже процессы. (Два из них, Idle и System, не являются процессами в строгом смысле этого слова, поскольку они не выполняют какойлибо код пользовательского ре жима.) 쐽 Процесс Idle (включает по одному потоку на процессор для учета време ни простоя процессора). 쐽 Процесс System (содержит большинство системных потоков режима ядра). 쐽 Диспетчер сеансов (Smss.exe). 쐽 Подсистема Windows (Csrss.exe). 쐽 Процесс входа в систему (Winlogon.exe). 쐽 Диспетчер управления сервисами (Services.exe) и создаваемые им дочер ние процессы сервисов (например, универсальный процесс для хостин га сервисов, Svchost.exe). 쐽 Серверный процесс локальной аутентификации (Lsass.exe). Чтобы понять взаимоотношения этих процессов, полезно просмотреть «дерево» процессов, отражающее связи между родительскими и дочерними процессами. Увидев, кем создается тот или иной процесс, вам будет легче понять, откуда берется каждый процесс. На рис. 26 показана часть экранно го снимка дерева процессов с комментариями по нескольким первым про цессам. (Process Explorer позволяет добавлять комментарии для индивидуаль ных процессов и выводить их как дополнительную колонку в окне.) В следующих разделах поясняются основные системные процессы, пере численные на рис. 26. Хотя в этих разделах дается краткое описание по следовательности запуска данных процессов, подробно все этапы загрузки Windows рассматриваются в главе 5.
ГЛАВА 9 Рис. 2-6. Архитектура системы 81 Начальное дерево системных процессов Процесс Idle Первый процесс, показанный на рис. 26, является процессом простоя сис темы (system idle process). Как будет показано в главе 6, процессы идентифи цируются по именам их образов. Однако этот процесс (как и процесс Sys tem) не выполняет реальный код пользовательского режима (в том смысле, что в каталоге \Windows нет «System Idle Process.exe»). Кроме того, разные утилиты изза особенностей реализации поразному именуют его. В табли це 28 приводится несколько имен процесса Idle (с идентификатором 0); подробнее о нем рассказывается в главе 6. Таблица 2-8. Имена процесса с идентификатором 0, сообщаемые различными утилитами Утилита Имя процесса с идентификатором 0 Task Manager System Idle Process Process Viewer (Pviewer.exe) Idle Process Status (Pstat.exe) Idle Process Process Explode (Pview.exe) System Process Task List (Tlist.exe) System Process QuickSlice (Qslice.exe) Systemprocess А теперь рассмотрим системные потоки и предназначение каждого сис темного процесса, выполняющего реальный код. Прерывания и DPC Две строки, помеченные как Interrupts и DPCs, отражают время, затраченное на обслуживание прерываний и обработку отложенных вызовов процедур (deferred procedure calls, DPC). Эти механизмы объясняются в главе 3. Заметь те: хотя Process Explorer показывает эти строки в списке процессов, они не имеют отношения к процессам. Они выводятся потому, что ведут учет про цессорного времени, не выделенного какомулибо процессу. Но Task Manager (Диспетчер задач) рассматривает время, затраченное на обработку преры
82 ГЛ А В А 2 БЕЗОПАСНОСТЬ ваний и DPC, как время простоя системы. Поэтому система, занятая интен сивной обработкой прерываний, будет выглядеть в Task Manager так, будто она ничем не занимается. Процесс System и его потоки Процесс System (с идентификатором 8 в Windows 2000 и идентификатором 4 в Windows XP и Windows Server 2003) служит носителем особых потоков, работающих только в режиме ядра, — системных потоков режима ядра (kernelmode system threads). У системных потоков имеются все атрибуты и контексты обычных потоков пользовательского режима (например, кон текст оборудования, приоритет и т. д.), но они отличаются тем, что выпол няются только в режиме ядра внутри системного кода, загруженного в сис темное пространство, — будь то Ntoskrnl.exe или какойлибо драйвер уст ройства. Кроме того, у системных потоков нет адресного пространства поль зовательского процесса, и поэтому нужная им динамическая память выделя ется из куч памяти операционной системы, например из пула подкачивае мых или неподкачиваемых страниц. Системные потоки создаются функцией PsCreateSystemThread (докумен тирована в DDK), вызываемой только в режиме ядра. Windows, как и драй веры устройств, создает системные потоки при инициализации системы для выполнения действий, требующих получения контекста потока, например для выдачи и ожидания запросов на вводвывод или опроса устройства. Ска жем, диспетчер памяти использует системные потоки для реализации таких функций, как запись измененных страниц в страничный файл (page file) или в спроецированные файлы, загрузки процессов в память или выгрузки из нее и т. д. Ядро создает системный поток под названием «диспетчер настройки баланса» (balance set manager), активизируемый раз в секунду для инициа ции при необходимости различных событий, связанных с планированием и управлением памятью. Диспетчер кэша также использует системные пото ки для реализации как опережающего чтения, так и отложенной записи. Драйвер файлсервера (Srv.sys) с помощью системных потоков отвечает на сетевые запросы вводавывода применительно к файлам на общих дисковых разделах, доступных в сети. Даже драйвер дисковода гибких дисков создает свой системный поток для опроса этого устройства (это повышает эффек тивность опроса, потому что драйвер дисковода гибких дисков, управляемый прерываниями, расходует много системных ресурсов). Подробнее о конк ретных системных потоках см. главы, где рассматриваются соответствующие компоненты. По умолчанию владельцем системных потоков является процесс System, но драйверы могут создавать системные потоки в любом процессе. Напри мер, драйвер подсистемы Windows (Win32k.sys) создает системные потоки в процессе подсистемы Windows (Csrss.exe), чтобы облегчить доступ к дан ным в адресном пространстве этого процесса в пользовательском режиме. Если вы занимаетесь поиском причин неполадок или системным анали зом, полезно сопоставить выполнение индивидуальных системных потоков
ГЛАВА 9 Архитектура системы 83 с создавшими их драйверами или даже с подпрограммой, содержащей соот ветствующий код. Так, на сильно загруженном файлсервере процесс System скорее всего потребляет значительную часть процессорного времени. Но для определения того, какой именно драйвер или компонент операционной системы выполняется, просто знать, что процесс System в данный момент выполняет «какойто системный поток», недостаточно. Так что, если в процессе System выполняются потоки, сначала определи те, какие это потоки (например, с помощью оснастки Performance). Найдя такой поток (или потоки), посмотрите, в каком драйвере началось выпол нение системного потока (это по крайней мере укажет на наиболее веро ятного создателя потока), либо проанализируйте стек вызовов (или хотя бы текущий адрес) интересующего вас потока, что позволит определить, в ка ком месте он сейчас выполняется. Оба этих метода демонстрируются следующими экспериментами. ЭКСПЕРИМЕНТ: идентификация системных потоков в процессе System Вы можете убедиться, что потоки внутри процесса System должны быть потоками режима ядра, поскольку стартовый адрес каждого из них больше адреса начала системного пространства (которое по умол чанию начинается с 0x80000000, если система загружена без парамет ра /3GB в Boot.ini). Кроме того, обратив внимание на процессорное время, выделяемое этим потокам, вы увидите, что они занимают про цессорное время только при выполнении в режиме ядра. Чтобы опре делить драйвер, создавший системный поток, найдите стартовый ад рес потока (с помощью Pviewer.exe) и ищите драйвер с базовым адре сом, ближайшим (с меньшей стороны) к этому стартовому адресу. Ути лита Pstat в конце своих выходных данных, как и команда !drivers от ладчика ядра, сообщает базовые адреса каждого загруженного драйве ра устройства. Чтобы быстро найти текущий адрес потока, воспользуйтесь коман дой !stacks 0 отладчика ядра. Ниже приводится образец вывода, полу ченный на работающей системе с помощью LiveKd. kd> !stacks 0 Proc.Thread Thread ThreadState Blocker [System] 8.000004 8146edb0 BLOCKED ntoskrnl!MmZeroPageThread+0x5f 8.00000c 8146e730 BLOCKED ?? Kernel stack not resident ?? 8.000010 8146e4b0 BLOCKED ntoskrnl!ExpWorkerThread+0x73 8.000014 8146d030 BLOCKED ?? Kernel stack not resident ?? 8.000018 8146ddb0 BLOCKED ntoskrnl!ExpWorkerThread+0x73 8.00001c 8146db30 BLOCKED ntoskrnl!ExpWorkerThread+0x73 8.000020 8146d8b0 BLOCKED ntoskrnl!ExpWorkerThread+0x73 8.000024 8146d630 BLOCKED ntoskrnl!ExpWorkerThread+0x73 8.000028 8146d3b0 BLOCKED ntoskrnl!ExpWorkerThread+0x73 8.00002c 8146c030 BLOCKED ntoskrnl!ExpWorkerThread+0x73 см. след. стр.
84 ГЛ А В А 2 8.000030 8.000034 8.000038 8.00003c 8.000040 8.000044 8.000048 8.00004c 8.000050 8.000054 8.000058 8.00005c 8.000060 8.000070 8.000074 8.00006c 8.000080 8.000084 8.00008c 8.00015c 8.000160 8.000178 8.0002d0 8.0002d4 8.000404 8.000430 8.00069c БЕЗОПАСНОСТЬ 8146cdb0 8146b470 8146b1f0 8146a030 8146adb0 8146a5b0 8146a330 81461030 8143a770 81439730 81436c90 813d9170 813d8030 8139c850 8139c5d0 81384030 81333330 813330b0 81321db0 81205570 81204570 811fcdb0 811694f0 81168030 811002b0 810f4990 80993030 BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED BLOCKED READY READY ntoskrnl!ExpWorkerThreadBalanceManager+0x55 ntoskrnl!MiDereferenceSegmentThread+0x44 ntoskrnl!MiModifiedPageWriterWorker+0x31 ntoskrnl!KeBalanceSetManager+0x7e ntoskrnl!KeSwapProcessOrStack+0x24 ntoskrnl!FsRtlWorkerThread+0x33 ntoskrnl!FsRtlWorkerThread+0x33 ACPI!ACPIWorker+0x46 ntoskrnl!MiMappedPageWriter+0x4d dmio!voliod_loop+0x399 NDIS!ndisWorkerThread+0x22 ltmdmntt!WakeupTimerThread+0x27 ltmdmntt!WriteRegistryThread+0x1c raspptp!MainPassiveLevelThread+0x78 raspptp!PacketWorkingThread+0xc0 rasacd!AcdNotificationRequestThread+0xd8 rdbss!RxpWorkerThreadDispatcher+0x6f rdbss!RxSpinUpRequestsDispatcher+0x58 ?? Kernel stack not resident ?? INO_FLTR+0x68bd INO_FLTR+0x80e9 irda!RxThread+0xfa ?? Kernel stack not resident ?? ?? Kernel stack not resident ?? rdbss!RxpWorkerThreadDispatcher+0x6f parallel!ParallelThread+0x3e rdbss!RxpWorkerThreadDispatcher+0x6f В первом столбце выводятся идентификаторы процесса и потока (в виде «Идентификатор процесса. Идентификатор потока»). Во вто ром сообщается текущий адрес потока, в третьем — состояние пото ка: ожидает, готов или выполняется (о состояниях потоков см. главу 6). В последнем столбце показывается адрес вершины стека потока. Эта информация помогает определить драйвер, в котором началось вы полнение того или иного потока. Имя функции потока в Ntoskrnl дает дополнительную подсказку о том, что именно делает поток. Однако, если выполняемый поток является одним из рабочих по токов системы (ExpWorkerThread), вы не сможете точно сказать, что он делает, поскольку любой драйвер может давать задания рабочему потоку системы. В этом случае единственный выход — поставить точку прерывания в ExQueueWorkItem. По достижении этой точки введите !dso work_queue_item esp+4. Эта команда даст вам первый аргумент функции ExQueueWorkItem, представляющий собой указатель на струк туру рабочего элемента, которая в свою очередь содержит адрес про цедуры рабочего потока, вызываемой в его контексте. В качестве аль тернативы можно использовать команду k отладчика ядра, которая сообщает текущее содержимое стека вызовов. А это подскажет, какой драйвер отправил задание рабочему потоку.
ГЛАВА 9 Архитектура системы 85 ЭКСПЕРИМЕНТ: увязка системного потока с драйвером устройства В этом эксперименте мы посмотрим, как увязать активность процес сора в процессе System с системным потоком (и драйвером, к которо му он относится), вызывающим эту активность. Это важно: чтобы по настоящему понять, что происходит, нужно перейти на уровень пото ков процесса System. В данном случае мы вызовем активность систем ного потока, создав нагрузку файлового сервера на компьютере. (Драйвер файлсервера Srv.sys создает системные потоки для обработ ки входящих запросов на файловый вводвывод. Подробнее об этом компоненте см. главу 13.) 1. Откройте окно командной строки. 2. Создайте список всех каталогов на диске C, используя сетевой путь для доступа к этому диску. Например, если имя вашего компьюте ра — COMPUTER1, введите dir \\computer1\c$ /s. (Ключ /s застав ляет перечислять все подкаталоги.) 3. Запустите Process Explorer и дважды щелкните процесс System. 4. Откройте вкладку Threads. 5. Отсортируйте список по столбцу CSwitch Delta (разница по числу переключений контекста). Вы должны увидеть один или более по токов в Srv.sys, как показано на следующей иллюстрации. Если вы видите работающий системный поток и не уверены, какой это драйвер, нажмите кнопку Module, которая открывает окно свойств для файла. Например, нажатие кнопки Module при выбранном, как на предыдущей иллюстрации, потоке в Srv.sys выводит результаты в сле дующем окне. см. след. стр.
86 ГЛ А В А 2 БЕЗОПАСНОСТЬ Диспетчер сеансов (Smss) Диспетчер сеансов (Session Manager) (\Windows\System32\Smss.exe) являет ся первым процессом пользовательского режима, создаваемым в системе. Он порождается системным потоком режима ядра, отвечающим за последний этап инициализации исполнительной системы и ядра. Диспетчер сеансов отвечает за некоторые важные этапы запуска Win dows, такие как создание дополнительных страничных файлов, выполнение отложенных операций по копированию, переименованию и удалению фай лов, а также создание системных переменных окружения. Он также запус кает процессы подсистем (обычно только Csrss.exe) и Winlogon, который в свою очередь создает остальные системные процессы. Значительная часть сведений о конфигурации, хранящихся в реестре и используемых при инициализации Smss, находится в HKLM\SYSTEM\Current ControlSet\Control\Session Manager. Некоторые из этих данных поясняются в главе 5 в разделе по Smss. (Более подробное описание разделов и парамет ров см. в справочном файле Regentry.chm из ресурсов Windows 2000). После выполнения этих этапов инициализации главный поток Smss пе реходит к бесконечному ожиданию описателей процессов Csrss и Winlogon. Так как от них зависит функционирование Windows, при неожиданном за вершении любого из них Smss вызывает крах системы (с кодом STATUS_SYS TEM_ PROCESS_TERMINATED, или 0xC000021A). Smss также ожидает запро сы на загрузку, события отладки и запросы на запуск новых сеансов серве ра терминала. (Описание служб терминала см. в главе 1.) Сеанс Terminal Services создается Smss. Когда Smss получает запрос на со здание сеанса, он сначала вызывает NtSetSystemInformation с запросом на настройку сеансовых структур данных режима ядра. Это приводит к вызову внутренней функции диспетчера памяти MmSessionCreate, настраивающей виртуальное адресное пространство сеанса, которое будет содержать пул подкачиваемой памяти для сеанса и сеансовые структуры данных, создава емые подсистемой Windows (а точнее, ее частью, работающей в режиме
ГЛАВА 9 Архитектура системы 87 ядра), а также другими драйверами устройств. (Детали см. в главе 7). Затем Smss создает экземпляр Winlogon и Csrss для данного сеанса. Winlogon, LSASS и Userinit Процесс входа в Windows (\Windows\System32\Winlogon.exe) обрабатывает интерактивный вход пользователя в систему и выход из нее. При нажатии комбинации клавиш SAS (secure attention sequence) Winlogon получает уве домление о запросе пользователя на вход в систему. По умолчанию SAS в Windows представляет собой комбинацию клавиш Ctrl+Alt+Del. Назначение SAS — защита пользователя от программ перехвата паролей, имитирующих процесс входа в систему, так как эту комбинацию клавиш нельзя перехватить в приложении пользовательского режима. Идентификация и аутентификация при входе в систему реализованы в заменяемой DLL под названием GINA (Graphical Identification and Authen tication). Стандартная GINA Windows, Msgina.dll, реализует интерфейс для входа в систему по умолчанию. Однако разработчики могут включать свои GINA DLL, реализующие другие механизмы аутентификации и идентифика ции вместо стандартного метода Windows на основе проверки имени и па роля пользователя — например, на основе распознавания образцов голоса. Кроме того, Winlogon может загружать дополнительные DLL компонентов сетевого доступа для дальнейшей аутентификации. Эта функция позволяет нескольким компонентам доступа к сетям единовременно собирать все не обходимые регистрационные данные в процессе обычного входа в систему. После ввода имя и пароль пользователя посылаются для проверки сервер ному процессу локальной аутентификации (local security authentication server process, LSASS) (\Windows\System32\Lsass.exe, описываемому в главе 8). LSASS вызывает соответствующую функциональность (реализованную в виде DLL) для проверки соответствия введенного пароля с тем, что хранится в актив ном каталоге или SAM (части реестра, содержащей определения пользова телей и групп). После успешной аутентификации LSASS вызывает какуюлибо функцию в мониторе состояния защиты (например, NtCreateToken), чтобы сгенерировать объект «маркер доступа» (access token object), содержащий профиль безопас ности пользователя. Впоследствии Winlogon использует его для создания на чального процесса оболочки. Информация о начальном процессе (или процес сах) хранится в параметре Userinit в разделе реестра HKLM\ SOFTWARE\ Micro soft\Windows NT\CurrentVersion\Winlogon. (По умолчанию начальным процес сом считается Userinit.exe, но в списке может быть более одного образа.) Userinit выполняет некоторые действия по инициализации пользователь ской среды (например, запускает сценарии регистрации и активизирует групповые политики), а затем ищет в реестре параметр Shell (в указанном выше разделе Winlogon) и создает процесс для запуска определенной сис темной оболочки (по умолчанию — Explorer.exe). После этого процесс Useri nit завершается. Вот почему для Explorer.exe не показывается родительский процесс — он уже завершился. Иначе говоря, Explorer является «внучатым»
88 ГЛ А В А 2 БЕЗОПАСНОСТЬ процессом Winlogon. (Имена процессов, чьи родительские процессы уже завершены, в списке Tlist выравниваются по левому краю.) Winlogon активен не только при входе и выходе пользователя, но и при перехвате ввода SAS с клавиатуры. Например, когда вы нажимаете Ctrl+Alt+ Del после входа в систему, Winlogon открывает диалоговое окно Windows Security (Безопасность Windows), предлагающее на выбор выход из системы, запуск Task Manager, блокировку рабочей станции, завершение работы сис темы и т. д. Полное описание этапов процесса входа см. в разделе «Smss, Csrss и Win logon» главы 5. Подробнее об аутентификации см. главу 8. Подробнее о вы зываемых функциях интерфейса LSASS (чьи имена начинаются с Lsa) см. до кументацию Platform SDK. Диспетчер управления сервисами (SCM) Вспомните, что термин «сервисы» в Windows обозначает как серверные про цессы, так и драйверы устройств. В этом разделе обсуждаются сервисы, яв ляющиеся процессами пользовательского режима. Они похожи на демоны UNIX или обособленные процессы VMS в том смысле, что могут быть скон фигурированы на автоматический запуск при загрузке системы, не требуя интерактивного входа. Их также можно запустить вручную, например, с по мощью оснастки Services (Службы) или вызовом Windowsфункции StartSer! vice. Как правило, сервисы не взаимодействуют с вошедшим в систему поль зователем, хотя при особых условиях это возможно (см. главу 4). Этими сервисами управляет специальный системный процесс, диспетчер управления сервисами (service control manager) (\Windows\System32\Servi ces.exe), отвечающий за запуск, остановку процессов сервисов и взаимодей ствие с ними. Сервисы представляют собой просто Windowsобразы испол няемых программ, вызывающие особые Windowsфункции для взаимодей ствия с диспетчером управления сервисами и с его помощью выполняющие такие операции, как регистрация успешного запуска сервиса, ответы на зап росы о состоянии, приостановку или завершение работы сервиса. Сервисы определяются в разделе реестра HKLM\SYSTEM\CurrentControlSet\Services. Сведения о подразделах и параметрах, относящихся к сервисам, см. в спра вочном файле Regentry.chm в ресурсах Windows. Учтите, что у сервисов есть три имени: имя процесса, выполняемого в си стеме, внутреннее имя в реестре и так называемое отображаемое имя (display name), которое можно увидеть в оснастке Services (Службы). (Не у каждого сервиса есть отображаемое имя, и в случае его отсутствия используется внут реннее имя.) Сервисы Windows также содержат поле описания, где находит ся более подробная информация о том, что делает конкретный сервис. Чтобы выяснить, какие именно сервисы содержатся в том или ином про цессе, введите команду tlist /s. Но заметьте, что иногда один процесс совме стно используется несколькими сервисами. Код типа в реестре позволяет узнать, какие сервисы имеют собственные процессы и какие из них делят процессы с другими сервисами данного образа файла.
ГЛАВА 9 Архитектура системы 89 В виде сервисов реализуются некоторые компоненты Windows, например диспетчер очереди печати (спулер), журнал системных событий, планиров щик задач, а также ряд сетевых компонентов. ЭКСПЕРИМЕНТ: вывод списка установленных сервисов Чтобы вывести список установленных сервисов (служб), дважды щел кните значок Administrative Tools (Администрирование) в окне Control Panel (Панель управления) и выберите Services (Службы). Вы должны увидеть чтонибудь в таком роде: Для просмотра детальных сведений о сервисе щелкните правой кнопкой мыши имя сервиса и выберите команду Properties (Свойства). Ниже показан пример окна свойств для службы Print Spooler (Диспет чер очереди печати). см. след. стр.
90 ГЛ А В А 2 БЕЗОПАСНОСТЬ Обратите внимание, что поле Path To Executable (Исполняемый файл) указывает на программу, включающую данный сервис. Помни те, что некоторые сервисы разделяют процессы с другими сервисами, поэтому число сервисов и используемых ими процессов не всегда на ходится в соотношении «один к одному». ЭКСПЕРИМЕНТ: просмотр сервисов внутри сервисных процессов Process Explorer выделяет процессы, которые являются хостами одного и более сервисов. (Для настройки поведения Process Explorer выберите Con figure Highlighting в меню Options.) Дважды щелкнув процесс — хост сер висов, вы откроете вкладку Services, где перечисляются сервисы внутри этого процесса. При этом по каждому сервису выводится имя раздела ре естра, где определен данный сервис, отображаемое имя, видимое админи стратору, и текст описания для этого сервиса (если такой текст есть). На пример, в Windows XP список сервисов в процессе Svchost.exe, выполняе мом под учетной записью System, выглядит следующим образом. Подробнее о сервисах рассказывается в главе 4. Резюме В этой главе мы познакомились с общими аспектами системной архитекту ры Windows. Мы также рассмотрели ключевые компоненты Windows и принципы их взаимодействия. В следующей главе будет подробнее расска зано о базовых системных механизмах, на которые опираются эти компо ненты, в том числе о синхронизации и диспетчере объектов.
Г Л А В А 3 Системные механизмы В Microsoft Windows существует несколько базовых механизмов, которыми пользуются компоненты режима ядра: исполнительная система (executive), ядро и драйверы устройств. В этой главе описываются следующие систем ные механизмы (а также способы их использования): 쐽 диспетчеризация ловушек (trap dispatching), в том числе прерываний, DPC (deferred procedure call), APC (asynchronous procedure call), исключе ний и системных сервисов; 쐽 диспетчер объектов исполнительной системы; 쐽 синхронизация, в том числе спинблокировки, объекты диспетчера ядра (kernel dispatcher objects) и реализация механизмов ожидания; 쐽 системные рабочие потоки; 쐽 различные механизмы вроде поддержки глобальных флагов Windows; 쐽 LPC (local procedure call); 쐽 Kernel Event Tracing; 쐽 Wow64. Диспетчеризация ловушек Прерывания и исключения — такие ситуации в операционной системе, в которых нормальный поток выполнения кода процессором прерывается. Эти ситуации обнаруживаются как программным, так и аппаратным обес печением. Термин ловушка (trap) относится к механизму, благодаря которо му при прерывании или исключении процессор перехватывает контроль над выполняемым потоком и передает управление определенной части опе рационной системы. В Windows процессор передает управление обработ чику ловушек (trap handler) — функции, специфичной для конкретного пре рывания или исключения. Рис. 31 иллюстрирует некоторые ситуации, в ко торых активизируются обработчики ловушек.
92 Рис. 3-1. ГЛ А В А 3 БЕЗОПАСНОСТЬ Диспетчеризация ловушек Ядро различает прерывания и исключения: прерывание (interrupt) явля ется асинхронным событием (т. е. оно может произойти в любой момент независимо от текущих команд, выполняемых процессором). Прерывания в основном генерируются устройствами вводавывода и таймерами. Их мож но включать и отключать. Исключение (exception), напротив, представляет собой синхронное событие, являющееся результатом выполнения конкрет ной команды. Повторный запуск программы в аналогичных условиях с теми же данными позволит воспроизвести исключение. Примерами исключений могут служить нарушения доступа (ошибки защиты памяти), выполнение некоторых команд отладчика, а также попытки деления на нуль. Ядро также считает исключениями вызовы системных сервисов (хотя с точки зрения технической реализации это системные ловушки). Прерывания и исключения можно генерировать как программно, так и аппаратно. Например, исключение «bus error» (ошибка шины) возникает из за аппаратной ошибки, а причиной исключения «dividebyzero» (деление на нуль) является ошибка в программе. Аналогичным образом прерывания мо гут генерироваться устройствами вводавывода или самим ядром (такие про граммные прерывания, как, например, APC или DPC). При аппаратном прерывании или исключении процессор записывает статусную информацию в стек ядра для прерванного потока, чтобы впослед ствии можно было вернуться к исходной точке в потоке управления и про должить выполнение команд так, будто ничего не произошло. Если поток выполнялся в пользовательском режиме, Windows переключается на стек режима ядра для потока. Затем создает в стеке ядра прерванного потока
ГЛАВА 9 Системные механизмы 93 фрейм ловушки (trap frame), в котором сохраняет информацию о состоянии потока. Фрейм ловушки является подмножеством полного контекста пото ка (см. главу 6), и вы можете просмотреть его определение, введя в отладчи ке ядра команду dt nt!_ktrap_frame. Программное прерывание ядро обслу живает либо при обработке аппаратного прерывания, либо синхронно — при вызове потоком функции ядра, относящейся к данному программному прерыванию. В большинстве случаев ядро устанавливает функции, выполняющие об щую обработку ловушек до и после передачи управления другим функциям, которые ставят ловушки. Например, когда устройство генерирует прерыва ние, обработчик ловушек аппаратных прерываний (принадлежащий ядру) передает управление процедуре обслуживания прерывания (interrupt service routine, ISR), предоставленной драйвером соответствующего устройства. Если прерывание возникло в результате вызова системного сервиса, обра ботчик ловушек общесистемных сервисов передает управление функции указанного системного сервиса в исполнительной системе. Ядро также ус танавливает обработчики для ловушек, которые оно не ожидает или не об рабатывает. Эти обработчики, как правило, выполняют системную функцию KeBugCheckEx. Она останавливает компьютер, если ядро обнаруживает в ра боте системы отклонения, способные привести к повреждению данных (подробнее об этом см. главу 14). Диспетчеризация прерываний, исключе ний и системных сервисов детальнее описывается в следующих разделах. Диспетчеризация прерываний Аппаратные прерывания обычно генерируются устройствами вводавывода, которые таким образом уведомляют процессор о необходимости уделить им внимание. Устройства, управляемые на основе прерываний, позволяют опе рационной системе максимально полно использовать процессор, совмещая основную обработку с обслуживанием вводавывода. Выдав запрос на ввод вывод, поток может заняться другой работой, пока устройство выполняет запрошенную операцию. Закончив, устройство генерирует прерывание, и процессор переключается на обслуживание этого устройства. Прерывания ми управляются, как правило, координатные устройства, принтеры, клавиа туры, дисковые устройства и сетевые платы. Системное программное обеспечение также может генерировать преры вания. Ядро способно отключать прерывания, чтобы не прерывать работу процессора, однако это делается нечасто — только в критические моменты, например при обработке прерываний или диспетчеризации исключения. Для обработки аппаратных прерываний ядро устанавливает обработчи ки ловушек прерываний, которые передают управление внешней процеду ре (ISR), обрабатывающей прерывание, или внутренней процедуре ядра, реагирующей на прерывание. Драйверы устройств предоставляют ISR для об служивания прерываний от своих устройств, а ядро — внутренние процеду ры для обработки других типов прерываний.
94 ГЛ А В А 3 БЕЗОПАСНОСТЬ Далее мы рассмотрим, как процессор уведомляется об аппаратных пре рываниях, какие типы прерываний поддерживаются ядром и как драйверы устройств взаимодействуют с ядром (в процессе обработки прерываний). Кроме того, мы поговорим о распознавании ядром программных прерыва ний и об объектах, используемых для реализации таких прерываний. Обработка аппаратных прерываний На аппаратных платформах, поддерживаемых Windows, прерывания, связан ные с внешним вводомвыводом, поступают по одной из линий контролле ра прерываний. Контроллер в свою очередь связан с процессором един ственной линией, по которой и уведомляет о прерывании. Как только про цессор прерывается, он требует от контроллера запрос прерывания (inter rupt request, IRQ). Контроллер транслирует IRQ в номер прерывания, исполь зуемый как индекс в структуре, называемой таблицей диспетчеризации прерываний (interrupt dispatch table, IDT), и передает управление соответ ствующей процедуре. При загрузке Windows заносит в IDT указатели на процедуры ядра, обрабатывающие каждое прерывание и исключение. ЭКСПЕРИМЕНТ: просмотр IDT Просмотреть содержимое IDT, включая сведения об обработчиках ло вушек, которые Windows назначила прерываниям, можно с помощью команды !idt отладчика ядра. Команда !idt без флагов показывает век торы, которые сопоставлены с адресами в модулях, отличных от Ntoskrnl.exe. Ниже показано, что выводит команда !idt. kd> !idt Dumping IDT: 30: 31: 34: 35: 38: 39: 3b: 806b14c0 hal!HalpClockInterrupt 8a39dc3c i8042prt!I8042KeyboardInterruptService (KINTERRUPT 8a39dc00) 8a436dd4 serial!SerialCIsrSw (KINTERRUPT 8a436d98) 8a44ed74 NDIS!ndisMIsr (KINTERRUPT 8a44ed38) portcls!CInterruptSync::Release+0x10 (KINTERRUPT 899c44a0) 806abe80 hal!HalpProfileInterrupt 8a4a8abc ACPI!ACPIInterruptServiceRoutine (KINTERRUPT 8a4a8a80) 8a48d8c4 pcmcia!PcmciaInterrupt (KINTERRUPT 8a48d888) ohci1394!OhciIsr (KINTERRUPT 8a41da18) VIDEOPRT!pVideoPortInterrupt (KINTERRUPT 8a1bc2c0) USBPORT!USBPORT_InterruptService (KINTERRUPT 8a2302b8) USBPORT!USBPORT_InterruptService (KINTERRUPT
ГЛАВА 9 3c: 3e: 3f: Системные механизмы 95 8a0b8008) USBPORT!USBPORT_InterruptService (KINTERRUPT 8a170008) USBPORT!USBPORT_InterruptService (KINTERRUPT 8a258380) NDIS!ndisMIsr (KINTERRUPT 8a0e0430) 8a39d3ec i8042prt!I8042MouseInterruptService (KINTERRUPT 8a39d3b0) 8a47264c atapi!IdePortInterrupt (KINTERRUPT 8a472610) 8a489b3c atapi!IdePortInterrupt (KINTERRUPT 8a489b00) В системе, задействованной в этом эксперименте, номер прерыва ния 0x3C — с ISR драйвера клавиатуры (I8042prt.sys), а прерывание 0x3B совместно используется несколькими устройствами, в том чис ле видеоадаптером, шиной PCMCIA, портами USB и IEEE 1394, а также сетевым адаптером. Windows увязывает аппаратные IRQ с номерами прерываний в IDT. Эта таблица используется системой и при конфигурировании обработчиков ловушек для исключений. Так, номер исключения для ошибки страницы на x86 и x64 (это исключение возникает, когда поток пытается получить дос туп к отсутствующей или не определенной в виртуальной памяти странице) равен 0xe. Следовательно, запись 0xe в IDT указывает на системный обработ чик ошибок страниц. Хотя архитектуры, поддерживаемые Windows, допус кают до 256 элементов в IDT, число IRQ на конкретной машине определяет ся архитектурой используемого в ней контроллера прерываний. У каждого процессора имеется своя IDT, так что разные процессоры мо гут при необходимости выполнять разные ISR. Например, в многопроцес сорной системе каждый процессор получает прерывания системного тай мера, но обновление значения системного таймера в результате обработки этого прерывания осуществляется только одним процессором. Однако все процессоры используют это прерывание для измерения кванта времени, выделенного потоку, и для инициации новой процедуры планирования по истечении этого кванта. Аналогичным образом в некоторых конфигураци ях может понадобиться, чтобы определенные аппаратные прерывания об рабатывал конкретный процессор. Контроллеры прерываний на платформе x86 В большинстве систем x86 применяется либо программируемый контрол лер прерываний (Programmable Interrupt Controller, PIC) i8259A, либо его разновидность, усовершенствованный программируемый контроллер пре рываний (Advanced Programmable Interrupt Controller, APIC) i82489. Новые компьютеры, как правило, оснащаются APIC. Стандарт PIC был разработан для оригинальных IBM PC. PIC работает только в однопроцессорных систе мах и имеет 15 линий прерываний. АPIC и SAPIC (о нем чуть позже) спосо бен работать в многопроцессорных системах и предлагает 256 линий пре
96 ГЛ А В А 3 БЕЗОПАСНОСТЬ рываний. Intel совместно с другими компаниями создали спецификацию Multiprocessor (MP) Specification, стандарт для многопроцессорных систем x86, основанный на использовании APIC. Для совместимости с однопроцес сорными операционными системами и загрузочным кодом, запускающим многопроцессорную систему в однопроцессорном режиме, APIC поддержи вает PICсовместимый режим с 15 линиями прерываний и передачей преры ваний лишь главному процессору. Архитектура APIC показана на рис. 32. На самом деле APIC состоит из нескольких компонентов: APIC вводавывода, принимающего прерывания от устройств, локальных APIC, принимающих прерывания от APIC вводавывода по выделенной шине и прерывающих ра боту того процессора, с которым они связаны, а также i8259Aсовместимо го контроллера прерываний, транслирующего входные сигналы APIC в со ответствующие PICэквиваленты. APIC вводавывода отвечает за реализацию алгоритмов перенаправления прерываний, и операционная система выби рает нужный ей алгоритм (в Windows выбор возлагается на HAL). Эти алго ритмы равномерно распределяют между процессорами нагрузку, связанную с обработкой прерываний от устройств, и в максимальной мере использу ют все преимущества локальности, направляя такие прерывания процессо ру, который только что обрабатывал прерывания аналогичного типа. Рис. 3-2. Архитектура x86 APIC Контроллеры прерываний на платформе x64 Поскольку архитектура x64 совместима с операционными системами для x86, системы на базе x64 должны предоставлять те же контроллеры преры ваний, что и на базе x86. Однако x64версии Windows не будут работать на системах без APIC (т. е. они не поддерживают PIC).
ГЛАВА 9 Системные механизмы 97 Контроллеры прерываний на платформе IA64 В архитектуре IA64 используется контроллер прерываний Streamlined Advanced Programmable Interrupt Controller (SAPIC) — результат эволюционного развития APIC. Главное различие между архитектурами APIC и SAPIC в том, что APIC вво давывода в APICсистеме направляет прерывания локальным APIC по выделен ной шине APIC, тогда как в системе SAPIC прерывания передаются по шине вво давывода и системы (I/O and system bus) для большего быстродействия. Еще одно различие — перенаправление прерываний и балансировка нагрузки в APICсистеме обрабатывается самой шиной APIC, а в SAPICсистеме, где нет выделенной шины APIC, требуется, чтобы соответствующая поддержка была запрограммирована в микрокоде (прошивке). Но, даже если эта поддержка имеется в микрокоде, Windows не использует ее — вместо этого она статичес ки назначает прерывания процессорам по принципу карусели. ЭКСПЕРИМЕНТ: просмотр конфигурации PIC и APIC Конфигурацию PIC в однопроцессорной системе и АPIC в многопро цессорной системе можно просмотреть с помощью команд !pic или !apic отладчика ядра. (Для этого эксперимента LiveKd не годится, так как она не может напрямую обращаться к оборудованию.) Ниже по казан образец вывода команды !pic в однопроцессорной системе (уч тите, что команда !pic не работает в системе, использующей APIC HAL). lkd> !pic —— IRQ Number —— 00 01 Physically in service: Physically masked: Physically requested: Level triggered: 02 . . . . 03 . . . . 04 . . . . 05 . Y . . 06 . . . . 07 . . . Y 08 . Y . . 09 . Y . . 0A . . . . 0B . . . Y 0C . Y . . 0D . . . Y 0E . . . . 0F . Y . . . . . . . . . . На следующем листинге приводится выходная информация коман ды !apic в системе, использующей MPS HAL. Префикс «0:» в командной строке отладчика говорит о том, что текущие команды выполняются на процессоре 0, поэтому данный листинг относится к APIC ввода вывода процессора 0. lkd> !apic Apic @ fffe0000 ID:0 (40010) LogDesc:01000000 DestFmt:ffffffff TPR 20 TimeCnt: 0bebc200clk SpurVec:3f FaultVec:e3 error:0 Ipi Cmd: 0004001f Vec:1F FixedDel Dest=Self edg high Timer..: 000300fd Vec:FD FixedDel Dest=Self edg high masked Linti0.: 0001003f Vec:3F FixedDel Dest=Self edg high masked Linti1.: 000184ff Vec:FF NMI Dest=Self lvl high masked TMR: 61, 82, 9192, B1 IRR: ISR: см. след. стр.
98 ГЛ А В А 3 БЕЗОПАСНОСТЬ Теперь взгляните на образец вывода команды !ioapic, показываю щей конфигурацию APIC вводавывода: 0: kd> !ioapic IoApic @ ffd02000 Inti00.: 000100ff Inti01.: 00000962 Inti02.: 000100ff Inti03.: 00000971 Inti04.: 000100ff Inti05.: 00000961 Inti06.: 00010982 Inti07.: 000100ff Inti08.: 000008d1 Inti09.: 000100ff Inti0A.: 000100ff Inti0B.: 000100ff Inti0C.: 00000972 Inti0D.: 000100ff Inti0E.: 00000992 Inti0F.: 000100ff Inti10.: 000100ff Inti11.: 000100ff Inti12.: 000100ff Inti13.: 000100ff Inti14.: 0000a9a3 Inti15.: 0000a993 Inti16.: 000100ff Inti17.: 000100ff ID:8 (11) Arb:0 Vec:FF FixedDel Vec:62 LowestDl Vec:FF FixedDel Vec:71 LowestDl Vec:FF FixedDel Vec:61 LowestDl Vec:82 LowestDl Vec:FF FixedDel Vec:D1 FixedDel Vec:FF FixedDel Vec:FF FixedDel Vec:FF FixedDel Vec:72 LowestDl Vec:FF FixedDel Vec:92 LowestDl Vec:FF FixedDel Vec:FF FixedDel Vec:FF FixedDel Vec:FF FixedDel Vec:FF FixedDel Vec:A3 LowestDl Vec:93 LowestDl Vec:FF FixedDel Vec:FF FixedDel PhysDest:00 Lg:03000000 PhysDest:00 Lg:03000000 PhysDest:00 Lg:03000000 Lg:02000000 PhysDest:00 Lg:01000000 PhysDest:00 PhysDest:00 PhysDest:00 Lg:03000000 PhysDest:00 Lg:03000000 PhysDest:00 PhysDest:00 PhysDest:00 PhysDest:00 PhysDest:00 Lg:03000000 Lg:03000000 PhysDest:00 PhysDest:00 edg edg edg edg edg edg edg edg edg edg edg edg edg edg edg edg edg edg edg edg lvl lvl edg edg masked masked masked masked masked masked masked masked masked masked masked masked masked masked masked masked Уровни запросов программных прерываний Хотя контроллеры прерываний различают уровни приоритетов прерыва ний, Windows использует свою схему приоритетов прерываний, известную под названием уровни запросов прерываний (interrupt request levels, IRQL). Внутри ядра IRQL представляются в виде номеров 0–31 в системах x86 и 0–15 в системах x64 и IA64, причем больший номер соответствует преры ванию с более высоким приоритетом. Ядро определяет стандартный набор IRQL для программных прерываний, а HAL увязывает IRQL с номерами ап паратных прерываний. IRQL, определенные для архитектуры x86, показаны на рис. 33, а аналогичные сведения для архитектур x64 и IA64 — на рис. 34. ПРИМЕЧАНИЕ Уровень SYNCH_LEVEL, используемый многопроцес сорными версиями ядра для защиты доступа к индивидуальным для каждого процессора блокам PRCB (processor control blocks), не пока зан на этих схемах, так как его значение варьируется в разных верси ях Windows. Описание SYNCH_LEVEL и его возможных значений см. в главе 6.
ГЛАВА 9 Системные механизмы Рис. 3-3. Уровни запросов прерываний (IRQL) в x86-системах Рис. 3-4. Уровни запросов прерываний (IRQL) в системах x64 и IA64 99 Прерывания обслуживаются в порядке их приоритета, и прерывания с более высоким приоритетом вытесняют обработку прерываний с меньшим приоритетом. При возникновении прерывания с высоким приоритетом процессор сохраняет информацию о состоянии прерванного потока и ак тивизирует сопоставленный с данным прерыванием диспетчер ловушки. Последний повышает IRQL и вызывает процедуру обслуживания прерывания (ISR). После выполнения ISR диспетчер прерывания понижает IRQL процес сора до исходного уровня и загружает сохраненные ранее данные о состо янии машины. Прерванный поток возобновляется с той точки, где он был прерван. Когда ядро понижает IRQL, могут «материализоваться» ранее замас кированные прерывания с более низким приоритетом. Тогда вышеописан ный процесс повторяется ядром для обработки и этих прерываний.
100 ГЛ А В А 3 БЕЗОПАСНОСТЬ Уровни приоритетов IRQL имеют совершенно иной смысл, чем приори теты в схеме планирования потоков (см. главу 6). Приоритет в этой схеме является атрибутом потока, тогда как IRQL — атрибутом источника преры вания, например клавиатуры или мыши. Кроме того, IRQL каждого процес сора меняется во время выполнения команд операционной системы. Значение IRQL определяет, какие прерывания может получать данный процессор. IRQL также используется для синхронизации доступа к структу рам данных режима ядра (о синхронизации мы поговорим позже). При вы полнении поток режима ядра повышает или понижает IRQL процессора либо напрямую (вызовом соответственно KeRaiseIrql или KeLowerIrql), ли бо — что бывает гораздо чаще — опосредованно (через функции, которые обращаются к синхронизирующим объектам ядра). Как показано на рис. 35, прерывания от источника с IRQL, превышающим текущий уровень, преры вают работу процессора, а прерывания от источников, IRQL которых мень ше или равен текущему уровню, маскируются до тех пор, пока выполняемый поток не понизит IRQL. Рис. 3-5. Маскирование прерываний Поскольку доступ к PIC — операция довольно медленная, в HAL, исполь зующих PIC, реализован механизм оптимизации «отложенный IRQL» (lazy IRQL), который избегает обращений к PIC. Когда IRQL повышается, HAL — вместо того чтобы изменять маску прерывания — просто отмечает новый IRQL. Если вслед за этим возникает прерывание с более низким приорите том, HAL устанавливает маску прерывания в соответствии с первым и откла дывает обработку прерывания с более низким приоритетом до понижения IRQL. Таким образом, если при повышенном IRQL не возникнет прерываний с более низким приоритетом, HAL не потребуется обращаться к PIC.
ГЛАВА 9 Системные механизмы 101 Поток режима ядра повышает и понижает IRQL процессора, на котором он выполняется, в зависимости от того, что именно делает этот поток. На пример, обработчик ловушки (или сам процессор) при прерывании повы шает IRQL процессора до IRQL источника прерывания. В результате все пре рывания с более низким или равным IRQL маскируются (только на этом про цессоре), что не дает прерыванию с таким же или более низким IRQL поме шать процессору обработать текущее прерывание. Замаскированные преры вания либо обрабатываются другим процессором, либо откладываются до понижения IRQL. Поэтому все системные компоненты, в том числе ядро и драйверы устройств, пытаются удерживать IRQL на уровне passive («пассив ный»), иногда называемом низким уровнем. Если бы IRQL долго оставался неоправданно высоким, драйверы устройств не смогли бы оперативно реа гировать на аппаратные прерывания. ПРИМЕЧАНИЕ Прерывания APC_LEVEL являются исключением из правила, которое гласит, что повышение IRQL блокирует прерывания такого же уровня и ниже. Если поток повышает IRQL до уровня APC_ LEVEL, а затем отключается от процессора изза появления прерыва ния DISPATCH_LEVEL, то система может доставить ему прерывание APC_LEVEL, как только он вновь получит процессорное время. Таким образом, APC_LEVEL можно считать IRQL, локальным для потока. ЭКСПЕРИМЕНТ: определяем IRQL Если вы работаете с отладчиком ядра в Windows Server 2003, то може те определить IRQL процессора командой !irql: kd> !irql Debugger saved IRQL for processor 0x0 — 0 (LOW_LEVEL) Заметьте, что в структуре данных, называемой PCR (processor control region), и ее расширении — PRCB (processor control block) име ется поле с именем Irql. Эти структуры содержат информацию о состо янии каждого процессора в системе, в том числе текущий IRQL, ука затель на аппаратную IDT, сведения о текущем потоке и потоке, кото рый будет выполняться следующим. Ядро и HAL используют эту ин формацию для выполнения операций, специфичных для данной ма шины и ее архитектуры. Отдельные части структур PCR и PRCB откры то определены в заголовочном файле Ntddk.h (в Windows DDK). Заг ляните в него, чтобы получить представление об этих структурах. Для просмотра содержимого PCR воспользуемся командой !pcr от ладчика ядра. kd> !pcr PCR Processor 0 @ffdff000 NtTib.ExceptionList: f8effc68 NtTib.StackBase: f8effdf0 NtTib.StackLimit: f8efd000 см. след. стр.
102 ГЛ А В А 3 БЕЗОПАСНОСТЬ NtTib.SubSystemTib: NtTib.Version: NtTib.UserPointer: NtTib.SelfTib: 00000000 00000000 00000000 7ffde000 SelfPcr: Prcb: Irql: IRR: IDR: InterruptMode: IDT: GDT: TSS: ffdff000 ffdff120 00000000 00000000 ffff28e8 00000000 80036400 80036000 802b5000 CurrentThread: 81638020 NextThread: 00000000 IdleThread: 8046bdf0 К сожалению, Windows не поддерживает поле Irql на платформах, не использующих отложенные IRQL, поэтому в большинстве систем это поле всегда содержит 0. Так как изменения IRQL процессора существенно влияют на функциони рование системы, они возможны только в режиме ядра. Потоки пользова тельского режима не могут изменять IRQL процессора. Это значит, что при выполнении потоков пользовательского режима значение IRQL процессо ра всегда равно passive. Только при выполнении кода режима ядра IRQL мо жет быть выше этого уровня. Каждый уровень прерывания имеет определенное назначение. Так, ядро генерирует межпроцессорное прерывание (interprocessor interrupt, IPI), что бы потребовать выполнения какойлибо операции от другого процессора, например, при диспетчеризации некоего потока или обновлении кэша ас социативного буфера трансляции [translation lookaside buffer (TLB) cache]. Системный таймер через регулярные промежутки генерирует прерывания, на которые ядро реагирует обновлением системного времени, и это исполь зуется для измерения продолжительности выполнения потока. Если аппарат ная платформа поддерживает два таймера, то для измерения производитель ности ядро добавляет еще один уровень прерываний от таймера. HAL под держивает несколько уровней запросов прерываний для устройств, управля емых прерываниями; конкретное число таких уровней зависит от процес сора и конфигурации системы. Ядро использует программные прерывания для инициации планирования потоков и асинхронного вмешательства в выполнение потока. Увязка прерываний с IRQL Уровни IRQL и запросы прерываний (IRQ) — вещи разные. Концепция IRQL в архитектурах, на которых работает Win dows, не реализована аппаратно. Тогда возникает вопрос: как Windows оп
ГЛАВА 9 Системные механизмы 103 ределяет, какой IRQL следует присвоить прерыванию? Ответ нужно искать в HAL. В Windows за определение устройств на конкретной шине (PCI, USB и т. д.) и назначение им прерываний отвечают драйверы устройств особого типа — драйверы шин. Драйвер шины сообщает эту информацию диспет черу Plug and Play, и тот, учитывая приемлемые для других устройств преры вания, принимает решение о конкретных прерываниях, выделяемых каждо му устройству. Далее он вызывает HALфункцию HalpGetSystemInterruptVector, которая увязывает прерывания со значениями IRQL. Этот алгоритм неодинаков в различных версиях HAL. В однопроцессор ных x86системах HAL выполняет прямую трансляцию: IRQL данного векто ра прерывания вычисляется путем вычитания значения вектора из 27. Таким образом, если устройство использует 5й вектор прерывания, его ISR выпол няется при IRQL, равном 22. В многопроцессорной x86системе преобразо вания более сложны. APIC поддерживает более 200 векторов прерываний, поэтому при трансляции «один в один» имеющихся IRQL окажется недоста точно. Многопроцессорная версия HAL присваивает IRQL векторам преры ваний, циклически перебирая значения из диапазона IRQL устройств (device IRQL, DIRQL). В итоге на многопроцессорной x86системе не такто просто предсказать или выяснить IRQL, назначаемый IRQ. Наконец, в x64 и IA64 системах HAL вычисляет IRQL для IRQ путем деления вектора прерывания, назначенного данному IRQ, на 16. Предопределенные IRQL Давайте повнимательнее приглядимся к предопределенным IRQL, начиная с самого верхнего уровня схемы, пред ставленной на рис. 35. 쐽 Уровень «high» (высокий) используется ядром, только если оно останав ливает систему в функции KeBugCheckEx и маскирует все прерывания. 쐽 Уровень «power fail» (отказ электропитания) был заложен еще в самый первый проект Microsoft Windows NT. Он определяет поведение системы при отказе электропитания, но никогда не применялся. 쐽 Уровень «interprocessor interrupt» (межпроцессорное прерывание) исполь зуется для того, чтобы запрашивать от другого процессора выполнение какойлибо операции, например, при постановке в очередь прерывания DISPATCH_LEVEL для планирования конкретного потока к выполнению, при обновлении кэша TLB, завершении работы или крахе системы. 쐽 Уровень «clock» (часы) используется для системных часов, с помощью которых ядро отслеживает время суток, измеряет и распределяет процес сорное время между потоками. 쐽 Уровень «profile» (профиль) используется системным таймером реально го времени, если активизирован механизм профилирования ядра (kernel profiling), т. е. измерения его производительности. Когда он активен, об работчик ловушки профилирования регистрирует адрес команды, выпол нявшейся на момент прерывания. Со временем создается таблица адре сов, которую можно извлечь и проанализировать с помощью соответству ющих утилит. Вы можете скачать утилиту Kernrate (http://www.microsoft.
104 ГЛ А В А 3 БЕЗОПАСНОСТЬ com/whdc/system/sysperf/krview.mspx), позволяющую просматривать ста тистику, полученную при использовании механизма профилирования ядра. Подробнее об этой утилите см. описание эксперимента с Kernrate. 쐽 Уровень «device» (устройство) применяется для задания приоритетов прерываний от устройств (о принципах увязки аппаратных прерываний с IRQL см. предыдущий раздел). 쐽 Прерывания уровней «DPC/dispatch» и «APC» являются программными; они генерируются ядром и драйверами устройств (о DPC и APC будет рассказано позже). 쐽 Самый низкий уровень IRQL, «passive» (пассивный), на самом деле вооб ще не является уровнем прерывания. При этом значении IRQL потоки выполняются обычным образом и могут возникать любые прерывания. ЭКСПЕРИМЕНТ: применение утилиты Kernrate Утилита профилирования ядра (Kernrate) позволяет включать таймер профилирования системы, собирать образцы кода, выполняемого при срабатывании таймера, и выводить сводную информацию, отражаю щую распределение процессорного времени по образам файлов и функциям. Ее можно использовать для отслеживания процессорного времени, потребляемого индивидуальными процессами, и/или време ни, проведенного в режиме ядра независимо от процессов (например, для выполнения процедур обслуживания прерываний). Профилирова ние ядра полезно, когда вы хотите выявить точки, в которых на выпол нение кода тратится больше всего процессорного времени. В своей простейшей форме Kernrate сообщает, сколько процессор ного времени было использовано каждым модулем ядра (Ntoskrnl, драйверами и т. д.). Попробуйте, к примеру, выполнить следующие операции. 1. Откройте окно командной строки. 2. Введите cd c:\program files\krview\kernrates. 3. Введите dir. (Вы увидите образы kernrate для каждой платформы.) 4. Запустите образ, который подходит для вашей платформы (без ар гументов или ключей). Например, Kernrate_i386_XP.exe — это образ для Windows XP на платформе x86. 5. Пока Kernrate выполняется, поделайте чтонибудь в системе. Ска жем, запустите Windows Media Player и проиграйте музыку, запус тите игру, интенсивно работающую с графикой, или перечислите содержимое каталога на удаленном сетевом ресурсе. 6. Нажмите Ctrl+C, чтобы остановить Kernrate. Это заставит Kernrate вывести статистику за прошедший период. Ниже приведена часть вывода Kernrate, когда выполнялся Windows Media Player, воспроизводивший дорожку с компактдиска.
ГЛАВА 9 Системные механизмы 105 C:\Program Files\KrView\Kernrates>Kernrate_i386_XP.exe /==============================\ < KERNRATE LOG > \==============================/ Date: 2004/05/13 Time: 9:48:28 Machine Name: BIGDAVID Number of Processors: 1 PROCESSOR_ARCHITECTURE: x86 PROCESSOR_LEVEL: 6 Kernrate UserSpecified Command Line: Kernrate_i386_XP.exe ***> Press ctrlc to finish collecting profile data ===> Finished Collecting Data, Starting to Process Results ——————Overall Summary:——————— P0 K 0:00:03.234 (11.7%) U 0:00:08.352 (30.2%) I 0:00:16.093 (58.1%) DPC 0:00:01.772 ( 6.4%) Interrupt 0:00:00.350 ( 1.3%) Interrupts= 52899, Interrupt Rate= 1911/sec. Time 7315 hits, 19531 events per hit ———— Module Hits msec %Total Events/Sec gv3 4735 27679 64 % 3341135 smwdm 872 27679 11 % 615305 win32k 764 27679 10 % 539097 ntoskrnl 739 27679 10 % 521457 hal 124 27679 1 % 87497 Сводные данные показывают, что система провела 11,7% времени в режиме ядра, 30,2% в пользовательском режиме, 58,1% в простое, 6,4% на уровне DPC и 1,3% на уровне прерываний (interrupt level). Модуль, чаще всего требовавший к себе внимания, был GV3.SYS, драйвер про цессора для Pentium M (семейства Geyserville). Он используется для сбора информации о производительности, поэтому и оказался на пер вом месте. Модуль, занявший второе место, — Smwdm.sys, драйвер зву ковой платы на компьютере, где проводился тест. Это вполне объяс нимо, учитывая, что основную нагрузку в системе создавал Windows Media Player, посылавший звуковой вводвывод этому драйверу. Если у вас есть файлы символов, вы можете исследовать индивиду альные модули и посмотреть, сколько времени было затрачено каждой из их функций. Например, профилирование системы в процессе бы строго перемещения окна по экрану давало такой вывод (здесь при ведена лишь его часть): C:\Program Files\KrView\Kernrates>Kernrate_i386_XP.exe –z ntoskrnl z win32k см. след. стр.
106 ГЛ А В А 3 БЕЗОПАСНОСТЬ /==============================\ KERNRATE LOG > \==============================/ Date: 2004/05/13 Time: 10:26:55 < Time 4087 hits, 19531 events per hit ———— Module Hits win32k 1649 ati2dvag 1269 ntoskrnl 794 gv3 162 msec %Total 10424 40 % 10424 31 % 10424 19 % 10424 3 % Events/Sec 3089660 2377670 1487683 303532 —— Zoomed module win32k.sys (Bucket size = 16 bytes, Rounding Down) ——— Module Hits msec %Total Events/Sec EngPaint 328 10424 19 % 614559 EngLpkInstalled 302 10424 18 % 565844 —— Zoomed module ntoskrnl.exe (Bucket size = 16 bytes, Rounding Down) —— Module Hits msec %Total Events/Sec KiDispatchInterrupt 243 10424 26 % 455298 ZwYieldExecution 50 10424 5 % 93682 InterlockedDecrement 39 10424 4 % 73072 В данном случае самым «прожорливым» был модуль Win32k.sys, драйвер системы, отвечающей за работу с окнами. Второй в списке — видеодрайвер. И действительно, основная нагрузка в системе была свя зана с рисованием окна на экране. В детальном выводе для Win32k.sys видно, что наиболее активна была его функция EngPaint, основная GDIфункция для рисования на экране. На код, выполняемый на уровне «DPC/dispatch» и выше, накладывается важное ограничение: он не может ждать освобождения объекта, если такое ожидание заставило бы планировщик подключить к процессору другой по ток (а это недопустимая операция, так как планировщик синхронизирует свои структуры данных на уровне «DPC/dispatch» и, следовательно, не может быть активизирован для выполнения перераспределения процессорного времени). Другое ограничение заключается в том, что при уровне IRQL «DPC/ dispatch» или выше доступна только неподкачиваемая память. На самом деле второе ограничение является следствием первого, так как обращение к от сутствующей в оперативной памяти странице вызывает ошибку страницы. Тогда диспетчер памяти должен был бы инициировать операцию дисково го вводавывода, после чего ждать, когда драйвер файловой системы загру зит эту страницу с диска. Это в свою очередь вынудило бы планировщик переключить контекст (возможно, на поток простоя, если нет ни одного пользовательского потока, ждущего выполнения). В результате было бы на рушено правило, запрещающее вызов планировщика в таких ситуациях (по скольку при чтении с диска IRQL все еще остается на уровне «DPC/dispatch»
ГЛАВА 9 Системные механизмы 107 или выше). При нарушении любого из этих двух ограничений происходит крах системы с кодом завершения IRQL_NOT_LESS_OR_EQUAL (подробнее о кодах завершения при крахе системы см. главу 4). Кстати, нарушение этих ограничений является довольно распространенной ошибкой в драйверах устройств. Локализовать причину ошибок такого типа помогает утилита Driver Verifier, о которой будет подробно рассказано в разделе «Утилита Driver Verifier» главы 7. Объекты «прерывание» (interrupt objects) Ядро предоставляет пе реносимый (портируемый) механизм — объект прерывания, позволяющий драйверам устройств регистрировать ISR для своих устройств. Этот объект содержит всю информацию, необходимую ядру для назначения конкретно го уровня прерывания для ISR устройства, включая адрес ISR, IRQL устрой ства и запись в IDT ядра, с которой должна быть сопоставлена ISR. При ини циализации в объект прерывания из шаблона обработки прерываний, KiIn terruptTemplate, копируется несколько ассемблерных инструкций — код дис петчеризации. Этот код выполняется при возникновении прерывания. Код, хранящийся в объекте прерывания, вызывает реальный диспетчер прерываний, которым обычно является процедура ядра KiInterruptDispatch или KiChainedDispatch, и передает ему указатель на объект прерывания. KiIn terruptDispatch обслуживает векторы прерываний, для которых зарегистри рован только один объект прерывания, а KiChainedDispatch — векторы, раз деляемые несколькими объектами прерываний. В объекте прерывания со держится информация, необходимая процедуре KiChainedDispatch для поис ка и корректного вызова ISR драйвера. Объект прерывания также хранит значение IRQL, сопоставленное с данным прерыванием, так что KiDispatch Interrupt или KiChainedDispatch может перед вызовом ISR повысить IRQL до нужного уровня и вернуть его к исходному после завершения ISR. Этот двух этапный процесс необходим изза того, что при начальной диспетчериза ции нельзя передать указатель (или какойлибо иной аргумент) объекту пре рывания, так как она выполняется не программно, а аппаратно. В многопро цессорных системах ядро создает и инициализирует объект прерывания для каждого процессора, позволяя их локальным APIC принимать конкретные прерывания. На рис. 36 показана типичная схема обслуживания прерыва ний, сопоставленных с объектами прерываний.
108 Рис. 3-6. ГЛ А В А 3 БЕЗОПАСНОСТЬ Типичная схема обслуживания прерываний ЭКСПЕРИМЕНТ: изучение внутреннего устройства прерываний С помощью отладчика ядра вы можете просмотреть детальные сведе ния об объекте прерывания, в том числе его IRQL, адрес ISR и собствен ный код диспетчеризации прерывания (custom interrupt dispatching code). Вопервых, введите команду !idt и найдите запись со ссылкой на I8042KeyboardInterruptService — процедуру ISR для устройства «PS2 клавиатура»: 31: 8a39dc3c i8042prt!I8042KeyboardInterruptService (KINTERRUPT 8a39dc00) Для просмотра содержимого объекта, сопоставленного с прерыва нием, введите dt nt!_kinterrupt, указав адрес, следующий за KINTER RUPT: kd> dt nt!_kinterrupt 8a39dc00 nt!_KINTERRUPT +0x000 Type : 22 +0x002 Size : 484 +0x004 InterruptListEntry : _LIST_ENTRY [ 0x8a39dc04  0x8a39dc04 ] +0x00c ServiceRoutine : 0xba7e74a2 i8042prt!I8042KeyboardInterruptService+0 +0x010 ServiceContext : 0x8a067898 +0x014 SpinLock : 0 +0x018 TickCount : 0xffffffff +0x01c ActualLock : 0x8a067958 > 0 +0x020 DispatchAddress : 0x80531140 nt!KiInterruptDispatch+0
ГЛАВА 9 +0x024 +0x028 +0x029 +0x02a +0x02b +0x02c +0x02d +0x030 +0x034 +0x038 +0x03c Vector Irql SynchronizeIrql FloatingSave Connected Number ShareVector Mode ServiceCount DispatchCount DispatchCode : : : : : : : : : : : Системные механизмы 109 0x31 0x1a '' 0x1a '' 0 '' 0x1 '' 0 '' 0 '' 1 ( Latched ) 0 0xffffffff [106] 0x56535554 В этом примере IRQL, назначенный Windows прерыванию, — 0x1a (или 26 в десятичной системе). Поскольку вывод получен на однопро цессорной x86системе, IRQ равно 1 (IRQL в таких системах вычисля ются путем вычитания IRQ из 27). Это можно проверить, открыв De vice Manager (Диспетчер устройств) [на вкладке Hardware (Оборудова ние) в окне свойств системы)], найдя PS/2клавиатуру и посмотрев назначенные ей ресурсы, как показано на следующей иллюстрации. В многопроцессорных x86системах IRQ назначается в основном случайным образом, а в x64 или IA64системе вы увидите, что IRQ — это номер вектора прерываний [0x31 (49 в десятичной системе)], де ленный на 16. Адрес ISR для объекта прерывания хранится в поле ServiceRoutine (его и показывает !idt в своем выводе), а код прерывания, срабатыва см. след. стр.
110 ГЛ А В А 3 БЕЗОПАСНОСТЬ ющий при появлении этого прерывания, — в массиве DispatchCode в конце объекта прерывания. Этот код программируется так, чтобы со здавать фрейм ловушки в стеке и потом вызывать функцию, хранящу юся в поле DispatchAddress (в нашем примере это KiInterruptDispatch), с передачей ей указателя на объект прерывания. Windows и обработка данных в реальном времени К средам, предназначенным для работы в реальном времени, предъяв ляются либо жесткие, либо очень жесткие требования к максимально му времени реакции. Реакция системы реального времени, к которой предъявляются очень жесткие требования (например, системы управ ления атомной электростанцией), должна быть исключительно быст рой, иначе неизбежны катастрофы, опасные не только для оборудова ния, но и для жизни людей. Менее ответственные системы реального времени (например, система экономичного расхода топлива автомо биля) могут в какойто мере отклоняться от этих требований, но их соблюдение все же желательно. В системах реального времени устрой ствами ввода служат датчики, а устройствами вывода — управляющие устройства. Проектировщик компьютерных систем реального време ни должен знать величину максимально допустимого запаздывания между моментом генерации прерывания устройством ввода и ответом управляющего устройства, контролируемого драйвером. Анализ самых неблагоприятных вариантов должен учитывать как запаздывание опе рационной системы, так и запаздывание драйверов и приложений. Поскольку проконтролировать расстановку приоритетов IRQ уст ройств операционной системой Windows нельзя, а пользовательские приложения выполняются лишь при IRQL уровня «passive», Windows не всегда подходит для обработки данных в реальном времени. Макси мальное запаздывание определяется в конечном счете устройствами и драйверами системы, а не самой Windows. Этот фактор становится проблемой при использовании готового оборудования, имеющегося в продаже. Проектировщик может столкнуться с трудностями при оп ределении максимального времени выполнения ISR или DPC драйве ра готового устройства. Даже после тестирования он не сможет гаран тировать, что запаздывание ни при каких обстоятельствах не превы сит заданного предела. Более того, суммарное запаздывание систем ных DPC и ISR, как правило, существенно превосходит значения, при емлемые для чувствительных к задержкам систем. Хотя ко многим типам встраиваемых систем (например, к принте рам и автомобильным компьютерам) предъявляются требования, как к системам реального времени, Windows XP Embedded не обладает соответствующими характеристиками. Это просто версия Windows XP, которая создана с использованием технологии, лицензированной Mic rosoft у компании VenturCom, и способна работать в системах с огра
ГЛАВА 9 Системные механизмы 111 ниченными ресурсами. Так, для устройства без сетевых функций ис ключается вся функциональность Windows XP, связанная с поддерж кой работы в сетях, включая средства управления сетью, драйверы сте ка протокола и сетевого адаптера. Тем не менее третьи фирмы поставляют версии ядра реального вре мени для Windows. Их подход заключается в том, что они встраивают ядро реального времени в собственный HAL и выполняют Windows как задачу в операционной системе реального времени. Windows, выпол няемая в таком виде, служит в качестве пользовательского интерфей са системы и имеет меньший приоритет по сравнению с задачами, ответственными за управление нужным устройством. Пример расши рения ядра Windows реального времени можно увидеть на Webсайте VenturCom www.venturcom.com. Сопоставление ISR с конкретным уровнем прерывания называется под ключением объекта прерывания, а разрыв связи между ISR и записью в IDT — отключением. Эти операции, выполняемые функциями ядра IoCon nectInterrupt и IoDisconnectInterrupt, позволяют драйверу устройства «вклю чать» ISR после своей загрузки и «отключать» ISR, если он не загружен. Применение объекта прерывания для регистрации ISR позволяет драйве рам устройств избегать прямого взаимодействия с контроллером прерыва ний (разным на разных процессорных архитектурах) и исключает необхо димость детального знания IDT. Это дает возможность создавать переноси мые драйверы устройств, поскольку благодаря такой функциональности ядра программировать драйверы устройств на ассемблере и учитывать в них особенности конкретных процессоров больше не нужно. Использование объекта прерывания дает и другие преимущества: ядро может синхронизировать выполнение ISR с другими частями драйвера уст ройства, которые могут разделять данные с ISR. (Подробнее о том, как драй веры устройств реагируют на прерывания, см. главу 9.) Более того, объекты прерывания позволяют ядру легко вызывать более одной ISR для любого уровня прерывания. Если несколько драйверов созда ют объекты прерывания и сопоставляют их с одной записью в IDT, то при прерывании на определенной линии диспетчер вызывает каждую из этих процедур (ISR). Такая функциональность позволяет ядру поддерживать кон фигурации в виде цепочек, когда несколько устройств совместно использу ют одну линию прерывания. Когда одна из ISR объявляет диспетчеру о зах вате прерывания, происходит разрыв цепочки. Если несколько устройств, разделяющих одну линию прерывания, одновременно запрашивают обслу живание, то устройства, не получившие подтверждения от своих ISR, будут вновь генерировать прерывания, как только диспетчер понизит IRQL. Свя зывание устройств в цепочку разрешается, только если все драйверы уст ройств, стремящиеся использовать одно и то же прерывание, сообщат ядру о своей способности разделять данное прерывание. Если они не в состоя нии совместно использовать это прерывание, диспетчер Plug and Play пере
112 ГЛ А В А 3 БЕЗОПАСНОСТЬ назначит IRQ с учетом запросов каждого устройства. Если разделяемым яв ляется вектор прерываний, объект прерывания вызывает KiChainedDispatch, которая поочередно обращается к ISR каждого зарегистрированного объек та прерывания, пока один из них не сообщит, что прерывание вызвано им, или пока все они не будут выполнены. В одном из предыдущих примеров вывода !idt вектор 0x3b был подключен к нескольким объектам прерываний, связанным в цепочку (chained interrupt objects). Программные прерывания Хотя большинство прерываний генерируется аппаратно, ядро Windows тоже может генерировать прерывания — только они являются программными. Этот вид прерываний служит для решения многих задач, в том числе: 쐽 инициации диспетчеризации потоков; 쐽 обработки прерываний, не критичных по времени; 쐽 обработки событий таймеров; 쐽 асинхронного выполнения какойлибо процедуры в контексте конкрет ного потока; 쐽 поддержки асинхронного вводавывода. Эти задачи подробно рассматриваются ниже. Прерывания DPC или диспетчеризации Когда дальнейшее выпол нение потока невозможно, например изза его завершения или перехода в ждущее состояние, ядро напрямую обращается к диспетчеру, чтобы вызвать немедленное переключение контекста. Однако иногда ядро обнаруживает, что перераспределение процессорного времени (rescheduling) должно про изойти при выполнении глубоко вложенных уровней кода. В этой ситуации ядро запрашивает диспетчеризацию, но саму операцию откладывает до вы полнения текущих действий. Такую задержку удобно организовать с помо щью программного прерывания DPC (deferred procedure call). При необходимости синхронизации доступа к разделяемым структурам ядра последнее всегда повышает IRQL процессора до уровня «DPC/dispatch» или выше. При этом дополнительные программные прерывания и диспет черизация потоков запрещаются. Обнаружив необходимость в диспетчери зации, ядро генерирует прерывание уровня «DPC/dispatch». Но поскольку IRQL уже находится на этом уровне или выше, процессор откладывает об работку этого прерывания. Когда ядро завершает свои операции, оно опре деляет, что должно последовать снижение IRQL ниже уровня «DPC/dispatch», и проверяет, не ожидают ли выполнения отложенные прерывания диспет черизации. Если да, IRQL понижается до уровня «DPC/dispatch», и эти отло женные прерывания обрабатываются. Активизация диспетчера потоков че рез программное прерывание — способ отложить диспетчеризацию до под ходящего момента. Однако Windows использует программные прерывания для отложенного выполнения и других операций.
ГЛАВА 9 Системные механизмы 113 При этом IRQL ядро обрабатывает не только диспетчеризацию потоков, но и DPC. DPC — это функция, выполняющая системную задачу, менее кри тичную по времени в сравнении с текущей. Эти функции называются отло женными (deferred), так как не требуют немедленного выполнения. DPC позволяют операционной системе генерировать прерывания и вы полнять системные функции в режиме ядра. Ядро использует DPC для обра ботки прерываний по таймеру (и освобождения потоков, ждущих на тайме рах), а также для перераспределения процессорного времени по истечении кванта времени, отведенного текущему потоку. Драйверы устройств исполь зуют DPC для выполнения запросов вводавывода. Для своевременного об служивания аппаратных прерываний Windows — во взаимодействии с драй верами устройств — пытается удерживать текущий IRQL ниже IRQL уст ройств. Один из способов достижения этой цели заключается в следующем. ISR должна выполнять минимум действий по обслуживанию своего устрой ства, сохранять переменные данные о состоянии прерывания и откладывать передачу данных или выполнение других не столь критичных по времени операций, как DPC, до снижения IRQL к уровню «DPC/dispatch» (подробнее о DPC и системе вводавывода см. главу 9). DPC представляется DPC объектом, управляющим объектом ядра, неви димым программам пользовательского режима, но видимым драйверам и системному коду. Наиболее важной частью информации DPCобъекта явля ется адрес системной функции, которую ядро должно вызвать для обработ ки прерывания DPC. DPCпроцедуры, ожидающие выполнения, хранятся в управляемых ядром очередях (по одной на каждый процессор). Эти очере ди называются очередями DPC. Запрашивая DPC, системный код вызывает ядро для инициализации DPCобъекта и помещает его в очередь DPC. По умолчанию ядро помещает DPCобъекты в конец очереди DPC про цессора, на котором был запрошен DPC (как правило, это процессор, на ко тором выполняется ISR). Однако драйвер устройства может изменить это, указав приоритет DPC (низкий, средний или высокий; по умолчанию — сред ний) или направив DPC конкретному процессору. DPC, направленный кон кретному процессору, называется целевым DPC (targeted DPC). Если у DPC низкий или средний приоритет, ядро помещает DPCобъект в конец очере ди, а если у DPC высокий приоритет, то — в начало. Когда IRQL процессора вотвот понизится с уровня «DPC/dispatch» или более высокого до уровня «APC» или «passive», ядро переходит к обработке всех DPC. Windows оставляет IRQL на уровне «DPC/dispatch» и извлекает все DPCобъекты из очереди данного процессора (т. е. ядро опустошает оче редь), поочередно вызывая каждую DPCфункцию. Ядро разрешает умень шить IRQL ниже уровня «DPC/dispatch» для продолжения выполнения обыч ных потоков только после опустошения очереди. Схема обработки DPC по казана на рис. 37.
114 ГЛ А В А 3 Рис. 3-7. БЕЗОПАСНОСТЬ Обработка DPC Приоритеты DPC могут влиять на поведение системы и иным способом. Обычно ядро начинает опустошение очереди DPC с прерывания уровня «DPC/dispatch». Такое прерывание генерируется ядром, только если DPC на правлен на процессор, на котором выполняется ISR, и DPC имеет средний или высокий приоритет. Если у DPC низкий приоритет, ядро генерирует прерывание, только если число незавершенных запросов DPC превышает пороговое значение или если число DPC, запрошенных на процессоре за установленный период, невелико. Если DPC направлен другому процессору (не тому, на котором выполняется ISR) и его приоритет высокий, ядро не медленно посылает ему диспетчерское IPI, сигнализируя целевому процес сору о необходимости опустошения его очереди DPC. Если приоритет DPC средний или низкий, для появления прерывания «DPC/dispatch» число DPC в очереди целевого процессора должно превышать пороговое значение. Системный поток простоя также опустошает очередь DPC процессора, на котором он выполняется. Хотя уровни приоритета и направление DPC яв ляются довольно гибкими средствами, у драйверов устройств редко возни кает необходимость в изменении заданного по умолчанию поведения сво их DPCобъектов. В таблице 31 даются сведения о ситуациях, в которых начинается опустошение очереди DPC. Таблица 3-1. Правила генерации прерываний DPC Приоритет DPC DPC, направленный на процессор ISR DPC, направленный на другой процессор Низкий Длина очереди DPC превышает по Длина очереди DPC превышает роговое значение, или частота зап пороговое значение, или систе росов DPC ниже минимальной ма не занята Средний Всегда Длина очереди DPC превышает пороговое значение, или систе ма не занята Высокий Всегда Всегда
ГЛАВА 9 Системные механизмы 115 Поскольку потоки пользовательского режима выполняются при низком IRQL, вероятность того, что DPC прервет выполнение обычного пользова тельского потока, довольно велика. DPCпроцедуры выполняются независи мо от того, какой поток работает в настоящий момент. Это означает, что выполняемая DPCпроцедура не в состоянии предугадать текущий размер спроецированного адресного пространства процесса. DPCпроцедуры мо гут вызывать функции ядра, но не могут обращаться к системным сервисам, генерировать ошибки страницы, создавать или ждать объекты диспетчера. Однако они способны получать доступ к неподкачиваемым областям сис темной памяти, поскольку системное адресное пространство всегда спрое цировано независимо от того, что представляет собой текущий процесс. DPC используются не только драйверами, но и ядром. Ядро чаще всего применяет DPC для обработки ситуации, когда истекает выделенный квант времени. При каждом такте системного таймера генерируется прерывание с IRQLуровнем «clock». Обработчик прерываний таймера (выполняемый при IRQL, равном «clock») обновляет системное время и уменьшает значение счетчика, отслеживающего время выполнения текущего потока. Когда зна чение счетчика обнуляется, квант времени, отведенный потоку, заканчива ется, и ядру может понадобиться перераспределить процессорное время — эта задача имеет более низкий приоритет и должна выполняться при IRQL, равном «DPC/dispatch». Обработчик прерываний таймера ставит DPC в оче редь, чтобы инициировать диспетчеризацию потоков, после чего заверша ет свою работу и понижает IRQL процессора. Поскольку приоритет преры ваний DPC ниже, чем аппаратных, перед генерацией прерывания DPC сна чала обрабатываются все аппаратные прерывания, возникающие до завер шения обработки прерывания таймера. ЭКСПЕРИМЕНТ: мониторинг активности прерываний и DPC Process Explorer позволяет вести мониторинг активности прерываний и DPC, добавив столбец Context Switch Delta и наблюдая за процесса ми Interrupt и DPC. Это не настоящие процессы, они показываются как процессы просто для удобства и не вызывают переключений контек ста. Счетчик переключений контекста в Process Explorer для этих псев допроцессов отражает число возникновений каждого из них в тече ние предыдущего интервала обновления (refresh interval). Вы можете имитировать активность прерываний и DPC, быстро перемещая кур сор мыши по экрану. см. след. стр.
116 ГЛ А В А 3 БЕЗОПАСНОСТЬ Вы также можете проследить выполнение конкретных процедур обслуживания прерываний (ISR) и отложенных вызовов процедур (DPC), используя встроенную поддержку трассировки событий (под робнее об этом будет рассказано позже) в Windows XP Service Pack 2 или Windows Server 2003 Service Pack 1 (и выше). 1. Инициируйте захват событий, введя команду: tracelog start f kernel.etl b 64 –UsePerfCounter eflag 8 0x307 0x4084 0 0 0 0 0 0 2. Остановите захват событий, введя: tracelog stop 3. Создайте отчеты по захваченным событиям, набрав команду: tracerpt kernel.etl df o report Это приведет к генерации двух файлов: workload.txt и dumpfile.csv. 4. Откройте workload.txt и вы увидите сводные сведения о времени, проведенном драйверами каждого типа в ISR и DPCпроцедурах. 5. Откройте файл dumpfile.csv, созданный на этапе 3; найдите строки, где во втором значении встречается «DPC» или «ISR». Например, следующие три строки из dumpfile.csv показывают DPC таймера, DPC и ISR: PerfInfo, 0, PerfInfo, 0, PerfInfo, 0, TimerDPC, 0xFFFFFFFF, 127383953645422825, 0, 127383953645421500, 0xFB03A385, 0, 0 DPC, 0xFFFFFFFF, 127383953645424040, 0, 127383953645421394, 0x804DC87D, 0, 0 ISR, 0xFFFFFFFF, 127383953645470903, 0, 127383953645468696, 0xFB48D5E0, 0, 0, 0 Введя команду ln в отладчике ядра и указав начальный адрес из каж дой записи события (восьмое значение в каждой строке), вы увидите имя функции, выполнявшей DPC или ISR: lkd> ln 0xFB03A385 (fb03a385) rdbss!RxTimerDispatch | (fb03a41e) rdbss!RxpWorkerThreadDispatcher lkd> ln 0x804DC87D (804dc87d) nt!KiTimerExpiration | (804dc93b) nt!KeSetTimerEx lkd> ln 0xFB48D5E0 (fb48d5e0) atapi!IdePortInterrupt | (fb48d622) atapi!IdeCheckEmptyChannel Первый адрес относится к DPC, вызванному срабатыванием тайме ра, который был поставлен в очередь клиентским драйвером редирек тора файловой системы (file system redirector client driver). Второй от носится к DPC, вызванному срабатыванием универсального таймера
ГЛАВА 9 Системные механизмы 117 (generic timer). Наконец, третий — это адрес ISR для портдрайвера ATAPI. Более подробные сведения см. по ссылке http://www.microsoft. com/whdc/driver/perform/mmdrv.mspx. Прерывания APC APC (asynchronous procedure call) позволяет выпол нять пользовательские программы и системный код в контексте конкретно го пользовательского потока (а значит, и в адресном пространстве конкрет ного процесса). Поскольку для выполнения в контексте конкретного пото ка APC ставятся в очередь и выполняются при IRQL ниже «DPC/dispatch», на их работу не налагаются ограничения, свойственные DPC. APCпроцедура может обращаться к ресурсам (объектам), ждать освобождения описателей объектов, генерировать ошибки страниц и вызывать системные сервисы. APC описывается управляющим объектом ядра — APC объектом. APC, ждущие выполнения, находятся в очереди APC (APC queue), управляемой яд ром. Очереди APC — в отличие от общесистемной очереди DPC — специ фичны для конкретного потока, так как у каждого потока своя очередь APC. При запросе на постановку APC в очередь ядро помещает его (APC) в оче редь того потока, который будет выполнять APCпроцедуру. Далее ядро ге нерирует программное прерывание с уровнем APC, и поток, когда он в ко нечном счете начинает выполняться, обрабатывает APC. APC бывают двух видов: режима ядра и пользовательского режима. APC режима ядра для выполнения в контексте целевого потока не нужно «разре шение» со стороны этого потока, тогда как для APC пользовательского ре жима это обязательно. APC режима ядра прерывает поток и выполняет про цедуру без вмешательства или согласия потока. APC режима ядра тоже бы вают двух типов: обычные (normal) и специальные (special). Поток может отключить все APC режима ядра, повысив IRQL до уровня APC_LEVEL или вызвав KeEnterGuardedRegion, которая впервые появилась в Windows Server 2003. KeEnterGuardedRegion отключает доставку APC, устанавливая поле Spe cialApcDisable в структуре KTHREAD вызвавшего потока (об этой структуре см. главу 6). Поток также может отключить только обычные APC режима ядра вызовом KeEnterCriticalRegion, которая устанавливает поле KernelApcDisable в структуре KTHREAD потока. Исполнительная система использует APC режима ядра для тех задач опе рационной системы, которые нужно выполнить в адресном пространстве (контексте) конкретного потока. Так, через специальные APC режима ядра она может указать потоку прекратить выполнение системного сервиса, до пускающего прерывание, или записать результаты операции асинхронного вводавывода в адресное пространство этого потока. Подсистемы окружения используют такие APC, чтобы приостановить поток или завершить себя, а также чтобы получить или установить контекст пользовательского потока. Подсистема POSIX эмулирует через APC режима ядра передачу POSIXсигна лов процессам POSIX. Драйверы устройств также применяют APC режима ядра. Например, если инициирована операция вводавывода и поток переходит в состояние ожи
118 ГЛ А В А 3 БЕЗОПАСНОСТЬ дания, к процессору может быть подключен другой поток из другого про цесса. По завершении передачи данных устройством система вводавывода должна както вернуться в контекст потока, инициировавшего эту операцию вводавывода, чтобы он мог скопировать ее результаты в буфер в адресном пространстве своего процесса. Система вводавывода использует для выпол нения подобных действий специальные APC режима ядра (применение APC в системе вводавывода подробно рассматривается в главе 9). Некоторые Windowsфункции вроде ReadFileEx, WriteFileEx и QueueUser APC вызывают APC пользовательского режима. Так, функции ReadFileEx и WriteFileEx позволяют вызывающей программе указать процедуру заверше ния вводавывода (completion procedure), которая будет вызвана по оконча нии операции вводавывода. Процедура завершения вводавывода реализу ется помещением APC в очередь потока, выдавшего запрос на вводвывод. Однако обратный вызов процедуры завершения не обязательно происходит в момент постановки APC в очередь, поскольку APC пользовательского ре жима передаются потоку, только если он находится в состоянии тревожно го ожидания (alertable wait state). Поток может перейти в такое состояние, вызвав одну из Windowsфункций: либо WaitForMultipleObjectsEx, либо Sleep Ex. В обоих случаях, как только в очереди появится APC пользовательского режима, ядро прервет поток, передаст управление APCпроцедуре и возоб новит его выполнение лишь после завершения APCпроцедуры. В отличие от APC режима ядра, которые выполняются на уровне «APC», APC пользователь ского режима выполняются на уровне «passive». Появление APC может переупорядочить очереди ожидания — списки, определяющие, какие потоки ждут, в каком порядке и на каких объектах (см. раздел по синхронизации далее в этой главе). Если в момент появления APC поток находится в состоянии ожидания, то после обработки APCпроцеду ры поток возвращается в состояние ожидания, но перемещается в конец списка потоков, ждущих те же объекты. Диспетчеризация исключений В отличие от прерываний, которые могут возникать в любой момент, исклю чения являются прямым следствием действий выполняемой программы. Windows вводит понятие структурной обработки исключений (structured exception handling, SEH), позволяющей приложениям получать управление при возникновении исключений. При этом приложение может исправить ситуацию, которая привела к исключению, провести раскрутку стека (завер шив таким образом выполнение подпрограммы, вызвавшей исключение) или уведомить систему о том, что данное исключение ему не известно, и тогда система продолжит поиск подходящего обработчика для данного ис ключения. В этом разделе мы исходим из того, что вы знакомы с базовыми концепциями структурной обработки исключений Windows; в ином случае сначала прочитайте соответствующую часть справочной документации Win dows API из Platform SDK или главы 23–25 из четвертого издания книги Джеффри Рихтера «Windows для профессионалов». Учтите: хотя обработка
ГЛАВА 9 Системные механизмы 119 исключений возможна через расширения языка программирования (напри мер, с помощью конструкции __try в Microsoft Visual C++), она является сис темным механизмом и поэтому не зависит от конкретного языка. В системах типа x86 все исключения имеют предопределенные номера прерываний, прямо соответствующие записям в IDT, ссылающимся на обра ботчики ловушек конкретных исключений. В таблице 32 перечислены ис ключения, определенные для систем типа x86, с указанием номеров преры ваний. Как уже говорилось, первая часть IDT используется для исключений, а аппаратные прерывания располагаются за ней. Таблица 3-2. Исключения в системах типа x86 и соответствующие им номера прерываний Номер прерывания Исключение 0 Divide Error (ошибка деления) 1 DEBUG TRAP (ловушка отладки) 2 NMI/NPX Error (ошибка NMI/NPX) 3 Breakpoint (точка прерывания) 4 Overflow (переполнение) 5 BOUND/Print Screen 6 Invalid Opcode (неправильный код операции) 7 NPX Not Available (NPX недоступен) 8 Double Exception (двойное исключение) 9 NPX Segment Overrun (выход за пределы сегмента NPX) A Invalid Task State Segment (TSS) (неправильный TSS) B Segment Not Present (сегмент отсутствует) C Stack Fault (ошибка стека) D General Protection (ошибка общей защиты) E Page Fault (ошибка страницы) F Зарезервировано Intel 10 Floating Point (ошибка в операции с плавающей точкой) 11 Alignment Check (ошибка контроля выравнивания) Все исключения, кроме достаточно простых, которые могут быть разре шены обработчиком ловушек, обслуживаются модулем ядра — диспетчером исключений (exception dispatcher). Его задача заключается в поиске обработ чика, способного «справиться» с данным исключением. Примерами незави симых от архитектуры исключений могут служить нарушения доступа к па мяти, целочисленное деление на нуль, переполнение целых чисел, исключе ния при операциях с плавающей точкой и точки прерывания отладчика. Полный список независимых от архитектуры исключений см. в справочной документации Windows API. Ядро перехватывает и обрабатывает некоторые из этих исключений про зрачно для пользовательских программ. Так, если при выполнении отлажи ваемой программы встретилась точка прерывания, генерируется исключе
120 ГЛ А В А 3 БЕЗОПАСНОСТЬ ние, обрабатываемое ядром за счет вызова отладчика. Ряд исключений ядро обрабатывает, просто возвращая код неудачной операции. Определенные исключения могут передаваться в неизменном виде поль зовательским процессам. Например, при ошибке доступа к памяти или при переполнении в ходе арифметической операции генерируется исключение, не обрабатываемое операционной системой. Для обработки этих исключений подсистема окружения может устанавливать обработчики исключений на основе SEH фрейма (далее для краткости — обработчик SEHфрейма). Этим термином обозначается обработчик исключения, сопоставленный с вызовом конкретной процедуры. При активизации такой процедуры в стек заталкива ется стековый фрейм, представляющий вызов этой процедуры. Со стековым фреймом можно сопоставить один или несколько обработчиков исключений, каждый из которых защищает определенный блок кода исходной програм мы. При возникновении исключения ядро ищет обработчик, сопоставленный с текущим стековым фреймом. Если его нет, ядро ищет обработчик, сопостав ленный с предыдущим стековым фреймом, — и так до тех пор, пока не будет найден подходящий обработчик. Если найти обработчик исключения не уда лось, ядро вызывает собственные обработчики по умолчанию. Когда происходит исключение (аппаратное или программное), цепочка событий начинается в ядре. Процессор передает управление обработчику ловушки в ядре, который создает фрейм ловушки по аналогии с тем, как это происходит при прерывании. Фрейм ловушки позволяет системе после об работки исключения возобновить работу с той точки, где она была прерва на. Обработчик ловушки также создает запись исключения, содержащую све дения о ее причине и другую сопутствующую информацию. Если исключение возникает в режиме ядра, то для его обработки диспет чер исключений просто вызывает процедуру поиска подходящего обработ чика SEHфрейма. Поскольку необработанные исключения режима ядра были бы фатальными ошибками операционной системы, диспетчер всегда находит какойнибудь обработчик. Если исключение возникает в пользовательском режиме, диспетчер исклю чений предпринимает более сложные действия. Как поясняется в главе 6, под система Windows предусматривает порт отладчика (debugger port) и порт исключений (exception port) для приема уведомлений об исключениях поль зовательского режима в Windowsпроцессах. Они применяются ядром при обработке исключений по умолчанию, как показано на рис. 38. Точки прерывания в отлаживаемой программе являются распространен ной причиной исключений. Поэтому диспетчер исключений первым делом проверяет, подключен ли к процессу, вызвавшему исключение, отладчик. Если подключен и системой является Windows 2000, диспетчер исключений посылает отладчику через LPC первое предупреждение. (Это уведомление на самом деле сначала поступает диспетчеру сеансов, а тот пересылает его со ответствующему отладчику.) В Windows XP и Windows Server 2003 диспетчер исключений посылает сообщение объекта отладчика (debugger object mes
ГЛАВА 9 Системные механизмы 121 sage) объекту отладки (debug object), сопоставленному с процессом (кото рый внутри системы рассматривается как порт). Рис. 3-8. Диспетчеризация исключений Если к процессу не подключен отладчик или если отладчик не в состоя нии обработать данное исключение, диспетчер исключений переключает ся в пользовательский режим, копирует фрейм ловушки в пользовательский стек, имеющий формат структуры данных CONTEXT (документирована в Platform SDK), и вызывает процедуру поиска обработчика SEHфрейма. Если поиск не дал результатов, диспетчер возвращается в режим ядра и снова вы зывает отладчик, чтобы пользователь мог продолжить отладку. При этом посылается второе (и последнее) предупреждение. Если отладчик не запущен и обработчики SEHфреймов не найдены, ядро посылает сообщение в порт исключений, сопоставленный с процессом по тока. Этот порт (если таковой есть) регистрируется подсистемой окружения, контролирующей данный поток. Порт исключений дает возможность под системе окружения (прослушивающей этот порт) транслировать исходное исключение в уведомление или исключение, специфичное для ее окружения. CSRSS (Client/Server RunTime Subsystem) просто выводит окно сообщения, уведомляющее пользователя о сбое, и завершает процесс. Когда подсистема POSIX получает от ядра сообщение о том, что один из потоков вызвал исклю чение, эта подсистема посылает вызвавшему исключение потоку сигнал в стиле POSIX. Но, если ядро уже дошло до этого этапа в обработке исключе ния, а подсистема не способна обработать данное исключение, выполняет ся обработчик ядра по умолчанию, просто завершающий процесс, поток которого вызвал исключение. Необработанные исключения На вершине стека любого Windowsпотока объявляется обработчик, имею щий дело с необработанными исключениями. За объявление отвечает внут
122 ГЛ А В А 3 БЕЗОПАСНОСТЬ ренняя Windowsфункция start of process или start of thread. Функция start of process срабатывает в момент начала выполнения первого потока процес са. Она вызывает главную точку входа в образе. Функция start of thread вы полняется при создании дополнительных потоков в процессе и вызывает стартовую процедуру, указанную в вызове CreateThread. ЭКСПЕРИМЕНТ: определение истинного стартового адреса Windows-потоков Тот факт, что выполнение каждого Windowsпотока начинается с сис темной (а не пользовательской) функции, объясняет, почему у каждо го Windowsпроцесса стартовый адрес нулевого потока одинаков (как и стартовые адреса вторичных потоков). Стартовый адрес нулевого потока Windowsпроцессов соответствует Windowsфункции start of process, а стартовые адреса остальных потоков являются адресом Win dowsфункции start of thread. Для определения адреса пользовательс кой функции применим утилиту Tlist из Windows Support Tools. Для по лучения детальной информации о процессе наберите tlist имя_про цесса или tlist идентификатор_процесса. Например, сравним стартовый адрес процесса Windows Explorer, сообщаемый утилитой Pstat (из Platform SDK), и стартовый адрес Tlist. C:\> pstat ... pid:3f8 pri: 8 Hnd: 329 Pf: 80043 Ws: tid pri Ctx Swtch StrtAddr User Time 7c 9 16442 77E878C1 0:00:01.241 42c 11 157888 77E92C50 0:00:07.110 44c 8 6357 77E92C50 0:00:00.070 1cc 8 3318 77E92C50 0:00:00.030 ... 4620K explorer.exe Kernel Time State 0:00:01.251 Wait:UserRequest 0:00:34.309 Wait:UserRequest 0:00:00.140 Wait:UserRequest 0:00:00.070 Wait:DelayExecution C:\> tlist explorer 1016 explorer.exe Program Manager CWD: C:\ CmdLine: Explorer.exe VirtualSize: 25348 KB PeakVirtualSize: 31052 KB WorkingSetSize: 1804 KB PeakWorkingSetSize: 3276 KB NumberOfThreads: 4 149 Win32StartAddr:0x01009dbd LastErr:0x0000007e State:Waiting 86 Win32StartAddr:0x77c5d4a5 LastErr:0x00000000 State:Waiting 62 Win32StartAddr:0x00000977 LastErr:0x00000000 State:Waiting 179 Win32StartAddr:0x0100d8d4 LastErr:0x00000002 State:Waiting ... Стартовый адрес нулевого потока, сообщаемый Pstat, соответству ет внутренней Windowsфункции start of process, а стартовые адреса потоков 1–3 указывают адреса внутренних Windowsфункций start of thread. С другой стороны, Tlist показывает стартовый адрес пользова
ГЛАВА 9 Системные механизмы 123 тельской функции, вызываемой внутренней стартовой Windowsфунк цией. Поскольку большинство потоков в Windowsпроцессах начинает ся в одной из системных функцийоболочек, Process Explorer, показы вая стартовые адреса потоков в процессе, пропускает фрейм началь ного вызова, представляющий функциюоболочку, и вместо этого ото бражает второй фрейм в стеке. Например, обратите внимание на стар товый адрес потока в процессе, выполняющем Notepad.exe. Process Explorer не выводит всю иерархию вызовов при отображе нии стека вызовов. Вот что вы получите, щелкнув кнопку Stack. В строке 12 на этой иллюстрации показан первый фрейм в сте ке — начало процессаоболочки. Второй фрейм (строка 11) является основной точкой входа в Notepad.exe. Базовый код внутренних стартовых функций выглядит так: void Win32StartOfProcess( LPTHREAD_START_ROUTINE lpStartAddr, LPVOID lpvThreadParm){ __try {
124 ГЛ А В А 3 БЕЗОПАСНОСТЬ DWORD dwThreadExitCode = lpStartAddr(lpvThreadParm); ExitThread(dwThreadExitCode); } __except(UnhandledExceptionFilter( GetExceptionInformation())) { ExitProcess(GetExceptionCode()); } } Заметьте: если при выполнении потока возникает исключение, не обра батываемое этим потоком, вызывается Windowsфильтр необработанных исключений. Эта функция реализует поведение системы, когда та обнаружи вает необработанное исключение. Поведение зависит от содержимого раз дела реестра HKLM\Software\Microsoft\Windows NT\CurrentVersion\AeDebug. В нем есть два важных параметра: Auto и Debugger. Auto сообщает фильтру необработанных исключений, надо ли автоматически запускать отладчик или спросить у пользователя, что делать. По умолчанию этому параметру присваивается 1, что подразумевает автоматический запуск отладчика. Од нако после установки средств разработки вроде Visual Studio его значение меняется на 0. Параметр Debugger является строкой, которая указывает путь к исполняемому файлу отладчика, который следует запускать при появлении необработанного исключения. Отладчик по умолчанию — \Windows\System32\Drwtsn32.exe (Dr. Wat son), который на самом деле является не отладчиком, а утилитой, сохраня ющей сведения о рухнувшем приложении в файле журнала (Drwtsn32.log) и обрабатывающей файл аварийного дампа (User.dmp). Оба этих файла по умолчанию помещаются в папку \Documents And Settings\All Users\ Docu ments\DrWatson. Для просмотра или изменения конфигурации утилиту Dr. Watson можно запустить в интерактивном режиме; при этом выводится окно с текущими параметрами (пример для Windows 2000 показан на рис. 39). Рис. 3-9. Параметры Dr. Watson (Доктор Ватсон) по умолчанию
ГЛАВА 9 Системные механизмы 125 Файл журнала содержит такую базовую информацию, как код исключе ния, имя рухнувшего образа, список загруженных DLL, а также содержимое стека и последовательность команд потока, вызвавшая исключение. Более подробные сведения о содержимом этого файла можно получить, запустив Dr. Watson и щелкнув кнопку Help (Справка) в его окне. В файл аварийного дампа записывается содержимое закрытых страниц процесса на момент возникновения исключения (но страницы кода из EXE и DLLмодулей не включаются). Этот файл можно открыть с помощью Win Dbg — Windowsотладчика, поставляемого с пакетом Debugging Tools или с Visual Studio 2003 и выше). Файл аварийного дампа перезаписывается при каждом крахе процесса. Поэтому, если его предварительно не скопировать или не переименовать, в нем будет содержаться информация лишь о послед нем крахе процесса. В Windows 2000 Professional визуальное уведомление включено по умол чанию. Окно сообщения, представленное на рис. 310, выводится Dr. Watson после того, как он сгенерирует аварийный дамп и запишет информацию в свой файл журнала. Рис. 3-10. Сообщение об ошибке от Dr. Watson (Windows 2000) Процесс Dr. Watson остается до тех пор, пока не будет закрыто это окно, и именно поэтому в Windows 2000 Server визуальное уведомление по умол чанию отключено. Дело вот в чем. Обычно сервер находится в отдельной комнате и возле него никто не сидит. Если на сервере рушится какоето при ложение, то подобное окно просто некому закрыть. По этой причине сер верные приложения должны регистрировать ошибки в журнале событий Windows. В Windows 2000, если параметр Auto установлен в 0, отображается окно, приведенное на рис. 311. Рис. 3-11. Сообщение о необработанном исключении (Windows 2000) После щелчка кнопки OK процесс завершается. А если вы нажимаете кнопку Cancel, запускается системный отладчик (заданный параметром De bugger в реестре).
126 ГЛ А В А 3 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: необработанные исключения Чтобы увидеть образец файла журнала Dr. Watson, запустите программу Accvio.exe, которую можно скачать по ссылке www.sysinternals.com/win dowsinternals.shtml. Эта программа вызовет нарушение доступа (ошибку защиты памяти) при попытке записи по нулевому адресу, всегда недей ствительному для Windowsпроцессов (см. таблицу 76 в главе 7). 1. Запустите Registry Editor (Редактор реестра) и найдите раздел HKLM\ SOFTWARE\Microsoft\Windows NT\CurrentVersion\AeDebug. 2. Если значение параметра Debugger равно «drwtsn32 p %ld e %ld  g», ваша система настроена на использование Dr. Watson в качестве отладчика по умолчанию. Переходите в п. 4. 3. Если в параметре Debugger не указан Drwtsn32.exe, вы все равно можете протестировать Dr. Watson, временно установив его, а затем восстановив исходные параметры своего отладчика: 쐽 сохраните гденибудь текущее значение параметра (например, в файле Notepad или в буфере обмена); 쐽 выберите из меню Start (Пуск) команду Run (Выполнить) и вве дите команду drwtsn32 i (чтобы инициализировать параметр Debugger для запуска Dr. Watson). 4. Запустите тестовую программу Accvio.exe. 5. Вы должны увидеть одно из окон, описанных ранее (в зависимос ти от версии Windows, в которой вы работаете). 6. Если вы используете параметры Dr. Watson по умолчанию, то те перь сможете изучить файл журнала и файл дампа в каталоге фай лов дампов. Для просмотра параметров Dr. Watson, запустите drwt sn32 без аргументов. (Выберите из меню Start команду Run и введи те drwtsn32.) 7. В качестве альтернативы щелкните последнюю запись в списке Application Errors (Ошибки приложения) и нажмите кнопку View (Показать) — будет выведена часть файла журнала Dr. Watson, со держащая сведения о нарушении доступа, вызванном Accvio.exe. Если вас интересуют детали формата файла журнала, щелкните кнопку Help (Справка) и выберите раздел Dr. Watson Log File Over view (Обзор файла журнала доктора Ватсона). 8. Если Dr. Watson не был отладчиком по умолчанию, восстановите исходное значение, сохраненное в п. 1. Проведите еще один эксперимент: попробуйте перенастроить пара метр Debugger на другую программу, например Notepad.exe (Блокнот) или Sol.exe (Solitaire). Снова запустите Accvio.exe. Обратите внимание, что запускается любая программа, указанная в параметре Debugger. То есть система не проверяет, действительно ли указанная в этом парамет ре программа является отладчиком. Обязательно восстановите исход ные значения параметров реестра (введите drwtsn32 i).
ГЛАВА 9 Системные механизмы 127 Windows-поддержка отчетов об ошибках В Windows XP и Windows Server 2003 появился новый, более изощренный механизм отчетов об ошибках, называемый Windows Error Reporting. Он ав томатизирует передачу информации о крахе как в пользовательском режи ме, так и в режиме ядра. (Как применить этот механизм для получения све дений о крахе системы, см. главу 14.) Windows Error Reporting можно настроить, последовательно выбрав My Computer (Мой компьютер), Properties (Свойства), Advanced (Дополнитель но) и Error Reporting (Отчет об ошибках) (на экране появится диалоговое окно, показанное на рис. 312); то же самое можно сделать через парамет ры локальной или доменной политики группы, которые хранятся в разделе реестра HKLM\Software\Microsoft\PCHealth\ErrorReporting. Рис. 3-12. Диалоговое окно настройки отчетов об ошибках Перехватив необработанное исключение (об этом шла речь в предыду щем разделе), фильтр необработанных исключений выполняет начальную проверку, чтобы решить, надо ли запустить механизм Windows Error Repor ting. Если параметр реестра HKLM\SOFTWARE\Microsoft\Windows NT\Current Version\AeDebug\Auto установлен в 0 или строка Debugger содержит текст «Drwtsn32», фильтр необработанных исключений загружает в аварийный процесс библиотеку \Windows\System32\Faultrep.dll и вызывает ее функцию ReportFault. Эта функция проверяет конфигурацию механизма отчетов об ошибках, которая хранится в разделе HKLM\Software\Microsoft\PCHealth\ ErrorReporting, и определяет, следует ли формировать отчет для данного процесса и, если да, то как. В обычном случае ReportFault создает процесс, выполняющий \Windows\System32\Dwwin.exe, который выводит окно, где пользователь уведомляется о крахе процесса и где ему предоставляется воз можность передать отчет об ошибках в Microsoft (рис. 313).
128 ГЛ А В А 3 Рис. 3-13. БЕЗОПАСНОСТЬ Диалоговое окно, выводимое Windows Error Reporting При щелчке кнопки Send Error Report (Послать отчет), отчет об ошибках (минидамп и текстовый файл с детальными сведениями о номерах версий DLL, загруженных в рухнувший процесс) передается на онлайновый сервер анализа аварийных ситуаций, Watson.Microsoft.com. (В отличие от краха сис темы в режиме ядра здесь нет возможности найти какоелибо решение на момент отправки отчета.) Затем фильтр необработанных исключений созда ет процесс для запуска отладчика (обычно Drwtsn32.exe), который по умол чанию создает свой файл дампа и запись в журнале. В отличие от Windows 2000 этот файл содержит не полный дамп, а минидамп. Поэтому в ситуации, где для отладки рухнувшего приложения нужен полный дамп памяти процес са, вы можете изменить конфигурацию Dr. Watson, запустив его без аргумен тов командной строки, как было описано в предыдущем разделе. В средах, где системы не подключены к Интернету или где администра тор хочет контролировать, какие именно отчеты об ошибках посылаются в Microsoft, эти отчеты можно передавать на внутренний файлсервер. Micro soft предоставляет опытным заказчикам утилиту Corporate Error Reporting, которая понимает структуру каталогов, создаваемую Windows Error Repor ting, и позволяет администратору задавать условия, при которых отчеты формируются и передаются в Microsoft. (Подробности см. по ссылке http:// www.microsoft.com/resources/satech/cer.) Диспетчеризация системных сервисов Как показано на рис. 31, обработчики ловушек ядра обслуживают прерывания, исключения и вызовы системных сервисов. Из предыдущих разделов вы знае те, как проводится обработка прерываний и исключений. Здесь будет расска зано о вызовах системных сервисов. Диспетчеризация системных сервисов начинается с выполнения инструкции, закрепленной за такой диспетчериза цией. Эта инструкция зависит от процессора, на котором работает Windows. Диспетчеризация 32-разрядных системных сервисов На процессорах x86 до Pentium II использовалась инструкция int 0x2e (де сятичное значение 46). В результате выполнения этой инструкции срабаты вает ловушка, и Windows заносит в запись IDT под номером 46 указатель на
ГЛАВА 9 Системные механизмы 129 диспетчер системных сервисов (см. таблицу 31). Эта ловушка заставляет выполняемый поток переключиться в режим ядра и войти в диспетчер сис темных сервисов. Номер запрошенного системного сервиса указывается числовым аргументом, переданным в регистр процессора EAX. Содержимое регистра EBX указывает на список параметров, передаваемый системному сервису вызывающей программой. На x86процессорах Pentium II и выше Windows использует инструкцию sysenter, которую Intel специально определил для быстрой диспетчеризации системных сервисов. Для поддержки этой инструкции Windows сохраняет на этапе загрузки адрес процедуры ядра — диспетчера системных сервисов в регистре, сопоставленном с данной инструкцией. Выполнение инструкции приводит к переключению в режим ядра и запуску диспетчера системных сервисов. Номер системного сервиса передается в регистре процессора EAX, а регистр EDX указывает на список аргументов, предоставленных вызвавшим кодом. Для возврата в пользовательский режим диспетчер системных серви сов обычно выполняет инструкцию sysexit. (В некоторых случаях, например, когда в процессоре включен флаг single step, диспетчер системных сервисов использует вместо sysexit инструкцию iretd.) На 32разрядных процессорах AMD K6 и выше Windows применяет спе циальную инструкцию syscall, которая функционирует аналогично x86ин струкции sysenter; Windows записывает в регистр процессора, связанный с инструкцией syscall, адрес диспетчера системных сервисов ядра. Номер сис темного вызова передается в регистре EAX, а в стеке хранятся аргументы, предоставленные вызвавшим кодом. После диспетчеризации ядро выполня ет инструкцию sysret. При загрузке Windows распознает тип процессора, на котором она рабо тает, и выбирает подходящий системный код. Этот код для NtReadFile в поль зовательском режиме выглядит так: ntdll!NtReadFile: 77f5bfa8 b8b7000000 77f5bfad ba0003fe7f 77f5bfb2 ffd2 77f5bfb4 c22400 mov mov call ret eax,0xb7 edx,0x7ffe0300 edx 0x24 Номер системного сервиса — 0xb7 (183 в десятичной форме), инструк ция вызова выполняет код диспетчеризации системного сервиса, установ ленный ядром, который в данном примере находится по адресу 0x7ffe0300. Поскольку пример взят для Pentium M, используется sysenter: SharedUserData!SystemCallStub: 7ffe0300 8bd4 mov edx,esp 7ffe0302 0f34 sysenter 7ffe0304 c3 ret
130 ГЛ А В А 3 БЕЗОПАСНОСТЬ Диспетчеризация 64-разрядных системных сервисов В архитектуре x64 операционная система Windows использует инструкцию syscall, которая работает аналогично инструкции syscall на процессорах AMD K6. Windows передает номер системного вызова в регистре EAX, первые че тыре параметра в других регистрах, а остальные параметры (если они есть) в стеке: ntdll!NtReadFile: 00000000'77f9fc60 00000000'77f9fc63 00000000'77f9fc68 00000000'77f9fc6a 4c8bd1 b8bf000000 0f05 c3 mov r10,rcx mov eax,0xbf syscall ret В архитектуре IA64 для тех же целей применяется инструкция epc (Enter Privileged Mode). Первые восемь аргументов системного вызова передаются в регистрах, а остальное в стеке. Диспетчеризация системных сервисов режима ядра Как показано на рис. 314, ядро использует номер системного сервиса для поиска информации о нем в таблице диспетчеризации системных серви сов (system service dispatch table). Эта таблица похожа на описанную ранее таблицу IDT и отличается от нее тем, что каждый ее элемент содержит ука затель на системный сервис, а не на процедуру обработки прерывания. ПРИМЕЧАНИЕ Номера системных сервисов могут различаться в раз ных сервисных пакетах (service packs) — Microsoft время от времени добавляет или удаляет некоторые системные сервисы, а их номера ге нерируются автоматически при компиляции ядра. Рис. 3-14. Исключения системных сервисов Диспетчер системных сервисов, KiSystemService, копирует аргументы выз вавшего кода из стека потока пользовательского режима в свой стек режи ма ядра (поэтому вызвавший код не может изменить значения аргументов после того, как они переданы ядру) и выполняет системный сервис. Если
ГЛАВА 9 Системные механизмы 131 переданные системному сервису аргументы содержат ссылки на буферы в пользовательском пространстве, код режима ядра проверяет возможность доступа к этим буферам, прежде чем копировать в них (или из них) данные. Как будет показано в главе 6, у каждого потока есть указатель на таблицу системных сервисов. Windows располагает двумя встроенными таблицами системных сервисов, но поддерживает до четырех. Диспетчер системных сервисов определяет, в какой таблице содержится запрошенный сервис, интерпретируя 2битное поле 32битного номера системного сервиса как указатель на таблицу. Младшие 12 битов номера системного сервиса служат индексом внутри указанной таблицы. Эти поля показаны на рис. 315. Рис. 3-15. Трансляция номера системного сервиса Таблицы дескрипторов сервисов Главная таблица по умолчанию, KeServiceDescriptorTable, определяет базовые сервисы исполнительной системы, реализованные в Ntoskrnl.exe. Другая таб лица, KeServiceDescriptorTableShadow, включает в себя сервисы USER и GDI, реализованные в Win32k.sys — той части подсистемы Windows, которая ра ботает в режиме ядра. Когда Windowsпоток впервые вызывает сервис USER или GDI, адрес таблицы системных сервисов потока меняется на адрес таб лицы, содержащей сервисы USER и GDI. Функция KeAddSystemServiceTable позволяет Win32k.sys и другим драйверам добавлять новые таблицы систем ных сервисов. Если в Windows 2000 установлены службы Internet Information Services (IIS), их драйвер поддержки (Spud.sys) после загрузки определяет
132 ГЛ А В А 3 БЕЗОПАСНОСТЬ дополнительную таблицу сервисов. Так что после этого стороннее про граммное обеспечение может определить только одну дополнительную таб лицу. Таблица сервисов, добавляемая KeAddSystemServiceTable (кроме табли цы Win32k.sys), копируется в таблицы KeServiceDescriptorTable и KeService DescriptorTableShadow. Windows поддерживает добавление лишь двух таблиц системных сервисов помимо главной и таблиц Win32. ПРИМЕЧАНИЕ Windows Server 2003 Service Pack 1 и выше не поддер живает добавление таблиц системных сервисов, если не считать те, которые включаются Win32k.sys, так что этот способ не годится для расширения функциональности этой системы. Инструкции для диспетчеризации сервисов исполнительной системы Windows содержатся в системной библиотеке Ntdll.dll. DLLмодули подсис тем окружения вызывают функции из Ntdll.dll для реализации своих доку ментированных функций. Исключением являются функции USER и GDI — здесь инструкции для диспетчеризации системных сервисов реализованы непосредственно в User32.dll и Gdi32.dll, а не в Ntdll.dll. Эти два случая иллю стрирует рис. 316. Рис. 3-16. Диспетчеризация системных сервисов
ГЛАВА 9 Системные механизмы 133 Как показано на рис. 316, Windowsфункция WriteFile в Kernel32.dll вы зывает функцию NtWriteFile из Ntdll.dll. Она в свою очередь выполняет соот ветствующую инструкцию, вызывающую срабатывание ловушки системно го сервиса и передающую номер системного сервиса NtWriteFile. Далее дис петчер системных сервисов (функция KiSystemService в Ntoskrnl.exe) вызы вает истинную NtWriteFile для обработки запроса на вводвывод. Для функ ций USER и GDI диспетчер системных сервисов вызывает функции из Win32k.sys, той части подсистемы Windows, которая работает в режиме ядра. ЭКСПЕРИМЕНТ: наблюдение за частотой вызова системных сервисов Вы можете наблюдать за частотой вызова системных сервисов с помо щью счетчика System Calls/Sec (Системных вызовов/сек) объекта Sys tem (Система). Откройте оснастку Performance (Производительность) и щелкните кнопку Add (Добавить), чтобы добавить на график счет чик. Выберите объект System и счетчик System Calls/Sec, затем щелк ните кнопки Add и Close (Закрыть). Диспетчер объектов Как говорилось в главе 2, реализованная в Windows модель объектов позво ляет получать согласованный и безопасный доступ к различным внутренним сервисам исполнительной системы. В этом разделе описывается диспетчер объектов (object manager) — компонент исполнительной системы, отвеча ющий за создание, удаление, защиту и отслеживание объектов. ЭКСПЕРИМЕНТ: исследование диспетчера объектов В этом разделе будут предлагаться эксперименты, которые покажут вам, как просмотреть базу данных диспетчера объектов. В них будут использоваться перечисленные ниже инструменты, которые вам нуж но освоить (если вы их еще не освоили). 쐽 Winobj можно скачать с сайта www.sysinternals.com. Она показывает пространство имен диспетчера объектов. Другая версия этой утили ты есть в Platform SDK (\Program Files\Microsoft Platform SDK\Bin\ Winnt\Winobj.exe). Однако версия с www.sysinternals.com сообщает более детальную информацию об объектах (например, счетчик ссы лок, число открытых описателей, дескрипторы защиты и т. д.). 쐽 Process Explorer и Handle с сайта www.sysinternals.com. Отображают открытые описатели для процесса. 쐽 Oh.exe (имеется в ресурсах Windows) выводит открытые описате ли для процесса, но требует предварительной установки специаль ного глобального флага. 쐽 Команда Openfiles /query (в Windows XP и Windows Server 2003) ото бражает открытые описатели для процесса, но требует предвари тельной установки специального глобального флага. см. след. стр.
134 ГЛ А В А 3 БЕЗОПАСНОСТЬ 쐽 Команда !handle отладчика ядра отображает открытые описатели для процесса. Средство просмотра объектов позволяет изучить пространство имен, поддерживаемое диспетчером объектов (имена есть не у всех объектов). Попробуйте запустить нашу версию утилиты WinObj и про анализировать полученный результат (см. иллюстрацию ниже). Как уже отмечалось, утилита OH и команда Openfiles /query требу ют установки глобального флага «поддержка списка объектов» (main tain objects list). (О глобальных флагах см. соответствующий раздел далее в этой главе.) OH установит этот флаг, если он еще не задан. Что бы узнать, включен ли данный флаг, введите Openfiles /Local. Вы мо жете включить его командой Openfiles /Local ON. В любом случае нуж но перезагрузить систему, чтобы новый параметр вступил в силу. Ни Process Explorer, ни Handle с сайта www.sysinternals.com не требуют включения слежения за объектами, потому что для получения соответ ствующей информации они используют драйвер устройства. При разработке диспетчера объекта был выдвинут ряд требований, в со ответствии с которыми он должен: 쐽 реализовать общий, унифицированный механизм использования систем ных ресурсов; 쐽 изолировать защиту объектов в одном участке операционной системы для соответствия требованиям безопасности класса С2; 쐽 предоставлять механизм учета использования объектов процессами, поз воляющий устанавливать лимиты на выделение процессам системных ресурсов;
ГЛАВА 9 Системные механизмы 135 쐽 поддерживать такую схему именования объектов, которая позволяла бы легко включать как существующие объекты (устройства, файлы и катало ги файловой системы), так и независимые наборы объектов; 쐽 соответствовать требованиям различных подсистем окружения операци онной системы — например, поддерживать наследование ресурсов роди тельских процессов дочерними (необходимо в Windows и POSIX) и име на файлов, чувствительные к регистру букв (требуется в POSIX); 쐽 устанавливать единообразные правила сохранения объектов в памяти (т. е. объект должен быть доступен, пока используется какимилибо процессами). В Windows существует два вида внутренних объектов: объекты исполни тельной системы (executive objects) и объекты ядра (kernel objects). Первые реализуются различными компонентами исполнительной системы (диспет чером процессов, диспетчером памяти, подсистемой вводавывода и т. д.). Вторые являются более примитивными объектами, которые реализуются ядром Windows. Эти объекты, невидимые коду пользовательского режима, создаются и используются только в исполнительной системе. Объекты ядра поддерживают фундаментальную функциональность (например, синхрони зацию), на которую опираются объекты исполнительной системы. Так, мно гие объекты исполнительной системы содержат (инкапсулируют) один или несколько объектов ядра, как показано на рис. 317. Рис. 3-17. Объекты исполнительной системы, включающие объекты ядра Структура объектов ядра и способы их применения для синхронизации других объектов будут рассмотрены в этой главе несколько позже. А сейчас мы сосредоточимся на принципах работы диспетчера объектов, а также на структуре объектов исполнительной системы, описателях и таблицах опи сателей. Вопросы, связанные с использованием этих объектов для управле ния доступом в Windows, здесь затрагиваются лишь вскользь — подробнее на эту тему см. главу 8.
136 ГЛ А В А 3 БЕЗОПАСНОСТЬ Объекты исполнительной системы Каждая подсистема окружения проецирует на свои приложения разные об разы операционной системы. Объекты исполнительной системы и сервисы объектов — именно те примитивы, из которых подсистемы окружения кон струируют собственные версии объектов и других ресурсов. Как правило, объекты исполнительной системы создаются подсистемой окружения в интересах пользовательских приложений или компонентов операционной системы в процессе обычной работы. Так, для создания фай ла Windowsприложение вызывает Windowsфункцию CreateFile, реализо ванную в DLL подсистемы Windows, Kernel32.dll. После проверки и инициа лизации CreateFile в свою очередь вызывает NtCreateFile, встроенный сервис Windows, для создания объекта «файл» исполнительной системы. Набор объектов, предоставляемый приложениям подсистемой окруже ния, может быть больше или меньше того набора, который предоставляет ся исполнительной системой. Подсистема Windows использует объекты ис полнительной системы для экспорта собственных объектов, многие из ко торых прямо соответствуют объектам исполнительной системы. Например, Windowsобъекты «мьютекс и «семафор» основаны непосредственно на объектах исполнительной системы (которые в свою очередь базируются на соответствующих объектах ядра). Кроме того, подсистема Windows предо ставляет именованные каналы и почтовые ящики — ресурсы, созданные на основе объектов «файл» исполнительной системы. Некоторые подсистемы вроде POSIX вообще не поддерживают объекты как таковые. Подсистема POSIX использует объекты и сервисы исполнительной системы просто как основу для POSIXпроцессов, каналов и других ресурсов, которые она пре доставляет своим приложениям. В таблице 33 кратко описываются основные объекты, предоставляемые исполнительной системой. Подробнее об объектах исполнительной систе мы см. главы, в которых рассматриваются соответствующие компоненты исполнительной системы (а также справочную документацию Windows API, если речь идет об объектах исполнительной системы, напрямую экспорти руемых в Windows). ПРИМЕЧАНИЕ В Windows 2000 исполнительная система реализует в общей сложности 27 типов объектов, а в Windows XP и Windows Server 2003 — 29. (В эти более новые версии Windows добавлены объекты DebugObject и KeyedEvent.) Многие из таких объектов предназначены только для использования компонентами исполнительной системы, которая и определяет их. Эти объекты недоступны Windows API напря мую. Пример таких объектов — Driver, Device и EventPair.
ГЛАВА 9 Системные механизмы 137 Таблица 3-3. Объекты исполнительной системы, доступные Windows API Тип объектов Представляет: Символьная ссылка (symbolic link) Механизм косвенной ссылки на имя объекта Процесс (process) Виртуальное адресное пространство и управляющую информацию, необходимую для выполнения набора объектов «поток» Поток (thread) Исполняемую часть процесса Задание (job) Совокупность процессов, управляемую как единая группа Раздел (section) Область разделяемой памяти (называемую объектом «проекция файла») Файл (file) Экземпляр открытого файла или устройства вводавывода Маркер доступа (access token) Профиль защиты (SID, права пользователя и т. д.) процесса или потока Событие (event) Объект, который может пребывать либо в занятом, либо в свободном состоянии; используется для синхрониза ции или уведомления Семафор (semaphore) Счетчик, действующий как шлюз к ресурсам; позволяет указывать максимальное число потоков, которым разре шен доступ к защищенным этим объектом ресурсам Мьютекс (mutex) Механизм синхронизации, используемый для упорядоче ния доступа к ресурсам Таймер (timer) Механизм уведомления потока об истечении фиксиро ванного периода времени IoCompletion Метод постановки в очередь и извлечения из нее уведом лений о завершении операций вводавывода (в Windows API называется портом завершения вводавывода) Раздел реестра (key) Механизм ссылки на данные в реестре; хотя разделы реестра появляются в пространстве имен диспетчера объектов, они управляются диспетчером конфигурации по аналогии с тем, как объекты «файл» управляются драйверами файловой системы; с объектом «раздел реестра» может быть сопоставлено произвольное коли чество параметров (от 0 и более) WindowStation Объект, содержащий буфер обмена, набор глобальных атомов и группу объектов «рабочий стол» Рабочий стол (desktop) Объект, содержащийся в объекте типа WindowStation; он описывает логическую поверхность экрана и содер жит окна, меню и ловушки ПРИМЕЧАНИЕ Мьютекс — это название объектов «мутант» (mutants) в Windows API; объект ядра, на котором основан мьютекс, имеет внут реннее имя мутант.
138 ГЛ А В А 3 БЕЗОПАСНОСТЬ Структура объектов Как показано на рис. 318, у каждого объекта есть заголовок и тело. Диспет чер объектов управляет заголовками объектов, а телами объектов управля ют владеющие ими компоненты исполнительной системы. Кроме того, каж дый заголовок объекта указывает на список процессов, которые открыли этот объект, и на специальный объект, называемый объектом типа (type object), — он содержит общую для всех экземпляров информацию. Рис. 3-18. Структура объекта Заголовки и тела объектов Диспетчер объектов использует данные, хранящиеся в заголовке, для управ ления объектами независимо от их типа. Стандартные атрибуты заголовка кратко описываются в таблице 34. Таблица 3-4. Стандартные атрибуты заголовка объекта Атрибут Описание Имя объекта (object name) Позволяет совместно использовать объект, делая его видимым для других процессов Каталог объектов (object directory) Предоставляет иерархическую структуру для хранения имен объектов Дескриптор защиты (security descriptor) Определяет, кто и как может использовать данный объект (должен быть null для безымянных объектов) Квота (quota charges) Устанавливает ограничения на объемы ресурсов при открытии процессом описателя данного объекта Счетчик открытых описателей (open handle count) Подсчитывает, сколько раз был открыт описатель объекта
ГЛАВА 9 Системные механизмы 139 Таблица 3-4. (окончание) Атрибут Описание Список открытых описателей (open handles list) Указывает на список процессов, открывших описатели данного объекта Тип объекта (object type) Указывает на объект типа, содержащий атрибуты, общие для объектов данного типа Счетчик ссылок (reference count) Подсчитывает, сколько раз компоненты режима ядра ссылались на адрес данного объекта Кроме заголовка у каждого объекта имеется тело, чей формат и содержи мое уникальны для данного типа объектов; все объекты одного типа имеют одинаковый формат тела. Создавая тип объектов и предоставляя для него сервисы, компонент исполнительной системы может контролировать мани пуляции с данными в телах всех объектов этого типа. Диспетчер объектов предоставляет небольшой набор базовых сервисов, которые работают с атрибутами заголовка объекта и применимы к объек там любого типа (хотя некоторые базовые сервисы не имеют смысла для отдельных объектов). Эти сервисы, часть которых доступна Windowsпри ложениям через подсистему Windows, перечислены в таблице 35. Базовые сервисы поддерживаются для всех типов объектов, но у каждого объекта есть свои сервисы для создания, открытия и запроса. Так, подсисте ма вводавывода реализует сервис создания файлов для объектов «файл», а диспетчер процессов — сервис создания процессов для объектов «процесс». Конечно, можно было бы реализовать единый сервис создания объектов, но подобная процедура оказалась бы весьма сложной, так как набор парамет ров, необходимых для инициализации объекта «файл», значительно отлича ется, скажем, от параметров инициализации объекта «процесс». А при вызове потоком сервиса объекта для определения его типа и обращении к соответ ствующей версии сервиса диспетчер объектов каждый раз сталкивался бы с необходимостью обработки дополнительных данных. В силу этих и иных причин сервисы, обеспечивающие создание, открытие и запросы, для каж дого типа объектов реализованы отдельно. Таблица 3-5. Базовые сервисы объектов Сервис Описание Закрытие (close) Закрывает описатель объекта Дублирование (duplicate) Позволяет совместно использовать объект за счет дубли рования его описателя и передачи его другому процессу Запрос объекта (query object) Сообщает информацию о стандартных атрибутах объекта Запрос защиты (query security) Сообщает дескриптор защиты объекта Установка защиты (set security) Изменяет защиту объекта см. след. стр.
140 ГЛ А В А 3 БЕЗОПАСНОСТЬ Таблица 3-5. (окончание) Сервис Описание Ожидание одного объекта (wait for a single object) Синхронизирует выполнение потока с одним объектом Ожидание нескольких объектов (wait for multiple objects) Синхронизирует выполнение потока с несколькими объектами Объекты типа В заголовках объектов содержатся общие для всех объектов атрибуты, но их значения могут меняться у конкретных экземпляров данного объекта. Так, у каждого объекта есть уникальное имя и может быть уникальный дескриптор защиты. Однако некоторые атрибуты объектов остаются неизменными для всех объектов данного типа. Например, при открытии описателя объекта можно выбрать права доступа из набора, специфичного для объектов данно го типа. Исполнительная система предоставляет в том числе атрибуты досту па «завершение» (terminate) и «приостановка» (suspend) для объектов «поток», а также «чтение» (read), «запись» (write), «дозапись» (append) и «удаление» (delete) для объектов «файл». Другой пример атрибута, специфичного для типа объектов, — синхронизация, о которой мы кратко расскажем ниже. Чтобы сэкономить память, диспетчер объектов сохраняет статические атрибуты, специфичные для конкретного типа объектов, только при созда нии нового типа объектов. Для записи этих данных он использует собствен ный объект типа. Как показано на рис. 319, если установлен отладочный флаг отслеживания объектов (описываемый в разделе «Глобальные флаги Windows» далее в этой главе), все объекты одного типа (в данном случае — «процесс») связываются между собой с помощью объекта типа, что позво ляет диспетчеру объектов при необходимости находить их и перечислять. Рис. 3-19. Объекты «процесс» и объект типа «процесс»
ГЛАВА 9 Системные механизмы 141 ЭКСПЕРИМЕНТ: просмотр заголовков объектов и объектов типа Вы можете увидеть список объектов типа, объявленных диспетчеру объектов, с помощью утилиты Winobj с сайта www.sysinternals.com. Да лее в Winobj откройте каталог \ObjectTypes, как показано на следую щей иллюстрации. Чтобы просмотреть структуру данных типа объектов «процесс» в отладчике ядра, сначала идентифицируйте этот объект командой !process: kd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** PROCESS 8a4ce668 SessionId: none Cid: 0004 Peb: 00000000 ParentCid: 0000 DirBase: 00039000 ObjectTable: e1001c88 HandleCount: 474. Image: System Затем выполните команду !object, указав адрес объекта «процесс» в качестве аргумента: kd> !object 8a4ce668 Object: 8a4ce668 Type: (8a4ceca0) Process ObjectHeader: 8a4ce650 HandleCount: 2 PointerCount: 89 Заметьте, что заголовок объекта начинается с 0x18 (24) байтов до нижней границы тела объекта. Увидеть заголовок объекта позволяет следующая команда: kd> dt _object_header 8a4ce650 nt!_OBJECT_HEADER +0x000 PointerCount : 79 +0x004 HandleCount : 2 +0x004 NextToFree : 0x00000002 см. след. стр.
142 ГЛ А В А 3 +0x008 +0x00c +0x00d +0x00e +0x00f +0x010 +0x010 +0x014 +0x018 БЕЗОПАСНОСТЬ Type : 0x8a4ceca0 NameInfoOffset : 0 '' HandleInfoOffset : 0 '' QuotaInfoOffset : 0 '' Flags : 0x22 '''' ObjectCreateInfo : 0x80545620 QuotaBlockCharged : 0x80545620 SecurityDescriptor : 0xe10001dc Body : _QUAD Теперь посмотрите на структуру данных типа этих объектов, полу чив ее адрес из поля Type в структуре данных заголовка объекта: kd> dt _object_type 8a4ceca0 ntdll!_OBJECT_TYPE +0x000 Mutex : _ERESOURCE +0x038 TypeList : _LIST_ENTRY [ 0x8a4cecd8  0x8a4cecd8 ] +0x040 Name : _UNICODE_STRING "Process" +0x048 DefaultObject : (null) +0x04c Index : 5 +0x050 TotalNumberOfObjects : 0x30 +0x054 TotalNumberOfHandles : 0x1b4 +0x058 HighWaterNumberOfObjects : 0x3f +0x05c HighWaterNumberOfHandles : 0x1b8 +0x060 TypeInfo : _OBJECT_TYPE_INITIALIZER +0x0ac Key : 0x636f7250 +0x0b0 ObjectLocks : [4] _ERESOURCE Этот вывод показывает, что структура типа включает имя типа объек та, счетчики активных объектов этого типа, а также счетчики пиково го числа описателей и объектов данного типа. В поле TypeInfo хранит ся указатель на структуру данных, в которой содержатся атрибуты, об щие для всех объектов этого типа, а также указатели на методы типа: kd> dt _object_type_initializer 8a4ceca0+60 ntdll!_OBJECT_TYPE_INITIALIZER +0x000 Length : 0x4c +0x002 UseDefaultObject : 0 '' +0x003 CaseInsensitive : 0 '' +0x004 InvalidAttributes : 0xb0 +0x008 GenericMapping : _GENERIC_MAPPING +0x018 ValidAccessMask : 0x1f0fff +0x01c SecurityRequired : 0x1 '' +0x01d MaintainHandleCount : 0 '' +0x01e MaintainTypeList : 0 '' +0x020 PoolType : 0 ( NonPagedPool ) +0x024 DefaultPagedPoolCharge : 0x1000 +0x028 DefaultNonPagedPoolCharge : 0x288 +0x02c DumpProcedure : (null)
ГЛАВА 9 Системные механизмы 143 +0x030 OpenProcedure : (null) +0x034 CloseProcedure : (null) +0x038 DeleteProcedure : 0x805abe6e nt!PspProcessDelete+0 +0x03c ParseProcedure : (null) +0x040 SecurityProcedure : 0x805cf682 nt!SeDefaultObjectMethod+0 +0x044 QueryNameProcedure : (null) +0x048 OkayToCloseProcedure : (null) Объектами типов нельзя управлять из пользовательского режима изза отсутствия соответствующих сервисов диспетчера объектов. Но некоторые из определяемых ими атрибутов видимы через отдельные системные серви сы и функции Windows API. Атрибуты, хранящиеся в объектах типа, описы ваются в таблице 36. Таблица 3-6. Атрибуты объекта типа Атрибут Описание Имя типа (type name) Название объектов этого типа («процесс», «событие», «порт» и т. д.) Тип пула (pool type) Определяет тип памяти, выделяемый для объектов этого типа (подкачиваемая или неподкачиваемая) Квота по умолчанию (default quota charges) Ограничение по умолчанию на объемы подкачиваемой и неподкачиваемой памяти при открытии процессом описателя данного объекта Виды доступа (access types) Виды доступа, который поток может запрашивать при открытии описателя объекта этого типа («чтение», «за пись», «завершение», «приостановка» и т. д.) Базовые права доступа (generic access rights mapping) Сопоставление четырех базовых прав доступа («чтение», «запись», «выполнение» и «все») с правами доступа, спе цифичными для данного типа Синхронизация (synchronization) Определяет, может ли поток ждать на объектах данного типа Методы (methods) Одна или несколько процедур, автоматически вызывае мых диспетчером объектов на определенных этапах жизненного цикла объекта Синхронизация, один из атрибутов, видимых Windowsприложениям, относится к способности потока синхронизировать свое выполнение, ожи дая изменения состояния определенного объекта. Поток можно синхрони зировать по таким объектам исполнительной системы, как задание, процесс, поток, файл, событие, семафор, мьютекс и таймер. Другие объекты исполни тельной системы не поддерживают синхронизацию. Способность объекта к синхронизации зависит от того, содержит ли он встроенный объект диспет чера — объект ядра, который будет рассмотрен далее в этой главе.
144 ГЛ А В А 3 БЕЗОПАСНОСТЬ Методы объекта Атрибут «методы», последний из перечисленных в таблице 36, состоит из набора внутренних процедур, похожих на конструкторы и деструкторы C++, т. е. на процедуры, автоматически вызываемые при создании или уничтоже нии объекта. В диспетчере объектов эта идея получила дальнейшее разви тие: он вызывает методы объекта и в других ситуациях, например при откры тии или закрытии описателя объекта или при попытке изменения парамет ров защиты объекта. В некоторых типах объектов методы определяются в зависимости от того, как должен использоваться данный тип объектов. При создании нового типа объектов компонент исполнительной систе мы может зарегистрировать у диспетчера объектов один или несколько ме тодов. После этого диспетчер объектов вызывает методы на определенных этапах жизненного цикла объектов данного типа — обычно при их созда нии, удалении или модификации. Поддерживаемые диспетчером объектов методы перечислены в таблице 37. Таблица 3-7. Методы объекта Метод Когда происходит вызов метода Open При открытии описателя объекта Close При закрытии описателя объекта Delete Перед удалением объекта диспетчером объектов Query name При запросе потоком имени объекта (например, файла), существующего во вторичном пространстве имен объектов Parse При поиске диспетчером объектов имени, существующего во вторичном пространстве имен объектов Security При считывании или изменении процессом параметров защиты объекта, например файла, существующего во вторич ном пространстве имен объектов Диспетчер объектов вызывает метод open всякий раз, когда создает опи сатель объекта (что происходит при создании или открытии объекта). Од нако метод open определен только в одном типе объектов — WindowStation. Этот метод необходим таким объектам для того, чтобы Win32k.sys мог ис пользовать часть памяти совместно с процессом, который служит в качестве пула памяти, связанного с объектом «рабочий стол». Пример использования метода close можно найти в подсистеме ввода вывода. Диспетчер вводавывода регистрирует метод close для объектов типа «файл», а диспетчер объектов вызывает метод close при закрытии каждого описателя объекта этого типа. Метод close проверяет, не осталось ли у про цесса, закрывающего описатель файла, какихлибо блокировок для файла, и, если таковые есть, снимает их. Диспетчер объектов не может и не должен самостоятельно проверять наличие блокировок для файла. Перед удалением временного объекта из памяти диспетчер объектов вы зывает метод delete, если он зарегистрирован. Например, диспетчер памяти регистрирует для объектов типа «раздел» метод delete, освобождающий фи
ГЛАВА 9 Системные механизмы 145 зические страницы, используемые данным разделом. Перед удалением объекта «раздел» этот метод также проверяет различные внутренние струк туры данных, выделенные для раздела диспетчером памяти. Диспетчер объектов не мог бы сделать эту работу, поскольку он ничего не знает о внут реннем устройстве диспетчера памяти. Методы delete других объектов вы полняют аналогичные функции. Если диспетчер объектов находит существующий вне его пространства имен объект, метод parse (по аналогии с методом query name) позволяет это му диспетчеру передавать управление вторичному диспетчеру объектов. Когда диспетчер объектов анализирует имя объекта, он приостанавливает анализ, встретив объект с сопоставленным методом parse, и вызывает метод parse, передавая ему оставшуюся часть строки с именем объекта. Кроме про странства имен диспетчера объектов, в Windows есть еще два пространства имен: реестра (реализуемое диспетчером конфигурации) и файловой сис темы (реализуемое диспетчером вводавывода через драйверы файловой системы). О диспетчере конфигурации см. главу 5; о диспетчере вводавы вода и драйверах файловой системы см. главу 9. Например, когда процесс открывает описатель объекта с именем \Device\ Floppy0\docs\resume.doc, диспетчер объектов просматривает свое дерево имен и ищет объект с именем Floppy0. Обнаружив, что с этим объектом со поставлен метод parse, он вызывает его, передавая ему остаток строки с име нем объекта (в данном случае — строку \docs\resume.doc). Метод parse объек тов «устройство» (device objects) является процедурой вводавывода, которая регистрируется диспетчером вводавывода при определении типа объекта «устройство». Процедура parse диспетчера вводавывода принимает строку с именем и передает ее соответствующей файловой системе, которая ищет файл на диске и открывает его. Подсистема вводавывода также использует метод security, аналогичный методу parse. Он вызывается каждый раз, когда поток пытается запросить или изменить параметры защиты файла. Эта информация для файлов отличает ся от таковой для других объектов, поскольку хранится в самом файле, а не в памяти. Поэтому для поиска, считывания или изменения параметров защи ты нужно обращаться к подсистеме вводавывода. Описатели объектов и таблица описателей, принадлежащая процессу Когда процесс создает или открывает объект по имени, он получает описа тель (handle), который дает ему доступ к объекту. Ссылка на объект по опи сателю работает быстрее, чем по имени, так как при этом диспетчер объек тов может сразу найти объект, не просматривая список имен. Процессы так же могут получать описатели объектов, вопервых, путем их наследования в момент своего создания (если процесссоздатель разрешает это, указывая со ответствующий флаг при вызове CreateProcess, и если описатель помечен как наследуемый либо в момент создания, либо позднее, вызовом Windowsфун кции SetHandleInformation), а вовторых, за счет приема дублированного опи сателя от другого процесса (см. описание Windowsфункции DuplicateHandle).
146 ГЛ А В А 3 БЕЗОПАСНОСТЬ Чтобы потоки процесса пользовательского режима могли оперировать объектом, им нужен описатель этого объекта. Идея применения описателей для управления ресурсами сама по себе не нова. Например, стандартные библиотеки языков С, Pascal (и других) при открытии файла возвращают его описатель. Описатели служат косвенными указателями на системные ресур сы, что позволяет прикладным программам избегать прямого взаимодей ствия с системными структурами данных. ПРИМЕЧАНИЕ Компоненты исполнительной системы и драйверы ус тройств могут обращаться к объектам напрямую, поскольку выполня ются в режиме ядра и ввиду этого имеют доступ к структурам объек тов в системной памяти. Однако они должны объявлять о своем ис пользовании объектов, увеличивая значение счетчика ссылок, что га рантирует сохранность нужного объекта (см. раздел «Хранение объек тов в памяти» далее в этой главе). Описатели дают и другие преимущества. Вопервых, описатели файлов, событий или процессов совершенно одинаковы — просто ссылаются на разные объекты. Это дает возможность создать унифицированный интер фейс для ссылок на объекты любого типа. Вовторых, только диспетчер объектов имеет право физически создавать описатели и искать их объекты, а значит, он может проанализировать любое действие с объектом в пользо вательском режиме и решить, позволяет ли профиль защиты вызывающей программы выполнить над объектом запрошенную операцию. ЭКСПЕРИМЕНТ: просмотр открытых описателей Запустите Process Explorer и убедитесь, что в его окне нижняя секция вклю чена и настроена на отображение открытых описателей. (Выберите View, Lower Pane View и Handles.) Затем откройте окно командной строки и про смотрите таблицу описателей для нового процесса Cmd.exe. Вы должны увидеть открытый описатель файла — текущего каталога. Например, если текущий каталог — C:\, Process Explorer выводит следующее.
ГЛАВА 9 Системные механизмы 147 Если вы теперь смените текущий каталог командой CD, то Process Explorer покажет, что описатель предыдущего каталога закрыт и от крыт описатель нового текущего каталога. Предыдущий описатель ненадолго выделяется красным цветом, а новый — зеленым. Длитель ность подсветки настраивается щелчком кнопки Options и регулиров кой параметра Difference Highlight Duration. Такая функциональность Process Explorer упрощает наблюдение за изменениями в таблице описателей. Например, если в процессе про исходит утечка описателей, просмотр таблицы описателей в Process Explorer позволяет быстро увидеть, какой описатель (или описатели) открывается, но не закрывается. Эта информация помогает програм мисту обнаружить утечку описателей. Таблицу открытых описателей также можно вывести, используя ко мандную строку утилиты Handle (www.sysinternals.com). Например, об ратите внимание на следующий фрагмент вывода Handle, где показана таблица описателей для процесса Cmd.exe до и после смены каталога: C:\>handle p cmd.exe Handle v2.2 Copyright (C) 19972004 Mark Russinovich Sysinternals  www.sysinternals.com ——————————————————————————————— cmd.exe pid: 3184 BIGDAVID\dsolomon b0: File C:\ C:\>cd windows C:\WINDOWS>handle p cmd.exe . . cmd.exe pid: 3184 BIGDAVID\dsolomon b4: File C:\WINDOWS Описатель объекта представляет собой индекс в таблице описателей, принадлежащей процессу. На нее указывает блок процесса исполнительной системы (EPROCESS), рассматриваемый в главе 6. Индекс первого описателя равен 4, второго — 8 и т. д. Таблица содержит указатели на все объекты, опи сатели которых открыты данным процессом. Эти таблицы реализованы по трехуровневой схеме аналогично тому, как блок управления памятью в сис темах типа x86 реализует трансляцию виртуальных адресов в физические, поддерживая более 16 000 000 описателей на каждый процесс (см. главу 7). При создании процесса в Windows 2000 диспетчер объектов формирует верхний уровень таблицы описателей, содержащий указатели на таблицы среднего уровня; средний уровень содержит первый массив указателей на таблицы вторичных описателей, а нижний — первую таблицу вторичных описателей. На рис. 320 показана структура таблицы описателей в Windows 2000. В этой операционной системе диспетчер объектов интерпретирует младшие 24 бита описателя объекта как три 8битных поля, являющиеся
148 ГЛ А В А 3 БЕЗОПАСНОСТЬ индексами для каждого из трех уровней таблицы описателей. В Windows XP и Windows Server 2003 при создании процесса создается лишь таблица опи сателей нижнего уровня — остальные уровни формируются по мере необ ходимости. В Windows 2000 таблица вторичных описателей состоит из 255 элементов. В Windows XP и Windows Server 2003 такая же таблица включает столько элементов, сколько помещается на страницу памяти минус один элемент, который используется для аудита описателей (handle auditing). На пример, на x86системах размер страницы составляет 4096 байтов. Делим это значение на размер элемента (8 байтов), вычитаем 1 и получаем всего 511 элементов в таблице описателей нижнего уровня. Наконец, таблица опи сателей среднего уровня в Windows XP и Windows Server 2003 содержит пол ную страницу указателей на таблицы вторичных описателей, поэтому коли чество таблиц вторичных описателей зависит от размеров страницы и ука зателя на конкретной аппаратной платформе. Рис. 3-20. Структура таблицы описателей, принадлежащая процессу в Windows 2000 ЭКСПЕРИМЕНТ: создание максимального количества описателей Тестовая программа Testlimit (www.sysinternals.com/windowsinternals. shtml) позволяет открывать описатели объекта до тех пор, пока не бу дет исчерпан их лимит. С ее помощью вы увидите, сколько описате лей можно создать в одном процессе в вашей системе. Поскольку па мять под таблицу описателей выделяется из пула подкачиваемых стра ниц, этот пул может быть исчерпан до того, как вы достигнете предель ного числа описателей, допустимых в одном процессе. 1. Скачайте файл Testlimit.zip по только что упомянутой ссылке и раз архивируйте его в какойнибудь каталог.
ГЛАВА 9 Системные механизмы 149 2. Запустите Process Explorer, щелкните View, затем System Information. Обратите внимание на текущий и максимальный размеры пула подкачиваемой памяти. (Для вывода максимальных размеров пулов Process Explorer нужно настроить на доступ к символам для образа ядра, Ntoskrnl.exe.) Пусть эта информация отображается, когда вы запустите программу Testlimit. 3. Откройте окно командной строки. 4. Запустите программу Testlimit с ключом –h (для этого введите test limit h). Когда Testlimit не удастся открыть очередной описатель, она сообщит общее число созданных ею описателей. Если это зна чение окажется меньше, чем около 16 миллионов, то, вероятно, вы исчерпали пул подкачиваемой памяти до достижения теоретичес ки предельного числа описателей. 5. Закройте окно командной строки; это приведет к завершению про цесса Testlimit и автоматическому закрытию всех открытых описа телей. Как показано на рис. 321, в x86системах каждый элемент таблицы опи сателей состоит из структуры с двумя 32битными элементами: указателем на объект (с флагами) и маской доступа. В 64разрядных системах каждый элемент имеет размер 12 байтов и состоит из 64битного указателя на заго ловок объекта и 32битной маски доступа (маски доступа описываются в главе 8). В Windows 2000 первый 32битный элемент содержит указатель на заго ловок объекта и четыре флага. Поскольку заголовки объектов всегда вырав ниваются по границе 8 байтов, в качестве флагов используются младшие 3 бита и один старший. Старший бит является флагом блокировки (lock). Ког да диспетчер объектов транслирует описатель в указатель на объект, он бло кирует соответствующую запись на время трансляции. Так как все объекты находятся в системном адресном пространстве, старший бит указателя на объект устанавливается в 1. (Гарантируется, что адреса всегда будут превы шать 0x80000000 даже на системах, запускаемых с ключом загрузки /3GB.) Так что, пока элемент таблицы описателей не заблокирован, диспетчер объектов может сбросить старший бит в 0. При блокировке элемента табли цы диспетчер объектов устанавливает этот бит и получает корректное зна чение указателя. Диспетчер блокирует всю таблицу описателей (используя специальную блокировку, сопоставляемую с каждым процессом), только если процесс создает новый описатель или закрывает существующий. В Windows XP и Windows Server 2003 флаг блокировки хранится в младшем бите указателя на объект. А флаг, который в Windows 2000 хранился в этом бите, теперь хранится в ранее зарезервированном бите маски доступа.
150 ГЛ А В А 3 Рис. 3-21. БЕЗОПАСНОСТЬ Структура элемента таблицы описателей Первый флаг указывает, имеет ли право вызывающая программа закры вать данный описатель. Второй определяет, получат ли процессы, созданные данным процессом, копию этого описателя. (Как уже отмечалось, наследо вание описателя можно указать при его создании или позже, через Windows функцию SetHandleInformation. Этот флаг тоже можно задать вызовом Set HandleInformation.) Третий задает, будет ли генерироваться сообщение ауди та при закрытии объекта. (Этот флаг не предоставляется в Windows и пред назначен для внутреннего использования диспетчером объектов.) Системным компонентам и драйверам устройств зачастую нужно откры вать описатели объектов, доступа к которым у приложений пользовательского режима нет. Это достигается созданием описателей в таблице описателей ядра (kernel handle table) (внутреннее имя — ObpKernelHandleTable). Описа тели в этой таблице доступны только в режиме ядра в контексте любого про цесса. Это значит, что функции режима ядра могут ссылаться на эти описа тели из контекста любого процесса без ущерба для производительности. Дис петчер объектов распознает ссылки на описатели в таблице описателей ядра, когда старший бит в них установлен, т. е. когда в таких ссылках содержатся значения, превышающие 0x80000000. В Windows 2000 таблица описателей ядра является независимой таблицей описателей, но в Windows XP и Windows Server 2003 она служит и таблицей описателей для процесса System. ЭКСПЕРИМЕНТ: просмотр таблицы описателей с помощью отладчика ядра Команда !handle отладчика ядра допускает следующие аргументы: !handle <индекс_описателя> <флаги> <идентификатор_процесса> Индекс описателя определяет элемент в таблице описателей (0 — вывод всех описателей). Индекс первого описателя равен 4, второго — 8 и т. д. Например, введя !handle 4, вы увидите первый описатель в те кущем процессе. Вы можете указывать флаги, являющиеся битовыми масками, где бит 0 означает, что нужно вывести лишь информацию из элемента таблицы, бит 1 — показать не только используемые, но и свободные описатели, а бит 2 — сообщить информацию об объекте, на который ссылается описатель. Следующая команда выводит полную информа цию о таблице описателей в процессе с идентификатором 0x408.
ГЛАВА 9 Системные механизмы 151 kd> !handle 0 7 408 processor number 0 Searching for Process with Cid == 408 PROCESS 865f0790 SessionId: 0 Cid: 0408 Peb: 7ffdf000 ParentCid: 01dc DirBase: 04fd3000 ObjectTable: 856ca888 TableSize: 21. Image: i386kd.exe Handle Table at e2125000 with 21 Entries in use 0000: free handle 0004: Object: e20da2e0 GrantedAccess: 000f001f Object: e20da2e0 Type: (81491b80) Section ObjectHeader: e20da2c8 HandleCount: 1 PointerCount: 1 0008: Object: 80b13330 GrantedAccess: 00100003 Object: 80b13330 Type: (81495100) Event ObjectHeader: 80b13318 HandleCount: 1 PointerCount: 1 Защита объектов Открывая файл, нужно указать, для чего это делается — для чтения или за писи. Если вы попытаетесь записать чтонибудь в файл, открытый для чте ния, то получите ошибку. Аналогичным образом действует и исполнитель ная система: когда процесс создает объект или открывает описатель суще ствующего объекта, он должен указывать набор желательных прав досту па (desired access rights), сообщая тем самым, что именно он собирается де лать с объектом. Процесс может запросить либо набор стандартных прав доступа (чтение, запись, выполнение), применимых ко всем объектам, либо специфические права доступа, различные для объектов разного типа. Так, в случае объекта «файл» процесс может запросить права на удаление файла или дозапись, а в случае объекта «поток» — права на приостановку потока или его завершение. Когда процесс открывает описатель объекта, диспетчер объектов вызы вает так называемый монитор состояния защиты* (security reference moni tor), часть подсистемы защиты, работающую в режиме ядра, и посылает ему уведомление о наборе желательных для процесса прав доступа. Монитор состояния защиты проверяет, разрешает ли дескриптор защиты объекта зап рашиваемый тип доступа. Если да, монитор состояния защиты возвращает процессу набор предоставленных прав доступа (granted access rights), ин формацию о которых диспетчер объектов сохраняет в создаваемом им опи сателе объекта. Как подсистема защиты определяет, кто и к каким объектам может получать доступ, рассматривается в главе 8. * На самом деле этот компонент представляет собой нечто вроде монитора запро сов к подсистеме защиты. — Прим. перев.
152 ГЛ А В А 3 БЕЗОПАСНОСТЬ После этого всякий раз, когда потоки процесса используют описатель, дис петчер объектов может быстро проверить, соответствует ли набор предостав ленных прав доступа, хранящихся в описателе, действиям, которые намере вается выполнить вызванный потоками сервис объекта. Так, если вызывающая программа запросила доступ для чтения к объекту «раздел», а затем вызывает сервис для записи в этот объект, последний сервис не выполняется. Хранение объектов в памяти Объекты бывают двух типов: временные (temporary) и постоянные (per manent). Большинство объектов временные, т. е. они хранятся, пока исполь зуются, и освобождаются, как только необходимость в них отпадает. Посто янные объекты существуют до тех пор, пока они не освобождаются явным образом. Поскольку большинство объектов временные, остальная часть это го раздела будет посвящена тому, как диспетчер объектов реализует хране ние объектов в памяти (object retention), т. е. сохранение временных объек тов лишь до тех пор, пока они используются, с их последующим удалением. Так как для доступа к объекту все процессы пользовательского режима дол жны сначала открыть его описатель, диспетчер объектов может легко отсле живать, сколько процессов и даже какие именно из них используют объект. Учет описателей является одним из механизмов, реализующих хранение объектов в памяти. Этот механизм двухфазный. Первая фаза называется хра нением имен (name retention) и контролируется числом открытых описате лей объекта. Каждый раз, когда процесс открывает описатель объекта, дис петчер увеличивает значение счетчика открытых описателей в заголовке объекта. По мере того как процессы завершают использование объекта и закрывают его описатели, диспетчер уменьшает значение этого счетчика. Когда счетчик обнуляется, диспетчер удаляет имя объекта из своего глобаль ного пространства имен. После этого новые процессы уже не смогут откры вать описатели данного объекта. Вторая фаза заключается в том, что прекращается хранение тех объектов, которые больше не используются (т. е. они удаляются). Так как код операци онной системы обычно обращается к объектам по указателям, а не описате лям, диспетчер объектов должен регистрировать и число указателей объектов, переданных процессам операционной системы. При каждой выдаче указате ля на объект он увеличивает значение счетчика ссылок на объект. Компонен ты режима ядра, прекратив использовать указатель, вызывают диспетчер объектов для уменьшения счетчика ссылок. Система также увеличивает счет чик ссылок при увеличении счетчика описателей, а при уменьшении счетчи ка описателей соответственно уменьшает счетчик ссылок, поскольку описа тель тоже является подлежащей учету ссылкой на объект (подробнее об этих механизмах см. описание функции ObReferenceObjectByPointer или ObDere ferenceObject в DDK). На рис. 322 показаны два задействованных объектасобытия. Процесс А открыл первый объект, а процесс В — оба объекта. Кроме того, на первый объект ссылается какаято структура режима ядра, и его счетчик ссылок ра
ГЛАВА 9 Системные механизмы 153 вен 3. Так что, даже если оба процесса закроют свои описатели первого объек та, он попрежнему будет существовать, поскольку его счетчик ссылок еще не обнулится. Но, когда процесс В закроет свой описатель второго объекта, этот объект будет удален. Рис. 3-22. Счетчики описателей и ссылок Таким образом, даже если счетчик открытых описателей объекта обну лится, счетчик ссылок может превышать нулевое значение, указывая, что операционная система еще использует объект. В конце концов счетчик ссы лок тоже обнулится, и тогда диспетчер удалит соответствующий объект из памяти. Такой механизм позволяет хранить объект и его имя в памяти, просто не закрывая его описатель. Программистам, создающим приложения с двумя и более взаимодействующими процессами, не приходится беспокоиться о том, что один из процессов удалит объект в то время, когда он еще используется другим процессом. Кроме того, закрытие описателей объекта, принадлежа щих приложению, еще не означает, что этот объект будет немедленно уда лен, — он может использоваться операционной системой. Например, какой то процесс создает второй процесс для выполнения программы в фоновом режиме, после чего немедленно закрывает описатель созданного процесса. Так как второй процесс еще не закончил свою работу и выполняется опера ционной системой, она поддерживает ссылку на этот объект «процесс». Дис
154 ГЛ А В А 3 БЕЗОПАСНОСТЬ петчер сможет обнулить счетчик ссылок на второй процесс и удалить его, только когда завершится выполнение этого процесса. Учет ресурсов Учет ресурсов, как и хранение объектов, тесно связан с использованием опи сателей объектов. Положительное значение счетчика открытых описателей указывает на то, что данный ресурс задействован какимито процессами. Когда счетчик описателей и счетчик ссылок на некий объект обнуляются, процессы, использовавшие этот объект, больше не занимают память, отве денную под него. Во многих операционных системах для ограничения доступа процессов к системным ресурсам применяется система квот. Однако типы устанавли ваемых для процессов квот иногда весьма разнообразны, а отслеживающий квоты код распределен по всей операционной системе. Так, в некоторых операционных системах компонент вводавывода может регистрировать и ограничивать число файлов, которые может открыть процесс, а компонент управления памятью может накладывать ограничения на объем памяти, вы деляемой потокам процесса. Компонент, отвечающий за управление процес сами, способен ограничивать максимальное число новых процессов или новых потоков процесса. Каждое из этих ограничений отслеживается и ре ализуется в различных частях операционной системы. Диспетчер объектов Windows, напротив, представляет собой компонент централизованного учета ресурсов. В заголовке каждого объекта содержит ся атрибут квоты, определяющий, насколько диспетчер объектов уменьша ет квоту подкачиваемой или неподкачиваемой памяти процесса при откры тии его потоком описателя этого объекта. У каждого процесса в Windows имеется структура квот, регистрирующая лимиты и текущее количество используемой памяти из подкачиваемого и неподкачиваемого пулов, а также из страничного файла. (Введите dt nt!_ EPROCESS_QUOTA_ENTRY в отладчике ядра, чтобы увидеть формат этой структуры.) Значения данных квот по умолчанию равны 0 (ограничений нет), но их можно указать, модифицировав параметры в реестре (см. пара метры NonPagedPoolQuota, PagedPoolQuota и PagingFileQuota в разделе HKLM\System\CurrentControlSet\Session Manager\Memory Management). За метьте, что все процессы в интерактивном сеансе используют один и тот же блок квот (документированного способа создания процессов с собственны ми блоками квот нет). Имена объектов Важное условие для создания множества объектов — эффективная система учета. Для учета диспетчеру объектов нужна следующая информация: 쐽 способ, которым можно было бы отличать один объект от другого; 쐽 метод поиска и получения конкретного объекта.
ГЛАВА 9 Системные механизмы 155 Первое требование реализуется за счет присвоения имен объектам. Это расширение обычной для большинства операционных систем функцио нальности, в которых отдельным системным ресурсам, например файлам, каналам или блокам разделяемой памяти, можно присваивать имена. Испол нительная система, напротив, позволяет именовать любой объект, представ ляющий ресурс. Второе требование (поиск и получение объектов) также реализуется через именование объектов. Если диспетчер хранит объекты в соответствии с их именами, он может быстро найти объект по его имени. Имена объектов отвечают и третьему требованию, не упомянутому в пре дыдущем списке: процессам должна быть предоставлена возможность совме стного использования объектов. Пространство имен объектов исполнитель ной системы является глобальным, видимым любому процессу в системе. Если один процесс создает объект и помещает его имя в глобальное про странство имен, то другой процесс может открыть описатель этого объек та, указав нужное имя. Если объект не предназначен для совместного исполь зования, процесссоздатель просто не присваивает ему имя. Для большей эффективности диспетчер объектов не ищет имя объекта при каждой попытке его использования. Поиск по имени ведется только в двух случаях. Вопервых, при создании процессом именованного объекта: перед тем как сохранить имя объекта в глобальном пространстве имен, дис петчер проверяет, нет ли в нем такого же имени. Вовторых, открывая опи сатель именованного объекта, диспетчер ищет объект по имени и возвраща ет его описатель, который затем используется для ссылки на объект. Диспет чер позволяет выбирать, надо ли при поиске учитывать регистр букв. Эта функциональность поддерживается POSIX и другими подсистемами окруже ния, в которых имена файлов чувствительны к регистру букв. Где именно хранятся имена объектов, зависит от типа объектов. В табли це 38 перечислены стандартные каталоги объектов, имеющиеся на всех системах под управлением Windows. Пользовательским программам видны только каталоги \BaseNamedObjects и \GLOBAL?? (\?? в Windows 2000). Поскольку имена базовых объектов ядра вроде мьютексов, событий, се мафоров, ожидаемых таймеров и разделов хранятся в одном каталоге, они не должны совпадать, даже если относятся к объектам разных типов. Это ограничение подчеркивает, насколько осторожно надо выбирать имена, что бы они не конфликтовали с другими (используйте, например, префиксы имен в виде названия вашей компании и программного продукта). Таблица 3-8. Стандартные каталоги объектов Каталог Типы объектов, имена которых хранятся в каталоге \GLOBAL?? (\?? в Windows 2000) Имена устройств MSDOS (\DosDevices является символь ной ссылкой на этот каталог) \BaseNamedObjects Мьютексы, события, семафоры, ожидаемые таймеры и разделы \Callback Объекты обратного вызова \Device Объекты устройств см. след. стр.
156 ГЛ А В А 3 БЕЗОПАСНОСТЬ Таблица 3-8. (окончание) Каталог Типы объектов, имена которых хранятся в каталоге \Driver Объекты драйверов \FileSystem Объекты драйверов файловых систем и объекты распознавания файловых систем \KnownDlls Имена разделов и пути поиска известных DLL (DLL, проецируемых системой при запуске) \Nls Имена разделов спроецированных таблиц поддержки национальных языков \ObjectTypes Имена типов объектов \RPC Control Объекты портов, используемые для вызова удаленных процедур (RPC) \Security Имена объектов, специфичных для системы защиты \Windows Порты подсистемы Windows и объекты WindowStation Имена объектов глобальны в пределах компьютера (или всех процессо ров на многопроцессорной системе) и невидимы через сеть. Однако метод parse диспетчера объектов позволяет получать доступ к именованным объек там, существующим на других компьютерах. Так, диспетчер вводавывода, предоставляющий сервисы объектов «файл», расширяет функции диспетче ра объектов для работы с файлами на удаленных компьютерах. При запро се на открытие объекта «файл» на удаленном компьютере диспетчер объек тов вызывает метод parse, что позволяет диспетчеру вводавывода перехва тить запрос и направить его сетевому редиректору — драйверу, обращающе муся к файлам через сеть. Серверный код на удаленной Windowsсистеме вызывает диспетчер объектов и диспетчер вводавывода на этой системе для поиска нужного объекта «файл» и возврата данных через сеть. ЭКСПЕРИМЕНТ: просмотр именованных базовых объектов Список именованных базовых объектов можно просмотреть с помо щью утилиты Winobj (www.sysinternals.com). Запустите Winobj.exe и щелкните каталог \BaseNamedObjects, как показано ниже.
ГЛАВА 9 Системные механизмы 157 Именованные объекты отображаются справа. Тип объектов обозна чается следующими значками: 쐽 «stop» — мьютексы; 쐽 в виде микросхем памяти — разделы (объекты «проекция файла»); 쐽 в виде восклицательного знака — события; 쐽 похожие на светофоры — семафоры; 쐽 в виде изогнутой стрелки — символьные ссылки. Объекты «каталоги объектов» (object directory objects) С помо щью этих объектов диспетчер объектов поддерживает иерархическую струк туру пространства имен. Этот объект аналогичен каталогу файловой систе мы и содержит имена других объектов, а также другие каталоги объектов. Он включает информацию, достаточную для трансляции имен объектов в ука затели на сами объекты. Диспетчер использует указатели для создания опи сателей объектов, возвращаемых программам пользовательского режима. Каталоги для хранения объектов могут создаваться как кодом режима ядра (включая компоненты исполнительной системы и драйверы устройств), так и кодом пользовательского режима (в том числе подсистемами). Например, диспетчер вводавывода создает каталог объектов \Device с именами объек тов, представляющих устройства вводавывода. Символьные ссылки (symbolic links) В некоторых файловых систе мах (например, NTFS и отдельных UNIXсистемах) с помощью символьной ссылки можно создать имя файла или каталога, которое при использовании будет транслироваться операционной системой в другое имя файла или ка талога. Символьные ссылки — простой метод неявного разделения файлов или каталогов за счет создания перекрестных ссылок между различными каталогами в обычной иерархической структуре каталогов. Диспетчер объектов реализует объект «символьная ссылка», который вы полняет аналогичную функцию в отношении имен объектов в пространстве имен. Символьная ссылка может находиться в любом месте строки с именем объекта. Когда вызывающая программа ссылается на имя объекта «символь ная ссылка», диспетчер просматривает пространство имен в поисках тако го объекта. Далее он анализирует содержимое символьной ссылки и нахо дит строку, которую надо подставить вместо ссылки. После этого начинает ся поиск другого объекта, соответствующего полученному имени. Исполнительная система использует такие объекты при трансляции имен устройств в стиле MSDOS во внутренние имена устройств Windows. Пользо ватель обращается к гибким и жестким дискам по именам A:, B:, C: и т. д. или к последовательным портам по именам COM1, COM2 и т. п. Подсистема Win dows делает эти объекты «символьная ссылка» в защищенные глобальные данные, помещая их в каталог объектов \?? (в Windows 2000) или \GLOBAL?? (в Windows XP и Windows Server 2003).
158 ГЛ А В А 3 БЕЗОПАСНОСТЬ Пространство имен сеанса Windows NT изначально создавалась в расчете на регистрацию в системе одного интерактивного пользователя и выполнение лишь одного экземпля ра любого из интерактивных приложений. Добавление Windows Terminal Services в Windows 2000 Server и поддержки быстрого переключения пользо вателей в Windows XP потребовало некоторых изменений в модели про странства имен диспетчера объектов для поддержки множества интерактив ных пользователей одновременно. (Базовые сведения о службах терминала и сеансах см. в главе 1.) Пользователь, зарегистрированный в консольном сеансе, получает доступ к глобальному пространству имен, которое является первым экземпляром пространства имен. Дополнительные сеансы получают свое (закрытое) пред ставление пространства имен, называемое локальным пространством имен. Части пространства имен, локальные для каждого сеанса, включают \Dos Devices, \Windows и \BaseNamedObjects. Формирование раздельных копий одних и тех же частей называется созданием экземпляров (instancing) про странства имен. Создание экземпляров каталога \DosDevices позволяет каж дому пользователю обозначать сетевые дисковые устройства разными буква ми и поразному именовать такие объекты, как, например, последовательные порты. В Windows 2000 глобальный каталог \DosDevices называется \?? и яв ляется каталогом, на который указывает символьная ссылка \DosDevices, а локальные каталоги \DosDevices идентифицируются по идентификатору для сеанса сервера терминала. В Windows XP и более поздних операционных си стемах глобальный каталог \DosDevices называется \Global?? и является ката логом, на который указывает \DosDevices, а локальные каталоги \DosDevices определяются по идентификатору сеанса входа (logon session). Win32k.sys создает в каталоге \Windows интерактивный объект Window Station, \WinSta0. Среда Terminal Services может поддерживать несколько интерактивных пользователей, но для сохранения иллюзии доступа к пред определенному интерактивному объекту WindowStation в Windows каждо му пользователю нужна собственная версия WinSta0. Наконец, в каталоге \BaseNamedObjects приложения и система создают разделяемые объекты, включая события, мьютексы и разделы. Если приложение, создающее име нованный объект, запущено двумя пользователями, то в каждом сеансе нуж на своя версия этого объекта, чтобы два экземпляра приложения не меша ли друг другу, обращаясь к одному объекту. Диспетчер объектов реализует локальное пространство имен, создавая закрытые версии трех каталогов, которые находятся в каталоге, сопоставлен ном с сеансом пользователя (\Sessions\X, где X — идентификатор сеанса). Например, когда некое Windowsприложение во время удаленного сеанса номер 2 создает именованное событие, диспетчер объектов перенаправля ет имя этого объекта из \BaseNamedObjects в \Sessions\2\BaseNamedObjects. Все функции диспетчера объектов, связанные с управлением простран ством имен, знают о локальных экземплярах каталогов и участвуют в под
ГЛАВА 9 Системные механизмы 159 держании иллюзии того, что в удаленных сеансах используется то же про странство имен, что и в консольных. DLLмодули подсистемы Windows до бавляют к именам, передаваемым Windowsприложениями, которые ссыла ются на объекты в \DosDevices, префиксы \?? (например, C:\Windows превра щается в \??\C:\Windows). Когда диспетчер объектов обнаруживает специаль ный префикс \??, предпринимаемые им действия зависят от версии Windows, но при этом он всегда полагается на поле DeviceMap в объекте «процесс», создаваемом исполнительной системой (executive process object) (EPROCESS, о котором пойдет речь в главе 6). Это поле указывает на структуру данных, разделяемую с другими процессами в том же сеансе. Поле DosDevicesDirectory структуры DeviceMap указывает на каталог диспетчера объектов, представ ляющий локальный \DosDevices процесса. Целевой каталог зависит от кон кретной системы. 쐽 Если системой является Windows 2000 и Terminal Services не установле ны, поле DosDevicesDirectory в структуре DeviceMap процесса указывает на каталог \??, так как локальных пространств имен нет. 쐽 Если системой является Windows 2000 и Terminal Services установлены, то, когда активным становится новый сеанс, система копирует все объекты из глобального каталога \?? в локальный для сеанса каталог \DosDevices, и поле DosDevicesDirectory структуры DeviceMap указывает на этот локаль ный каталог. 쐽 В Windows XP и Windows Server 2003 система не копирует глобальные объекты в локальные каталоги DosDevices. Диспетчер объектов, встретив ссылку на \??, находит локальный для процесса каталог \DosDevices, ис пользуя поле DosDevicesDirectory структуры DeviceMap. Если нужного объекта в этом каталоге нет, он проверяет поле DeviceMap объекта «ката лог» и, если это допустимо, ищет объект в каталоге, на который указыва ет поле GlobalDosDevicesDirectory структуры DeviceMap. Этим каталогом всегда является \Global??. В определенных обстоятельствах приложениям, поддерживающим Termi nal Services, нужен доступ к объектам в консольном сеансе, даже если сами приложения выполняются в удаленном сеансе. Это может понадобиться при ложениям для синхронизации со своими экземплярами, выполняемыми в других удаленных или консольных сеансах. В таких случаях для доступа к глобальному пространству имен приложения могут использовать специаль ный префикс \Global, поддерживаемый диспетчером объектов. Так, объект \Global\ApplicationInitialized, открываемый приложением в сеансе номер 2, направляется вместо каталога \Sessions\2\BaseNamedObjects\Application Initialized в каталог \BasedNamedObjects\ApplicationInitialized. В Windows XP и Windows Server 2003 приложение, которому нужно об ратиться к объекту в глобальном каталоге \DosDevices, не требуется исполь зовать префикс \Global, если только этого объекта нет в локальном катало ге \DosDevices. Это вызвано тем, что диспетчер объектов автоматически ищет объект в глобальном каталоге, не найдя его в локальном. Однако при
160 ГЛ А В А 3 БЕЗОПАСНОСТЬ ложение, работающее в Windows 2000 с Terminal Services, должно всегда ука зывать префикс \Global для доступа к объектам в глобальном каталоге \Dos Devices. ЭКСПЕРИМЕНТ: просмотр экземпляров пространства имен Вы можете увидеть, как диспетчер объектов создает экземпляры про странства имен, создав сеанс, отличный от консольного, и просмот рев таблицу описателей для процесса в этом сеансе. В Windows XP Home Edition или Windows XP Professional в системе, которая не вхо дит в домен, отключите консольный сеанс [откройте меню Start (Пуск), щелкните Log Off (Выход из системы) и выберите Disconnect and Switch User (Смена пользователя) или нажмите комбинацию клавиш Win dows+L]. Теперь войдите в систему под новой учетной записью. Если вы работаете с Windows 2000 Server, Advanced Server или Datacenter Server, запустите клиент Terminal Services, подключитесь к серверу и войдите в систему. Войдя в систему в новом сеансе, запустите Winobj (www.sysinternals.com), щелкните каталог \Sessions и вы увидите подкаталог с числовым име нем для каждого активного удаленного сеанса. Открыв один из таких каталогов, вы обнаружите подкаталоги \DosDevices, \Windows и \Base NamedObjects, которые относятся к локальному пространству имен сеанса. Одно из таких локальных пространств имен показано на ил люстрации ниже. Далее запустите Process Explorer и выберите какойнибудь процесс в новом сеансе (вроде Explorer.exe). Просмотрите таблицу описателей, щелкнув View, Lower Pane View и Handles. Вы должны увидеть описа тель \Windows\Windowstations\WinSta0 под \Sessions\n, где n — иден тификатор сеанса. Объекты с глобальными именами появятся в \Ses sions\n\BaseNamedObjects.
ГЛАВА 9 Системные механизмы 161 Синхронизация Концепция взаимоисключения (mutual exclusion) является одной из ключе вых при разработке операционных систем. Ее смысл в следующем: в каждый момент к конкретному ресурсу может обращаться один — и только один — поток. Взаимоисключение необходимо, когда ресурс не предназначен для разделения или когда такое разделение может иметь непредсказуемые по следствия. Например, если бы два потока одновременно копировали данные в порт принтера, отпечатанный документ представлял бы собой нечитаемую мешанину. Аналогичным образом, если бы один поток считывал какойто участок памяти, когда другой записывал бы туда данные, первый поток по лучил бы непредсказуемый набор данных. В общем случае доступные для записи ресурсы нельзя разделять без ограничений. Рис. 323 иллюстрирует, что происходит, когда два потока, выполняемые на разных процессорах, одновременно записывают данные в циклическую очередь. Рис. 3-23. Некорректное разделение памяти Поскольку второй поток получил значение указателя на конец очереди до того, как первый поток завершил его обновление, второй вставил свои данные в то же место, что и первый. Таким образом, данные первого потока были перезаписаны другими данными, а один участок очереди остался пус тым. Хотя рис. 323 иллюстрирует, что могло бы случиться в многопроцес сорной системе, аналогичную ошибку было бы нельзя исключить и в одно процессорной системе — при переключении контекста на второй поток до того, как первый поток успел бы обновить указатель на конец очереди. Разделы кода, обращающиеся к неразделяемым ресурсам, называются кри тическими секциями (critical sections). В критической секции единовремен но может выполняться только один поток. Пока один поток записывает в файл, обновляет базу данных или модифицирует общую переменную, доступ к этому ресурсу со стороны других потоков запрещен. Псевдокод, показанный на рис. 323, представляет собой критическую секцию, которая некорректно обращается к разделяемой структуре данных без взаимоисключения.
162 ГЛ А В А 3 БЕЗОПАСНОСТЬ Взаимоисключение, важное для всех операционных систем, особенно зна чимо (и запутанно) в случае операционной системы с жестко связанной сим метричной мультипроцессорной обработкой (tightlycoupled symmetric multiprocessing), например в Windows, в которой один и тот же системный код, выполняемый на нескольких процессорах одновременно, разделяет не которые структуры данных, хранящиеся в глобальной памяти. В Windows под держка механизмов, с помощью которых системный код может предотвра тить одновременное изменение двумя потоками одной и той же структуры, возлагается на ядро. Оно предоставляет специальные примитивы взаимоис ключения, используемые им и остальными компонентами исполнительной системы для синхронизации доступа к глобальным структурам данных. Так как планировщик синхронизирует доступ к своим структурам данных при IRQL уровня «DPC/dispatch», ядро и исполнительная система не могут полагаться на механизмы синхронизации, которые могли бы привести к ошибке страницы или к перераспределению процессорного времени при IRQL уровня «DPC/dispatch» или выше (эти уровни также известны под на званием «высокий IRQL»). Из следующих разделов вы узнаете, как ядро и ис полнительная система используют взаимоисключение для защиты своих глобальных структур данных при высоком IRQL и какие механизмы синхро низации и взаимоисключения они применяют при низких уровнях IRQL (ниже «DPC/dispatch»). Синхронизация ядра при высоком IRQL Ядро должно гарантировать, что в каждый момент только один процессор выполняет код в критической секции. Критическими секциями ядра являют ся разделы кода, модифицирующие глобальные структуры данных, напри мер базу данных диспетчера ядра или его очередь DPC. Операционная сис тема не смогла бы корректно работать, если бы ядро не гарантировало вза имоисключающий доступ потоков к этим структурам данных. В этом плане больше всего проблем с прерываниями. Так, в момент об новления ядром глобальной структуры данных может возникнуть прерыва ние, процедура обработки которого изменяет ту же структуру. В простых однопроцессорных системах развитие событий по такому сценарию исклю чается путем отключения всех прерываний на время доступа к глобальным данным, однако в ядре Windows реализовано более сложное решение. Перед использованием глобального ресурса ядро временно маскирует прерывания, обработчики которых используют тот же ресурс. Для этого ядро повышает IRQL процессора до самого высокого уровня, используемого любым потен циальным источником прерываний, который имеет доступ к глобальным данным. Например, прерывание на уровне «DPC/dispatch» приводит к запус ку диспетчера ядра, использующего диспетчерскую базу данных. Следова тельно, любая другая часть ядра, имеющая дело с этой базой данных, повы шает IRQL до уровня «DPC/dispatch», маскируя прерывания того же уровня перед обращением к диспетчерской базе данных.
ГЛАВА 9 Системные механизмы 163 Эта стратегия хорошо работает в однопроцессорных системах, но не го дится для многопроцессорных конфигураций. Повышение IRQL на одном из процессоров не исключает прерываний на другом процессоре, а ядро дол жно гарантировать взаимоисключающий доступ на всех процессорах. Взаимоблокирующие операции Простейшая форма механизмов синхронизации опирается на аппаратную поддержку безопасных операций над целыми значениями и выполнения сравнений в многопроцессорной среде. Сюда относятся такие функции, как InterlockedIncrement, InterlockedDecrement, InterlockedExchange и Interlocked CompareExchange. Скажем, функция InterlockedDecrement, использует пре фикс x86инструкции lock (например, lock xadd) для блокировки многопро цессорной шины на время операции вычитания, чтобы другой процессор, модифицирующий тот же участок памяти, не смог выполнить свою опера цию в момент между чтением исходных данных и записью их нового (мень шего) значения. Эта форма базовой синхронизации используется ядром и драйверами. Спин-блокировки Механизм, применяемый ядром для взаимоисключения в многопроцес сорных системах, называется спин блокировкой (spinlock). Спинблокиров ка — это блокирующий примитив, сопоставленный с какойлибо глобальной структурой данных вроде очереди DPC (рис. 324). Рис. 3-24. Применение спин-блокировки Перед входом в любую из критических секций, показанных на рис. 324, ядро должно установить спинблокировку, связанную с защищенной очередью DPC. Если спинблокировка пока занята, ядро продолжает попытки установить спинблокировку до тех пор, пока не достигнет успеха. Термин получил такое название изза поведения ядра (и соответственно процессора), которое «кру тится» (spin) в цикле, повторяя попытки, пока не захватит блокировку.
164 ГЛ А В А 3 БЕЗОПАСНОСТЬ Спинблокировки, как и защищаемые ими структуры данных, находятся в глобальной памяти. Код для их установки и снятия написан на языке ас семблера для максимального быстродействия. Во многих архитектурах спинблокировка реализуется аппаратно поддерживаемой командой test andset, которая проверяет значение переменной блокировки и устанавли вает блокировку, выполняя всего одну атомарную команду. Это предотвра щает захват блокировки вторым потоком в промежуток между проверкой переменной и установкой блокировки первым потоком. Всем спинблокировкам режима ядра в Windows назначен IRQL, всегда соответствующий уровню «DPC/dispatch» или выше. Поэтому, когда поток пытается установить спинблокировку, все действия на этом или более низ ком уровне IRQL на данном процессоре прекращаются. Поскольку диспетче ризация потоков осуществляется при уровне «DPC/dispatch», поток, удержи вающий спинблокировку, никогда не вытесняется, так как данный IRQL мас кирует механизмы диспетчеризации. Такая маскировка не дает прервать вы полнение критической секции кода под защитой спинблокировки и обеспе чивает быстрое ее снятие. Спинблокировки используются в ядре с большой осторожностью и устанавливаются на минимально возможное время. ПРИМЕЧАНИЕ Поскольку IRQL — достаточно эффективный меха низм синхронизации для однопроцессорных систем, функции уста новки и снятия спинблокировки в однопроцессорных версиях HAL на самом деле просто повышают и понижают IRQL. Ядро предоставляет доступ к спинблокировкам другим компонентам исполнительной системы через набор функций ядра, включающий KeAcqui reSpinlock и KeReleaseSpinlock. Например, драйверы устройств требуют спин блокировки, чтобы система гарантировала единовременный доступ к реги страм устройства и другим глобальным структурам данных со стороны лишь одной части драйвера (и только с одного процессора). Спинблокировка не предназначена для пользовательских программ — они должны оперировать объектами, которые рассматриваются в следующем разделе. Спинблокировки ядра накладывают ограничения на использующий их код. Как уже отмечалось, их IRQL всегда равен «DPC/dispatch», поэтому уста новивший спинблокировку код может привести к краху системы, если по пытается заставить планировщик выполнить операцию диспетчеризации или вызовет ошибку страницы. Спин-блокировки с очередями В некоторых ситуациях вместо стандартной спинблокировки применяет ся особый тип спинблокировки — с очередью (queued spinlock). Спинбло кировка с очередью лучше масштабируется в многопроцессорных системах, чем стандартная. Как правило, Windows использует лишь стандартные спин блокировки, когда конкуренция за спинблокировку ожидается низкой. Спинблокировка с очередью работает так: процессор, пытаясь устано вить такую спинблокировку, которая в данный момент занята, ставит свой
ГЛАВА 9 Системные механизмы 165 идентификатор в очередь, сопоставленную с этой спинблокировкой. Осво бодив спинблокировку, удерживавший ее процессор передает блокировку тому процессору, чей идентификатор стоит в очереди первым. Между тем процессор, ожидающий занятую спинблокировку, проверяет статус не са мой спинблокировки, а флага того процессора, чей идентификатор распо лагается в очереди прямо перед идентификатором ждущего процессора. Тот факт, что спинблокировка с очередью устанавливает флаги, а не гло бальные блокировки, имеет два следствия. Вопервых, уменьшается интенсив ный трафик, связанный с межпроцессорной синхронизацией. Вовторых, вместо случайного выбора процессора из группы ожидающих спинблоки ровку реализуется четкий порядок спинблокировки по типу FIFO («первым вошел, первым вышел»). Такой порядок позволяет достичь более согласован ной работы процессоров, использующих одну и ту же блокировку. Windows определяет ряд глобальных спинблокировок с очередями, со храняя указатели на них в массиве, который содержится в блоке PCR (pro cessor control region) каждого процессора. Глобальную спинблокировку можно получить вызовом KeAcquireQueuedSpinlock с индексом в массиве PCR, по которому сохранен указатель на эту спинблокировку. Количество гло бальных спинблокировок растет по мере появления новых версий опера ционной системы, и таблица их индексов публикуется в заголовочном файле Ntddk.h, поставляемом с DDK. ЭКСПЕРИМЕНТ: просмотр глобальных спин-блокировок с очередями Вы можете наблюдать за состоянием глобальных спинблокировок с очередями, используя команду !qlock отладчика ядра. Эта команда име ет смысл лишь в многопроцессорной системе, так как в однопроцес сорной версии HAL спинблокировки не реализованы. В следующем примере (подготовленном в Windows 2000) спинблокировка с очере дью для базы данных диспетчера ядра удерживается процессором но мер 1, а остальные спинблокировки этого типа не затребованы (о базе данных диспетчера ядра см. главу 6). kd> !qlocks Key: O = Owner, 1n = Wait order, blank = not owned/waiting, C = Corrupt Lock Name KE KE MM MM CC CC       Dispatcher Context Swap PFN System Space Vacb Master Processor Number 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 O
166 ГЛ А В А 3 БЕЗОПАСНОСТЬ Внутристековые спин-блокировки с очередями Помимо статических спинблокировок с очередями, определяемых глобаль но, ядра Windows XP и Windows Server 2003 поддерживают динамически создаваемые спинблокировки с очередями. Для их создания предназначе ны функции KeAcquireInStackQueuedSpinlock и KeReleaseInStackQueuedSpin lock. Этот тип блокировок используется несколькими компонентами, в том числе диспетчером кэша, диспетчером пулов исполнительной системы (exe cutive pool manager) и NTFS. Упомянутые функции документированы в DDK для сторонних разработчиков драйверов. KeAcquireInStackQueuedSpinlock принимает указатель на структуру данных спинблокировки и описатель очереди спинблокировки. Этот описатель в дей ствительности является структурой данных, в которой ядро хранит информа цию о состоянии блокировки, в частности сведения о владельце блокировки и об очереди процессоров, ожидающих освобождения этой блокировки. Взаимоблокирующие операции в исполнительной системе Ядро предоставляет ряд функций синхронизации, использующих спинблоки ровки для более сложных операций, например для добавления и удаления эле ментов из одно и двунаправленных связанных списков. К таким функциям, в частности, относятся ExInterlockedPopEntryList и ExInterlockedPushEntryList (для однонаправленных связанных списков), ExInterlockedInsertHeadList и ExInter lockedRemoveHeadList (для двунаправленных связанных списков). Все эти функ ции требуют передачи стандартной спинблокировки в качестве параметра и интенсивно используются в ядре и драйверах устройств. Синхронизация при низком IRQL Компоненты исполнительной системы вне ядра также нуждаются в синхро низации доступа к глобальным структурам данных в многопроцессорной среде. Например, у диспетчера памяти есть только одна база данных блоков страниц. Обращение к ней осуществляется как к глобальной структуре дан ных, и драйверам устройств необходима гарантия получения монопольно го доступа к своим устройствам. Вызывая функции ядра, исполнительная система может создать спинблокировку, установить ее и снять. Однако спинблокировка лишь частично удовлетворяет потребности ис полнительной системы в синхронизации. Поскольку спинблокировка озна чает фактическую остановку процессора, она применяется только при двух условиях: 쐽 требуется непродолжительное обращение к защищенным ресурсам без сложного взаимодействия с другим кодом; 쐽 код критической секции нельзя выгрузить в страничный файл, он не ссы лается на данные в подкачиваемой памяти, не вызывает внешние проце дуры (включая системные сервисы) и не генерирует прерывания или ис ключения.
ГЛАВА 9 Системные механизмы 167 Эти противоречащие друг другу ограничения нельзя соблюсти одновре менно ни при каких обстоятельствах. Более того, кроме взаимоисключения, исполнительная система должна выполнять и другие алгоритмы синхрони зации, а также предоставлять механизмы синхронизации пользовательско му режиму. Существует несколько дополнительных механизмов синхронизации, при меняемых, когда спинблокировки не годятся: 쐽 объекты диспетчера ядра (kernel dispatcher objects); 쐽 быстрые мьютексы (fast mutexes) и защищенные мьютексы (guarded mu texes); 쐽 блокировки с заталкиванием указателя (push locks); 쐽 ресурсы исполнительной системы (executive resources). В таблице 39 кратко сравниваются возможности этих механизмов и их взаимосвязь с доставкой APC режима ядра. Таблица 3-9. Механизмы синхронизации режима ядра Предоставляется драйверам устройств Отключает обычные APC режима ядра доступ Отключает специальные APC режима ядра Поддерживает разделяемый и моно- Поддерживапольный ет рекурсивзахват ный захват Мьютексы диспетчера ядра Да Да Нет Да Нет Семафоры диспетчера ядра Да Нет Нет Нет Нет Быстрые мьютексы Да Да Да Нет Нет Защищенные мьютексы Нет Да Да Нет Нет Блокировки с заталкиванием указателя Нет Нет Нет Нет Да Да Нет Да Да Ресурсы исполни Да тельной системы Объекты диспетчера ядра Ядро предоставляет исполнительной системе дополнительные механизмы синхронизации в форме объектов, в совокупности известных как объекты диспетчера ядра. Синхронизирующие объекты, видимые из пользовательско го режима, берут свое начало именно от этих объектов диспетчера ядра. Каж дый синхронизирующий объект, видимый из пользовательского режима, ин капсулирует минимум один объект диспетчера ядра. Семантика синхрониза ции исполнительной системы доступна программистам через Windowsфунк ции WaitForSingleObject и WaitForMultipleObjects, реализуемые подсистемой Windows на основе аналогичных системных сервисов, предоставляемых дис петчером объектов. Поток в Windowsприложении можно синхронизировать
168 ГЛ А В А 3 БЕЗОПАСНОСТЬ по таким Windowsобъектам, как процесс, поток, событие, семафор, мьютекс, ожидаемый таймер, порт завершения вводавывода или файл. Еще один тип синхронизирующих объектов исполнительной системы назван (без особой на то причины) ресурсами исполнительной системы (executive resources). Эти ресурсы обеспечивают как монопольный доступ (по аналогии с мьютексами), так и разделяемый доступ для чтения (когда несколько потоков«читателей» обращается к одной структуре только для чтения). Однако они доступны лишь коду режима ядра, а значит, недоступ ны через Windows API. Ресурсы исполнительной системы являются не объек тами диспетчера ядра, а скорее структурами данных, память для которых выделяется прямо из неподкачиваемого пула, имеющего свои специализи рованные сервисы для инициализации, блокировки, освобождения, запро са и ожидания. Структура ресурсов исполнительной системы определена в Ntddk.h, а соответствующие процедуры описаны в DDK. В остальных подразделах мы детально обсудим, как реализуется ожида ние на объектах диспетчера ядра. Ожидание на объектах диспетчера ядра Поток синхронизируется с объектом диспетчера ядра, ожидая освобождения его описателя. При этом ядро приостанавливает поток и соответственно меняет состояние диспет чера, как показано на рис. 325. Ядро удаляет поток из очереди готовых к выполнению потоков и перестает учитывать его в планировании. ПРИМЕЧАНИЕ На рис. 325 показана схема перехода состояний с выделением состояний «готов» (ready), «ожидает» (waiting) и «выпол няется» (running) — они относятся к ожиданию на объектах. Прочие состояния описываются в главе 6. Рис. 3-25. Ожидание на объекте диспетчера ядра
ГЛАВА 9 Системные механизмы 169 В любой момент синхронизирующий объект находится в одном из двух состояний: свободном (signaled) или занятом (nonsignaled). Для синхрони зации с объектом поток вызывает один из системных сервисов ожидания, предоставляемых диспетчером объектов, и передает описатель этого объек та. Поток может ожидать на одном или нескольких объектах, а также указать, что ожидание следует прекратить, если объект (или объекты) не освободил ся в течение определенного времени. Всякий раз, когда ядро переводит объект в свободное состояние, функция KiWaitTest ядра проверяет, ждут ли этот объект какиенибудь потоки и не ждут ли они какихлибо других объек тов. Если да, ядро выводит один или более потоков из состояния ожидания, после чего их выполнение может быть продолжено. Взаимосвязь синхронизации с диспетчеризацией потоков иллюстриру ет следующий пример с использованием объекта «событие». 쐽 Поток пользовательского режима ждет на описателе объекта «событие» (т. е. ждет перехода этого объекта в свободное состояние). 쐽 Ядро изменяет состояние потока с «готов» на «ожидает» и добавляет его в список потоков, ждущих объект «событие». 쐽 Другой поток устанавливает объект «событие». 쐽 Ядро просматривает список потоков, ожидающих этот объект. Если усло вия ожидания какоголибо потока выполнены (см. примечание ниже), ядро переводит его из состояния «ожидает» в состояние «готов». Если это поток с динамическим приоритетом, ядро может повысить его приори тет для выполнения. 쐽 Поскольку новый поток теперь готов к выполнению, происходит пере распределение процессорного времени. Если при этом диспетчер обна ружит, что приоритет выполняемого потока ниже, чем приоритет пото ка, только что перешедшего в состояние «готов», он вытеснит поток с более низким приоритетом и выдаст программное прерывание для ини циации переключения контекста на поток с более высоким приоритетом. 쐽 Если в данный момент вытеснение невозможно ни на одном из процес соров, диспетчер включает поток в свою очередь потоков, готовых к вы полнению. ПРИМЕЧАНИЕ Некоторые потоки могут ждать более одного объекта, и в таком случае их ожидание продолжается. Условия перехода объектов в свободное состояние Эти условия различны для разных объектов. Например, объект «поток» находится в заня том состоянии в течение всего срока своей жизни и переводится ядром в свободное состояние лишь при завершении. Аналогичным образом, ядро пе реводит объект «процесс» в свободное состояние в момент завершения пос леднего потока процесса. Но такой объект, как таймер, переводится в сво бодное состояние по истечении заданного времени.
170 ГЛ А В А 3 БЕЗОПАСНОСТЬ Выбирая механизм синхронизации, вы должны учитывать в своей про грамме поведение синхронизирующих объектов. В таблице 310 показано, когда переходят в свободное состояние синхронизирующие объекты раз личных типов. Таблица 3-10. Условия освобождения различных синхронизирующих объектов Тип объекта Переводится в свободное состояние при: Действие на ожидающие потоки Процесс Завершении последнего потока Все потоки освобождаются Поток Завершении данного потока Все потоки освобождаются Файл Завершении операции вводавывода Все потоки освобождаются Событие (уведом ляющего типа) Установке события потоком Все потоки освобождаются Событие (синхро Установке события потоком низирующего типа) Освобождается один поток, и объект «событие» сбрасыва ется Семафор Освобождается один поток Уменьшении счетчика семафора на 1 Таймер (уведомля Истечении заданного времени ющего типа) или наступлении очередного момента срабатывания Все потоки освобождаются Таймер (синхро Истечении заданного времени низирующего типа) или наступлении очередного момента срабатывания Освобождается один поток Мьютекс Освобождении объекта «мьютекс» потоком Освобождается один поток Очередь Добавлении элемента в очередь Освобождается один поток Когда объект переводится в свободное состояние, ожидающие его пото ки обычно немедленно выходят из ждущего состояния. Однако, как показа но на рис. 326, некоторые объекты диспетчера ядра и системные события ведут себя иначе. Например, объект «событие уведомления» — в Windows API он называет ся событием со сбросом вручную (manual reset event) — используется для уведомления о какомлибо событии. Когда этот объект переводится в свобод ное состояние, все потоки, ожидающие его, освобождаются. Исключением является тот поток, который ждет сразу несколько объектов: он может про должать ожидание, пока не освободятся дополнительные объекты. В отличие от события мьютекс предусматривает возможность владения. Этот объект используется для взаимоисключающего доступа к ресурсу, по этому единовременно только один поток может владеть мьютексом. При освобождении мьютекса ядро переводит его в свободное состояние и выби рает для выполнения один из ожидающих потоков. Выбранный ядром по ток захватывает мьютекс, а остальные потоки остаются в ожидании.
ГЛАВА 9 Рис. 3-26. Некоторые объекты диспетчера ядра Системные механизмы 171
172 ГЛ А В А 3 БЕЗОПАСНОСТЬ События с ключом и критические секции Синхронизирующий объект, впервые появившийся в Windows XP и названный событием с ключом (keyed event), заслуживает особого упоминания. Он помогает процессам справляться с нехваткой памя ти при использовании критических секций. Это недокументирован ное событие позволяет потоку указать «ключ» в следующей ситуации: данный поток должен пробуждаться, когда другой поток того же про цесса освобождает событие с тем же ключом. Windowsпроцессы часто используют функции критических сек ций — EnterCriticalSection и LeaveCriticalSection — для синхронизации доступа потоков к личным ресурсам процесса. Вызовы этих функций эффективнее прямого обращения к объектам «мьютекс», так как в от сутствие конкуренции они не заставляют переходить в режим ядра. При наличии конкуренции EnterCriticalSection динамически создает объект «событие», и поток, которому нужно захватить критическую секцию, ждет, когда поток, владеющий этой секцией, освободит ее вызовом LeaveCriticalSection. Если создать объект «событие» для критической секции не удалось изза нехватки системной памяти, EnterCriticalSection использует гло бальное событие с ключом — CritSecOutOfMemoryEvent (в каталоге \Ker nel пространства имен диспетчера объектов). Если EnterCriticalSection вынуждена задействовать CritSecOutOfMemoryEvent вместо стандартно го события, поток, ждущий критическую секцию, использует адрес этой секции как ключ. Это обеспечивает корректную работу функций кри тических секций даже в условиях временной нехватки памяти. Мы не ставили себе задачу исчерпывающе описать все объекты исполни тельной системы, а лишь хотели дать представление об их базовой функци ональности и механизмах синхронизации. Об использовании этих объек тов в Windowsпрограммах см. справочную документацию Windows или чет вертое издание книги Джеффри Рихтера «Windows для профессионалов». Структуры данных Учет ожидающих потоков и их объектов ожидания базируется на двух ключевых структурах данных: заголовках диспетчера (dispatcher headers) и блоках ожидания (wait blocks). Обе эти структуры оп ределены в Ntddk.h, заголовочном файле DDK. Для удобства мы воспроизво дим здесь эти определения. typedef struct _DISPATCHER_HEADER { UCHAR Type; UCHAR Absolute; UCHAR Size; UCHAR Inserted; LONG SignalState; LIST_ENTRY WaitListHead; } DISPATCHER_HEADER;
ГЛАВА 9 Системные механизмы 173 typedef struct _KWAIT_BLOCK { LIST_ENTRY WaitListEntry; struct _KTHREAD *RESTRICTED_POINTER Thread; PVOID Object; struct _KWAIT_BLOCK *RESTRICTED_POINTER NextWaitBlock; USHORT WaitKey; USHORT WaitType; } KWAIT_BLOCK, *PKWAIT_BLOCK, *RESTRICTED_POINTER PRKWAIT_BLOCK; Заголовок диспетчера содержит тип объекта, информацию о состоянии (занят/свободен) и список потоков, ожидающих этот объект. У каждого жду щего потока есть список блоков ожидания, где перечислены ожидаемые потоком объекты, а у каждого объекта диспетчера ядра — список блоков ожидания, где перечислены ожидающие его потоки. Этот список ведется так, что при освобождении объекта диспетчера ядро может быстро определить, кто ожидает данный объект. В блоке ожидания имеются указатели на объект ожидания, ожидающий поток и на следующий блок ожидания (если поток ждет более одного объекта). Он также регистрирует тип ожидания («любой» или «все») и позицию соответствующего элемента в таблице описателей, переданную потоком в функцию WaitForMultipleObjects (позиция 0 — если поток ожидает лишь один объект). Рис. 3-27. Структуры данных, необходимые для поддержки ожидания
174 ГЛ А В А 3 БЕЗОПАСНОСТЬ На рис. 327 показана связь объектов диспетчера ядра с блоками ожида ния потоков. В данном примере поток 1 ждет объект В, а поток 2 — объек ты А и В. Если объект А освободится, поток 2 не сможет возобновить свое выполнение, так как ядро обнаружит, что он ждет и другой объект. С другой стороны, при освобождении объекта B ядро сразу же подготовит поток 1 к выполнению, поскольку он не ждет никакие другие объекты. ЭКСПЕРИМЕНТ: просмотр очередей ожидания Хотя многие утилиты просмотра процессов умеют определять, нахо дится ли поток в состоянии ожидания (отмечая в этом случае и тип ожидания), список объектов, ожидаемых потоком, можно увидеть только с помощью команды !process отладчика ядра. Например, следу ющий фрагмент вывода команды !process показывает, что поток ждет на объектесобытии. kd> !process ... THREAD 8a12a328 Cid 0bb8.0d50 Teb: 7ffdd000 Win32Thread: e7c9aeb0 WAIT: (WrUserRequest) UserMode NonAlertable 8a21bf58 SynchronizationEvent Команда dt позволяет интерпретировать содержимое заголовка диспетчера, например, такого объекта: kd> dt nt!_dispatcher_header nt!_DISPATCHER_HEADER +0x000 Type : +0x001 Absolute : +0x002 Size : +0x003 Inserted : +0x004 SignalState : +0x008 WaitListHead : 8a21bf58 0x1 '' 0 '' 0x4 '' 0 '' 0 _LIST_ENTRY [ 0x8a12a398  0x8a12a398 ] Эти данные позволяют нам убедиться в отсутствии других потоков, ожидающих данный объект, поскольку указатели начала и конца спис ка ожидания указывают на одно и то же место (на один блок ожида ния). Копия блока ожидания (по адресу 0x8a12a398) дает следующее: kd> dt nt!_kwait_block 0x8a12a398 nt!_KWAIT_BLOCK +0x000 WaitListEntry : _LIST_ENTRY [ 0x8a21bf60  0x8a21bf60 ] +0x008 Thread : 0x8a12a328 +0x00c Object : 0x8a21bf58 +0x010 NextWaitBlock : 0x8a12a398 +0x014 WaitKey : 0 +0x016 WaitType : 1
ГЛАВА 9 Системные механизмы 175 Если в списке ожидания более одного элемента, вы можете выпол нить ту же команду со вторым указателем в поле WaitListEntry каждого блока ожидания (команду !thread применительно к указателю потока в блоке ожидания) для прохода по списку и просмотра других пото ков, ждущих данный объект. Быстрые и защищенные мьютексы Быстрые мьютексы (fast mutexes), также известные как мьютексы исполни тельной системы, обычно обеспечивают более высокую производитель ность, чем объекты «мьютекс». Почему? Дело в том, что быстрые мьютексы, хоть и построены на объектах событий диспетчера, в отсутствие конкурен ции не требуют ожидания объекта «событие» (и соответственно спинбло кировок, на которых основан этот объект). Эти преимущества особенно ярко проявляются в многопроцессорной среде. Быстрые мьютексы широко используются в ядре и драйверах устройств. Однако быстрые мьютексы годятся, только если можно отключить дос тавку обычных APC режима ядра. В исполнительной системе определены две функции для захвата быстрых мьютексов: ExAcquireFastMutex и ExAcquire FastMutexUnsafe. Первая функция блокирует доставку всех APC, повышая IRQL процессора до уровня APC_LEVEL, а вторая — ожидает вызова при уже от ключенной доставке обычных APC режима ядра (такое отключение возмож но повышением IRQL до уровня «APC» или вызовом KeEnterCriticalRegion). Другое ограничение быстрых мьютексов заключается в том, что их нельзя захватывать рекурсивно, как объекты «мьютекс». Защищенные мьютексы (guarded mutexes) — новшество Windows Server 2003; они почти идентичны быстрым мьютексам (хотя внутренне использу ют другой синхронизирующий объект, KGATE). Захватить защищенные мью тексы можно вызовом функции KeAcquireGuardedMutex, отключающей дос тавку всех APC режима ядра через KeEnterGuardedRegion, а не KeEnterCritical Region, которая на самом деле отключает только обычные APC режима ядра. Защищенные мьютексы недоступны вне ядра и используются в основном диспетчером памяти для защиты глобальных операций вроде создания стра ничных файлов, удаления определенных типов разделов общей памяти и расширения пула подкачиваемой памяти. (Подробнее о диспетчере памяти см. главу 7.) Ресурсы исполнительной системы Ресурсы исполнительной системы (executive resources) — это механизм син хронизации, который поддерживает разделяемый (совместный) и моно польный доступ и по аналогии с быстрыми мьютексами требует предвари тельного отлючения доставки обычных APC режима ядра. Они основаны на объектах диспетчера, которые используются только при наличии конкурен ции. Ресурсы исполнительной системы широко применяются во всей сис теме, особенно в драйверах файловой системы.
176 ГЛ А В А 3 БЕЗОПАСНОСТЬ Потоки, которым нужно захватить какойлибо ресурс для совместного доступа, ждут на семафоре, сопоставленном с этим ресурсом, а потоки, ко торым требуется захватить ресурс для монопольного доступа, — на событии. Семафор с неограниченным счетчиком применяется потому, что в первом случае можно пробудить все ждущие потоки и предоставить им доступ к ресурсу, как только этот семафор перейдет в свободное состояние (ресурс будет освобожден потоком, захватившим его в монопольное владение). Ког да потоку нужен монопольный доступ к занятому на данный момент ресур су, он ждет на синхронизирующем объекте «событие», так как при освобож дении события пробуждается только один из ожидающих потоков. Для захвата ресурсов предназначен целый ряд функций: ExAcquireResour ceSharedLite, ExAcquireResourceExclusiveLite, ExAcquireSharedStarveExclusive, ExAcquireWaitForExclusive и ExTryToAcquireResourceExclusiveLite. Эти функции документированы в DDK. ЭКСПЕРИМЕНТ: перечисление захваченных ресурсов исполнительной системы Команда !locks отладчика ядра ищет в пуле подкачиваемой памяти объекты ресурсов исполнительной системы и выводит их состояние. По умолчанию эта команда перечисляет только захваченные на дан ный момент ресурсы, но ключ –d позволяет перечислять все ресурсы исполнительной системы. Вот фрагмент вывода этой команды: lkd> !locks **** DUMP OF ALL RESOURCE OBJECTS **** KD: Scanning for held locks. Resource @ nt!MmSystemWsLock (0x805439a0) Exclusively owned Contention Count = 123 Threads: 89b3602001<*> KD: Scanning for held locks.................................... ............................................................... ............................................................... ............. Resource @ 0x89da1a68 Shared 1 owning threads Threads: 8a4cb53301<*> *** Actual Thread 8a4cb530 Заметьте, что счетчик конкурирующих потоков (contention count), извлекаемый из структуры ресурса, фиксирует, сколько раз потоки пытались захватить данный ресурс и были вынуждены переходить в состояние ожидания изза того, что он уже занят. Для изучения деталей конкретного объекта ресурса (в частности, кто владеет ресурсом и кто ждет его освобождения) укажите ключ –v и адрес ресурса: lkd> !locks v 0x805439a0
ГЛАВА 9 Resource @ nt!MmSystemWsLock (0x805439a0) Contention Count = 123 Threads: 89b3602001<*> Системные механизмы 177 Exclusively owned THREAD 89b36020 Cid 0e98.0bd4 Teb: 7ffd9000 Win32Thread: e2bcc538 RUNNING on processor 0 Not impersonating DeviceMap e1df7d18 Owning Process 8999d020 Wait Start TickCount 492582 Elapsed Ticks: 15 Context Switch Count 532 LargeStack UserTime 00:00:01.0462 KernelTime 00:00:00.0320 Start Address 0x77e7d342 Win32 Start Address 0x0101f1d0 Stack Init a9d20000 Current a9d1fd44 Base a9d20000 Limit a9d1d000 Call 0 Priority 11 BasePriority 8 PriorityDecrement 2 DecrementCount 16 Unable to get context for thread running on processor 0, HRESULT 0x80004001 Блокировки с заталкиванием указателя Блокировки с заталкиванием указателя (push locks), впервые появившие ся в Windows XP, являются еще одним оптимизированным механизмом син хронизации, который основан на объекте «событие» (в Windows Server 2003 такие блокировки базируются на внутреннем синхронизирующем объекте KGATE) и подобно быстрым мьютексам заставляет ждать этот объект толь ко при наличии конкуренции. Такие блокировки имеют преимущества над быстрыми мьютексами, так как их можно захватывать как в разделяемом, так и в монопольном режиме. Они не документированы и не экспортируются ядром, так как зарезервированы для использования самой операционной системой. Существует два типа блокировок с заталкиванием указателя: обычный и с поддержкой кэша (cache aware). Первый тип занимает в памяти тот же объем, что и указатель (4 байта в 32разрядных системах и 8 байтов в 64 разрядных). Когда поток захватывает обычную блокировку с заталкиванием указателя, код этой блокировки помечает ее как занятую, если она на дан ный момент свободна. Если блокировка захвачена для монопольного досту па или если потоку нужно захватить ее монопольно, а она уже захвачена для разделяемого доступа, ее код создает в стеке потока блок ожидания, иници ализирует объект «событие» в этом блоке и добавляет последний в список ожидания, сопоставленный с блокировкой. Как только блокировка освобож дается, ее код пробуждает ждущий поток (если таковой имеется), освобож дая событие в блоке ожидания потока.
178 ГЛ А В А 3 БЕЗОПАСНОСТЬ Второй тип создает обычную блокировку с заталкиванием указателя для каждого процессора в системе и сопоставляет ее с блокировкой с заталки ванием указателя, поддерживающей кэш. Когда потоку нужно захватить та кую блокировку, он просто захватывает обычную блокировку, созданную для текущего процессора в соответствующем режиме доступа. Подобные блокировки используются, в том числе, диспетчером объектов, когда возникает необходимость в защите глобальных структур данных и дескрипторов защиты объектов, а также диспетчером памяти для защиты структур данных AWE. Обнаружение взаимоблокировки с помощью Driver Verifier Взаимоблокировка (deadlock) — это проблема синхронизации, возни кающая, когда два потока или процессора удерживают ресурсы, нуж ные другому, и ни один из них не отдает их. Такая ситуация может приводить к зависанию системы или процесса. Утилита Driver Verifier, описываемая в главах 7 и 9, позволяет проверять возможность взаимо блокировки, в том числе на спинблокировках, быстрых и обычных мьютексах. О том, как пользоваться Driver Verifier для анализа зависа ния системы, см. главу 14. Системные рабочие потоки При инициализации Windows создает несколько потоков в процессе System, которые называются системными рабочими потоками (system worker thre ads). Они предназначены исключительно для выполнения работы по пору чению других потоков. Во многих случаях потоки, выполняемые на уровне «DPC/dispatch», нуждаются в вызове таких функций, которые могут быть вызваны только при более низком IRQL. Например, DPCпроцедуре, выпол няемой в контексте произвольного потока при IRQL уровня «DPC/dispatch» (DPC может узурпировать любой поток в системе), нужно обратиться к пулу подкачиваемой памяти или ждать на объекте диспетчера для синхронизации с потоком какоголибо приложения. Поскольку DPCпроцедура не может понизить IRQL, она должна передать свою задачу потоку, который сможет выполнить ее при IRQL ниже уровня «DPC/dispatch». Некоторые драйверы устройств и компоненты исполнительной системы создают собственные потоки для обработки данных на уровне «passive», но большинство вместо этого использует системные рабочие потоки, что по могает избежать слишком частого переключения потоков и чрезмерной нагрузки на память изза диспетчеризации дополнительных потоков. Драй вер устройства или компонент исполнительной системы запрашивает сер висы системных рабочих потоков через функцию исполнительной системы ExQueueWorkItem или IoQueueWorkItem. Эти функции помещают рабочий элемент (work item) в специальную очередь, проверяемую системными ра бочими потоками (см. раздел «Порты завершения вводавывода» главы 9).
ГЛАВА 9 Системные механизмы 179 Рабочий элемент включает указатель на процедуру и параметр, передавае мый потоком этой процедуре при обработке рабочего элемента. Процеду ра реализуется драйвером устройства или компонентом исполнительной системы, выполняемым на уровне «passive». Например, DPCпроцедура, которая должна ждать на объекте диспетче ра, может инициализировать рабочий элемент, который указывает на про цедуру в драйвере, ждущем на объекте диспетчера, и, возможно, на указатель на объект. На какомто этапе системный рабочий поток извлекает из своей очереди рабочий элемент и выполняет процедуру драйвера. После ее выпол нения системный рабочий поток проверяет, нет ли еще рабочих элементов, подлежащих обработке. Если нет, системный рабочий поток блокируется, пока в очередь не будет помещен новый рабочий элемент. Выполнение DPC процедуры может и не закончиться в ходе обработки ее рабочего элемента системным рабочим потоком. (В однопроцессорной системе выполнение этой процедуры всегда завершается до обработки ее рабочего элемента, так как на уровне IRQL «DPC/dispatch» потоки не планируются.) Существует три типа системных рабочих потоков: 쐽 отложенные (delayed worker threads) — выполняются с приоритетом 12, обрабатывают некритичные по времени рабочие элементы и допускают выгрузку своего стека в страничный файл на время ожидания рабочих элементов; 쐽 критичные (critical worker threads) — выполняются с приоритетом 13, обрабатывают критичные по времени рабочие элементы. В Windows Ser ver их стек всегда находится только в физической памяти; 쐽 гиперкритичный (hypercritical worker thread) — единственный поток, выполняемый с приоритетом 15. Его стек тоже всегда находится в памя ти. Диспетчер процессов использует гиперкритичные по времени рабо чие элементы для выполнения функции, освобождающей завершенные потоки. Число отложенных и критичных системных рабочих потоков, создавае мых функцией исполнительной системы ExpWorkerInitialization, которая вызывается на ранних стадиях процесса загрузки, зависит от объема памя ти в системе и от того, является ли система сервером. В таблице 311 пока зано количество потоков, изначально создаваемых в системах с различной конфигурацией. Вы можете указать ExpInitializeWorker создать дополнитель но до 16 отложенных и 16 критичных системных рабочих потоков. Для это го используйте параметры AdditionalDelayedWorkerThreads и AdditionalCri ticalWorkerThreads в разделе реестра HKLM\SYSTEM\CurrentControlSet\Cont rol\ Session Manager\Executive.
180 ГЛ А В А 3 Таблица 3-11. БЕЗОПАСНОСТЬ Начальное количество системных рабочих потоков Windows 2000 Windows 2000 Server Windows XP и Windows Server 2003 Отложенный 3 3 7 Критичный 5 10 5 Гиперкритичный 1 1 1 Исполнительная система старается балансировать число критичных сис темных рабочих потоков в соответствии с текущей рабочей нагрузкой. Каж дую секунду функция исполнительной системы ExpWorkerThreadBalance Manager проверяет, надо ли создавать новый критичный рабочий поток. Кстати, критичный рабочий поток, создаваемый функцией ExpWorkerThread BalanceManager, называется динамическим (dynamic worker thread). Для со здания такого потока должны быть выполнены следующие условия. 쐽 Очередь критичных рабочих элементов не должна быть пустой. 쐽 Число неактивных критичных потоков (блокированных в ожидании ра бочих элементов или на объектах диспетчера при выполнении рабочей процедуры) должно быть меньше количества процессоров в системе. 쐽 В системе должно быть менее 16 динамических рабочих потоков. Динамические потоки завершаются через 10 минут пребывания в неак тивном состоянии. В зависимости от рабочей нагрузки исполнительная сис тема может создавать до 16 таких потоков. ЭКСПЕРИМЕНТ: просмотр списка системных рабочих потоков Для получения списка системных рабочих потоков, сгруппированных по типу, используйте команду !exqueue отладчика ядра: kd> !exqueue Dumping ExWorkerQueue: 8046A5C0 **** Critical WorkQueue( current = 0 maximum = 1 ) THREAD 818a2d40 Cid 8.c Teb: 00000000 Win32Thread: THREAD 818a2ac0 Cid 8.10 Teb: 00000000 Win32Thread: THREAD 818a2840 Cid 8.14 Teb: 00000000 Win32Thread: THREAD 818a25c0 Cid 8.18 Teb: 00000000 Win32Thread: THREAD 818a2340 Cid 8.1c Teb: 00000000 Win32Thread: **** Delayed WorkQueue( current THREAD 818a20c0 Cid 8.20 Teb: THREAD 818a1020 Cid 8.24 Teb: THREAD 818a1da0 Cid 8.28 Teb: 00000000 00000000 00000000 00000000 00000000 WAIT WAIT WAIT WAIT WAIT = 0 maximum = 1 ) 00000000 Win32Thread: 00000000 WAIT 00000000 Win32Thread: 00000000 WAIT 00000000 Win32Thread: 00000000 WAIT **** HyperCritical WorkQueue( current = 0 maximum = 1 ) THREAD 818a1b20 Cid 8.2c Teb: 00000000 Win32Thread: 00000000 WAIT
ГЛАВА 9 Системные механизмы 181 Глобальные флаги Windows Windows поддерживает набор флагов, который хранится в общесистемной глобальной переменной NtGlobalFlag, предназначенной для отладки, трасси ровки и контроля операционной системы. При загрузке системы перемен ная NtGlobalFlag инициализируется значением параметра GlobalFlag из раз дела реестра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager. По умолчанию его значение равно 0, и в системах с обычной конфигурацией глобальные флаги обычно не используются. Кроме того, каждый образ ис полняемого файла имеет набор глобальных флагов, позволяющих включать код внутренней трассировки и контроля (хотя битовая структура этих фла гов совершенно не соответствует структуре общесистемных глобальных флагов). Эти флаги не документированы, но могут пригодиться при изуче нии внутреннего устройства Windows. К счастью, в Platform SDK и средствах отладки есть утилита Gflags.exe, позволяющая просматривать и изменять системные глобальные флаги (либо в реестре, либо в работающей системе) и глобальные флаги образов испол няемых файлов. Gflags поддерживает как GUIинтерфейс, так и командную строку. Параметры командной строки можно узнать, введя gflags /?. При за пуске утилиты без параметров выводится диалоговое окно, показанное на рис. 328. Рис. 3-28. Настройка в Gflags системных отладочных параметров Вы можете переключаться между реестром (System Registry) и текущим значением переменной в системной памяти (Kernel Mode). Для внесения изменений нужно щелкнуть кнопку Apply (кнопка ОК просто закрывает про грамму). Хотя вы можете изменять флаги в работающей системе, большин ство из них требует перезагрузки для того, чтобы изменения вступили в силу.
182 ГЛ А В А 3 БЕЗОПАСНОСТЬ Поскольку документации на этот счет нет, лучше перезагрузиться после любых изменений. Выбрав Image File Options, вы должны ввести имя исполняемого в систе ме файла. Этот переключатель позволяет изменять набор глобальных фла гов отдельного образа (а не всей системы). Заметьте, что флаги на рис. 329 отличаются от флагов на рис. 328. Рис. 3-29. Настройка в Gflags глобальных флагов образа исполняемого файла ЭКСПЕРИМЕНТ: включение трассировки загрузчика образов и просмотр NtGlobalFlag Чтобы увидеть пример детальной трассировочной информации, кото рую можно получить при установке глобальных флагов, попробуйте запустить Gflags в системе с загруженным отладчиком ядра, которая подключена к компьютеру с запущенной утилитой Kd или Windbg. Далее попробуйте установить, например, глобальный флаг Show Loader Snaps. Для этого выберите Kernel Mode, установите флажок Show Loader Snaps и щелкните кнопку Apply. Теперь запустите на этой машине какуюнибудь программу, и отладчик ядра будет выдавать ин формацию, аналогичную показанной ниже. LDR: PID: 0xb8 started  'notepad' LDR: NEW PROCESS Image Path: C:\Windows\system32\notepad.exe (notepad.exe) Current Directory: C:\ddk\bin Search Path: C:\Windows\System32;C:\Windows\system;C:\Windows LDR: notepad.exe bound to comdlg32.dll LDR: ntdll.dll used by comdlg32.dll LDR: Snapping imports for comdlg32.dll from ntdll.dll
ГЛАВА 9 LDR: LDR: LDR: LDR: ... KERNEL32.dll loaded. RPCRT4.dll loaded.  ADVAPI32.dll loaded. USER32.dll loaded.  Системные механизмы 183  Calling init routine at 77f01000 Calling init routine at 77e1b6d5  Calling init routine at 77dc1000 Calling init routine at 77e78037 Для просмотра состояния переменной NtGlobalFlag можно исполь зовать команды !gflags и !gflag отладчика ядра. Первая выводит список всех флагов, указывая, какие из них установлены, а !gflag показывает только установленные флаги. kd> !gflags NT!NtGlobalFlag 0x4400 STOP_ON_EXCEPTION DEBUG_INITIAL_COMMAND HEAP_ENABLE_TAIL_CHECK HEAP_VALIDATE_PARAMETERS *POOL_ENABLE_TAGGING USER_STACK_TRACE_DB *MAINTAIN_OBJECT_TYPELIST ENABLE_CSRDEBUG DISABLE_PAGE_KERNEL_STACKS ENABLE_CLOSE_EXCEPTIONS ENABLE_HANDLE_TYPE_TAGGING DEBUG_INITIAL_COMMAND_EX SHOW_LDR_SNAPS STOP_ON_HUNG_GUI HEAP_ENABLE_FREE_CHECK HEAP_VALIDATE_ALL HEAP_ENABLE_TAGGING KERNEL_STACK_TRACE_DB HEAP_ENABLE_TAG_BY_DLL ENABLE_KDEBUG_SYMBOL_LOAD HEAP_DISABLE_COALESCING ENABLE_EXCEPTION_LOGGING HEAP_PAGE_ALLOCS DISABLE_DBGPRINT kd> !gflag NtGlobalFlag at 8046a164 Current NtGlobalFlag contents: 0x00004400 ptg  Enable pool tagging otl  Maintain a list of objects for each type LPC LPC (local procedure call) — это механизм межпроцессной связи для высоко скоростной передачи сообщений. Он недоступен через Windows API напря мую и является внутренним механизмом, которым пользуются только ком поненты операционной системы Windows. Вот несколько примеров того, где применяется LPC. 쐽 Windowsприложения, использующие RPC (документированный API), неявно используют и LPC, когда указывают локальный RPC — разновид ность RPC, применяемую для взаимодействия между процессами в рам ках одной системы. 쐽 Некоторые функции Windows API обращаются к LPC, посылая сообщения процессу подсистемы Windows.
184 ГЛ А В А 3 БЕЗОПАСНОСТЬ 쐽 Winlogon взаимодействует с процессом LSASS через LPC. 쐽 Монитор состояния защиты (компонент исполнительной системы, рас сматриваемый в главе 8) также взаимодействует с процессом LSASS через LPC. ЭКСПЕРИМЕНТ: просмотр объектов «порт LPC» Вы можете увидеть именованные объекты «порт LPC» (LPC port objects) с помощью утилиты Winobj с сайта www.sysinternals.com. Запустите Winobj.exe и выберите корневой каталог. Интересующие нас объекты обозначаются значком в виде разъема, как показано ниже. Для просмотра объектов «порт LPC», используемых RPC, выберите каталог \RPC Control, как на следующей иллюстрации. Вы также можете наблюдать объекты «порт LPC» с помощью коман ды !lpc отладчика ядра. Параметры этой команды позволяют перечис лять порты LPC, сообщения LPC и потоки, ожидающие или посылаю щие эти сообщения. Для просмотра порта аутентификации LSASS (в него Winlogon посылает запросы на вход в систему) сначала нужно получить список портов в данной системе.
ГЛАВА 9 Системные механизмы 185 kd> !lpc Usage: !lpc  Display this help !lpc message [MessageId]  Display the message with a given ID and all related information If MessageId is not specified, dump all messages !lpc port [PortAddress]  Display the port information !lpc scan PortAddress  Search this port and any connected port !lpc thread [ThreadAddr]  Search the thread in rundown port queues and display the port info If ThreadAddr is missing, display all threads marked as doing some lpc operations kd> !lpc port Scanning 206 objects 1 Port: 0xe1360320 Connection: 0xe1360320 Communication: 0x00000000 'SeRmCommandPort' 1 Port: 0xe136bc20 Connection: 0xe136bc20 Communication: 0x00000000 'SmApiPort' 1 Port: 0xe133ba80 Connection: 0xe133ba80 Communication: 0x00000000 'DbgSsApiPort' 1 Port: 0xe13606e0 Connection: 0xe13606e0 Communication: 0x00000000 'DbgUiApiPort' ... 1 Port: 0xe205f040 Connection: 0xe205f040 Communication: 0x00000000 'LsaAuthenticationPort' ... Найдите порт с именем LsaAuthenticationPort и передайте команде !lpc его адрес, как показано ниже. kd> !lpc port 0xe205f040 Server connection port e205f040 Name: LsaAuthenticationPort Handles: 1 References: 37 Server process : ff7d56c0 (lsass.exe) Queue semaphore : ff7bfcc8 Semaphore state 0 (0x0) The message queue is empty The LpcDataInfoChainHead queue is empty Как правило, LPC используются для взаимодействия между серверным процессом и одним или несколькими клиентскими процессами. LPCсоеди нение может быть установлено между двумя процессами пользовательско го режима или между компонентом режима ядра и процессом пользователь
186 ГЛ А В А 3 БЕЗОПАСНОСТЬ ского режима. Например, как говорилось в главе 2, Windowsпроцессы иног да посылают сообщения подсистеме Windows через LPC. Некоторые систем ные процессы вроде Winlogon и LSASS тоже используют LPC. Примерами компонентов режима ядра, взаимодействующих с пользовательскими про цессами через LPC, могут служить монитор состояния защиты и LSASS. LPC предусматривает три способа обмена сообщениями. 쐽 Сообщение длиной менее 256 байтов можно передать вызовом LPC с бу фером, содержащим сообщение. Затем это сообщение копируется из ад ресного пространства процессаотправителя в системное адресное про странство, а оттуда — в адресное пространство процессаполучателя. 쐽 Если клиент и сервер хотят обменяться данными, размер которых превы шает 256 байтов, они могут использовать общий раздел, на который они оба спроецированы. Отправитель помещает данные в общий раздел и посылает получателю уведомление с указателем на область раздела, где находятся данные. 쐽 Если серверу нужно считать или записать данные, объем которых превы шает размер общего раздела, то их можно напрямую считать из клиент ского адресного пространства или записать туда. Для этого LPC предо ставляет серверу две функции. Сообщение, посланное первой функцией, обеспечивает синхронизацию передачи последующих сообщений. LPC экспортирует единственный объект исполнительной системы — объект «порт» (port object). Однако порты бывают нескольких видов. 쐽 Порт серверного соединения (server connection port) Именован ный порт, служащий точкой запроса связи c сервером. Через него клиен ты могут соединяться с сервером. 쐽 Коммуникационный порт сервера (server communication port) Безымянный порт, используемый сервером для связи с конкретным кли ентом. У сервера имеется по одному такому порту на каждый активный клиент. 쐽 Коммуникационный порт клиента (client communication port) Безымянный порт, используемый конкретным клиентским потоком для связи с конкретным сервером. 쐽 Безымянный коммуникационный порт (unnamed communica tion port) Порт, создаваемый для связи между двумя потоками одного процесса. LPC обычно используется так. Сервер создает именованный порт соеди нения. Клиент посылает в него запрос на установление связи. Если запрос удовлетворен, создается два безымянных порта — коммуникационный порт клиента и коммуникационный порт сервера. Клиент получает описатель коммуникационного порта клиента, а сервер — описатель коммуникацион ного порта сервера. После этого клиент и сервер используют новые порты для обмена данными. Схема соединения между клиентом и сервером показана на рис. 330.
ГЛАВА 9 Рис. 3-30. Системные механизмы 187 Использование LPC-портов Трассировка событий ядра Различные компоненты ядра Windows и несколько базовых драйверов уст ройств оснащены средствами мониторинга для записи трассировочных дан ных об их работе, используемых при анализе проблем в системе. Эти ком поненты опираются на общую инфраструктуру в ядре, которая предостав ляет трассировочные данные механизму пользовательского режима — Event Tracing for Windows (ETW). Приложение, использующее ETW, попадает в одну или более следующих категорий. 쐽 Контроллер (controller) Начинает и прекращает сеансы протоколи рования (logging sessions), а также управляет буферными пулами. 쐽 Провайдер (provider) Определяет GUID (globally unique identifiers) для классов событий, для которых он может создавать трассировочные дан ные, и регистрирует их в ETW. Провайдер принимает команды от кон троллера на запуск и остановку трассировки классов событий, за которые он отвечает. 쐽 Потребитель (consumer) Выбирает один или более сеансов трасси ровки, для которых ему нужно считывать трассировочные данные. При нимает информацию о событиях в буферы в режиме реального времени или в файлы журнала. В системы Windows Server встроено несколько провайдеров пользова тельского режима, в том числе для Active Directory, Kerberos и Netlogon. ETW
188 ГЛ А В А 3 БЕЗОПАСНОСТЬ определяет сеанс протоколирования с именем NT Kernel Logger [также из вестный как регистратор ядра (kernel logger)] для использования ядром и базовыми драйверами. Провайдер для NT Kernel Logger реализуется драйве ром устройства Windows Management Instrumentation (WMI) (драйвер назы вается Wmixwdm), который является частью Ntoskrnl.exe. (Подробнее о WMI см. соответствующий раздел в главе 5.) Этот драйвер не только служит ос новой регистратора ядра, но и управляет регистрацией классов событий ETW пользовательского режима. Драйвер WMI экспортирует интерфейсы управления вводомвыводом для применения в ETWпроцедурах пользовательского режима и драйверах ус тройств, предоставляющих трассировочные данные для регистратора ядра. (О командах управления вводомвыводом см. главу 9.) Он также реализует функции для использования компонентами в Ntoskrnl.exe режима ядра, ко торые формируют трассировочный вывод. Когда в пользовательском режиме включается контроллер, регистратор ядра (библиотека ETW, реализованная в \Windows\System32\Ntdll.dll) посы лает запрос управления вводомвыводом (I/O control request) драйверу WMI, сообщая ему, для каких классов событий контроллер хочет начать трасси ровку. Если настроено протоколирование в файлы журналов (в противопо ложность протоколированию в буфер памяти), драйвер WMI создает специ альный системный поток в системном процессе, а тот создает файл журна ла. Принимая события трассировки от активизированных источников трас сировочных данных, драйвер WMI записывает их в буфер. Поток записи в журнал пробуждается раз в секунду, чтобы сбросить содержимое буферов в файл журнала. Записи трассировки, генерируемые для регистратора ядра, имеют стан дартный ETWзаголовок события трассировки, в котором содержатся вре менная метка, идентификаторы процесса и потока, а также сведения о том, какому классу события соответствует данная запись. Классы событий могут предоставлять дополнительные данные, специфичные для их событий. На пример, класс дисковых событий (disk event class) указывает тип операции (чтение или запись), номер диска, на котором выполняется операция, а так же смещение начального сектора и количество секторов, затрагиваемых данной операцией. Классы трассировки, которые можно включить для регистратора ядра, и компонент, генерирующий каждый класс, перечислены ниже. 쐽 Дисковый вводвывод Драйвер класса дисков. 쐽 Файловый вводвывод Драйверы файловой системы. 쐽 Конфигурирование оборудования Диспетчер Plug and Play (см. главу 9). 쐽 Загрузка/выгрузка образов 쐽 Ошибки страниц Системный загрузчик образов в ядре. Диспетчер памяти (см. главу 7). 쐽 Создание/удаление процессов 쐽 Создание/удаление потоков Диспетчер процессов (см. главу 6). Диспетчер процессов.
ГЛАВА 9 쐽 Операции с реестром в главе 4). Системные механизмы 189 Диспетчер конфигурации (см. раздел «Реестр» 쐽 Активность TCP/UDP Драйвер TCP/IP. Более подробные сведения о ETW и регистраторе ядра, в том числе при меры кода для контроллеров и потребителей, см. в Platform SDK. ЭКСПЕРИМЕНТ: трассировка активности TCP/IP с помощью регистратора ядра Чтобы включить регистратор ядра и получить от него файл журнала активности TCP/IP, действуйте следующим образом. 1. Запустите оснастку Performance (Производительность) и выбери те узел Performance Logs And Alerts (Журналы и оповещения произ водительности). 2. Укажите Trace Logs (Журналы трассировки) и выберите из меню Action (Действие) команду New Log Settings (Новые параметры журнала). 3. В появившемся окне присвойте имя новым параметрам (например, experiment). 4. В следующем диалоговом окне выберите Events Logged By System Provider (События, протоколируемые системным поставщиком) и сбросьте все, кроме Network TCP/IP (События сети TCP/IP). 5. В поле ввода Run As (От имени) введите имя учетной записи адми нистратора и ее пароль. 6. Закройте это диалоговое окно и создайте активность в сети, открыв браузер и зайдя на какойнибудь Webсайт. 7. Укажите журнал трассировки, созданный в узле таких журналов, и выберите Stop (Остановка) из меню Action (Действие). 8. Откройте окно командной строки и перейдите в каталог C:\Perflogs (или тот каталог, который вы указали как место хранения файла журнала). см. след. стр.
190 ГЛ А В А 3 БЕЗОПАСНОСТЬ 9. Если вы используете Windows XP или Windows Server 2003, запус тите Tracerpt (эта утилита находится в каталоге \Windows\Sys tem32) и передайте ей имя файла журнала трассировки. Если вы работаете в Windows 2000, скачайте и запустите Tracedmp из ресур сов Windows 2000. Обе утилиты генерируют два файла: dumpfile.csv и summary.txt. 10. Откройте dumpfile.csv в Microsoft Excel или в любом текстовом ре дакторе. Вы должны увидеть записи трассировки TCP и/или UDP: TcpIp Recv 4608 0 0 0 TcpIp Send 4608 0 0 0 TcpIp Recv 4608 0 0 0 TcpIp Send 4608 0 0 0 TcpIp Recv 4608 0 0 0 TcpIp Send 4608 0 0 0 TcpIp Recv 4608 0 0 0 TcpIp Send 4608 0 0 0 0xFFFFFFFF 1.27E+17 0 0 4 88 192.168.001.101 192.168.001.108 0xFFFFFFFF 1.27E+17 0 0 4 76 192.168.001.101 192.168.001.108 0xFFFFFFFF 1.27E+17 0 0 4 88 192.168.001.101 192.168.001.108 0xFFFFFFFF 1.27E+17 0 0 4 76 192.168.001.101 192.168.001.108 0xFFFFFFFF 1.27E+17 0 0 4 88 192.168.001.101 192.168.001.108 0xFFFFFFFF 1.27E+17 0 0 4 76 192.168.001.101 192.168.001.108 0xFFFFFFFF 1.27E+17 0 0 4 88 192.168.001.101 192.168.001.108 0xFFFFFFFF 1.27E+17 0 0 4 76 192.168.001.101 192.168.001.108 Wow64 Wow64 (эмуляция Win32 в 64разрядной Windows) относится к програм мному обеспечению, которое дает возможность выполнять 32разрядные x86приложения в 64разрядной Windows. Этот компонент реализован как набор DLL пользовательского режима. 쐽 Wow64.dll — управляет созданием процессов и потоков, подключается к диспетчеризации исключений и перехватывает вызовы базовых систем ных функций, экспортируемых Ntoskrnl.exe. Также реализует перенаправ ление файловой системы (file system redirection) и перенаправление ре естра и отражение (reflection). 쐽 Wow64Cpu.dll — управляет 32разрядным контекстом процессора каждо го потока, выполняемого внутри Wow64, и предоставляет специфичную для процессорной архитектуры поддержку переключения режима про цессора из 32разрядного в 64разрядный и наоборот. 쐽 Wow64Win.dll — перехватывает вызовы системных GUIфункций, экспор тируемых Win32k.sys. Взаимосвязь этих DLL показана на рис. 331.
ГЛАВА 9 Рис. 3-31. Системные механизмы 191 Архитектура Wow64 Системные вызовы Wow64 ставит ловушки на всех путях выполнения, где 32разрядный код дол жен взаимодействовать с родным 64разрядным или где 64разрядной систе ме нужно обращаться к 32разрядному коду пользовательского режима. При создании процесса диспетчер процессов проецирует на его адресное про странство 64разрядную библиотеку Ntdll.dll. Загрузчик 64разрядной систе мы проверяет заголовок образа и, если этот процесс 32разрядный для плат формы x86, загружает Wow64.dll. После этого Wow64 проецирует 32разряд ную Ntdll.dll (она хранится в каталоге \Windows\Syswow64). Далее Wow64 настраивает стартовый контекст внутри Ntdll, переключает процессор в 32 разрядный режим и начинает выполнять 32разрядный загрузчик. С этого момента все идет так же, как в обычной 32разрядной системе. Специальные 32разрядные версии Ntdll.dll, User32.dll и Gdi32.dll находят ся в каталоге \Windows\Syswow64. Они вызывают Wow64, не выдавая инст рукции вызова, которые используются в истинно 32разрядной системе. Wow64 переключается в «родной» 64разрядный режим, захватывает пара метры, связанные с системным вызовом, преобразует 32разрядные указате ли в 64разрядные и выдает соответствующий для 64разрядной системы системный вызов. Когда последняя возвращает управление, Wow64 при не обходимости преобразует любые выходные параметры из 64битных в 32 битные форматы и вновь переключается в 32разрядный режим. Диспетчеризация исключений Wow64 перехватывает диспетчеризацию исключений через KiUserException Dispatcher в Ntdll. Всякий раз, когда 64разрядное ядро собирается направить исключение Wow64процессу, Wow64 перехватывает его и запись контекста (context record) в пользовательском режиме, а затем, создав на их основе 32 разрядные исключение и запись контекста, направляет их своему процессу так же, как это сделало бы истинно 32разрядное ядро.
192 ГЛ А В А 3 БЕЗОПАСНОСТЬ Пользовательские обратные вызовы Wow64 перехватывает все обратные вызовы из режима ядра в пользователь ский режим. Wow64 интерпретирует их как системные вызовы; однако трансляция данных происходит в обратном порядке: входные параметры преобразуются из 64битных форматов в 32битные, а выходные (после воз врата из обратного вызова) — из 32битных в 64битные. Перенаправление файловой системы Чтобы обеспечить совместимость приложений и упростить перенос Win32 программ на платформу 64разрядной Windows, имена системных катало гов сохранены прежними. Поэтому в \Windows\System32 содержатся «род ные» 64разрядные исполняемые файлы. Так как Wow64 ставит ловушки на все системные вызовы, этот компонент транслирует все APIвызовы, отно сящиеся к путям, и заменяет в них каталог \Windows\System32 на \Win dows\Syswow64. Wow64 также перенаправляет \Windows\System32 \Ime в \Windows\System32\IME (x86), чтобы обеспечить совместимость 32разряд ных приложений в 64разрядных системах с установленной поддержкой дальневосточных языков. Кроме того, 32разрядные программы устанавли ваются в каталог \Program Files (x86), тогда как 64разрядные — в обычный каталог \Program Files. В каталоге \Windows\System32 есть несколько подкаталогов, которые по соображениям совместимости исключаются из перенаправления. Так что, если 32разрядным приложениям понадобится доступ к этим каталогам, они смогут обращаться к ним напрямую. В число таких каталогов входят: 쐽 %windir%\system32\drivers\etc; 쐽 %windir%\system32\spool; 쐽 %windir%\system32\catroot2; 쐽 %windir%\system32\logfiles. Наконец, Wow64 предоставляет механизм, позволяющий отключать пе ренаправление файловой системы, встроенное в Wow64, для каждого пото ка индивидуально. Данный механизм доступен через функцию Wow64Enab leWow64FsRedirection, которая впервые появилась в Windows Server 2003. Перенаправление реестра и отражение Приложения и компоненты хранят свои конфигурационные данные в рее стре. Эту информацию компоненты обычно записывают в реестр при реги страции в ходе установки. Если один и тот же компонент поочередно уста навливается и регистрируется как 32 и 64разрядный, тогда компонент, зарегистрированный последним, переопределяет регистрацию предыдуще го, поскольку оба они пишут по одному адресу в реестре. Чтобы решить эту проблему, не модифицируя 32разрядные компоненты, реестр делится на две части: Native и Wow64. По умолчанию 32разрядные
ГЛАВА 9 Системные механизмы 193 компоненты получают доступ к 32разрядному представлению реестра, а 64 разрядные — к 64разрядному представлению. Это создает безопасную среду исполнения для 32 и 64разрядных компонентов и отделяет состояние 32 разрядных приложений от состояния 64разрядных (если таковые есть). Реализуя это решение, Wow64 перехватывает все системные вызовы, от крывающие разделы реестра, и модифицирует пути к разделам так, чтобы они указывали на контролируемое Wow64 представление реестра. Wow64 разбивает реестр в следующих точках: 쐽 HKLM\Software; 쐽 HKEY_CLASSES_ROOT; 쐽 HKEY_CURRENT_USER\Software\Classes. В каждом из этих разделов Wow64 создает раздел с именем Wow6432 Node. В нем сохраняется конфигурационная информация 32разрядного программного обеспечения. Остальные части реестра 32 и 64разрядные приложения используют совместно (например, HKLM\System). При вызове функций RegOpenKeyEx и RegCreateKeyEx приложения могут передавать следующие флаги: 쐽 KEY_WOW64_64KEY — для явного открытия 64разрядного раздела из 32 или 64разрядного приложения; 쐽 KEY_WOW64_32KEY — для явного открытия 32разрядного раздела из 32 или 64разрядного приложения. Для обеспечения взаимодействия через 32 и 64разрядные COMкомпо ненты Wow64 отражает изменения в некоторых частях одного представле ния реестра на другое. Для этого Wow64 перехватывает операции обновле ния любого из отслеживаемых разделов в одном из представлений и отра жает соответствующие изменения на другое представление. Вот список от слеживаемых разделов: 쐽 HKLM\Software\Classes; 쐽 HKLM\Software\Ole; 쐽 HKLM\Software\Rpc; 쐽 HKLM\Software\COM3; 쐽 HKLM\Software\EventSystem. Wow64 использует интеллектуальный подход к отражению HKLM\Soft ware\Classes\CLSID: транслируются только CLSIDидентификаторы Local Server32, так как они могут быть COMактивированы 32 или 64разрядны ми приложениями, а CLSIDидентификаторы InProcServer32 не отражаются, поскольку 32разрядные COM DLL нельзя загрузить в 64разрядный процесс, равно как и 64разрядные COM DLL в 32разрядный процесс. При отражении раздела или параметра механизм отражения реестра (registry reflector) помечает раздел так, чтобы было понятно, что он создан именно этим механизмом. Это позволяет ему выбирать дальнейший алго ритм действий при удалении отражаемого раздела.
194 ГЛ А В А 3 БЕЗОПАСНОСТЬ Запросы управления вводом-выводом Приложения могут не только выполнять обычные операции чтения и запи си, но и взаимодействовать с некоторыми драйверами устройств через ин терфейс управления вводомвыводом на устройствах, используя APIфунк цию DeviceIoControlFile. При ее вызове можно указать входной и/или выход ной буфер. Если он содержит данные, зависимые от указателя, и процесс, посылающий запрос, является Wow64процессом, тогда у 32разрядного приложения и 64разрядного драйвера разные представления входной и/ или выходной структуры, так как 32разрядные программы используют ука затели длиной 4 байта, а 64разрядные — длиной 8 байтов. В этом случае предполагается, что драйвер режима ядра сам преобразует соответствующие структуры, зависимые от указателей. Чтобы определить, исходит ли запрос от Wow64процесса, драйверы могут вызывать функцию IoIs32bitProcess. 16-разрядные программы установки Wow64 не поддерживает выполнение 16разрядных приложений. Но по скольку многие программы установки являются 16разрядными, в Wow64 предусмотрен специальный код, все же позволяющий выполнять 16разряд ные программы установки общеизвестных приложений. К таким средствам установки, в частности, относятся: 쐽 Microsoft ACME Setup версий 2.6, 3.0, 3.01 и 3.1; 쐽 InstallShield версий 5.x. Всякий раз, когда с помощью APIфункции CreateProcess предпринимается попытка создать 16разрядный процесс, система загружает Ntvdm64.dll и пере дает ей управление, чтобы та определила, относится ли данный 16разрядный исполняемый файл к одной из поддерживаемых программ установки. Если да, то выдается другой вызов CreateProcess, чтобы запустить 32разрядную версию этого установщика с теми же аргументами командной строки. Печать Использовать 32разрядные драйверы принтера в 64разрядной Windows нельзя. Они должны быть 64разрядными версиями, «родными» для данной системы. Однако, поскольку драйверы принтера работают в пользователь ском адресном пространстве запрашивающего процесса, а 64разрядная Windows поддерживает лишь истинно 64разрядные драйверы принтера, ну жен специальный механизм для поддержки печати из 32разрядных процес сов. Для этого все вызовы функций печати перенаправляются в Splwow64.exe — RPCсервер печати Wow64. Так как Splwow64 является 64разрядным про цессом, он может загрузить 64разрядные драйверы принтера. Ограничения Wow64 (в отличие от 32разрядных версий Windows) не поддерживает вы полнение 16разрядных приложений или загрузку 32разрядных драйверов
ГЛАВА 9 Системные механизмы 195 устройств режима ядра (их нужно перевести в истинно 64разрядные). Wow64процессы могут загружать лишь 32разрядные DLL (загрузка истин но 64разрядных DLL невозможна). Аналогичным образом 64разрядные процессы не могут загружать 32разрядные DLL. В дополнение к сказанному Wow64 в системах IA64 изза различий в раз мерах страниц памяти не поддерживает функции ReadFileScatter, WriteFile Gather, GetWriteWatch или Address Window Extension (AWE). Кроме того, Wow64 процессам недоступно аппаратное ускорение операций через DirectX (та ким процессам предоставляется лишь программная эмуляция). Резюме В этой главе мы изучили важнейшие базовые механизмы, на которых пост роена исполнительная система Windows. В следующей главе будут рассмот рены три важных механизма, образующих инфраструктуру управления в Windows: реестр, сервисы и WMI (Windows Management Instrumentation).
Г Л А В А 4 Механизмы управления В этой главе описываются три фундаментальных механизма Microsoft Win dows, критически важных для управления системой и ее конфигурирования: 쐽 реестр; 쐽 сервисы; 쐽 Windows Management Instrumentation (Инструментарий управления Windows). Реестр Реестр играет ключевую роль в конфигурировании и управлении Windows. Это хранилище общесистемных и пользовательских параметров. Реестр не является статичной совокупностью хранящихся на жестком диске данных, как думают многие. Прочитав этот раздел, вы увидите, что он представляет собой окно в мир различных структур, которые хранятся в памяти компью тера и поддерживаются ядром и исполнительной системой. Данный раздел не претендует на роль полного справочника по реестру Windows. Исчерпы вающая информация такого рода для Windows 2000 находится в справочном файле «Technical Reference to the Windows 2000 Registry» (Regentry.chm), ко торый поставляется с ресурсами Windows 2000, а для Windows XP и Windows Server 2003 эта информация доступна через Интернет по ссылке http:// www.microsoft.com/windowsserver2003/techinfo/reskit/deploykit.mspx. Мы начнем с обзора структуры реестра, рассмотрим поддерживаемые им типы данных и ключевую информацию, хранящуюся в реестре Windows. Потом заглянем поглубже внутрь и обсудим механизмы, используемые дис петчером конфигурации — компонентом исполнительной системы, кото рый отвечает за реализацию базы данных реестра. Среди прочего мы кос немся внутренней структуры реестра на диске, способов выборки конфигу рационной информации по запросу приложений и мер защиты этой важ нейшей системной базы данных. Просмотр и изменение реестра Как правило, следует избегать прямого редактирования реестра — приложе ния и система, хранящие в реестре параметры, которые могут потребовать настройки вручную, должны предоставлять соответствующий пользователь
ГЛАВА 9 Механизмы управления 197 ский интерфейс (UI) для их модификации. Однако, как вы уже неоднократно видели в этой книге, для изменения некоторых дополнительных и отладоч ных параметров никакого UI не предусмотрено. Поэтому в Windows включен ряд утилит, позволяющих просматривать и модифицировать реестр. Windows 2000 поставляется с двумя утилитами для редактирования рее стра — Regedit.exe и Regedt32.exe, — тогда как в Windows XP и Windows Server 2003 имеется лишь Regedit.exe. Причина в том, что версия Regedit в Windows 2000 была перенесена из Windows 98 и поэтому не поддерживала редакти рование или просмотр параметров защиты и типов данных, не определен ных в Windows 98. Поэтому в Windows 2000 была добавлена Regedt32, кото рая не обладала развитыми средствами поиска и поддержки импорта/экс порта, но поддерживала параметры защиты и специфичные для Windows 2000 типы данных. Regedit, поставляемая с Windows XP и Windows Server 2003, распознает все типы данных в реестре и позволяет редактировать па раметры защиты, ввиду чего необходимость в Regedt32 отпала. Существует также целый ряд утилит для работы с реестром из командной строки. Например, Reg.exe, включенная в Windows XP и Windows Server 2003 и доступная в Windows 2000 Support Tools, дает возможность импортировать, экспортировать, создавать резервные копии и восстанавливать разделы ре естра, а также сравнивать, модифицировать и удалять разделы и параметры. Использование реестра Конфигурационные данные всегда считываются в следующих случаях. 쐽 В ходе загрузки система читает параметры, указывающие, какие драйве ры устройств нужно загрузить, а различные подсистемы (вроде диспет чера памяти и диспетчера процессов) — параметры, позволяющие им настраивать себя и поведение системы. 쐽 При входе Explorer и другие Windowsкомпоненты считывают из реест ра предпочтения данного пользователя, в том числе буквы подключенных сетевых дисков, размещение ярлыков, а также настройки рабочего сто ла, меню и др. 쐽 При запуске приложения считывают общесистемные параметры, например список дополнительных установленных компонентов, информацию о ли цензировании, настройки для данного пользователя (меню, размещение панелей инструментов, список недавно открывавшихся документов и т. д.). Однако чтение реестра возможно и в другие моменты, скажем, в ответ на модификацию его параметра или раздела. Некоторые приложения ведут мониторинг своих конфигурационных параметров в реестре и считывают обновленные значения, как только обнаруживают изменения. Но в целом, если система простаивает, работы с реестром не должно быть. Реестр обычно модифицируется в следующих ситуациях. 쐽 Исходная структура реестра и многие настройки по умолчанию опреде ляются его прототипной версией, поставляемой на дистрибутиве Win dows и копируемой при установке новой системы.
198 ГЛ А В А 4 БЕЗОПАСНОСТЬ 쐽 Программы установки различных приложений создают для них настрой ки по умолчанию и настройки, отражающие выбор пользователя в про цессе установки. 쐽 При установке драйвера устройства подсистема Plug and Play создает раз делы и параметры в реестре, которые сообщают диспетчеру вводавыво да, как запускать драйвер, а также создает другие параметры, определяю щие работу этого драйвера. (Подробнее об установке драйверов уст ройств см. главу 9.) 쐽 Когда вы изменяете параметры приложения или системы через UI, эти изменения часто сохраняются в реестре. ПРИМЕЧАНИЕ Как ни печально, но некоторые приложения периоди чески опрашивают реестр на предмет изменений, тогда как делать это следует через функцию RegNotifyChangeKey, которая отправляет поток в сон до тех пор, пока в интересующей его части реестра не произой дет какоенибудь изменение. Типы данных в реестре Реестр — это база данных, структура которой аналогична структуре логичес кого тома. Он содержит разделы (keys), напоминающие дисковые каталоги, и параметры (values), которые можно сравнить с файлами на диске. Раздел представляет собой контейнер, содержащий другие разделы, называемые подразделами (subkeys), и/или параметры. Параметры хранят собственно данные. Разделы верхнего уровня называются корневыми. Здесь мы будем использовать термины «подраздел» и «раздел» как синонимы (лишь корне вые разделы не могут быть подразделами). Соглашение об именовании разделов и параметров заимствовано из фай ловой системы. Таким образом, параметру можно присвоить имя, которое сохраняется в какомлибо разделе. Исключением из этой схемы является безымянный параметр, присутствующий в каждом разделе. Утилиты реест ра, Regedit и Regedt32, поразному показывают этот параметр: Regedit обо значает его как (Default) [(По умолчанию)], а Regedt32 — как <No Name> (<БЕЗ ИМЕНИ>). В параметрах хранятся данные 15 типов, перечисленных в таблице 41. Большинство параметров реестра имеет тип REG_DWORD, REG_BINARY или REG_SZ. Параметры типа REG_DWORD содержат числовые или булевы значе ния, параметры типа REG_BINARY — данные, требующие более 32 битов, или произвольные двоичные данные (например зашифрованные пароли), а пара метры типа REG_SZ — строки (естественно, в Unicodeформате), которые могут представлять такие элементы, как имена, пути, типы и имена файлов.
ГЛАВА 9 Механизмы управления 199 Таблица 4-1. Типы параметров реестра Тип параметра Описание REG_NONE Нетипизированный параметр REG_SZ Unicodeстрока фиксированной длины REG_EXPAND_SZ Unicodeстрока переменной длины; может включать переменные окружения REG_BINARY Двоичные данные произвольной длины REG_DWORD 32битное число REG_DWORD_LITTLE_ ENDIAN 32битное число, в котором первым является младший байт; эквивалентно REG_DWORD REG_DWORD_BIG_ ENDIAN 32битное число, в котором первым является старший байт REG_LINK Символьная ссылка в формате Unicode REG_MULTI_SZ Массив Unicodeстрок с завершающим нулем REG_RESOURCE_LIST Описание аппаратного ресурса REG_FULL_RESOURCE_ DESCRIPTOR Описание аппаратного ресурса REG_RESOURCE_ REQUIREMENTS_LIST Список требований к ресурсам REG_QWORD 64битное число REG_QWORD_LITTLE_ ENDIAN 64битное число, в котором первым является младший байт; эквивалентно REG_QWORD REG_QWORD_BIG_ ENDIAN 64битное число, в котором первым является старший байт Особенно интересен тип REG_LINK, поскольку он позволяет разделу ссы латься на другой раздел или параметр. Например, если параметр \Root1\Link содержит значение \Root2\RegKey типа REG_LINK, а параметр RegKey — RegValue, то значение RegValue можно идентифицировать двумя путями: \Root1\Link\RegValue и \Root2\RegKey\RegValue. Как поясняется в следующем разделе, Windows интенсивно использует ссылки в реестре: три из шести корневых разделов реестра представляют собой ссылки на подразделы трех корневых разделов, которые ссылками не являются. Ссылки не записываются на диск, а создаются динамически при каждой загрузке системы. Логическая структура реестра Вы можете проследить схему организации реестра через данные, которые в нем хранятся. Существует шесть корневых разделов (добавлять или удалять корневые разделы нельзя), описанных в таблице 42.
200 ГЛ А В А 4 Таблица 4-2. БЕЗОПАСНОСТЬ Корневые разделы реестра Корневой раздел Описание HKEY_CURRENT_USER Содержит данные, сопоставленные с пользователем, который вошел в систему на данный момент HKEY_USERS Хранит информацию обо всех учетных записях на компьютере HKEY_CLASSES_ROOT Хранит сопоставления файлов и регистрационную информацию COMобъектов HKEY_LOCAL_MACHINE Содержит информацию, специфичную для системы HKEY_PERFORMANCE_ DATA Хранит сведения о производительности HKEY_CURRENT_CONFIG Включает некоторые сведения о текущем профиле оборудования Почему имена корневых разделов начинаются с буквы «Н»? Дело в том, что имена корневых разделов представляют Windowsописатели (Handles) разделов (KEY). Как говорилось в главе 1, HKLM является аббревиатурой HKEY_LOCAL_MACHINE. В таблице 43 приводится список всех корневых разделов и их аббревиатур. Содержимое и предназначение каждого из них подробно обсуждаются в следующих разделах главы. Таблица 4-3. Предназначение корневых разделов реестра Корневой раздел Аббревиатура Описание HKEY_CURRENT_ USER HKCU Ссылается на профиль На подраздел в пользователя, вошедшего HKEY_USERS, соот в систему ветствующий текуще му вошедшему в сис тему пользователю HKEY_USERS HKU Содержит подразделы Не является ссылкой для всех загруженных профилей пользователей HKEY_CLASSES_ ROOT HKCR Содержит сведения о со HKLM\SOFTWARE\ поставлениях файлов Classes и регистрационную информацию COM HKEY_LOCAL_ MACHINE HKLM Контейнер, содержащий Не является ссылкой другие разделы HKCC Текущий профиль обо рудования HKLM\SYSTEM\ CurrentControlSet\ HardwareProfiles\ Current HKPD Счетчики производи тельности Не является ссылкой HKEY_CURRENT_ CONFIG HKEY_PERFOR MANCE_DATA Ссылка HKEY_CURRENT_USER Корневой раздел HKCU содержит данные о предпочтениях и конфигурации программного обеспечения для локально зарегистрированного пользовате
ГЛАВА 9 Механизмы управления 201 ля. Этот раздел ссылается на профиль текущего пользователя, находящийся на жестком диске в файле \Documents and Settings\<имя_пользователя>\ Ntuser.dat (описание файлов реестра см. в разделе «Внутренние механизмы реестра» далее в этой главе). При каждой загрузке профиля пользователя (например, при регистрации в системе или при выполнении сервисного процесса в увязке с именем какоголибо пользователя) HKCU создается как ссылка на подраздел соответствующего пользователя в HKEY_USERS. Неко торые подразделы HKCU перечислены в таблице 44. Таблица 4-4. Подразделы в HKEY_CURRENT_USER Подраздел Описание AppEvents Сопоставления звуковых сигналов с событиями Console Параметры окна командной строки (ширина, высота, цвет и т. д.) Control Panel Текущая экранная заставка, оформление рабочего стола, параметры клавиатуры и мыши, настройки специальных возможностей, а также язык и региональные стандарты Environment Определения переменных окружения Keyboard Layout Раскладки клавиатуры Network Имена и параметры подключенных сетевых дисков Printers Параметры подключения принтеров Software Настройки программ, специфичные для пользователя Программные группы Группы главного меню, специфичные для пользователя Информация о переходе с Windows 3.1 Данные о состоянии файлов для систем, обновляемых с Windows 3.x до Windows 2000 и выше HKEY_USERS HKU содержит подраздел для каждого загруженного профиля пользователя, регистрационную базу данных классов и подраздел HKU\.DEFAULT, связан ный с профилем для системы (этот профиль предназначен для процессов, выполняемых под локальной системной учетной записью; см. раздел «Сер висы» далее в этой главе). Данный профиль используется Winlogon, напри мер, чтобы изменения в параметрах фона рабочего стола были реализова ны на экране входа. Если пользователь входит в систему в первый раз и если его учетная запись не зависит от доменного профиля роуминга (т. е. про филь пользователя извлекается из централизованного хранилища в сети по указанию контроллера домена), система создает профиль для его учетной записи на основе профиля, хранящегося в каталоге C:\Documents and Set tings\Default User. Каталог, где система хранит профили, определяется параметром реестра HKLM\Software\Microsoft\Windows NT\CurrentVersion\ProfileList\ProfilesDi rectory, который по умолчанию устанавливается в %SystemDrive%\Documents and Settings. Раздел ProfileList также хранит список профилей, имеющихся в системе. Информация по каждому профилю помещается в подраздел, имя
202 ГЛ А В А 4 БЕЗОПАСНОСТЬ которого отражает SID учетной записи, соответствующей данному профи лю (сведения о SID см. в главе 8). Информация в разделе профиля включает время последней загрузки этого профиля (параметры ProfileLoadTimeLow и ProfileLoadTimeHigh), двоичное представление SID учетной записи (параметр Sid) и путь к кусту профиля на диске в каталоге ProfileImagePath (о кустах см. раздел «Кусты» далее в этой главе). Windows XP и Windows Server 2003 пока зывают список профилей в диалоговом окне управления профилями пользо вателей, которое представлено на рис. 41. Чтобы открыть это окно, запус тите апплет System (Система) из Control Panel (Панель управления), перей дите на вкладку Advanced (Дополнительно) и в разделе User Profiles (Профи ли пользователей) щелкните кнопку Settings (Параметры). Рис. 4-1. Диалоговое окно User Profiles (Профили пользователей) ЭКСПЕРИМЕНТ: наблюдение за загрузкой и выгрузкой профилей Чтобы увидеть, как профиль загружается в реестр, а потом выгружает ся, запустите командой runas какойнибудь процесс под учетной запи сью пользователя, не вошедшего на данный момент в систему. Пока новый процесс выполняется, запустите Regedit и обратите внимание на загруженный раздел профиля в HKEY_USERS. После завершения процесса нажмите в Regedit клавишу F5 для обновления, и этого про филя в реестре больше не будет. HKEY_CLASSES_ROOT HKCR включает информацию двух типов: сопоставления расширений фай лов и регистрационные данные COMклассов. Для каждого зарегистрирован ного типа файлов существует свой раздел. Большинство разделов содержит
ГЛАВА 9 Механизмы управления 203 параметры типа REG_SZ, ссылающиеся на другие разделы HKCR, где находит ся информация о сопоставлениях классов файлов. Например, HKCR\.xls ссы лается на сведения о файлах Microsoft Excel в разделе HKCU\Excel.Sheet.8 (последняя цифра указывает на версию Microsoft Excel). Другие разделы со держат детальную информацию о конфигурации COMобъектов, зарегист рированных в системе. Раздел HKEY_CLASSES_ROOT формируется на основе: 쐽 специфичных для конкретного пользователя регистрационных данных классов в HKCU\SOFTWARE\Classes (хранятся в \Documents and Settings\ <имя_пользователя>\Local Settings\Application Data\Microsoft\Windows\ Usrclass.dat); 쐽 общесистемных регистрационных данных классов в HKLM\SOFTWARE\ Classes. Причина, по которой регистрационные данные, специфичные для каж дого пользователя, были отделены от общесистемных, заключается в том, что это дает возможность включать соответствующие настройки и в профи ли «блуждающих» пользователей (профили роуминга). Это же устранило дыру в защите: непривилегированный пользователь не может изменить или удалить разделы в HKEY_CLASSES_ROOT и тем самым повлиять на функци онирование приложений в системе. Непривилегированные пользователи и приложения могут считывать общесистемные данные и добавлять новые разделы и параметры в общесистемные данные (которые отражаются на данные, специфичные для этих пользователей), но изменять существующие разделы и параметры им разрешается лишь в собственных данных. HKEY_LOCAL_MACHINE HKLM — корневой раздел, содержащий подразделы с общесистемной конфи гурационной информацией: HARDWARE, SAM, SECURITY, SOFTWARE и SYSTEM. Подраздел HKLM\HARDWARE содержит описание аппаратного обеспече ния системы и все сопоставления драйверов с устройствами. Диспетчер уст ройств, который запускается с вкладки Hardware (Оборудование) окна свойств системы, позволяет просматривать информацию об устройствах, получаемую простым считыванием значений параметров из раздела HARDWARE. ЭКСПЕРИМЕНТ: забавы с разделом Hardware Вы можете обмануть своих коллег или друзей, заставив их поверить в то, что у вас самый последний процессор, модифицировав параметр Pro cessorNameString в разделе HKLM\HARDWARE\DESCRIPTION\System\ Cent ralProcessor\0. Апплет System (Система) отображает значение параметра ProcessorNameString на вкладке General (Общие). Но изменение осталь ных параметров никак не влияет на информацию, выводимую апплетом System, так как система кэширует многие параметры для использования функциями, через которые приложения запрашивают у системы возмож ности установленного на данном компьютере процессора.
204 ГЛ А В А 4 БЕЗОПАСНОСТЬ В HKLM\SAM находится информация о локальных учетных записях и группах, например пароли, определения групп и сопоставления с доменами. Система Windows Server, работающая как контроллер домена, хранит домен ные и групповые учетные записи в Active Directory — базе данных, которая содержит общедоменные параметры и сведения. (Active Directory в этой кни ге не рассматривается.) По умолчанию дескриптор защиты раздела SAM сконфигурирован так, что к нему не имеет доступа даже администратор. В HKLM\SECURITY хранятся данные, которые относятся к общесистем ным политикам безопасности, а также сведения о правах, назначенных поль зователям. HKLM\SAM связан с подразделом SECURITY в разделе HKLM\SE CURITY\SAM. По умолчанию содержимое HKLM\SECURITY недоступно для просмотра, поскольку параметры защиты разрешают доступ только по учет ной записи System. Вы можете сменить дескриптор защиты, чтобы админи страторы получили доступ к этому разделу для чтения, или, если вам любо пытно, что там находится, запустить Regedit под локальной системной учет ной записью с помощью PsExec (как это сделать, будет показано в соответ ствующем эксперименте). Но это почти ничего не даст, так как данные в нем не документированы, а пароли зашифрованы (по алгоритму необратимого шифрования). HKLM\SOFTWARE — то место, где Windows хранит общесистемную кон фигурационную информацию, не требуемую при загрузке системы. Кроме того, здесь сохраняют свои общесистемные настройки приложения сторон них разработчиков (пути к файлам, каталоги приложений, даты лицензий и сроки их окончания). HKLM\SYSTEM содержит общесистемную конфигурационную информа цию, необходимую для загрузки системы, например списки загружаемых драйверов и запускаемых сервисов. Поскольку эта информация критична для запуска системы, Windows делает ее копию, называемую последней удач ной конфигурацией (last known good control set). Она позволяет вернуться к последней работоспособной конфигурации, если после изменений, вне сенных в текущую конфигурацию, система перестала загружаться. Подроб нее об этом — ближе к концу главы. HKEY_CURRENT_CONFIG HKEY_CURRENT_CONFIG — просто ссылка на текущий профиль оборудова ния, хранящийся в HKLM\SYSTEM\CurrentControlSet\Hardware Profiles\Cur rent. Профили оборудования позволяют администратору изменять базовые настройки системных драйверов. Хотя реальный профиль может меняться от загрузки к загрузке, благодаря разделу HKCC приложения всегда имеют дело с текущим активным профилем. Управление профилями оборудования осу ществляется через диалоговое окно Hardware Profiles (Профили оборудова ние), которое открывается кнопкой Settings (Профили оборудования) в одно именном разделе на вкладке Hardware (Оборудование) в апплете System. При загрузке Ntldr предложит указать, какой профиль вам нужен, если он не один.
ГЛАВА 9 Механизмы управления 205 HKEY_PERFORMANCE_DATA Реестр также является механизмом, который в Windows обеспечивает дос туп к значениям счетчиков производительности. При этом не важно, предо ставлены счетчики компонентами операционной системы или серверными приложениями. Одна из дополнительных выгод обращения к счетчикам производительности через реестр — возможность удаленного мониторин га рабочих характеристик без лишних издержек, поскольку удаленный дос туп к реестру легко получить через обычные APIфункции реестра. Обратиться напрямую к этим данным можно только программным путем через Windowsфункции реестра типа RegQueryValueEx, открыв специальный раздел с именем HKEY_PERFORMANCE_DATA. Доступ к разделу HKPD из ре дактора реестра невозможен — здесь хранится не сама информация о про изводительности, а ссылки на соответствующие источники этих данных. Информация, относящаяся к счетчикам производительности, доступна и через функции Performance Data Helper (PDH), предоставляемые Performance Data Helper API (Pdh.dll). Компоненты, используемые для получения значе ний счетчиков производительности, показаны на рис. 42. Рис. 4-2. Архитектура доступа к информации счетчиков производительности Анализ и устранение проблем с реестром Поскольку система и приложения сильно зависят от конфигурационных параметров, изменение данных в реестре может вызвать их сбои. Когда сис теме или приложению не удается считать параметры, которые, как предпо лагается, всегда доступны, это программное обеспечение может рухнуть и при этом выводить сообщения об ошибках, скрывающие корень проблемы. Не понимая, как сбоящая система или программа обращается к реестру, практически невозможно выяснить, какие разделы или параметры реестра
206 ГЛ А В А 4 БЕЗОПАСНОСТЬ сконфигурированы неправильно. В такой ситуации ответ может дать утили та Regmon с сайта www.sysinternals.com. Regmon позволяет наблюдать за обращениями к реестру. При этом Reg mon выводит информацию о процессе, обращающемся к реестру, а также сообщает время, тип и результат доступа. Эти сведения полезны для того, чтобы увидеть, как приложения и система взаимодействуют с реестром, най ти места хранения конфигурационных параметров, записываемых приложе ниями и системой, и устранить неполадки, связанные с отсутствием каких либо разделов или параметров реестра. Regmon включает расширенные средства фильтрации и выделения информации, чтобы вы могли сосредо точиться на операциях над выбранными разделами или параметрами, либо операциях, выполняемых конкретными процессами. Как работает Regmon Утилита Regmon полагается на драйвер устройства, который она извлекает из своего исполняемого образа и запускает в период своего выполнения. При первом запуске она требует, чтобы в учетной записи, под которой она выполняется, были привилегии Load Driver и Debug; при последующих запус ках в том же сеансе загрузки системы достаточно одной привилегии Debug, так как драйвер является резидентным. На самом деле внутри исполняемого файла Regmon хранится три драй вера: один — для Windows 95, Windows 98 и Windows Millennium, другой — для Windows NT, Windows 2000 и Windows XP, а третий — для Windows Server 2003. Почему драйвер для Windows Server 2003 отделен от драйвера для ана логичных систем? А потому, что в Windows NT, Windows 2000 и Windows XP единственный способ, которым драйвер может вести мониторинг всех опе раций с реестром — перехват системных вызовов (systemcall hooking), и потому, что в Windows Server 2003 драйвер может использовать с той же це лью механизм обратного вызова реестра (registry callback mechanism). (Win dows 95, Windows 98 и Windows Millennium поддерживают другой механизм мониторинга реестра.) Вспомните раздел «Диспетчеризация системных сервисов» главы 3 — там говорилось, что адреса функций системных сервисов хранятся в диспетчер ской таблице системных сервисов в ядре. Драйвер может обнаруживать вы зов системного сервиса, сохранив адрес соответствующей функции из мас сива и заменив этот элемент массива адресом своей функцииловушки (hook function). После этого любые вызовы данного сервиса поступают в функ циюловушку, установленную драйвером, и эта функция может проверять или модифицировать параметры вызова, а при необходимости и выполнять исходную функцию системного сервиса. Если функцияловушка вызывает исходную функцию, драйвер также получает возможность изучить резуль тат операции и возвращаемые ею данные, например значения параметров реестра. На рис. 43 показано, как Regmon перехватывает вызовы функций реестра в режиме ядра.
ГЛАВА 9 Рис. 4-3. Механизмы управления 207 Так Regmon использует перехват системных сервисов Механизм обратного вызова реестра впервые появился в Windows XP; однако Regmon попрежнему использует перехват системных вызовов (sys temcall hooking), работая в Windows XP, потому что в ней этот механизм сообщает не обо всех операциях с реестром. Используя механизм обратно го вызова, драйвер регистрирует в диспетчере конфигурации функцию об ратного вызова. Диспетчер конфигурации запускает функции обратного вызова, установленные драйвером, в определенные моменты выполнения системных сервисов реестра, чтобы драйвер видел все обращения к реест ру и мог их контролировать. Этот механизм используют антивирусные про граммы, которые сканируют данные реестра или блокируют неавторизован ным процессам доступ к реестру для записи. ЭКСПЕРИМЕНТ: анализ операций с реестром в простаивающей системе Поскольку реестр реализует функцию RegNotifyChangeKey, с помощью которой приложения могут запрашивать уведомление об изменениях в реестре, не опрашивая его постоянно, в простаивающей системе Regmon не должен обнаруживать повторяющиеся обращения к одним и тем же разделам или параметрам реестра. Любая такая активность указывает на плохо написанное приложение, которое отрицательно влияет на общую производительность системы. Запустите Regmon и через несколько секунд изучите журнал вывода, чтобы выяснить, не пытается ли какаято программа постоянно опраши вать реестр. Найдя в выводе строку, связанную с опросом, щелкните ее правой кнопкой мыши и выберите из контекстного меню команду Process Properties, чтобы узнать, какой процесс занимается такой деятельностью.
208 ГЛ А В А 4 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: поиск параметров приложения в реестре с помощью Regmon Иногда при анализе проблем нужно определить, где в реестре хранят ся те или иные параметры системы или приложения. В этом экспери менте вы используете Regmon для поиска параметров Notepad (Блок нот). Notepad, как и большинство Windowsприложений, сохраняет пользовательские предпочтения (например, включение режима пере носа строк, выбранный шрифт и его размер, позиция окна) между за пусками. Наблюдая с помощью Regmon, когда Notepad считывает или записывает свои параметры, вы сможете выявить раздел реестра, в котором хранятся эти параметры. Вот как это делается. 1. Пусть Notepad сохранит какойнибудь параметр, который вы лег ко найдете в трассировочном выводе Regmon. Для этого запустите Notepad, выберите шрифт Times New Roman и закройте Notepad. 2. Запустите Regmon. Откройте диалоговое окно фильтра выделения информации и введите notepad.exe в фильтре Include. Тогда Reg mon будет протоколировать только активность notepad.exe в столб це Process или Path. 3. Снова запустите Notepad и остановите в Regmon перехват событий, просто выбрав командупереключатель Capture Events в меню File утилиты Regmon. 4. Прокрутите полученный журнал к верхней строке и выберите ее. 5. Нажмите Ctrl+F, чтобы открыть диалоговое окно Find, и введите строку поиска times new. Regmon должен выделить строку вроде показанной на следующей иллюстрации. Остальные операции в непосредственной близости должны относиться к другим парамет рам Notepad. 6. Наконец, дважды щелкните выделенную строку. Regmon запустит Regedit (если он еще не выполняется) и заставит его перейти к со ответствующему параметру реестра.
ГЛАВА 9 Механизмы управления 209 Методики анализа проблем с применением Regmon Выявить причины сбоев приложения или системы, связанные с реестром, позволяют две базовые методики анализа с использованием Regmon. 쐽 Найдите в трассировке Regmon последнее, что делало приложение перед сбоем. Это может указать на источник проблемы. 쐽 Сравните трассировку Regmon для сбойного приложения с аналогичной трассировкой в работающей системе. При первом подходе запустите сначала Regmon, затем приложение. В момент сбоя вернитесь в Regmon и остановите протоколирование (нажав Ctrl+E). Прокрутите журнал до конца и найдите последние операции, выпол нявшиеся приложением перед сбоем (крахом, зависанием или чемто еще). Начните с последней строки и изучайте, на какие файлы и/или разделы ре естра были ссылки, — это часто помогает локализовать источник проблемы. Второй подход полезен, когда приложение сбоит в одной системе, но работает в другой. Создайте в Regmon журналы трассировки приложения в сбойной и работающей системе, потом откройте их в Microsoft Excel (согла ситесь с параметрами по умолчанию, предлагаемыми мастером импорта) и удалите первые три столбца. (Если вы их не удалите, сравнение покажет, что все строки различаются, так как в первых трех столбцах содержится инфор мация, которая меняется между запусками.) Наконец, сравните полученные файлы журналов. (Для этого можно использовать и утилиту WinDiff, которая в Windows XP включена в дистрибутив как один из бесплатных инструмен тов, а для Windows 2000 предлагается в составе ресурсов.) Вы должны обратить особое внимание на записи в трассировке Regmon со значениями «NOTFOUND» или «ACCESS DENIED» в столбце Result. NOTFO UND сообщается, когда приложение пыталось обратиться к несуществующе му разделу или параметру реестра. Во многих случаях отсутствующий раз дел или параметр — вещь безобидная, так как процесс, не сумевший обна ружить искомое в реестре, просто использует значения по умолчанию. Но для некоторых параметров нет значений по умолчанию, и поэтому прило жения сбоят, не найдя их в реестре. Ошибки, связанные с отказом в доступе, — частая причина сбоев прило жений; такие ошибки возникают, когда у приложения нет разрешения на доступ к нужному разделу реестра. Это касается приложений, в которых не проверяются результаты операций с реестром или не предусматривается восстановление после соответствующих ошибок. Также подозрительна строка со значением «BUFROVERFLOW». Она не ука зывает на наличие в приложении эксплойта (exploit), использующего пере полнение буфера. Такое значение посылается диспетчером конфигурации программе, которая выделила под буфер для хранения параметра реестра слишком мало места. Разработчики приложений часто пользуются этим, чтобы определить, какой буфер надо выделить для хранения того или ино го значения. Сначала выполняется запрос к реестру с буфером нулевой дли ны и в ответ поступает сообщение с ошибкой переполнения буфера и ис
210 ГЛ А В А 4 БЕЗОПАСНОСТЬ тинным размером данных. Тогда программа создает буфер указанного раз мера и повторно считывает данные. Поэтому вы должны обнаружить опера ции, которые возвращают BUFROVERFLOW и при повторной попытке дают успешный результат. Вот один из примеров использования Regmon для анализа реальной про блемы. Эта утилита избавила пользователя от полной переустановки Win dows XP. Симптом был таким: Internet Explorer зависал при запуске, если пользователь предварительно не устанавливал вручную соединение с Интер нетом. Оно было задано как соединение по умолчанию, поэтому запуск Internet Explorer должен бы вызывать автоматическое подключение к Ин тернету (Internet Explorer был настроен на отображение начальной страни цы по умолчанию при запуске). Изучение журнала Regmon для операций Internet Explorer при запуске, начиная с того места, где Internet Explorer зависал, позволило обнаружить запрос, адресованный разделу в HKCU\Software\Microsoft\RAS Phonebook. Пользователь сообщил, что ранее он удалил средство набора телефонных номеров, сопоставленное с этим разделом, и вручную создал соединение по коммутируемой линии. Поскольку имя такого соединения не совпадало с именем удаленной программы, получалось, что соответствующий раздел не был удален программой удаления средства набора телефонных номеров и что именно это было причиной зависания Internet Explorer. После удаления этого раздела Internet Explorer стал работать нормально. Протоколирование операций под непривилегированными учетными записями или во время входа/выхода Нередко наблюдается следующая ситуация. Приложение работает при вы полнении под учетной записью, входящей в группу Administrators (Админи страторы), и сбоит при запуске под учетной записью непривилегированного пользователя. Как уже говорилось, Regmon требует привилегий, которые обычно не выдаются стандартным учетным записям пользователей, но вес ти трассировку приложений, выполняемых в сеансе входа непривилегиро ванного пользователя, все же можно. Для этого запустите Regmon под адми нистративной учетной записью командой runas. Если проблема с реестром относится ко входу или выходу по учетной записи, вы также должны предпринять особые меры, чтобы использовать Regmon для трассировки этих этапов сеанса входа. Приложения, выполняе мые под системной учетной записью, не завершаются при выходе пользо вателя, и благодаря этому вы можете работать с Regmon, несмотря на выход текущего пользователя и последующий вход того же или другого пользова теля. Чтобы запустить Regmon под системной учетной записью, введите ко манду at, встроенную в Windows, и укажите флаг /interactive или запустите утилиту PsExec с сайта www.sysinternals.com, например так: psexec i s d c:\regmon.exe
ГЛАВА 9 Механизмы управления 211 Ключ –i сообщает PsExec, что окно Regmon должно появиться в интерак тивной консоли, ключ –s заставляет PsExec запустить Regmon под систем ной учетной записью, а ключ –d указывает PsExec запустить Regmon и завер шиться, не дожидаясь закрытия Regmon. После этой команды данный экзем пляр Regmon переживет выход пользователя, и его окно вновь появится на рабочем столе, когда ктото войдет в систему; при этом он будет протоко лировать активность в реестре в обоих случаях. Еще один способ мониторинга активности в реестре во время входа, вы хода, загрузки системы или ее выключения — использовать функцию Reg mon для протоколирования с момента загрузки системы. Для этого вы дол жны выбрать Log Boot в меню Options. При следующем запуске системы драйвер устройства Regmon будет протоколировать активность в реестре с самых ранних этапов загрузки, записывая информацию в журнал \Windows\ Regmon.log. Протоколирование будет продолжаться до тех пор, пока не за кончится свободное место на диске, пока система не будет выключена или пока вы не запустите Regmon. Файл журнала, хранящий трассировку опера ций над реестром при загрузке, входе, выходе и выключении системы Win dows XP, обычно занимает 50–150 Мб. Внутренние механизмы реестра Из этого раздела вы узнаете, как диспетчер конфигурации (компонент ис полнительной системы, реализующий реестр) организует файлы реестра на диске. Мы исследуем, как диспетчер конфигурации управляет реестром по мере его чтения и изменения приложениями и другими компонентами сис темы. Мы также обсудим механизмы, с помощью которых диспетчер конфи гурации позволяет восстанавливать реестр, даже если система рухнула не посредственно в ходе внесения в него изменений. Кусты Реестр представлен на диске не просто одним большим файлом, а набором отдельных файлов, называемых кустами (hives). В каждом кусте содержит ся дерево реестра, у которого есть раздел, служащий корнем, или начальной точкой, дерева. Подразделы с их параметрами находятся под корнем. Воз можно, вы подумали, что корневые разделы, показываемые редактором ре естра, соответствуют корневым разделам кустов, но это не так. В табли це 45 перечислены кусты реестра и имена их файлов на диске. Полные име на всех файлов кустов (вместе с путями), кроме относящихся к профилям пользователей, жестко определяются самим диспетчером конфигурации. При загрузке кустов диспетчер конфигурации отмечает путь к каждому кус ту в подразделе HKLM\SYSTEM\CurrentControlSet\Control\Hivelist и удаляет пути к выгруженным из памяти кустам. (Профили пользователей выгружа ются в отсутствие ссылок на них.) Для формирования привычной структу ры реестра, отображаемой редактором реестра, диспетчер конфигурации создает корневые разделы и связывает кусты друг с другом.
212 ГЛ А В А 4 Таблица 4-5. БЕЗОПАСНОСТЬ Дисковые файлы, соответствующие путям в реестре Путь к кусту в реестре Путь к файлу куста HKEY_LOCAL_MACHINE\SYSTEM \Windows\System32\Config\System HKEY_LOCAL_MACHINE\SAM \Windows\System32\Config\Sam HKEY_LOCAL_MACHINE\SECURITY \Windows\System32\Config\Security HKEY_LOCAL_MACHINE\SOFTWARE \Windows\System32\Config\Software HKEY_LOCAL_MACHINE\HARDWARE Изменяемый (volatile) куст HKEY_LOCAL_MACHINE\SYSTEM\Clone Изменяемый куст (только в Windows 2000) HKEY_USERS\<SID_для_пользователя> \Documents and Settings\ <имя_ пользова теля>\Ntuser.dat HKEY_USERS\<SID_для_пользователя> _Classes \Documents and Settings\ <имя_пользователя>\Local Settings\ Application Data\Microsoft\Windows\ Usrclass.dat HKEY_USERS\.DEFAULT \Windows\System32\Config\Default Заметьте, что некоторые кусты, перечисленные в таблице 45, являются изменяемыми и не имеют сопоставленных файлов. Система создает и мани пулирует такими кустами только в памяти, поэтому они существуют лишь временно. Изменяемые кусты создаются при каждой загрузке системы. При мер подобного куста — HKLM\HARDWARE, в котором хранятся сведения о физических устройствах и назначенных им ресурсах. Распознавание обору дования и распределение ресурсов происходят при каждой загрузке систе мы, поэтому было бы нелогично хранить данные этого куста на диске. ЭКСПЕРИМЕНТ: загрузка и выгрузка кустов вручную Regedt32 в Windows 2000 и Regedit в Windows XP или Windows Server 2003 позволяют загружать кусты, к которым можно обращаться через меню File этих редакторов реестра. Такая возможность полезна при анализе проблем, когда нужно просмотреть или отредактировать куст, получен ный с незагружаемой системы или из резервной копии. В этом экспери менте вы используете Regedt32 (при наличии Windows 2000) или Regedit (при наличии Windows XP или Windows Server 2003) для загрузки версии куста HKLM\SYSTEM, создаваемой программой Windows Setup и сохра няемый в каталоге \Windows\Repair в ходе установки. 1. Кусты можно загружать только в HKLM или HKU, поэтому открой те Regedit или Regedt32, укажите HKLM, а затем выберите Load Hive (Загрузить куст) из меню File (Файл) в Regedit или из меню Registry (Реестр) в Regedt32. 2. Перейдите в каталог \Windows\Repair в диалоговом окне Load Hive (Загрузить куст), выберите System.bak и откройте его. При запросе введите Test в качестве имени раздела, в который будет загружать ся этот куст.
ГЛАВА 9 Механизмы управления 213 3. Откройте только что созданный раздел HKLM\Test и изучите содер жимое куста. 4. Откройте HKLM\System\CurrentControlSet\Control\Hivelist и найди те элемент \Registry\Machine\Test, который продемонстрирует, как диспетчер конфигурации перечисляет загруженные кусты в разде ле HiveList. 5. Укажите HKLM\Test и выберите Unload Hive (Выгрузить куст) из меню File в Regedit или из меню Registry в Regedt32 для выгрузки этого куста. Лимиты на размеры кустов В некоторых случаях размеры кустов ограничиваются. Например, Windows ограничивает размер куста HKLM\SYSTEM. Это делается изза того, что Ntldr считывает весь куст HKLM\SYSTEM в физическую память почти в самом на чале процесса загрузки, когда поддержки виртуальной памяти еще нет. Кро ме того, Ntldr загружает в физическую память Ntoskrnl и драйверы устройств периода загрузки. (Подробнее о роли Ntldr в процессе загрузки см. главу 6.) В Windows 2000 Ntldr устанавливает фиксированный верхний предел на раз мер этого куста в 12 Мб, но в Windows XP и Windows Server 2003 тот же куст может быть размером до 200 Мб или до четверти объема физической памя ти, установленной в системе (в зависимости от того, какой предел будет до стигнут раньше). В Windows 2000 также существует лимит на общий размер всех загружен ных кустов. Она использует для хранения кустов реестра пул подкачиваемой памяти, и поэтому общий объем загруженных данных реестра ограничен до ступным размером этого пула. При инициализации диспетчер памяти опре деляет его размер на основе целого ряда факторов, в том числе объема фи зической памяти в системе. В системе, где диспетчер памяти создает самый большой из возможных пул подкачиваемой памяти, размер реестра ограни чен 376 Мб. Поскольку система не сможет эффективно работать, если пула подкачиваемой памяти будет недостаточно для других целей, Windows 2000 не позволит данным реестра занять более 80% этого пула. Для просмотра или модификации ограничения на размер реестра, как показано на рис. 44, щел кните кнопку Change (Изменить) в разделе Virtual Memory (Виртуальная па мять) диалогового окна Performance Options (Параметры быстродействия), доступного с вкладки Advanced (Дополнительно) окна свойств системы. Лимит на общий размер загруженных кустов реестра может привести к ограничению числа пользователей, одновременно входящих в систему Win dows 2000 с Terminal Services, поскольку каждый профиль пользователя уве личивает размер загруженных кустов. В Windows XP и Windows Server 2003 диспетчер конфигурации использует не пул подкачиваемой памяти, а функ ции проецирования в системную память, предоставляемые диспетчером памяти. При этом проецируются лишь те части кустов реестра, к которым происходят обращения в данный момент времени. Ограничений на размер
214 ГЛ А В А 4 БЕЗОПАСНОСТЬ реестра в Windows XP или Windows Server 2003 нет, и общий размер загру женных кустов не сказывается на масштабируемости Terminal Services. Рис. 4-4. Задание лимита на размер реестра в Windows 2000 ЭКСПЕРИМЕНТ: просмотр описателей кустов Диспетчер конфигурации открывает кусты, используя таблицу описа телей режима ядра (см. главу 3), поэтому он может обращаться к ним из контекста любого процесса. Применение такой таблицы — эффек тивная альтернатива подходу, основанному на использовании драйве ров или компонентов исполнительной системы для простого обраще ния из системных процессов к одним лишь описателям (которые дол жны быть защищены от пользовательских процессов). Просмотреть описатели кустов можно с помощью утилиты Process Explorer (www.sys internals.com). В Windows 2000 диспетчер объектов сообщает об опи сателях из таблицы как об открытых в системном процессе System Idle, а в Windows XP и Windows Server 2003 он показывает описатели как открытые в процессе System. Укажите нужный процесс и выберите Handles из подменю Lower Pane View в меню View. Задайте сортиров ку по типу описателя и прокручивайте список, пока не увидите фай лы кустов, как на следующей иллюстрации.
ГЛАВА 9 Механизмы управления 215 Особый тип разделов, символьная ссылка (symbolic link), позволяет дис петчеру конфигурации связывать кусты для организации реестра. Символь ная ссылка — это раздел, который переадресует диспетчер конфигурации к другому разделу. Так, раздел HKLM\SAM представляет собой символьную ссылку на раздел в корне куста SAM. Структура куста Диспетчер конфигурации делит куст на логические единицы, называемые блоками (blocks), по аналогии с тем, как файловая система делит диск на кла стеры. По определению размер блока реестра составляет 4096 байтов (4 Кб). Размер куста увеличивается кратно размеру блоков. Первый блок куста назы вается базовым (base block); он включает глобальную информацию о кусте, в том числе сигнатуру regf, идентифицирующую файл как куст, порядковые но мера, метку времени последней записи в куст, номер версии формата, конт рольную сумму и внутреннее имя файла куста (например, \Устройство\Раз дел_жесткого_диска1\WINDOWS\SYSTEM32\Config\SAM). Мы поясним смысл порядковых номеров и метки времени, когда будем рассматривать механизм записи данных в файл куста. Номер версии формата указывает формат дан ных куста. В Windows 2000 диспетчер конфигурации использует формат дан ных куста версии 1.3. В Windows XP и Windows Server 2003 применяется тот же формат данных для совместимости с профилями роуминга Windows 2000, но для кустов System и Software используется формат версии 1.5, обеспечива ющий более эффективный поиск, а также хранение больших значений. Windows упорядочивает хранимые в кусте данные с помощью контейне ров, которые называются ячейками (cells). Ячейка может содержать раздел, параметр, дескриптор защиты, список подразделов или параметров раздела. Поле в начале ячейки описывает тип ее данных. Все типы данных поясняют ся в таблице 46. Размер ячейки указывается в ее заголовке. Когда ячейка при соединяется к кусту, последний должен быть соответственно увеличен. Для этого система создает блок, называемый приемником (bin). Размер приемни ка равен размеру ячейки, округленному до ближайшего большего значения, кратного размеру блока. Пространство между концом ячейки и концом при
216 ГЛ А В А 4 БЕЗОПАСНОСТЬ емника считается свободным, и система может помещать в него другие ячей ки. Приемники тоже имеют заголовки, но с сигнатурой hbin, и поле, в кото рое записывается размер приемника и его смещение в файле куста. Таблица 4-6. Типы данных в ячейках Тип данных Описание Ячейка раздела (key cell) Ячейка, содержащая раздел реестра; также называется узлом раздела (key node). Включает сигнатуру (kn — раз дел, kl — символьная ссылка), метку времени последнего обновления, имя раздела (например, CurrentControlSet) и следующие индексы: родительской ячейки того же ти па, ячейки списка подразделов данного раздела, ячейки дескриптора защиты раздела и строки с именем класса раздела Ячейка параметра (value cell) Ячейка, содержащая информацию о параметре раздела. Включает сигнатуру kv, тип параметра (например, REG_ DWORD или REG_BINARY) и его имя (скажем, BootExe cute). Ячейка этого типа также содержит индекс ячейки с данными параметра Ячейка списка подраз делов (subkeylist cell) Ячейка, состоящая из списка индексов для ячеек разде лов, которые являются подразделами общего родитель ского раздела Ячейка списка парамет ров (valuelist cell) Ячейка, состоящая из списка индексов для ячеек пара метров, которые являются параметрами общего роди тельского раздела Ячейка дескриптора защиты (securitydescrip tor cell) Ячейка с дескриптором защиты. Включает сигнатуру (ks) и счетчик ссылок, регистрирующий число узлов разде лов, использующих этот дескриптор. Ячейки разделов могут совместно использовать ячейки дескрипторов защиты Используя для отслеживания активных частей реестра приемники вместо ячеек, Windows упрощает себе управление реестром. Так, система обычно со здает и удаляет приемники реже, чем ячейки, а это позволяет диспетчеру кон фигурации эффективнее управлять памятью. Считывая куст в память, диспет чер конфигурации может выбирать только приемники, содержащие ячейки (т. е. активные приемники), и игнорировать пустые (удаленные). В результа те добавления или удаления ячеек куст может содержать пустые приемники вперемешку с активными. Такая ситуация напоминает фрагментацию диска, возникающую при создании и удалении файлов. Когда приемник становится пустым, диспетчер конфигурации объединяет его со смежными пустыми при емниками, формируя непрерывный пустой приемник как можно большего размера. Диспетчер конфигурации также объединяет смежные пустые ячей ки для формирования свободных ячеек большего размера. (Диспетчер конфи гурации уплотняет куст, только когда приемники в конце куста освобождают ся. Вы можете уплотнить реестр за счет его резервного копирования и пос ледующего восстановления с помощью Windowsфункций RegSaveKey и Reg ReplaceKey, используемых утилитой Windows Backup.)
ГЛАВА 9 Механизмы управления 217 Ссылки, образующие структуру куста, называются индексами ячеек (cell indexes). Индекс ячейки представляет собой ее смещение в файле куста. Та ким образом, он похож на указатель из одной ячейки на другую и интерпре тируется диспетчером конфигурации относительно начала куста. Например, как видно из таблицы 46, ячейка раздела содержит поле с индексом ячейки родительского раздела; индекс ячейки подраздела указывает на ячейку со списком подчиненных ему подразделов. Ячейка списка подразделов содер жит список индексов, ссылающихся на ячейки подчиненных подразделов. Поэтому если вам нужно найти, скажем, ячейку раздела для подраздела А, родительским разделом которого является раздел В, вы должны сначала най ти ячейку со списком подразделов раздела В по ее индексу в ячейке раздела В. После этого с помощью списка индексов из ячейки списка подразделов раздела В можно отыскать ячейки любых подразделов раздела В. При этом для каждой ячейки подраздела вы проверяете, не совпадает ли хранящееся там имя раздела с именем искомого (в данном случае — А). Ячейки, приемники и блоки можно легко перепутать, поэтому для про яснения различий между ними обратимся к структуре простого куста реес тра. Образец файла куста реестра, схема которого показана на рис. 45, вклю чает в себя базовый блок и два приемника. Первый приемник пуст, а во вто ром есть несколько ячеек. Логично, что в таком кусте может быть всего два раздела: корневой Root и его подраздел, Sub Key. В Root находятся два пара метра: Val 1 и Val 2. Ячейка списка подразделов определяет местонахожде ние подразделов корневого раздела, а ячейка списка параметров — адрес параметров корневого раздела. Свободные промежутки во втором приемни ке являются пустыми ячейками. Учтите, что на схеме не показаны ячейки дескрипторов защиты для двух разделов, которые должны присутствовать в составе куста. Рис. 4-5. Внутренняя структура куста реестра На рис. 46 показано окно утилиты Disk Probe (Dskprobe.exe) с образцом содержимого первого приемника куста SYSTEM. Обратите внимание на сиг натуру приемника, hbin. Под ней можно увидеть сигнатуру nk. Это сигнатура ячейки раздела (kn). Обратный порядок отображения сигнатуры определяется
218 ГЛ А В А 4 БЕЗОПАСНОСТЬ порядком хранения данных в системах типа x86. Ячейка, которой диспетчер конфигурации присвоил внутреннее имя $$$PROTO.HIV, является корневой ячейкой куста SYSTEM, как указывает следующее за сигнатурой nk имя. Рис. 4-6. Двоичное содержимое первого приемника в кусте SYSTEM Для оптимизации поиска подразделов и параметров диспетчер конфигу рации сортирует ячейки списков подразделов в алфавитном порядке. Если нужно найти подраздел в списке, диспетчер использует двоичный поиск. При этом он сразу обращается в середину списка. Если искомое имя в соот ветствии с алфавитным порядком находится перед разделами из середины списка, диспетчер узнает, что оно хранится в первой половине списка. В ином случае оно должно быть во второй половине списка подразделов. И так до тех пор, пока диспетчер не найдет искомый подраздел или не обнаружит его отсутствие. Ячейки списков параметров не сортируются, так что новые параметры всегда добавляются в конец списка. Карты ячеек Диспетчер конфигурации не обращается к файлам кустов на диске при каж дом обращении к реестру. Windows хранит в адресном пространстве ядра версию каждого куста. При инициализации куста диспетчер конфигурации определяет размер его файла, выделяет из подкачиваемого пула нужный объем памяти и считывает файл куста в память (о пуле подкачиваемой па мяти см. главу 7). Поскольку все загруженные кусты реестра хранятся в под качиваемом пуле, в Windows 2000 они, как правило, занимают его наиболь шую часть. (Для исследования этого пула используйте утилиту Poolmon, опи сываемую в одном из экспериментов главы 7.)
ГЛАВА 9 Механизмы управления 219 В Windows XP и Windows Server 2003 диспетчер конфигурации проеци рует части куста в память по мере того, как возникает необходимость в дос тупе к ним. При этом он обращается к функциям проецирования файлов в диспетчере кэша для отображения 16килобайтных представлений на фай лы кустов (о диспетчере кэша см. главу 10). Чтобы проекция куста не заняла весь адресный диапазон диспетчера кэша, диспетчер конфигурации пыта ется хранить не более 256 представлений куста в любой момент времени, отменяя проецирование реже всего используемых представлений по дости жении этого предела. Диспетчер конфигурации попрежнему использует подкачиваемый пул для хранения различных структур данных, но занимает в нем лишь малую часть по сравнению с Windows 2000. ПРИМЕЧАНИЕ В Windows XP и Windows Server 2003 диспетчер кон фигурации сохраняет блок в подкачиваемом пуле вместо его проеци рования, если размер этого блока превышает 256 Кб. Если бы размер кустов никогда не увеличивался, диспетчер конфигура ции мог бы выполнять все операции с копией реестра в памяти, как с обык новенным файлом. Зная индекс ячейки, диспетчер конфигурации мог бы вычислить ее адрес в памяти, просто сложив индекс ячейки, представляю щий смещение в файле куста, с базовым адресом копии куста в памяти. Именно так и поступает Ntldr с кустом SYSTEM на ранних этапах загрузки: он полностью считывает его в память как неизменяемый и для поиска нуж ных ячеек суммирует их индексы с базовым адресом копии куста в памяти. К сожалению, по мере появления новых разделов и параметров кусты раз растаются, а это означает, что система должна выделять дополнительную память из подкачиваемого пула для хранения новых приемников с добавля емыми разделами и параметрами. Так что данные реестра не обязательно хранятся в непрерывной области подкачиваемой памяти. ЭКСПЕРИМЕНТ: наблюдение за использованием пула подкачиваемой памяти для кустов реестра Административных утилит, которые показывали бы объем памяти из подкачиваемого пула, используемой кустами реестра вместе с профи лями пользователей, в Windows 2000 нет. Однако команда !reg dump pool отладчика ядра сообщает не только число страниц, задействован ных каждым загруженным кустом, но и количество страниц, занятых постоянными и переменными данными. В конце отчета команда вы водит суммарный объем памяти, занятой кустами реестра. (Учтите, что эта команда показывает лишь последние 32 символа в имени куста.) kd> !reg dumppool dumping hive at e20d66a8 (a\Microsoft\Windows\UsrClass.dat) Stable Length = 1000 1/1 pages present Volatile Length = 0 см. след. стр.
220 ГЛ А В А 4 БЕЗОПАСНОСТЬ dumping hive at e215ee88 (ettings\Administrator\ntuser.dat) Stable Length = f2000 242/242 pages present Volatile Length = 2000 2/2 pages present dumping hive at e13fa188 (\SystemRoot\System32\Config\SAM) Stable Length = 5000 5/5 pages present Volatile Length = 0 ... ЭКСПЕРИМЕНТ: наблюдение за использованием памяти кустами В Windows XP и Windows Server 2003 статистику по использованию памяти кустами реестра можно просмотреть командой !reg hivelist. Вывод команды включает размеры постоянных (сохраняемых на дис ке) и переменных данных, число активных представлений и количе ство представлений, заблокированных в памяти: —————————————————————————————— ———————————————————————— | HiveAddr |Stable Length|Stable Map|Volatile Length|Volatile Map|MappedViews|PinnedViews|U(Cnt)| BaseBlock | FileName —————————————————————————————— ———————————————————————— | e22f8b68 | 5000 | e22f8bc4 | 1000 | e22f8ca0 | 2 | 0 | 0| e2353000 | \Microsoft \Windows\UsrClass.dat | e28c3008 | 3fe000 | e1e84000 | c000 | e28c3140 | 116 | 0 | 0| e1e48000 | ttings\Adm inistrator\ntuser.dat | e23ec008 | 1000 | e23ec064 | 0 | 00000000 | 1 | 0 | 0| e23ee000 | \Microsoft \Windows\UsrClass.dat | e23ed760 | 37000 | e23ed7bc | 1000 | e23ed898 | 14 | 0 | 0| e23ef000 | ettings\Lo calService\ntuser.dat ... Здесь куст профиля для учетной записи Administrator (полный путь к которому, \Documents and Settings\Administrator\ntuser.dat, в выводе обрезан) имеет 116 спроецированных представлений и размер около 4 Мб (0x3f000 в шестнадцатеричной форме). Команда !reg viewlist по казывает спроецированные представления заданного куста. Вот как выглядит вывод этой команды при ее выполнении применительно к кусту UsrClass.dat, который был показан как первый куст в выводе ко манды !reg hivelist:
ГЛАВА 9 Механизмы управления 221 kd> !reg viewlist e22f8b68 0 Pinned Views ; PinViewListHead = e22f8da0 e22f8da0 2 Mapped Views ; LRUViewListHead = e1cf4448 e1c5d440 —————————————————————————————— ———————————————————————— | ViewAddr |FileOffset| Size |ViewAddress| Bcb | LRUViewList | PinViewList | UseCount | —————————————————————————————— ———————————————————————— | e1cf4448 | 0 | 4000 | c9a40000 | 8a4bb0e9 | e1c5d440 e22f8d98 | e1cf4450 e1cf4450 | 0 | | e1c5d440 | 4000 | 2000 | c9a44000 | 8a4bb0e9 | e22f8d98 e1cf4448 | e1c5d448 e1c5d448 | 0 | —————————————————————————————— ———————————————————————— В этом выводе показаны адреса двух представлений, которые ко манда hivelist сообщила для куста в столбце ViewAddress. Используя команду db отладчика ядра для получения содержимого памяти по ад ресу первого представления, вы обнаружите, что это проекция базо вого блока куста (она распознается по сигнатуре regf): kd> db c9a40000 c9a40000 72 65 c9a40010 3d 40 c9a40020 01 00 c9a40030 5c 00 c9a40040 66 00 c9a40050 77 00 c9a40060 61 00 c9a40070 00 00 67 c4 00 4d 74 73 73 00 66 01 00 00 00 00 00 00 d5 01 20 69 5c 5c 73 00 01 00 00 00 00 00 00 00 00 00 00 63 57 55 2e 00 00d5 0003 0000 0072 0069 0073 0064 0000 01 00 50 00 00 00 00 00 00 00 00 6f 6e 72 61 00 00 00 00 00 00 00 00 00 cc 00 01 73 64 43 74 00 20 00 00 00 00 00 00 00 43 00 00 6f 6f 6c 00 00 c7 00 00 00 00 00 00 00 regf......... C. =@.............. .... ....P...... \.M.i.c.r.o.s.o. f.t.\.W.i.n.d.o. w.s.\.U.s.r.C.l. a.s.s...d.a.t... ................ Для работы с дискретными адресами, ссылающимися на данные кустов в памяти, диспетчер конфигурации использует стратегию, аналогичную при меняемой диспетчером памяти Windows для проецирования виртуальных адресов памяти на физические. Двухуровневая схема, принятая для диспет чера конфигурации, показана на рис. 47. На входе принимается индекс ячейки (т. е. смещение в файле куста), а на выходе возвращается адрес бло ка, в который попадает индекс данной ячейки, и адрес блока, в котором на ходится указанная ячейка. Вспомните, что в приемнике может быть более одного блока, а куст разрастается за счет увеличения размеров приемников. Ввиду этого Windows всегда отводит под приемник непрерывную область памяти, и все его блоки находятся в одном и том же представлении, принад лежащем диспетчеру кэша (в Windows XP и Windows Server 2003), или в од ной и той же части пула подкачиваемой памяти.
222 Рис. 4-7. ГЛ А В А 4 БЕЗОПАСНОСТЬ Структура индекса ячейки Диспетчер конфигурации реализует такое проецирование, разбивая ин декс ячейки на логические поля, — точно так же поступает и диспетчер па мяти с виртуальными адресами. Windows интерпретирует первое поле ин декса ячейки как индекс каталога карты ячеек куста. В каталоге карты ячеек имеется 1024 элемента, каждый из которых ссылается на таблицу карты яче ек, а каждая таблица в свою очередь содержит 512 элементов. Элемент в таб лице карты ячеек определяется вторым полем индекса ячейки. В этом эле менте содержатся адреса приемника и блоков с ячейкой в памяти. В Windows XP и Windows Server 2003 не все приемники обязательно проецируются в память, и, если поиск ячейки дает нулевой адрес, диспетчер конфигурации проецирует приемник в память, при необходимости отменяя проецирова ние другого приемника из своего списка. На завершающем этапе процесса проецирования диспетчер конфигура ции интерпретирует последнее поле индекса ячейки как смещение в найден ном блоке для определения точного местонахождения ячейки в памяти. При инициализации куста диспетчер конфигурации динамически создает табли цы сопоставлений с записями для всех блоков куста, а в дальнейшем добав ляет и удаляет таблицы из каталога ячеек по мере изменения размера куста. Пространство имен и механизмы работы реестра Для интеграции пространства имен реестра с общим пространством имен ядра диспетчер конфигурации определяет тип объектов «раздел реестра». Он помещает такой объект с именем Registry в корень пространства имен Win dows и использует его как точку входа в реестр. Regedit показывает имена разделов в виде HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet, но под система Windows транслирует эти имена в соответствии с пространством имен своих объектов (например, \Registry\Machine\System\CurrentControl Set). Диспетчер объектов, анализируя подобное имя, распознает ссылку на объект Registry и тут же передает остальную часть имени диспетчеру конфи
ГЛАВА 9 Механизмы управления 223 гурации. Последний берет на себя дальнейший разбор имени, просматривая свое внутреннее дерево куста для поиска нужного раздела или параметра. Прежде чем описывать последовательность действий при типичной опера ции с реестром, нужно обсудить объекты «раздел реестра» и блоки управле ния разделом (key control blocks). Всякий раз, когда программа создает или открывает раздел реестра, диспетчер объектов передает ей описатель для ссылки на этот раздел. Описатель соответствует объекту «раздел реестра», созданному диспетчером конфигурации с участием диспетчера объектов. Опираясь на диспетчер объектов, диспетчер конфигурации использует все предоставляемые им преимущества в защите объектов и учете ссылок. Для каждого открытого раздела реестра диспетчер конфигурации созда ет блок управления разделом. В таком блоке хранится полный путь раздела, индекс ячейки узла раздела, к которому относится данный блок, и флаг, уве домляющий диспетчер конфигурации, надо ли удалять ячейку раздела (на которую ссылается данный блок) после закрытия последнего описателя раз дела. Windows помещает все блоки управления разделами в хэштаблицу, что обеспечивает быстрый поиск нужного блока по имени. Объекты «раздел реестра» указывают на соответствующие блоки управления, и, если два при ложения открывают один и тот же раздел реестра, каждое получает свой объект, указывающий на общий блок управления. Приложение, открывая существующий раздел реестра, начинает с того, что сообщает его имя APIфункции реестра, которая вызывает процедуру разбора имени, принадлежащую диспетчеру объектов. Найдя нужный объект «раздел реестра» в пространстве имен диспетчера конфигурации, диспетчер объектов возвращает ему полученный путь. Диспетчер конфигурации, используя струк туры данных куста, содержащиеся в памяти, ищет указанный раздел среди всех разделов и подразделов. Если он находит ячейку раздела, поиск продолжается в дереве блоков управления разделами, что позволяет узнать, открыт ли данный раздел (тем же или другим приложением). Процедура поиска оптимизирова на так, чтобы поиск всегда начинался с ближайшего предка с уже открытым блоком управления. Например, если приложение открывает \Registry\Machine\ Key1\Subkey2 в то время, как \Registry\Machine уже открыт, то процедура раз бора в качестве отправной точки использует блок управления разделом \Re gistry\Machine. Если раздел открыт, диспетчер конфигурации увеличивает счет чик ссылок в блоке управления этим разделом. В ином случае диспетчер кон фигурации создает новый блок управления и помещает его в дерево. Далее дис петчер конфигурации создает объект «раздел реестра», передает указатель на него блоку управления разделом и возвращает управление диспетчеру объек тов, который передает приложению описатель. Когда приложение создает новый раздел реестра, диспетчер конфигура ции сначала ищет для нового раздела ячейку родительского раздела. Далее он находит список свободных ячеек куста, в котором будет находиться но вый раздел, и определяет, есть ли достаточно большие ячейки для размеще ния ячейки нового раздела. Если таковых нет, диспетчер конфигурации со здает новый приемник и помещает в него ячейку, а остальное свободное
224 ГЛ А В А 4 БЕЗОПАСНОСТЬ пространство приемника регистрирует в списке свободных ячеек. Новая ячейка раздела заполняется соответствующей информацией, включая имя раздела. Диспетчер конфигурации добавляет ячейку раздела в список под разделов ячейки родительского раздела. Наконец, система сохраняет в но вой ячейке индекс родительской ячейки. Диспетчер конфигурации использует счетчик ссылок блока управления разделом для определения момента его удаления. Когда закрываются все описатели, счетчик ссылок обнуляется, и это говорит о том, что данный блок управления разделом больше не нужен. Если приложение, вызывающее API функцию для удаления раздела, устанавливает флаг удаления, диспетчер кон фигурации может удалить соответствующий раздел куста, так как он боль ше не используется ни одним приложением. ЭКСПЕРИМЕНТ: просмотр блоков управления разделами Команда !reg openkeys отладчика ядра позволяет перечислить все бло ки управления разделами, созданные в системе. В качестве альтерна тивы, если вы хотите просмотреть блок управления разделом для конк ретного открытого раздела, используйте !reg findkcb: kd> !reg findkcb \registry\machine\software\microsoft Found KCB = e1034d40 :: \REGISTRY\MACHINE\SOFTWARE\MICROSOFT Для анализа блока управления разделом, о котором сообщила пре дыдущая команда, предназначена команда !reg kcb: kd> !reg kcb e1034d40 Key : RefCount : Flags : ExtFlags : Parent : KeyHive : KeyCell : TotalLevels : DelayedCloseIndex: MaxNameLen : MaxValueNameLen : MaxValueDataLen : LastWriteTime : KeyBodyListHead : SubKeyCount : ValueCache.Count : KCBLock : KeyLock : \REGISTRY\MACHINE\SOFTWARE\MICROSOFT 1f CompressedName, Stable 0xe1997368 0xe1c8a768 0x64e598 [cell index] 4 2048 0x3c 0x0 0x0 0x 1c42501:0x7eb6d470 0xe1034d70 0xe1034d70 137 0 0xe1034d40 0xe1034d40 Поле Flags указывает, что имя хранится в сжатой форме, а поле SubKeyCount — что в разделе имеется 137 подразделов.
ГЛАВА 9 Механизмы управления 225 Надежность хранения данных реестра Для обеспечения гарантированной возможности восстановления постоян ных кустов реестра (т. е. кустов, которым соответствуют файлы на диске) диспетчер конфигурации использует регистрационные кусты (log hives). С каждым постоянным кустом сопоставлен регистрационный, представляю щий собой скрытый файл с именем куста и расширением LOG. Так, в ката логе \Windows\System32\Config присутствуют System.log, Sam.log и другие LOGфайлы. При инициализации куста диспетчер конфигурации создает битовый массив, в котором каждый бит представляет часть куста размером 512 байтов — сектор куста (hive sector). Поэтому и массив называется мас сивом измененных секторов (dirty sector array). Установленный бит этого массива указывает на то, что соответствующий сектор куста в памяти изме нен системой и должен быть записан в файл куста на диске, а сброшенный бит означает, что его сектор не обновлялся. При создании нового или изменении уже существующего раздела или параметра диспетчер конфигурации отмечает модифицированные секторы куста в массиве измененных секторов. Далее он планирует операцию отло женной записи, или синхронизацию куста (hive sync). Системный поток отложенной записи активизируется через 5 секунд после запроса на синх ронизацию куста и записывает измененные секторы всех кустов из памяти на диск. Таким образом, система сбрасывает на диск и все изменения в дан ных реестра, произошедшие за период между запросом на синхронизацию и самой синхронизацией. Следующая синхронизация возможна не ранее, чем через 5 секунд. ПРИМЕЧАНИЕ В Windows Server 2003 можно изменить 5секундную задержку по умолчанию, используемую системным потоком отложен ной записи. Для этого модифицируйте в реестре параметр HKLM\ System\CurrentControlSet\Session Manager\Configuration Manager\Re gistryLazyFlushInterval. Если бы поток отложенной записи сразу записывал все измененные сек торы в файл куста и при этом произошел бы крах системы, то файл куста оказался бы в несогласованном состоянии, и возможность его восстановле ния была бы утрачена. Чтобы предотвратить такую ситуацию, массив изме ненных секторов куста и все измененные секторы сначала записываются в регистрационный куст, и при необходимости его размер увеличивается. Далее поток отложенной записи обновляет порядковый номер базового бло ка куста и записывает измененные секторы в файл. Закончив эту операцию, поток отложенной записи обновляет второй порядковый номер в базовом блоке. Поэтому, если в момент записи в куст система рухнет, при ее перезаг рузке диспетчер конфигурации обнаружит, что два порядковых номера в базовом блоке куста не совпадают, и сможет обновить куст, используя изме ненные секторы из файла регистрационного куста (т. е. произведет опера цию отката вперед). В результате данные куста останутся актуальными и в согласованном состоянии.
226 ГЛ А В А 4 БЕЗОПАСНОСТЬ Для еще большей защиты целостности критически важного куста SYSTEM диспетчер конфигурации в Windows 2000 поддерживает на диске его зер кальную копию. Вы можете найти соответствующий файл в каталоге \Win dows\System32\Config файл с именем System без атрибута «скрытый» — Sys tem.alt. Файл System.alt является резервной копией куста. При каждой синх ронизации куста SYSTEM происходит обновление и System.alt. Если при за пуске системы диспетчер конфигурации обнаружит повреждение куста SYS TEM, он попытается загрузить его резервную копию. Если она не поврежде на, то будет использована для обновления исходного куста SYSTEM. Windows XP и Windows Server 2003 не поддерживают куст System.alt, так как NTLDR в этих версиях Windows знает, как обрабатывать файл System.log для актуализации куста System, который пришел в рассогласованное состо яние при выключении системы или ее крахе. В Windows Server 2003 внесе ны и другие усовершенствования для большей устойчивости к повреждени ям реестра. До Windows Server 2003 диспетчер конфигурации вызывал крах системы, обнаружив базовый блок, приемник или ячейку с данными, кото рые не проходят проверки на целостность. Диспетчер конфигурации в Win dows Server 2003 справляется с такими проблемами и, если повреждения не слишком сильны, заново инициализирует поврежденные структуры данных (с возможным удалением подразделов в ходе этого процесса) и продолжает работу. Если же ему нужно прибегнуть к самовосстановлению, он уведомля ет об этом пользователя, отображая диалоговое окно с сообщением о сис темной ошибке. ПРИМЕЧАНИЕ В каталоге \Windows\System32\Config также имеется скрытый файл System.sav. Это версия куста SYSTEM, которая служила изначальной копией куста System. Именно этот файл копируется про граммой Windows Setup с дистрибутива. Оптимизация операций с реестром Диспетчер конфигурации предпринимает некоторые меры для оптимиза ции операций с реестром. Вопервых, практически у каждого раздела реес тра имеется дескриптор защиты от несанкционированного доступа. Но было бы очень неэффективно хранить копии уникальных дескрипторов защиты для каждого раздела в кусте, поскольку сходные параметры защиты часто применяются к целым ветвям дерева реестра. Когда система устанавливает защиту для какоголибо раздела, диспетчер конфигурации в Windows 2000 прежде всего проверяет дескриптор защиты его родительского раздела, а потом просматривает все подразделы родительского раздела. Если дескрип тор защиты одного из них совпадает с дескриптором защиты, запрошенным системой для раздела, диспетчер конфигурации просто использует уже су ществующий дескриптор. Учет числа разделов, совместно использующих один и тот же дескриптор, ведется с помощью счетчика ссылок. В Windows XP и Windows Server 2003 диспетчер конфигурации проверяет пул уникаль
ГЛАВА 9 Механизмы управления 227 ных дескрипторов защиты, чтобы убедиться, что в кусте имеется по крайней мере одна копия каждого уникального дескриптора защиты. Диспетчер конфигурации также оптимизирует хранение имен разделов и параметров в кусте. Реестр полностью поддерживает Unicode, но, если в какомлибо имени присутствуют только ASCIIсимволы, диспетчер конфи гурации сохраняет это имя в кусте в ASCIIформате. Когда диспетчер кон фигурации считывает имя (например, при поиске по имени), он преобра зует его формат в памяти в Unicode. Хранение имен в формате ASCII позво ляет существенно уменьшить размер куста. Чтобы свести к минимуму нагрузку на память, блоки управления разде лами не хранят полные пути разделов реестра. Вместо этого они ссылаются лишь на имя раздела. Так, блок управления разделом \Registry\System\Control хранит не полный путь, а имя Control. Дополнительная оптимизация в ис пользовании памяти выражается в том, что диспетчер конфигурации хранит имена разделов в блоках управления именами разделов (key name control blocks), и все блоки управления разделов с одним и тем же именем исполь зуют один и тот же блок управления именем раздела. Для ускорения про смотра диспетчер конфигурации хранит имена блоков управления раздела ми в специальной хэштаблице. Для быстрого доступа к блокам управления разделами диспетчер конфи гурации сохраняет наиболее часто используемые блоки управления в кэш таблице, сконфигурированной как хэштаблица. При поиске блока диспетчер конфигурации первым делом проверяет кэштаблицу. Более того, у диспетче ра конфигурации имеется другой кэш, таблица отложенного закрытия (de layed close table), в которой хранятся блоки управления разделов, закрытых приложениями. В результате приложение при необходимости может быстро открыть недавно закрытый раздел. По мере добавления новых недавно зак рытых блоков диспетчер удаляет из этой таблицы самые старые блоки. Сервисы Практически в каждой операционной системе есть механизм, запускающий при загрузке системы процессы, которые предоставляют сервисы, не увязы ваемые с интерактивным пользователем. В Windows такие процессы назы ваются сервисами, или Windowsсервисами, поскольку при взаимодействии с системой они полагаются на Windows API. Сервисы аналогичны демонам UNIX и часто используются для реализации серверной части клиентсервер ных приложений. Примером Windowsсервиса может служить Webсервер, поскольку он должен запускаться вместе с системой и работать независимо от того, зарегистрировался ли в системе какойнибудь пользователь. Windowsсервисы состоят из трех компонентов — сервисного приложе ния (service application), программы управления сервисом (service control program, SCP) и диспетчера управления сервисами (service control manager, SCM). Для начала мы обсудим сервисные приложения, учетные записи сер висов и работу SCM. Далее мы поясним, как происходит автоматический за
228 ГЛ А В А 4 БЕЗОПАСНОСТЬ пуск сервисов при загрузке системы, и рассмотрим, что делает SCM в случае сбоя сервиса при его загрузке и как он завершает работу сервисов. Сервисные приложения Сервисные приложения вроде Webсерверов состоят минимум из одной про граммы, выполняемой как Windowsсервис. Для запуска, остановки и настрой ки сервиса предназначена SCP. Хотя в Windows имеются встроенные SCP, обеспечивающие базовую функциональность для запуска, остановки, приос тановки и возобновления сервисных приложений, некоторые сервисные при ложения предоставляют собственные SCP, позволяющие администраторам указывать параметры конфигурации того сервиса, которым они управляют. Сервисные приложения представляют собой просто Windowsпрограм мы (GUI или консольные) с дополнительным кодом для обработки команд от SCM и возврата ему статусной информации. Поскольку у большинства сервисов нет пользовательского интерфейса, они создаются в виде консоль ных программ. Когда вы устанавливаете приложение, в состав которого входит некий сервис, программа установки приложения должна зарегистрировать этот сервис в системе. Для его регистрации вызывается Windowsфункция Create Service, реализованная в Advapi32.dll (\Windows\System32\Advapi32.dll). Эта DLL, название которой расшифровывается как «Advanced API», реализует всю клиентскую часть SCM API. Регистрируя сервис через CreateService, программа установки посылает SCM сообщение о том, где будет находиться данный сервис. Затем SCM со здает в реестре раздел для сервиса по адресу HKLM\SYSTEM\CurrentControl Set\Services. Раздел Services является постоянным представлением базы дан ных SCM. Индивидуальные разделы для каждого сервиса определяют пути к соответствующим исполняемым файлам, а также параметры и конфигура ционные настройки сервисов. Зарегистрировав сервис, программа установки или управляющее прило жение может запустить его через функцию StartService. Поскольку некоторые приложения, основанные на сервисах, нужно инициализировать при загруз ке системы, программа установки обычно регистрирует сервис как автома тически запускаемый, просит пользователя перезагрузить систему для завер шения установки и при загрузке системы позволяет SCM запустить сервис. При вызове CreateService программа должна указывать некоторые парамет ры, описывающие характеристики сервиса. Эти характеристики включают тип сервиса (выполняется ли этот сервис в собственном процессе или совме стно с другими сервисами), местонахождение его исполняемого файла, не обязательное экранное имя, необязательные имя и пароль для запуска серви са в контексте защиты определенной учетной записи, тип запуска (запуска ется ли он автоматически при загрузке системы или вручную под управлени ем SCP), код, указывающий, как система должна реагировать на ошибку при запуске сервиса, и необязательную информацию о моменте запуска относи тельно других сервисов (если данный сервис запускается автоматически).
ГЛАВА 9 Механизмы управления 229 SCM хранит каждую характеристику как параметр в разделе, созданном для данного сервиса. Пример такого раздела реестра показан на рис. 48. Рис. 4-8. Пример раздела реестра для сервиса В таблице 47 перечислены характеристики сервиса, многие из которых применимы и к драйверам устройств. (Заметьте, что не все из них свойствен ны каждому типу сервисов или драйверов устройств.) Для хранения соб ственной конфигурационной информации сервиса в его разделе создается подраздел Parameters, в котором и будут находиться параметры конфигура ции этого сервиса. Сервис получает значения параметров через стандартные функции реестра. ПРИМЕЧАНИЕ SCM не обращается к подразделу Parameters сервиса до тех пор, пока данный сервис не удаляется; лишь в момент его удале ния SCM уничтожает весь раздел сервиса вместе с подразделами вро де Parameters. Таблица 4-7. Параметры реестра для сервисов и драйверов Параметр Значения Описание Start SERVICE_BOOT_START (0) Ntldr или Osloader предварительно за гружают драйвер, чтобы во время за грузки он находился в памяти. Подоб ные драйверы инициализируются не посредственно перед драйверами «типа» SERVICE_SYSTEM_START SERVICE_SYSTEM_START (1) Драйвер загружается и инициализирует ся после инициализации драйверов «типа» SERVICE_BOOT_START см. след. стр.
230 ГЛ А В А 4 Таблица 4-7. Параметр БЕЗОПАСНОСТЬ (продолжение) Значения Описание SERVICE_AUTO_START (2) Драйвер или сервис запускается SCM после запуска SCMпроцесса Services.exe SERVICE_DEMAND_START (3) Драйвер или сервис запускается SCM по требованию SERVICE_DISABLED (4) Драйвер или сервис не загружается и не инициализируется ErrorControl SERVICE_ERROR_IGNORE (0) Диспетчер вводавывода игнорирует возвращаемые драйвером или сервисом коды ошибок. Предупреждения не выво дятся и не регистрируются SERVICE_ERROR_NORMAL (1) Если драйвер или сервис сообщает об ошибке, выводится предупреждение SERVICE_ERROR_SEVERE (2) Если драйвер или сервис сообщает об ошибке и последняя удачная конфи гурация еще не используется, загружает ся именно эта конфигурация. Если она уже используется, загрузка продолжается SERVICE_ERROR_CRITICAL (3) Если драйвер или сервис сообщает об ошибке и последняя удачная конфигу рация еще не используется, загружается именно эта конфигурация. Если она уже используется, загрузка останавливается и выводится «синий экран» Type SERVICE_KERNEL_DRIVER (1) Драйвер устройства SERVICE_FILE_SYSTEM_ DRIVER (2) Драйвер файловой системы режима ядра SERVICE_ADAPTER (4) Устаревшее значение SERVICE_RECOGNIZER_ DRIVER (8) Драйвер, распознающий файловую систему SERVICE_WIN32_OWN_ PROCESS (16) Сервис выполняется в собственном про цессе, предназначенном только для него SERVICE_WIN32_SHARE_ PROCESS (32) Сервис выполняется в процессе, исполь зуемом несколькими сервисами SERVICE_INTERACTIVE_ PROCESS (256) Сервис может выводить на консоль окна и принимать ввод от пользователя Group Имя группы Драйвер или сервис инициализируется при инициализации этой группы Tag Номер тэга Указывает порядковый номер в последо вательности инициализации группы. Этот параметр неприменим к сервисам ImagePath Путь к исполняемому файлу сервиса или драйвера Если ImagePath не определен, диспетчер вводавывода ищет драйверы в \Win dows\System32\Drivers, а SCM использу ет Windowsфункции для поиска образа по значению переменной окружения PATH
ГЛАВА 9 Механизмы управления 231 Таблица 4-7. (окончание) Параметр Значения Описание DependOn Group Имя группы Драйвер или сервис не загружается, пока не будет загружен драйвер или сервис из указанной группы Depend OnService Имя сервиса Сервис не загружается, пока не будет загружен указанный сервис. Этот пара метр неприменим к драйверам уст ройств, кроме тех, у которых тип запус ка определен как SERVICE_AUTO_START ObjectName Обычно Local System, но может быть именем учет ной записи, например .\Administrator Указывает учетную запись, под которой будет работать сервис. Если ObjectName не определен, используется учетная за пись Local System. Этот параметр непри меним к драйверам устройств DisplayName Имя сервиса Имя сервиса, показываемое сервисным приложением на экране. Если это имя не указано, именем сервиса считается имя его раздела в реестре Description Описание сервиса Строка длиной до 32767 байтов Failure Actions Описание действий SCM при неожиданном заверше нии процесса сервиса Действия при сбое включают перезапуск процесса сервиса, перезагрузку систе мы и запуск указанной программы. Этот параметр неприменим к драйверам FailureCom Командная строка mand программы SCM считывает этот параметр, только если в FailureActions указана необходи мость запуска какойлибо программы при сбое сервиса. Этот параметр непри меним к драйверам Security Содержит дескриптор защиты, опреде ляющий, кто и с какими правами может получать доступ к объекту сервиса, созданному SCM Дескриптор защиты Заметьте, что к драйверам устройств применимы три значения параметра Type. Они используются драйверами устройств, которые также хранят свои параметры в разделе реестра Services. SCM отвечает за запуск драйверов со значением Start, равным SERVICE_AUTO_START или SERVICE_DE MAND_START, поэтому база данных SCM естественным образом включает и драйверы. Сер висы используют другие типы (SERVICE_WIN32_OWN_PROCESS и SERVICE_ WIN32_SHARE_PROCESS), которые являются взаимоисключающими. Про граммы, содержащие более одного сервиса, указывают тип SERVICE_WIN32_ SHARE_PROCESS. Преимущество совместного использования процесса не сколькими сервисами — экономия ресурсов, которые в ином случае пона добились бы на диспетчеризацию индивидуальных процессов. Но потенци альный недостаток этой схемы в том, что работа всех сервисов данного про цесса прекращается, если один из них вызывает ошибку, изза которой за
232 ГЛ А В А 4 БЕЗОПАСНОСТЬ вершается их процесс. Кроме того, все сервисы в одном процессе должны выполняться под одной и той же учетной записью. Когда SCM запускает сервисный процесс, тот немедленно вызывает Start ServiceCtrlDispatcher. Эта функция принимает список точек входа в сервисы — по одной на каждый сервис процесса. Каждая точка входа идентифицирует ся именем соответствующего сервиса. Установив соединение с SCM по име нованному каналу, StartServiceCtrlDispatcher входит в цикл, ожидая, когда от SCM поступит команда. SCM посылает команду запуска сервиса, и функция StartServiceCtrlDispatcher — всякий раз, когда получает такую команду, — созда ет поток, называемый потоком сервиса (service thread); он вызывает точку входа запускаемого сервиса и реализует цикл ожидания команд для сервиса. StartServiceCtrlDispatcher находится в бесконечном ожидании команд SCM и возвращает управление основной функции процесса только после останов ки всех сервисов в этом процессе, давая ему время на очистку ресурсов. Первое, что происходит при передаче управления входной точке серви са, — вызов RegisterServiceCtrlHandler. Эта функция принимает и хранит ука затель на функцию — обработчик управления (control handler), которую реализует сервис для обработки различных команд SCM. Она не взаимодей ствует с SCM, а лишь хранит только что упомянутую функцию в локальной памяти процесса для функции StartServiceCtrlDispatcher. Входная точка про должает инициализацию сервиса, выделяя нужную память, создавая конеч ные точки коммуникационного канала и считывая из реестра данные о соб ственной конфигурации сервиса. По соглашению, которому следует боль шинство сервисов, эти параметры хранятся в подразделе Parameters разде ла соответствующего сервиса. Входная точка, инициализируя сервис, может периодически посылать SCM сообщения о ходе процесса запуска сервиса (при этом используется функция SetServiceStatus). Когда входная точка закан чивает инициализацию, поток сервиса обычно входит в цикл ожидания зап росов от клиентских приложений. Например, Webсервер должен инициа лизировать TCPсокет и ждать запросы на входящие HTTPсоединения. Основной поток сервисного процесса, выполняемый в функции Start ServiceCtrlDispatcher, принимает команды SCM, направляемые сервисам в этом процессе, и вызывает функцию — обработчик управления (хранимой RegisterServiceCtrlHandler) для соответствующего сервиса. SCM посылает сле дующие команды: stop (стоп), pause (пауза), resume (возобновление), inter rogate (опрос), shutdown (выключение) и команды, определенные приложе нием. Схема внутренней организации сервисного процесса показана на рис. 49. На этой иллюстрации изображены два потока процесса, предостав ляющего один сервис (основной поток и поток сервиса).
ГЛАВА 9 Рис. 4-9. Механизмы управления 233 Внутри процесса сервиса Утилита SrvAny Если у вас есть какаято программа, которую нужно запускать как сервис, вы должны модифицировать ее стартовый код в соответствии с требо ваниями к сервисам, кратко описанным в этом разделе. Если исходный код этой программы отсутствует, можно воспользоваться утилитой Srv Any из ресурсов Windows. SrvAny позволяет выполнять любое приложе ние как сервис. Она считывает путь файла, который должен быть загру жен как сервис, из подраздела Parameters в разделе реестра, соответству ющего данному сервису. При запуске SrvAny уведомляет SCM о том, что она предоставляет определенный сервис, и, получив от него команду, запускает исполняемый файл сервиса как дочерний процесс. Последний получает копию маркера доступа процесса SrvAny и ссылку на тот же объект WindowStation. Таким образом, сервис выполняется с параметра ми защиты и настройками, указанными вами при конфигурировании SrvAny. Сервисы SrvAny не поддерживают значение параметра Type, со ответствующее совместному использованию процесса, поэтому каждое приложение, установленное утилитой SrvAny как сервис, выполняется в отдельном процессе с отдельной копией хостпрограммы SrvAny. Учетные записи сервисов Контекст защиты сервиса очень важен для разработчиков и системных ад министраторов, поскольку он определяет, к каким ресурсам получит доступ этот сервис. Большинство сервисов выполняется в контексте защиты учет ной записи локальной системы, если системным администратором или про граммой установки не указано иное. (В пользовательском интерфейсе назва ние учетной записи локальной системы показывается как Local System или SYSTEM.) В Windows XP введены две разновидности учетной записи локаль
234 ГЛ А В А 4 БЕЗОПАСНОСТЬ ной системы: сетевой сервис (network service) и локальный сервис (local service). По сравнению с учетной записью локальной системы новые учет ные записи обладают меньшими правами, и любой встроенный в Windows сервис, не требующий всей мощи учетной записи локальной системы, вы полняется под соответствующей альтернативной учетной записью. Особен ности этих учетных записей описываются в следующих разделах. Учетная запись локальной системы Под этой учетной записью выполняются базовые компоненты пользователь ского режима, включая диспетчер сеансов (\Windows\System32\Smss.exe), процесс подсистемы Windows (Csrss.exe), подсистему локальной аутентифи кации (\Windows\System32\LSASS.exe) и процесс Winlogon (\Windows\Sys tem32\Winlogon.exe). С точки зрения защиты, учетная запись Local System обладает исключи тельными возможностями — бóльшими, чем любая другая локальная или доменная учетная запись. Вот ее характеристики. 쐽 Ее обладатель является членом группы локальных администраторов. В таблице 48 перечислены группы, которым назначается учетная запись локальной системы. (О том, как информация о членстве в группах ис пользуется при проверках прав доступа к объектам, см. в главе 8.) 쐽 Она дает право на задание практически любых привилегий (даже таких, которые обычно не назначаются учетной записи локального админист ратора, например создания маркеров защиты). Список привилегий, на значаемых учетной записи Local System, приведен в таблице 49. (Описа ние каждой привилегии см. в главе 8.) 쐽 Она дает право на полный доступ к большинству файлов и разделов ре естра. Даже если какието объекты не разрешают полный доступ, процес сы под этой учетной записью могут воспользоваться привилегией захва та объекта во владение (takeownership privilege) и тем самым получить нужный вид доступа. 쐽 Процессы, работающие под учетной записью Local System, применяют профиль пользователя по умолчанию (HKU\.DEFAULT). Поэтому им недо ступна конфигурационная информация, которая хранится в профилях пользователей, сопоставленных с другими учетными записями. 쐽 Если данная система входит в домен Windows, учетная запись Local System включает идентификатор защиты (SID) для компьютера, на котором вы полняется сервисный процесс. Поэтому сервис, работающий под учетной записью Local System, будет автоматически аутентифицирован на других машинах в том же лесу. (Лес — это группа доменов в Active Directory.) 쐽 Если только учетной записи компьютера специально не назначены пра ва доступа (к общим сетевым ресурсам, именованным каналам и т. д.), процесс может получать доступ к сетевым ресурсам, разрешающим так называемые nullсеансы, т. е. соединения, не требующие соответствующих удостоверений защиты. Вы можете указывать общие ресурсы и каналы,
ГЛАВА 9 Механизмы управления 235 разрешающие nullсеансы на конкретном компьютере, в параметрах Null SessionPipes и NullSessionShares раздела реестра HKLM\SYSTEM\Current ControlSet\Services\LanmanServer\Parameters. Таблица 4-8. Членство учетной записи сервиса в группах Local System Network Service Local Service Everyone Everyone Everyone Authenticated Users Authenticated Users Authenticated Users Administrators Users Users Local Local Network Service Local Service Service Service Таблица 4-9. Привилегии учетной записи сервиса Local System Network Service Local Service SeAssignPrimaryToken Privilege SeAssignPrimary TokenPrivilege SeAssignPrimaryTokenPrivilege SeAuditPrivilege SeAuditPrivilege SeAuditPrivilege SeBackupPrivilege SeChangeNotifyPrivilege SeChangeNotifyPrivilege SeChangeNotifyPrivilege SeIncreaseQuotaPrivilege SeIncreaseQuotaPrivilege SeCreateGlobalPrivilege Привилегии, назначае Привилегии, назначаемые мые группам Everyone, группам Everyone, Authenticated Users и Users Authenticated Users и Users SeCreatePagefilePrivilege SeCreatePermanentPrivilege SeCreateTokenPrivilege1 SeDebugPrivilege SeImpersonatePrivilege SeIncreaseBasePriorityPrivilege SeLoadDriverPrivilege SeLockMemoryPrivilege SeManageVolumePrivilege SeProfileSingleProcessPrivilege SeRestorePrivilege SeSecurityPrivilege SeShutdownPrivilege SeSystemEnvironmentPrivilege SeSystemTimePrivilege SeTakeOwnershipPrivilege SeTcbPrivilege SeUndockPrivilege 1 Учетная запись локальной системы в Windows Server 2003 эту привилегию не включает.
236 ГЛ А В А 4 БЕЗОПАСНОСТЬ Учетная запись Network Service Эта учетная запись предназначена для сервисов, которым нужно аутентифи цироваться на других компьютерах в сети по учетной записи компьютера, как это делается в случае учетной записи Local System, но не требуется член ство в административных группах или привилегии, назначаемые учетной записи Local System. Поскольку учетная запись Network Service не относит ся к группе администраторов, выполняемые под ней сервисы по умолчанию получают доступ к гораздо меньшему количеству разделов реестра, а также каталогов и файлов в файловой системе, чем учетная запись Local System. Более того, назначение меньшего числа привилегий ограничивает возмож ности скомпрометированного процесса сетевого сервиса. Например, про цесс, работающий под учетной записью Network Service, не может загрузить драйвер устройства или открыть произвольный процесс. Процессы, выполняемые под учетной записью Network Service, использу ют ее профиль; он загружается в раздел HKU\S1520, а его файлы и катало ги находятся в \Documents and Settings\NetworkService. В Windows XP и Win dows Server 2003 под учетной записью Network Service выполняется DNSкли ент, отвечающий за разрешение DNSимен и поиск контроллеров домена. Учетная запись Local Service Эта учетная запись практически идентична Network Service с тем отличием, что позволяет обращаться лишь к тем сетевым ресурсам, которые разреша ют анонимный доступ. В таблице 49 показано, что у нее те же привилегии, что и у учетной записи Network Service, а таблица 48 — что она принадле жит к тем же группам (если не считать группы Network Service и Local Ser vice). Профиль, используемый процессами, выполняемыми под учетной за писью Local Service, загружается в HKU\S1519 и хранится в \Documents and Settings\LocalService. В Windows XP и Windows Server 2003 под учетной записью Local Service работают такие компоненты, как Remote Registry Service (Служба удаленно го реестра), предоставляющая удаленный доступ к реестру локальной сис темы, служба оповещения, принимающая широковещательные сообщения с административными уведомлениями, и служба LmHosts, обеспечивающая разрешение NetBIOSимен. Выполнение сервисов под другими учетными записями В силу вышеописанных ограничений некоторые сервисы должны работать с удостоверениями защиты учетной записи пользователя. Вы можете скон фигурировать сервис на выполнение под другой учетной записью при его создании или с помощью оснастки Services (Службы) консоли MMC, указав в ней пароль и учетную запись, под которой должен работать сервис. В ос настке Services щелкните правой кнопкой мыши нужный сервис, выберите из контекстного меню команду Properties (Свойства), перейдите на вкладку Log On (Вход в систему) и щелкните переключатель This Account (С учетной записью), как показано на рис. 410.
ГЛАВА 9 Рис. 4-10. Механизмы управления 237 Параметры учетной записи сервиса Интерактивные сервисы Другое ограничение сервисов, работающих под учетными записями Local System, Local Service или Network Service, заключается в том, что они не мо гут выводить окна на рабочий стол интерактивного пользователя (без спе циального флага в функции MessageBox, о котором мы расскажем чуть поз же). Такое ограничение не является прямым следствием выполнения под этими учетными записями, а вызвано тем, как подсистема Windows назна чает сервисные процессы объектам WindowStation. Дело в том, что подсистема Windows сопоставляет каждый Windowsпро цесс с объектом WindowStation. Он включает объекты «рабочий стол», а те в свою очередь — объекты «окно». На консоли видим только объект Window Station, и только он принимает пользовательский ввод от мыши и клавиату ры. В среде Terminal Services видимым является лишь один объект Window Station для каждого сеанса, а все сервисы выполняются как часть консоль ного сеанса. Windows присваивает видимому объекту WindowStation имя WinSta0, и к нему обращаются все интерактивные процессы. Если не указано иное, подсистема Windows сопоставляет сервисы, выпол няемые под учетной записью Local System, с невидимым WindowStation объектом Service0x03e7$, который разделяется всеми неинтерактивными сервисами. Числовая часть его имени, 3e7, представляет назначаемый LSASS идентификатор сеанса входа в систему, который используется SCM для не интерактивных сервисов, работающих под учетной записью Local System. Сервисы, сконфигурированные на запуск под учетной записью пользо вателя (т. е. под учетной записью, отличной от Local System), выполняются в
238 ГЛ А В А 4 БЕЗОПАСНОСТЬ другом невидимом объекте WindowStation, имя которого формируется из идентификатора, назначаемого LSASS сеансу входа в систему. На рис. 411 показано окно программы Winobj (ее можно скачать с сайта www.sysinter nals.com) при просмотре каталога диспетчера объектов, в который Windows помещает объекты WindowStation. Обратите внимание на интерактивный WindowStationобъект WinSta0, неинтерактивный WindowStationобъект системного сервиса Service0x03e7$ и неинтерактивный WindowStation объект Service0x06368f$, назначенный сервисному процессу, который за регистрирован как пользователь. Рис. 4-11. Список объектов WindowStation Независимо от того, работает ли сервис под учетной записью пользова теля или под учетными записями Local System, Local Service либо Network Service, он не может получать пользовательский ввод или выводить окна на консоль, если он не сопоставлен с видимым объектом WindowStation. Фак тически, если бы сервис попытался вывести обычное диалоговое окно, он бы казался зависшим, так как ни один пользователь не увидел бы это окно и не смог бы его закрыть с помощью мыши или клавиатуры. (Единственное ис ключение — вызов MessageBox со специальным флагом MB_SERVICE_NOTI FICATION или MB_DEFAULT_DESKTOP_ONLY. При MB_SERVICE_NOTIFICA TION окно всегда выводится через интерактивный объект WindowStation, даже если сервис не сконфигурирован на взаимодействие с пользователем, а при MB_DEFAULT_DESKTOP_ONLY окно показывается на рабочем столе по умолчанию интерактивного объекта WindowStation.) Иногда, хоть и очень редко, сервису нужно взаимодействовать с пользо вателем через информационные или диалоговые окна. Чтобы предоставить сервису право на взаимодействие с пользователем, в параметр Type в разде ле реестра данного сервиса следует добавить модификатор SERVICE_INTER ACTIVE_PROCESS. (Учтите, что сервисы, сконфигурированные для работы
ГЛАВА 9 Механизмы управления 239 под учетной записью пользователя, нельзя помечать как интерактивные.) В случае сервиса, помеченного как интерактивный, SCM запускает его про цесс в контексте защиты учетной записи Local System, но сопоставляет сер вис с WinSta0, а не с неинтерактивным объектом WindowStation. Это позво ляет сервису выводить на консоль окна и реагировать на ввод пользователя. ПРИМЕЧАНИЕ Microsoft не рекомендует запускать интерактивные сервисы (особенно под учетной записью Local System), так как это вре дит безопасности. Windows, представленная интерактивным сервисом, уязвима перед оконными сообщениями, с помощью которых злонаме ренный процесс, работающий как непривилегированный пользова тель, может вызывать переполнения буферов в сервисном процессе и подменять его собой, чтобы повысить уровень своих привилегий в подсистеме защиты. Диспетчер управления сервисами Исполняемым файлом SCM является \Windows\System32\Services.exe, и по добно большинству процессов сервисов он выполняется как консольная Windowsпрограмма. Процесс Winlogon запускает SCM на ранних этапах загрузки (см. главу 5) вызовом функции SvcCtrlMain. Она управляет запуском сервисов, сконфигурированных на автоматический старт. SvcCtrlMain выпол няется почти сразу после появления на экране пустого рабочего стола, но, как правило, до загрузки процессом Winlogon графического интерфейса GINA, открывающего диалоговое окно для входа в систему. Прежде всего SvcCtrlMain создает синхронизирующее событие с именем SvcCtrlEvent_A3752DX и в занятом состоянии. SCM освобождает этот объект только по завершении всех операций, необходимых для подготовки к полу чению команд от SCP. Последний устанавливает диалог с SCM через функцию OpenSCManager, которая не дает SCP связаться с SCM до его инициализации, реализуя это за счет ожидания перехода объекта SvcCtrlEvent_A3752DX в свободное состояние. Далее SvcCtrlMain переходит к делу и вызывает функцию ScCreateService DB, создающую внутреннюю базу данных сервисов SCM. Функция ScCreate ServiceDB считывает и сохраняет в разделе HKLM\SYSTEM\CurrentControlSet\ Control\ServiceGroupOrder\List параметр типа REG_MULTI_SZ, в котором со держится список имен и порядок определенных групп сервисов. Если сер вису или драйверу нужно контролировать свой порядок запуска относитель но сервисов других групп, в раздел реестра этого сервиса включается допол нительный параметр Group. Например, сетевой стек Windows построен по принципу «снизу вверх», поэтому сетевые сервисы должны указывать пара метры Group, благодаря которым при загрузке системы они будут запускать ся после загрузки сетевых драйверов. SCM создает в памяти внутренний спи сок групп, где хранится порядок групп, считанный из реестра. В список вхо дят NDIS, TDI, Primary Disk, Keyboard Port, Keyboard Class и другие группы. Дополнительные приложения и программное обеспечение от сторонних
240 ГЛ А В А 4 БЕЗОПАСНОСТЬ разработчиков могут определять собственные группы и вносить их в спи сок. Так, Microsoft Transaction Server добавляет группу MS Transactions. ScCreateServiceDB сканирует раздел HKLM\SYSTEM\CurrentControlSet\ Services и создает для каждого его подраздела запись в базе данных серви сов. Такая запись включает все параметры, определенные для сервиса, и поля, предназначенные для слежения за состоянием сервиса. SCM добавляет запи си для драйверов устройств и сервисов, так как отвечает за запуск компонен тов, помеченных для автоматического запуска. При этом SCM обнаружива ет любые ошибки, вызываемые драйверами, которые помечены как запуска емые при загрузке системы (bootstart) и после нее (systemstart). (Он также предоставляет приложениям средства для запроса состояния драйверов.) Диспетчер вводавывода загружает такие драйверы до начала выполнения какоголибо процесса пользовательского режима, поэтому они загружают ся до старта SCM. ScCreateServiceDB считывает параметр Group сервиса, определяя принад лежность этого сервиса к той или иной группе, и сопоставляет его значение с элементом в созданном ранее списке групп. Эта функция также считывает и сохраняет в базе данных зависимости сервиса от групп и других сервисов, запрашивая из реестра значения его параметров DependOnGroup и Depend OnService. На рис. 412 показано, что представляет собой база данных SCM. Заметьте, что сервисы отсортированы в алфавитном порядке. Это вызвано тем, что SCM создает список на основе раздела Services, а Windows сортиру ет разделы реестра по алфавиту. Рис. 4-12. Организация базы данных сервисов При запуске сервиса SCM может понадобиться обращение к LSASS (напри мер, для регистрации сервиса под учетной записью пользователя), поэтому он ждет, когда LSASS освободит синхронизирующее событие LSA_RPC_SERVER_ ACTIVE, которое переходит в свободное состояние после инициализации LSASS. Winlogon тоже запускает процесс LSASS, поэтому инициализация LSASS
ГЛАВА 9 Механизмы управления 241 проходит параллельно инициализации SCM, но завершаться эти операции могут в разное время. После этого SvcCtrlMain вызывает ScGetBootAndSystem DriverState, которая сканирует базу данных сервисов и ищет записи для драй веров устройств, запускаемых при загрузке системы и после нее. ScGetBoot AndSystemDriverState определяет, успешно ли запустился драйвер, проверяя наличие его имени в каталоге \Driver пространства имен диспетчера объек тов. При успешной загрузке драйвера его объект помещается в данный ката лог пространства имен диспетчером вводавывода, так что имена незагружен ных драйверов присутствовать там не могут. Содержимое каталога Driver, по лученное с помощью Winobj, показано на рис. 413. Если драйвер не загружен, SCM ищет его имя в списке, возвращаемом функцией PnP_DeviceList, которая сообщает о драйверах, включенных в текущий профиль оборудования систе мы. SvcCtrlMain отмечает имена драйверов из текущего профиля, которые не удалось запустить, в списке с именем ScFailedDrivers. Перед запуском автоматически запускаемых сервисов SCM предпринима ет еще несколько действий. Он создает именованный канал RPC с именем \Pipe\Ntsvcs, а затем RPC запускает поток, отслеживающий приходящие по этому каналу сообщения SCP. Далее SCM освобождает свой объект SvcCtrl Event_A3752DX, сигнализируя о завершении инициализации. Рис. 4-13. Список объектов драйверов Буквы сетевых дисков SCM не только предоставляет интерфейс к сервисам, но и играет еще одну роль, никак не связанную с сервисами: он уведомляет GUIприло жения о создании или удалении сопоставления буквы с сетевым диском. SCM ждет, когда маршрутизатор многосетевого доступа (Multiple Pro vider Router, MPR) освободит объект \BaseNamedObjects\ScNetDrvMsg. Это происходит, когда приложение назначает букву диска удаленному см. след. стр.
242 ГЛ А В А 4 БЕЗОПАСНОСТЬ сетевому ресурсу или удаляет ее. (Сведения о MPR см. в главе 13.) При освобождении объектасобытия маршрутизатором многосетевого до ступа SCM вызывает Windowsфункцию GetDriveType, чтобы получить список букв подключенных сетевых дисков. Если этот список изменя ется в результате освобождения объектасобытия, SCM посылает ши роковещательное Windowsсообщение типа WM_DEVICECHANGE с подтипом DBT_DEVICEREMOVECOMPLETE или DBT_DEVICEARRIVAL. Это сообщение адресовано главным образом Windows Explorer, что бы он мог обновить любые открытые окна My Computer (Мой компью тер) с учетом изменений в наборе подключенных сетевых дисков. Запуск сервиса SvcCtrlMain вызывает SCMфункцию ScAutoStartServices для запуска всех сер висов, значение параметра Start которых указывает на автостарт. ScAutoStart Services также осуществляет автоматический запуск драйверов. Чтобы не за путаться, помните, что термином «сервисы» обозначаются как сервисы, так и драйверы, если явно не указано иное. Алгоритм ScAutoStartServices разби вает процесс запуска сервисов на несколько фаз, причем в каждой фазе за пускаются определенные группы сервисов. Порядок запуска определяется параметром List в разделе реестра HKLM\SYSTEM\CurrentControlSet\Control\ ServiceGroupOrder. Этот параметр, показанный на рис. 414, включает име на групп в том порядке, в каком они должны запускаться SCM. Таким обра зом, единственное, для чего сервис включается в ту или иную группу, — точ ная настройка момента его запуска относительно других сервисов. Рис. 4-14. Раздел реестра ServiceGroupOrder В начале каждой фазы ScAutoStartServices отмечает все сервисы, относя щиеся к группе, которая запускается на данной фазе. После этого ScAuto StartServices перебирает отмеченные сервисы, определяя возможность запус ка каждого из них. При этом функция проверяет зависимость текущего сер виса от другой группы, на существование которой указывает наличие в со ответствующем разделе реестра параметра DependOnGroup. Если сервис зависит от какойлибо группы, она должна быть уже инициализирована и
ГЛАВА 9 Механизмы управления 243 хотя бы один ее сервис должен быть успешно запущен. Если сервис зависит от группы, запускаемой позже группы данного сервиса, SCM генерирует ошибку, которая сообщает о «круговой зависимости». Если ScAutoStartServices имеет дело с Windowsсервисом или с автоматически запускаемым драйве ром устройства, она дополнительно проверяет, зависит ли данный сервис от какихлибо других сервисов, и, если да, то запущены ли они. Зависимости сервисов указываются в параметре DependOnService раздела, соответствую щего сервису. Если сервис зависит от других сервисов из групп, запускаемых позднее, SCM также генерирует ошибку, связанную с «круговой зависимос тью». Если же сервис зависит от еще не запущенных сервисов из той же груп пы, он просто пропускается. Если все зависимости корректны, ScAutoStartServices делает последнюю пе ред запуском сервиса проверку: входит ли он в состав загружаемой в данный момент конфигурации. В разделе реестра HKLM\SYSTEM\CurrentControlSet\ Control\SafeBoot имеется два подраздела — Minimal и Network. Какой из них будет использован SCM для проверки зависимостей, определяется типом бе зопасного режима, выбранного пользователем. Если пользователь выбрал Safe Mode (Безопасный режим) или Safe Mode With Command Prompt (Безопасный режим с поддержкой командной строки), SCM обращается к подразделу Mini mal, а если пользователь выбрал Safe Mode With Networking (Безопасный ре жим с загрузкой сетевых драйверов), то — к подразделу Network. Наличие в разделе SafeBoot строкового параметра Option говорит не только о загрузке системы в безопасном режиме, но и указывает выбранный пользователем тип безопасного режима. Подробнее о безопасных режимах см. главу 5. Как только SCM принимает решение о запуске сервиса, он вызывает ScStartService, которая запускает сервисы иначе, чем драйверы устройств. В случае Windowsсервиса эта функция сначала определяет имя файла, за пускающего процесс сервиса, и для этого считывает параметр ImagePath из раздела, соответствующего сервису. Далее она определяет значение парамет ра Type, и, если оно равно SERVICE_WIN32_SHARE_PROCESS (0x20), SCM про веряет, зарегистрирован ли процесс, запускающий данный сервис, по той же учетной записи, что и запускаемый сервис. Учетная запись пользователя, под которой должен работать сервис, хранится в разделе этого сервиса в пара метре ObjectName. Если параметр ObjectName сервиса содержит значение LocalSystem или этот параметр вовсе отсутствует, данный сервис запускает ся под учетной записью Local System. SCM удостоверяется, что процесс сервиса еще не запущен под другой учетной записью. Для этого он ищет в своей внутренней базе данных, назы ваемой базой данных образов (image database), запись для параметра Image Path сервиса. Если такой записи нет, SCM создает ее. При этом он сохраняет имя учетной записи, используемой сервисом, и данные из параметра Image Path. SCM требует от сервисов наличия параметра ImagePath. Если его нет, SCM генерирует ошибку, сообщая, что найти путь к сервису не удалось и за пуск этого сервиса невозможен. Если SCM находит существующую запись в базе данных с теми же данными, что и в ImagePath, то проверяет, совпадают
244 ГЛ А В А 4 БЕЗОПАСНОСТЬ ли сведения об учетной записи пользователя запускаемого сервиса с инфор мацией в базе данных. Процесс регистрируется только под одной учетной записью, и поэтому SCM сообщает об ошибке, если имя учетной записи сер виса отличается от имени, указанного другим сервисом, который уже выпол няется в том же процессе. Чтобы зарегистрировать (если это указано в конфигурации сервиса) и запустить процесс сервиса, SCM вызывает ScLogonAndStartImage. SCM регис трирует сервисы, выполняемые не под системной учетной записью, с помо щью LSASSфункции LsaLogonUser. Обычно LsaLogonUser требует пароль, но SCM указывает LSASS, что пароль хранится как «секрет» LSASS в разделе рее стра HKLM\SECURITY\Policy\Secrets. (Учтите, что содержимое SECURITY обычно невидимо, поскольку его параметры защиты по умолчанию разре шают доступ только по системной учетной записи.) SCM, вызывая LsaLogon User, указывает тип регистрации, и поэтому LSASS ищет пароль в подразде ле раздела Secrets с именем типа _SC_<имя сервиса>. Конфигурируя регист рационную информацию сервиса, SCM командует LSASS сохранить регист рационный пароль как секрет, используя функцию LsaStorePrivateData. Если регистрация проходит успешно, LsaLogonUser возвращает описатель марке ра доступа. В Windows такие маркеры применяются для установки контек ста защиты пользователя, и SCM сопоставляет маркер доступа с процессом, реализующим сервис. После успешной регистрации SCM загружает информацию из профиля учетной записи (если она еще не загружена), для чего вызывает функцию LoadUserProfile из \Windows\System32\Userenv.dll. Местонахождение куста, который LoadUserProfile загружает в реестр как раздел HKEY_CURRENT_USER, определяется параметром HKLM\SOFTWARE\Microsoft\Windows NT\Current Version\ProfileList\<раздел профиля пользователя>\ProfileImagePath. Интерактивный сервис должен открыть WindowStationобъект WinSta0. Но прежде чем разрешить интерактивному сервису доступ к WinSta0, ScLo gonAndStartImage проверяет, установлен ли параметр HKLM\SYSTEM\Cur rentControlSet\Control\Windows\NoInteractiveServices. Этот параметр уста навливается администратором для того, чтобы запретить сервисам, поме ченным как интерактивные, вывод окон на консоль. Такой вариант приме няется при работе сервера в необслуживаемом режиме, когда пользователей, взаимодействующих с интерактивными сервисами, нет. Далее ScLogonAndStartImage запускает процесс сервиса, если он еще не выполняется. SCM запускает процессы в приостановленном состоянии, ис пользуя Windowsфункцию CreateProcessAsUser. После этого SCM создает именованный канал для взаимодействия с процессом сервиса и присваива ет ему имя \Pipe\Net\NtControlPipeX, где Х — счетчик количества созданных SCM каналов. SCM возобновляет выполнение процесса сервиса через функ цию ResumeThread и ждет подключения сервиса к созданному каналу. Сколь ко времени SCM ждет вызова сервисом функции StartServiceCtrlDispatcher и соединения с каналом, зависит от значения параметра реестра HKLM\SYS TEM\CurrentControlSet\Control\ServicesPipeTimeout (если такой параметр
ГЛАВА 9 Механизмы управления 245 существует). По истечении этого времени SCM завершает процесс и счита ет запуск сервиса несостоявшимся. Если параметра ServicesPipeTimeout в реестре нет, SCM использует таймаут по умолчанию, равный 30 секундам. Этот же таймаут распространяется на все виды коммуникационной связи между SCM и сервисами. Когда сервис подключается по каналу к SCM, последний посылает сервису команду запуска. Если сервис в течение определенного периода не реагирует на нее, SCM переходит к запуску следующего сервиса. В данном случае SCM не завершает процесс сервиса, а заносит запись об ошибке в системный жур нал событий, указывая, что сервис не смог своевременно начать работу. Если параметр реестра Type для сервиса, запускаемого SCM с помощью ScStartService, равен SERVICE_KERNEL_DRIVER или SERVICE_FILE_SYSTEM_ DRIVER, то данный сервис является драйвером устройства, и ScStartService вызывает для его загрузки ScLoadDeviceDriver. Она выдает процессу SCM пра во на загрузку драйвера и вызывает сервис ядра NtLoadDriver, передавая ему значение параметра реестра ImagePath для данного драйвера. В отличие от сервисов драйверам не обязательно указывать значение ImagePath. Если оно не указано, SCM формирует путь к образу исполняемого файла, добавляя имя драйвера к строке \Windows\System32\Drivers\. ScAutoStartServices продолжает поочередно обрабатывать сервисы, при надлежащие какойлибо группе, до тех пор, пока все они не будут запуще ны или не вызовут ошибку, связанную с нарушением зависимостей. Такая циклическая обработка позволяет SCM автоматически упорядочивать серви сы внутри группы в соответствии с их параметрами DependOnService. SCM сначала запускает сервисы, на которые полагаются другие сервисы, пропус кая зависимые сервисы. Заметьте, что SCM игнорирует параметры Tag в под разделах Windowsсервисов раздела HKLM\SYSTEM\CurrentControlSet\ Servi ces. Эти параметры использует диспетчер вводавывода, упорядочивая запуск драйверов устройств в группе драйверов, запускаемых при загрузке и при старте системы. Как только SCM завершает операции запуска для всех групп, перечислен ных в списке ServiceGroupOrder\List, он переходит к запуску сервисов, при надлежащих к группам, которые не входят в этот список, а потом обрабаты вает сервисы, не включенные ни в одну группу. Закончив, SCM переводит событие \BaseNamedObjects\SC_AutoStartComplete в свободное состояние. Ошибки при запуске Если драйвер или сервис в ответ на команду запуска SCM сообщает об ошиб ке, реакция SCM определяется значением параметра ErrorControl из раздела реестра для соответствующего сервиса. Если ErrorControl равен SERVICE_ ERROR_IGNORE (0) или вообще не указан, SCM игнорирует ошибку и про должает обработку запуска сервисов. Если ErrorControl равен SERVICE_ER ROR_NORMAL (1), SCM заносит в журнал событий запись такого вида: «The <имя сервиса> service failed to start due to the following error:» («Служба <имя сервиса> завершена изза ошибки:»). SCM добавляет возвращаемый сервисом
246 ГЛ А В А 4 БЕЗОПАСНОСТЬ Windowsкод ошибки, указывая его в записи в качестве причины сбоя при запуске. На рис. 415 показан пример такой записи. Рис. 4-15. Запись в журнале событий, уведомляющая об ошибке при запуске сервиса Если сервис, значение ErrorControl которого равно SERVICE_ERROR_SEVE RE (2) или SERVICE_ERROR_CRITICAL (3), сообщает об ошибке при запуске, SCM делает запись в журнале событий и вызывает внутреннюю функцию ScRevertToLastKnownGood. Эта функция активизирует версию реестра, соответ ствующую последней удачной конфигурации, в которой система была успеш но загружена. После этого она перезагружает систему, вызывая сервис NtShut downSystem, реализуемый исполнительной системой. Если система уже загру жена в последней удачной конфигурации, она просто перезагружается. Критерии успешной загрузки и последняя удачная конфигурация Кроме запуска сервисов система возлагает на SCM определение того, когда следует сохранять раздел реестра HKLM\SYSTEM\CurrentControlSet в каче стве последней удачной конфигурации. Раздел Services входит в раздел Cur rentControlSet, поэтому CurrentControlSet включает представление реестра из базы данных SCM. CurrentControlSet также включает раздел Control, где хра нятся многие параметры конфигурации подсистем режима ядра и пользо вательского режима. По умолчанию загрузка считается успешной, если были запущены все автоматически запускаемые драйверы и пользователь смог войти в систему. Загрузка считается неудачной, если система остановилась изза краха драйвера устройства или если автоматически запускаемый сер
ГЛАВА 9 Механизмы управления 247 вис с параметром ErrorControl, равным SERVICE_ERROR_SEVERE или SER VICE_ERROR_CRITICAL, сообщил об ошибке при запуске. SCM узнает, успешно ли стартовали автоматически запускаемые сервисы, но уведомление об успешном входе пользователя он должен получить от Winlogon (\Windows\System32\Winlogon.exe). При входе пользователя Win logon вызывает функцию NotifyBootConfigStatus, которая посылает сообщение SCM. После успешного старта автоматически запускаемых сервисов или при ема сообщения от NotifyBootConfigStatus (в зависимости от того, какое из этих событий будет последним) SCM вызывает системную функцию NtInitialize Registry для сохранения текущей конфигурации системы. Сторонние разработчики программного обеспечения могут заменить определение успешного входа Winlogon собственным. Например, если в сис теме работает Microsoft SQL Server, загрузка считается успешной только пос ле того, как SQL Server может принимать и обрабатывать транзакции. Разра ботчики указывают свое определение успешной загрузки, используя про грамму верификации загрузки и регистрируя ее местонахождение в пара метре, который сохраняется в разделе реестра HKLM\SYSTEM\CurrentContro lSet\Control\BootVerificationProgram. Кроме того, при установке программы верификации загрузки нужно отключить вызов Winlogon функции Notify BootConfigStatus, присвоив параметру HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\ReportBootOk значение, равное 0. Если такая программа установлена, SCM запускает ее, закончив обработку автоматичес ки запускаемых сервисов. Перед сохранением последней удачной конфигу рации SCM ждет вызова NotifyBootConfigStatus из этой программы. Windows поддерживает несколько копий CurrentControlSet, который на самом деле представляет собой символьную ссылку на одну из этих копий. Им присваиваются имена в виде HKLM\SYSTEM\ControlSetnnn, где nnn — порядковый номер вроде 001 или 002. Раздел HKLM\SYSTEM\Select хранит параметры, определяющие роль каждой копии CurrentControlSet. Так, если CurrentControlSet ссылается на ControlSet001, значение параметра Current в разделе Select равно 1. Параметр LastKnownGood в разделе Select хранит номер последней удачной конфигурации. В разделе Select может быть еще один параметр, Failed, указывающий номер конфигурации, загрузка которой признана неудачной и прервана, после чего была предпринята попытка ис пользования последней удачной конфигурации. На рис. 416 показаны на боры CurrentControlSet и параметры раздела Select. NtInitializeRegistry синхронизирует набор параметров последней удачной конфигурации с содержимым дерева CurrentControlSet. После первой успеш ной загрузки системы последней удачной конфигурации еще нет, и систе ма создает для нее новый набор параметров. Если же набор параметров пос ледней удачной конфигурации уже есть, система просто обновляет его дан ные так, чтобы они совпадали с данными из CurrentControlSet. Последняя удачная конфигурация может помочь, когда изменения, вне сенные в CurrentControlSet при оптимизации системы или установке серви са, вызывают сбои при следующей загрузке. Нажав клавишу F8 в самом на
248 ГЛ А В А 4 БЕЗОПАСНОСТЬ чале загрузки, пользователь может вызвать меню, которое позволит ему ак тивизировать последнюю удачную конфигурацию и вернуть реестр к исход ному состоянию (детали см. в главе 5). Рис. 4-16. Раздел, предназначенный для выбора конфигурации Сбои сервисов В разделах сервисов могут присутствовать необязательные параметры Failu reActions и FailureCommand, записываемые SCM при запуске сервисов. Cис тема уведомляет SCM о неожиданном завершении процесса сервиса, так как SCM соответствующим образом регистрируется в системе. В этом случае SCM определяет, какие сервисы выполнялись в этом процессе, и предпринимает действия по их восстановлению. Эти действия определяются параметрами реестра, относящимися к сбоям сервисов. Сервисы могут указывать для SCM такие действия, как перезапуск серви са, запуск какойлибо программы и перезагрузка компьютера. Более того, сервис может задавать действия, предпринимаемые при первом, втором и последующих сбоях его процесса, а также задавать период ожидания SCM перед перезапуском сервиса, если это действие определено сервисом. На пример, сбой IIS Admin Service заставляет SCM запустить приложение IISRe set, которое освобождает ресурсы и перезапускает сервис. Вы можете легко настроить действия, предпринимаемые для восстановления сервиса, на вкладке Recovery (Восстановление) окна свойств сервиса в оснастке Services (Службы), как показано на рис. 417.
ГЛАВА 9 Рис. 4-17. Механизмы управления 249 Параметры восстановления сервиса Завершение работы сервиса Когда Winlogon вызывает Windowsфункцию ExitWindowsEx, она посылает сообщение Csrss, процессу подсистемы Windows, для вызова его процедуры завершения. Csrss по очереди уведомляет активные процессы о завершении работы системы. Для каждого процесса, кроме SCM, Csrss ждет его завершения в течение времени, указанного в HKU\.DEFAULT\Control Panel\Desktop\ WaitToKillAppTimeout (по умолчанию — 20 секунд). Дойдя до SCM, Csrss так же уведомляет его о завершении работы системы, но использует особый тайм аут. Csrss опознает SCM по идентификатору процесса, сохраненному SCM при инициализации системы вызовом RegisterServicesProcess. Таймаут SCM отличен от таймаутов других процессов изза того, что он обменивается сообщения ми с сервисами. При завершении работы сервисы должны освободить ресур сы, поэтому администратору может быть достаточно настроить лишь тайма ут SCM. Это значение хранится в HKLM\SYSTEM\CurrentControlSet\ Cont rol\WaitToKillServiceTimeout и по умолчанию равно 20 секундам. Обработчик завершения SCM отвечает за рассылку уведомлений о за вершении работы всем сервисам, которые сообщали при инициализации о необходимости посылки им таких уведомлений. SCMфункция ScShutdown AllServices ищет в базе данных SCM сервисы, которым требуется уведомление о завершении работы, и посылает каждому из них команду на завершение. Для каждого сервиса, которому посылается уведомление о завершении ра боты, SCM фиксирует срок ожидания (wait hint), который указывается и са мим сервисом при его регистрации. SCM определяет наибольший срок ожи дания. Разослав уведомления о завершении работы, SCM ждет, пока не завер
250 ГЛ А В А 4 БЕЗОПАСНОСТЬ шится хотя бы один из получивших уведомление сервисов или пока не ис течет наибольший срок ожидания. Если по истечении этого срока сервис так и не завершился, SCM проверя ет, не получил ли он сообщения о ходе процесса завершения от одного или нескольких ожидаемых им сервисов. Если хотя бы один сервис прислал та кое сообщение, SCM снова ждет в течение периода, равного сроку ожидания. SCM выходит из этого цикла ожидания, если все сервисы завершились или если ни один из них не прислал ему сообщение о ходе процесса завершения. Пока SCM занят рассылкой уведомлений и ожиданием завершения сер висов, Csrss ожидает завершения SCM. Если период ожидания Csrss (равный значению WaitToKillServiceTimeout) истекает, а SCM все еще выполняется, Csrss просто переходит к другим операциям, необходимым для завершения работы системы. Таким образом, сервисы, не прекратившие свою работу вовремя, продолжают выполняться вместе с SCM до момента выключения системы. К сожалению, нет никакого способа, который позволил бы адми нистратору узнать, надо ли увеличить значение WaitToKillServiceTimeout, чтобы все сервисы успевали завершаться до выключения системы. (Подроб нее о процессе выключения системы см. в главе 5.) Разделяемые процессы сервисов Выполнение каждого сервиса в собственном процессе может оказаться очень расточительным по отношению к системным ресурсам. С другой сто роны, если в какомто из сервисов, совместно использующих один процесс, возникает ошибка, вызывающая завершение этого процесса, работа всех сервисов этого процесса прекращается. Некоторые из встроенных сервисов Windows выполняются в собствен ных процессах, а некоторые делят процессы совместно с другими сервиса ми. Например, процесс SCM включает сервисы Event Log (Журнал системы) и Plug and Play пользовательского режима, а процесс LSASS содержит такие службы защиты, как Security Accounts Manager (SamSs) (Диспетчер учетных записей безопасности), Net Logon (Netlogon) (Сетевой вход в систему) и IPSec Policy Agent (PolicyAgent) (Агент политики IPбезопасности). Существует также «универсальный» процесс, Service Host (SvcHost) (\Win dows\System32\Svchost.exe), который включает множество разнообразных сервисов. В различных процессах может выполняться несколько экземпля ров SvcHost. К сервисам, размещаемым в процессах SvcHost, относятся, в ча стности, Telephony (TapiSrv), Remote Procedure Call (RpcSs) и Remote Access Connection Manager (RasMan). Windows реализует сервисы, выполняемые в SvcHost, в виде DLL и включает в раздел реестра каждого из этих сервисов определение ImagePath в формате «%SystemRoot%\System32\Svchost.exe –k netsvcs». В подразделе Parameters раздела такого сервиса должен присутство вать и параметр ServiceDll, указывающий на DLLфайл сервиса. Для всех сервисов, использующих общий процесс SvcHost, должен быть указан один и тот же параметр («–k netsvcs» — в примере из предыдущего абзаца), чтобы у них была одна запись в базе данных образов. Когда SCM,
ГЛАВА 9 Механизмы управления 251 запуская сервисы, обнаруживает первый сервис с ImagePath, указывающим на SvcHost с какимто параметром, он создает новую запись в базе данных образов и запускает процесс SvcHost с этим параметром. Новый процесс SvcHost принимает этот параметр и ищет одноименный параметр в разде ле реестра HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Svchost. SvcHost считывает его, интерпретируя как список имен сервисов, и при ре гистрации уведомляет SCM о предоставляемых сервисах. Пример раздела Svchost показан на рис. 418. Здесь процесс Svchost, запущенный с парамет ром «–k netsvcs», настроен на выполнение нескольких сетевых сервисов. Рис. 4-18. Раздел реестра Svchost Если при запуске сервисов SCM обнаруживает сервис SvcHost со значе нием ImagePath, которое соответствует уже существующей записи в базе дан ных образов, он не запускает второй процесс, а просто посылает уже выпол няемому SvcHost команду на запуск этого сервиса. Существующий процесс SvcHost считывает из раздела реестра сервиса параметр ServiceDll и загружа ет DLL этого сервиса. ЭКСПЕРИМЕНТ: просмотр сервисов, выполняемых в процессах Утилита Process Explorer (www.sysinternals.com) выводит детальные све дения о сервисах, выполняемых внутри процессов. Запустите Process Explorer и откройте вкладки Services в окнах свойств для следующих процессов: Services.exe, Lsass.exe и Svchost.exe. В вашей системе долж но выполняться несколько экземпляров SvcHost, и вы сможете увидеть, под какой учетной записью работает каждый из них, добавив столбец Username в окне Process Explorer или взглянув на поле Username на вкладке Image окна свойств процесса. На иллюстрации ниже показан список сервисов, выполняемых внутри SvcHost, который работает под учетной записью локальной системы. см. след. стр.
252 ГЛ А В А 4 БЕЗОПАСНОСТЬ Отображаемая информация включает имя сервиса, его экранное имя (display name) и описание (если таковое есть); описание выводит ся в Process Explorer внизу списка при выборе конкретного сервиса. Просмотреть список сервисов, выполняемых внутри процессов, также можно с помощью утилит командной строки tlist.exe из Win dows Support Tools и Tasklist, которая входит в состав Windows XP и Windows Server 2003. В первом случае синтаксис для просмотра сер висов выглядит так: tlist /s А во втором — так: tasklist /svc Заметьте, что эти утилиты не показывают описания или экранные имена сервисов. Программы управления сервисами Программы управления сервисами (service control programs, SCP) — стандарт ные Windowsприложения, использующие SCMфункции управления серви сами CreateService, OpenService, StartService, ControlService, QueryServiceStatus и DeleteService. Для вызова SCMфункций SCP сначала должна установить ка нал связи с SCM через функцию OpenSCManager. При запросе на открытие канала связи SCP должна указать, какие действия ей нужно выполнить. На пример, если SCP требуется просто вывести список сервисов, присутствую щих в базе данных SCM, то при вызове она запрашивает доступ для перечис ления сервисов (enumerateservice access). При инициализации SCM создает внутренний объект, представляющий его базу данных. Для защиты этого объекта применяются функции защиты Windows. В частности, для него со здается дескриптор защиты, определяющий, по каким учетным записям мож но открывать объект и с какими правами. Например, в дескрипторе защиты
ГЛАВА 9 Механизмы управления 253 указывается, что получить доступ к объекту SCM для перечисления сервисов может группа Authenticated Users, но открыть объект SCM для создания или удаления сервиса могут только администраторы. SCM реализует защиту не только своей базы данных, но и сервисов. Со здавая сервис вызовом CreateService, SCP указывает дескриптор защиты, со поставляемый с записью сервиса в базе данных. SCM хранит дескриптор за щиты в параметре Security раздела, соответствующего сервису. При инициа лизации SCM сканирует раздел Services и считывает дескриптор защиты, так что параметры защиты сохраняются между загрузками системы. SCP долж на указывать SCM тип доступа к сервису при вызове OpenService по аналогии с тем, как она это делает, вызывая OpenSCManager для обращения к базе дан ных SCM. SCP может запрашивать доступ для получения информации о со стоянии сервиса, а также для его настройки, остановки и запуска. SCP, которая вам, наверное, хорошо знакома, — оснастка Services (Служ бы) консоли MMC в Windows. Эта оснастка содержится в файле Windows\ System32\Filemgmt.dll. Windows XP и Windows Server 2003 включают SCP ко мандной строки Sc.exe (Service Controller), а для Windows 2000 такая про грамма доступна в ресурсах Windows 2000. Иногда SCP расширяет политику управления сервисами по сравнению с той, которая реализуется SCM. Удачный пример — таймаут, устанавливаемый оснасткой Services при запуске сервисов (служб) вручную. Эта оснастка вы водит индикатор, отражающий ход запуска сервиса. Если SCM ждет ответа сервиса на команду запуска неопределенно долго, то оснастка Services — только 2 минуты, после чего сообщает, что сервис не смог своевременно начать работу. Сервисы косвенно взаимодействуют с SCPпрограммами, из меняя свой статус, который отражает их прогресс в выполнении команды SCM. SCP запрашивают этот статус через функцию QueryServiceStatus и спо собны отличать зависшие сервисы от активно обновляющих свой статус. Благодаря этому они могут уведомлять пользователя о том, что делает тот или иной сервис. Windows Management Instrumentation В Windows NT всегда были интегрированные средства мониторинга произ водительности и системных событий. Приложения и система, как правило, используют Event Manager (Диспетчер событий) для вывода сообщений об ошибках и диагностической информации. С помощью Event Viewer (Про смотр событий) администраторы могут просматривать список событий как на локальном компьютере, так и на любом компьютере в сети. Аналогичным образом механизм поддержки счетчиков производительности позволяет приложениям и операционной системе передавать соответствующие стати стические сведения таким программам мониторинга производительности, как Performance Monitor. Хотя средства мониторинга событий и производительности в Windows NT 4 решают поставленные при разработке задачи, для них характерны
254 ГЛ А В А 4 БЕЗОПАСНОСТЬ некоторые ограничения. Так, их программные интерфейсы различаются, что усложняет приложения, использующие для сбора данных не только мони торинг событий, но и мониторинг производительности. Вероятно, самый серьезный недостаток средств мониторинга в Windows NT 4 в том, что они слабо расширяемы (если вообще расширяемы) и не поддерживают двусто роннее взаимодействие, необходимое для API управления. Приложения дол жны предоставлять данные в жестко предопределенных форматах. Perfor mance API не позволяет приложениям получать уведомления о событиях, связанных с производительностью, а приложения, запрашивающие уведом ления о событиях Event Manager, не могут ограничиться конкретными типа ми событий или источниками. Наконец, клиенты любого из механизмов мониторинга не могут взаимодействовать через Event Manager или Perfor mance API с провайдерами данных, относящихся к событиям или счетчикам производительности. Для устранения этих ограничений и поддержки средств управления дру гими типами источников данных в Windows включен новый механизм управ ления, Windows Management Instrumentation (WMI) (Инструментарий управ ления Windows). WMI — это реализация WebBased Enterprise Management (WBEM) (Управление предприятием на основе Web), стандарта, введенного промышленным консорциумом Distributed Management Task Force (DMTF). Стандарт WBEM определяет правила проектирования средств управления и сбора данных в масштабах предприятия, обладающих достаточной расширя емостью и гибкостью для управления локальными и удаленными системами, которые состоят из произвольных компонентов. Поддержка WMI добавляет ся в Windows NT 4 установкой Service Pack 4. WMI также поддерживается в Windows 95 OSR2, Windows 98 и Windows Millennium. Хотя многие сведения из этого раздела применимы ко всем платформам Windows, поддерживающим WMI, особенности реализации WMI, о которых мы здесь рассказываем, все же специфичны для Windows 2000, Windows XP и Windows Server 2003. Архитектура WMI WMI состоит из четырех главных компонентов, как показано на рис. 419: управляющих приложений, инфраструктуры WMI, компонентов доступа (провайдеров) и управляемых объектов. Первые являются Windowsприло жениями, получающими сведения об управляемых объектах для последую щей обработки или вывода. Пример простого управляющего приложения — утилита Performance (Производительность), использующая WMI вместо Per formance API. К более сложным программам относятся промышленные сред ства управления, позволяющие администраторам автоматизировать инвен таризацию программноаппаратных конфигураций всех компьютеров на своих предприятиях.
ГЛАВА 9 Рис. 4-19. Механизмы управления 255 Архитектура WMI Управляющие приложения, как правило, предназначены для управления определенными объектами и сбора данных от них. Объект может представ лять единственный компонент, например сетевую плату, или совокупность компонентов вроде компьютера. (Объект «компьютер» может включать объект «сетевая плата».) Провайдеры должны определять и экспортировать форму представления объектов, нужных управляющим приложениям. Так, изготовитель может добавить специфичную функциональность для сетевой платы, поддерживаемой WMI. Поэтому он должен написать свой провайдер, который открывал бы управляющим приложениям объекты, связанные с этой функциональностью. Инфраструктура WMI, центральное место в которой занимает Common Information Model (CIM) Object Manager (CIMOM), связывает воедино управ ляющие приложения и провайдеры (о CIM — чуть позже). Инфраструктура также служит хранилищем классов объектов и зачастую диспетчером хра нения свойств постоянных объектов. WMI реализует это хранилище в виде базы данных на диске, которая называется репозитарием объектов CIMOM (CIMOM Object Repository). WMI поддерживает несколько API, через которые управляющие приложения обращаются к данным объектов, провайдерам и определениям классов. Для прямого взаимодействия с WMI Windowsпрограммы используют WMI COM API, основной API управления. Остальные API размещаются поверх COM
256 ГЛ А В А 4 БЕЗОПАСНОСТЬ API и включают ODBCадаптер для СУБД Microsoft Access. Разработчик может использовать этот адаптер для встраивания ссылок на данные объектов в свою базу данных. После этого можно легко генерировать отчеты с помощью зап росов к базе данных, содержащей WMIинформацию. ActiveXэлементы WMI поддерживают другой многоуровневый API. Webразработчики используют ActiveXэлементы для создания Webинтерфейсов к WMIданным. API для на писания сценариев WMI представляет собой еще один API управления, ис пользуемый в приложениях, построенных на основе сценариев («скриптов»), и в программах Microsoft Visual Basic. Поддержка сценариев WMI предусмот рена во всех технологиях языков программирования Microsoft. Как и для управляющих приложений, интерфейсы WMI COM образуют основной API для провайдеров. Но в отличие от управляющих приложений, являющихся COMклиентами, провайдеры — это COM или DCOMсерверы, т. е. провайдеры реализуют COMобъекты, с которыми взаимодействует WMI. Провайдеры могут быть реализованы в виде DLL, загружаемых в процесс дис петчера WMI, а также в виде отдельных Windowsприложений или сервисов. Microsoft предлагает ряд встроенных провайдеров, которые представляют данные из таких общеизвестных источников, как Performance API, реестр, Event Manager, Active Directory, SNMP и WDMдрайверы устройств. Сторонние разработчики могут создавать свои компоненты доступа, используя WMI SDK. Провайдеры В основе WBEM лежит спецификация CIM, разработанная DMTF. CIM опреде ляет, как управляющие системы представляют любые компоненты вычисли тельной системы — от компьютера до устройств и приложений. Разработчи ки провайдеров используют CIM для представления компонентов приложе ния, для которого они предусматривают возможность управления. Реализация CIMпредставлений осуществляется на языке Managed Object Format (MOF). Провайдер должен не только определять классы, представляющие объек ты, но и обеспечивать WMIинтерфейс с объектами. WMI классифицирует провайдеры в соответствии с функциями их интерфейса. Эта классифика ция показана в таблице 410. Заметьте, что провайдер может реализовать несколько функций и благодаря этому выступать сразу в нескольких ролях, например провайдера классов и провайдера событий. Чтобы лучше понять определения функций в таблице 410, рассмотрим провайдер Event Log, ре ализующий несколько таких функций. Он поддерживает несколько объек тов, включая Event Log Computer, Event Log Record и Event Log File. Event Log является провайдером Instance, так как способен определять несколько эк земпляров своих классов. Один из классов, определяемых Event Log в не скольких экземплярах, — Event Log File (Win32_NTEventlogFile); экземпляр этого класса определяется для каждого журнала событий: System Event Log (Журнал системы), Application Event Log (Журнал приложений) и Security Event Log (Журнал безопасности).
ГЛАВА 9 Механизмы управления 257 Таблица 4-10. Классификация провайдеров Классификация Описание Class (провайдер классов) Предоставляет, изменяет, удаляет и перечисляет клас сы, специфичные для конкретного провайдера. Также может поддерживать обработку запросов. Примером этого редкого вида провайдеров служит Active Directory Instance (провайдер экземпляров) Предоставляет, изменяет, удаляет и перечисляет эк земпляры системных или специфичных для провай дера классов. Каждый экземпляр представляет управ ляемый объект. Также может поддерживать обработку запросов Property (провайдер свойств) Предоставляет и изменяет значения свойств индиви дуальных объектов Method (провайдер методов) Предоставляет методы класса, специфичного для провайдера Event (провайдер событий) Генерирует уведомления о событиях Event consumer (провайдер потребителя событий) Увязывает физического потребителя с логическим для поддержки уведомлений о событиях Провайдер Event Log определяет данные экземпляра и позволяет управ ляющим приложениям перечислять записи. Методы backup и restore, реали зуемые Event Log для объектов Event Log File, позволяют управляющим при ложениям создавать резервные копии файлов Event Log и восстанавливать их через WMI. А это дает основания считать Event Log и провайдером Me thod. Наконец, управляющее приложение может зарегистрироваться на по лучение уведомлений о создании новых записей в файлах Event Log. Таким образом, Event Log, уведомляя WMI о создании новых записей, выступает еще и в роли провайдера Event. CIM и язык Managed Object Format CIM следует по стопам объектноориентированных языков типа С++ и Java, в которых средства моделирования создают представления в виде классов. Работая с классами, программисты могут использовать мощные методы мо делирования, например наследование и включение. Подклассы могут насле довать атрибуты классапредка, добавляя при этом собственные и даже пе реопределяя унаследованные. Класс, наследующий свойства другого класса, считается производным. В то же время классы можно составлять, создавая новый класс, включающий другие. DMTF предоставляет набор классов как часть стандарта WBEM. Эти клас сы образуют базовый язык CIM и представляют объекты, применимые во всех сферах управления. Классы являются частью базовой модели CIM (CIM core model). Примером базового класса может служить CIM_ManagedSys temElement. У него есть несколько базовых свойств, идентифицирующих физические компоненты вроде аппаратных устройств и логические компо ненты типа процессов и файлов. К свойствам относятся заголовок (caption),
258 ГЛ А В А 4 БЕЗОПАСНОСТЬ описание (description), дата установки (installation date) и статус (status). Та ким образом, классы CIM_LogicalElement и CIM_PhysicalElement наследуют атрибуты класса CIM_ManagedSystemElement. Эти два класса тоже входят в базовую модель CIM. В стандарте WBEM эти классы называются абстракт ными, поскольку они существуют только как наследуемые другими класса ми (т. е. создать объект абстрактного класса нельзя). Абстрактные классы можно считать шаблонами, которые определяют свойства, используемые в других классах. Вторая категория классов представляет объекты, специфичные для сфер управления, но независимые от конкретной реализации. Эти классы обра зуют общую модель (common model) и считаются расширением базовой модели. Пример класса общей модели — CIM_FileSystem, наследующий атри буты CIM_LogicalElement. Поскольку практически все операционные систе мы, включая Windows, Linux и прочие вариации UNIX, опираются на храни лище данных, структурируемое на основе той или иной файловой системы, класс CIM_FileSystem является важной частью общей модели. Последняя категория классов, расширенная модель (extended model), включает расширения, специфичные для конкретных технологий. В Win dows определен обширный набор таких классов, представляющих объекты, специфичные для подсистемы Windows. Так как все операционные системы хранят данные в файлах, в общую модель CIM входит класс CIM_LogicalFile. Класс CIM_DataFile наследует свойства CIM_LogicalFile, а Windows добавля ет классы Win32_PageFile и Win32_ShortcutFile для соответствующих типов файлов в подсистеме Windows. Провайдер Event Log интенсивно использует наследование. На рис. 420 показано, как выглядит WMI CIM Studio, браузер классов, поставляемый с WMI Administrative Tools (этот набор можно бесплатно получить с сайта Microsoft). Использование наследования в провайдере Event Log можно на блюдать на примере его класса Win32_NTEventlogFile, производного от CIM_ DataFile. Файлы Event Log — это файлы данных, которые имеют дополни тельные атрибуты, специфичные для файлов журналов: имя файла журнала (LogfileName) и счетчик числа записей в файле (NumberOfRecords). Отобра жаемое браузером дерево классов показывает, что Win32_NTEventlogFile использует несколько уровней наследования: CIM_DataFile является произ водным от CIM_LogicalFile, тот — от CIM_LogicalElement, а последний — от CIM_ManagedSystemElement. Как уже говорилось, разработчики провайдеров WMI пишут свои классы на языке MOF. Ниже показано определение класса Win32_NTEventlogFile компонента Event Log, выбранного на рис. 420. Обратите внимание на кор реляцию свойств, перечисленных в правой секции окна браузера классов, и их определений. Свойства, наследуемые классом, помечаются в CIM Studio желтыми стрелками, и в определении Win32_NTEventlogFile эти свойства отсутствуют.
ГЛАВА 9 Рис. 4-20. Механизмы управления WMI CIM Studio — браузер классов [dynamic: ToInstance, provider("MS_NT_EVENTLOG_PROVIDER"), Locale(1033), UUID("{8502C57B5FBB11D2AAC1006008C78BC7}")] class Win32_NTEventlogFile : CIM_DataFile { [read] string LogfileName; [read,write] uint32 MaxFileSize; [read] uint32 NumberOfRecords; [read,volatile,ValueMap{"0", "1..365", "4294967295"}] string OverWritePolicy; [read,write,Units("Days"),Range("0365 | 4294967295")] uint32 OverwriteOutDated; [read] string Sources[]; [implemented,Privileges{"SeSecurityPrivilege", "SeBackupPrivilege"}] uint32 ClearEventlog([in] string ArchiveFileName); [implemented,Privileges{"SeSecurityPrivilege", 259
260 ГЛ А В А 4 БЕЗОПАСНОСТЬ "SeBackupPrivilege"}] uint32 BackupEventlog([in] string ArchiveFileName); }; Одно ключевое слово, на которое стоит обратить внимание в заголовке класса Win32_NTEventlogFile, — dynamic. Его смысл в том, что всякий раз, когда управляющее приложение запрашивает свойства объекта, инфраструк тура WMI обращается к WMIпровайдеру за значениями соответствующих свойств, сопоставленных с объектом данного класса. Статическим (static) считается класс, находящийся в репозитарии WMI; в этом случае инфра структура WMI получает значения свойств из репозитария и не обращается к WMIпровайдеру. Поскольку обновление репозитария — операция отно сительно медленная, динамические компоненты доступа более эффективны в случае объектов с часто изменяемыми свойствами. ЭКСПЕРИМЕНТ: просмотр MOF-определений WMI-классов Для просмотра MOFопределения любого WMIкласса используйте утилиту WbemTest, поставляемую с Windows. В этом эксперименте мы покажем, как увидеть MOFопределение класса Win32_NTEventLogFile. 1. Запустите Wbemtest через диалоговое окно Run (Запуск програм мы), открываемое из меню Start (Пуск). 2. Щелкните кнопку Connect (Подключить), измените Namespace (Na mespace) на root\cimv2 и вновь щелкните кнопку Connect. 3. Выберите Enum Classes (Классы), установите переключатель Recur sive (Рекурсивно) и нажмите OK. 4. Найдите Win32_NTEventLogFile в списке классов и дважды щелкни те его, чтобы увидеть свойства этого класса. 5. Щелкните кнопку Show MOF (Вывести MOF), чтобы открыть окно с MOFопределением. После создания классов на MOF разработчики могут предоставлять их оп ределения в WMI несколькими способами. Разработчик провайдера компили рует MOFфайл в двоичный (BMF), более компактную форму представления, и передает BMFфайл инфраструктуре WMI. Другой способ заключается в ком пиляции MOFфайла и программной передаче определений от провайдера в инфраструктуру WMI через функции WMI COM API. Наконец, можно задей ствовать утилиту MOF Compiler (Mofcomp.exe), чтобы передать скомпилиро ванное представление классов непосредственно инфраструктуре WMI. Пространство имен WMI Классы определяют свойства объектов, а объекты являются экземплярами клас сов в системе. Для иерархического упорядочения объектов WMI использует пространство имен, в котором может содержаться несколько подпространств имен. Управляющее приложение должно подключиться к пространству имен, прежде чем оно сможет получить доступ к расположенным там объектам.
ГЛАВА 9 Механизмы управления 261 Корневой каталог пространства имен WMI называется корнем и обознача ется как Root. В каждой WMIсистеме есть четыре предопределенных простран ства имен, расположенных под корнем: CIMV2, Default, Security и WMI. Некото рые из них тоже включают другие пространства. Так, в CIMV2 входят подпрос транства имен Applications и ms_409. Иногда провайдеры определяют собствен ные пространства имен, например в Windows можно увидеть пространство имен WMI (определяемое WMIпровайдером для драйверов устройств). ЭКСПЕРИМЕНТ: просмотр пространств имен WMI Увидеть, какие пространства имен определены в системе, позволяет WMI CIM Studio. Этот браузер открывает при запуске диалоговое окно подключения, в котором справа от поля ввода пространства имен име ется кнопка для просмотра пространств имен. Выбрав интересующее вас пространство имен, вы заставите WMI CIM Studio подключиться к этому пространству имен. В Windows Server 2003 под корнем опреде лено свыше десятка пространств имен, некоторые из которых видны на следующей иллюстрации. В отличие от пространства имен файловой системы, которое включает иерархию каталогов и файлов, пространство имен WMI имеет только один уровень вложения. Вместо имен WMI использует свойства объектов, которые определяет как ключи (keys), идентифицирующие эти объекты. Указывая объект в пространстве имен, управляющие приложения сообщают имя клас са и ключ. Таким образом, каждый экземпляр класса уникально идентифи цируется его ключом. Например, компонент доступа Event Log представля ет записи в журнале событий классом Win32_NTLogEvent. У этого класса есть два ключа: Logfile (строковый) и RecordNumber (беззнаковый целочислен ный). Поэтому, запрашивая у WMI экземпляры записей журнала событий, управляющее приложение идентифицирует их парой ключей. Вот пример ссылки на одну из записей: \\DARYL\root\CIMV2:Win32_NTLogEvent.Logfile="Application", RecordNumber="1"
262 ГЛ А В А 4 БЕЗОПАСНОСТЬ Первая часть имени (\\DARYL) идентифицирует компьютер, на котором находится объект, а вторая (\root\CIMV2) — пространство имен, где разме щен объект. Имя класса следует после двоеточия, а имена ключей и их зна чения — после точки. Значения ключей отделяются запятыми. WMI предоставляет интерфейсы, позволяющие приложениям перечислять все объекты конкретного класса или выполнять запросы, которые возвраща ют экземпляры какоголибо класса, удовлетворяющие критериям запроса. Классы сопоставления Многие типы объектов так или иначе связаны между собой. Например, объект «компьютер» включает объекты «процессор», «программное обеспе чение», «операционная система», «активный процесс» и т. д. WMI позволяет создавать класс сопоставления (association class), представляющий логичес кую связь между двумя классами и поэтому имеющий всего два свойства: имя класса и модификатор Ref. Ниже показан исходный текст на MOF, сопостав ляющий классы Win32_NTLogEvent и Win32_ComputerSystem. Получив ка който объект, управляющее приложение может запрашивать и сопоставлен ные объекты. Благодаря таким сопоставлениям компонент доступа получа ет возможность определять иерархию объектов. [dynamic: ToInstance, provider("MS_NT_EVENTLOG_PROVIDER"): ToInstance, EnumPrivileges{"SeSecurityPrivilege"}: ToSubClass, Locale(1033): ToInstance, UUID("{8502C57F5FBB11D2AAC1 006008C78BC7}"): ToInstance, Association : DisableOverride ToInstance ToSubClass] class Win32_NTLogEventComputer { [key, read: ToSubClass] Win32_ComputerSystem ref Computer; [key, read: ToSubClass] Win32_NTLogEvent ref Record; }; На рис. 421 показан WMI Object Browser (еще один инструмент, включа емый в WMI Administrative Tools), который показывает содержимое про странства имен CIMV2. В это пространство имен обычно помещают свои объекты системные компоненты Windows. Браузер объектов сначала опре деляет местонахождение объекта MRXEON, экземпляра Win32_Computer System, представляющего компьютер. Далее браузер получает объекты, сопо ставленные с Win32_ComputerSystem и отображает их под MRXEON. Поль зовательский интерфейс браузера объектов помечает сопоставленные объекты значком папки с двуглавой стрелкой. Как видите, класс сопоставления Win32_NTLogEventComputer показывает ся под MRXEON и существует несколько экземпляров класса Win32_NTLog Event. Посмотрите на предыдущий листинг — вы убедитесь, что класс Win32_ NTLogEventComputer определен для сопоставления классов Win32_ Computer System и Win32_NTLogEvent. Выбрав в браузере объектов экземпляр Win32_ NTLogEvent, вы увидите в правой секции на вкладке Properties свойства этого класса. Microsoft предоставляет WMI Object Browser, чтобы WMIразработчики
ГЛАВА 9 Механизмы управления 263 могли изучать свои объекты, но управляющие приложения, выполняя те же операции, показывают свойства или собранные данные более наглядно. Рис. 4-21. WMI Object Browser ЭКСПЕРИМЕНТ: использование WMI-сценариев для управления системами Сильная сторона WMI — его поддержка языков сценариев. Microsoft создала сотни сценариев, выполняющих распространенные админи стративные задачи для управления учетными записями пользователей, файлами, реестром, процессами и аппаратными устройствами. Неко торые сценарии поставляются с ресурсами Windows, но основная их часть находится на сайте Microsoft TechNet Scripting Center. Использо вать сценарий с этого сайта очень легко: достаточно скопировать его текст из окна Интернетбраузера, сохранить в файле с расширением .vbs и запустить командой cscript script.vbs, где script — имя, присво енное вами данному сценарию. Cscript — это интерфейс командной строки для Windows Script Host (WSH). Вот пример сценария из TechNet, который регистрируется на полу чение событий при создании экземпляров Win32_Process (его экземп ляр создается всякий раз, когда запускается какойлибо процесс) и вы водит строку с именем процесса, представляемым данным объектом: strComputer = "." Set objWMIService = GetObject("winmgmts:" _ & "{impersonationLevel=impersonate}!\\" & _ strComputer & "\root\cimv2") Set colMonitoredProcesses = objWMIService. _ ExecNotificationQuery("select * from _ __instancecreationevent " _ & " within 1 where TargetInstance isa 'Win32_Process'") i = 0 см. след. стр.
264 ГЛ А В А 4 БЕЗОПАСНОСТЬ Do While i = 0 Set objLatestProcess = colMonitoredProcesses.NextEvent Wscript.Echo objLatestProcess.TargetInstance.Name Loop В строке, где вызывается ExecNotificationQuery, этой функции пере дается параметр, который включает выражение select из поддержива емого WMI подмножества ANSIстандарта Structured Query Language (SQL) только для чтения. Это подмножество называется WQL, и оно предоставляет WMIпотребителям гибкий способ задания информа ции, которую им нужно запросить от WMIпровайдеров. Если вы за пустите этот сценарий с помощью Cscript, а затем запустите Notepad, то получите следующий вывод: C:\>cscript monproc.vbs Microsoft (R) Windows Script Host Version 5.6 Copyright (C) Microsoft Corporation 19962001. All rights reserved. NOTEPAD.EXE Реализация WMI В Windows 2000 WMIсервис реализован в \Windows\System32\Winmgmt.exe, который запускается SCM при первой попытке доступа управляющего при ложения или WMIпровайдера к WMI API. В Windows XP и Windows Server 2003 WMIсервис работает в общем процессе Svchost, выполняемом под учетной записью локальной системы. В Windows 2000 WMI загружает провайдеры как внутренние (внутрипро цессные) DCOMсерверы, выполняемые внутри сервисного процесса Win mgmt. Если ошибка в провайдере приведет к краху процесса WMI, WMIсер вис завершится, а затем перезапустится в ответ на следующий запрос к WMI. Поскольку WMIсервис разделяет свой процесс Svchost с несколькими дру гими сервисами, которые тоже могут завершаться при ошибке в WMIпро вайдере, вызывающей закрытие этого процесса, в Windows XP и Windows Server 2003 WMI загружает провайдеры в хостпроцесс Wmiprvse.exe. Он за пускается как дочерний по отношению к сервисному процессу RPC. WMI выполняет Wmiprvse под учетной записью Local System, Local Service или Network Service в зависимости от значения свойства HostingModel экземп ляра WMIобъекта Win32Provider, который представляет реализацию про вайдера. Процесс Wmiprvse завершается, как только провайдер удаляется из кэша, спустя минуту после приема последнего запроса к провайдеру. ЭКСПЕРИМЕНТ: наблюдение за созданием Wmiprvse Чтобы понаблюдать за созданием Wmiprvse, запустите Process Explorer и выполните Wmic. Процесс Wmiprvse появится под процессом Svc
ГЛАВА 9 Механизмы управления 265 host, который служит хостом сервиса RPC. Если в Process Explorer включена функция выделения заданий, вы увидите, что появился не только новый процесс, но и новое задание. Дело здесь вот в чем. Что бы предотвратить исчерпание всей виртуальной памяти в системе плохо написанным провайдером, Wmiprvse запускается в объекте «за дание», который ограничивает количество создаваемых дочерних про цессов и объемы виртуальной памяти, допустимые для выделения каж дым процессом. (Об объектах «задание» см. главу 6.) Большинство компонентов WMI, в том числе MOFфайлы, DLL встроенных провайдеров и DLL управляющих приложений, по умол чанию размещаются в каталогах \Windows\System32 и \Windows\Sys tem32\Wbem. Во втором каталоге вы найдете MOFфайл провайдера Event Log, Ntevt.mof. Там же находится и Ntevt.dll, DLL провайдера Event Log, используемая WMIсервисом. В подкаталогах каталога \Windows\System32\Wbem находятся репо зитарий, файлы журналов и MOFфайлы сторонних разработчиков. Репозитарий, называемый репозитарием CIMOM, реализуется в WMI с применением закрытой версии ядра баз данных Microsoft JET. В Win dows 2000 база данных хранится в файле \Windows\System32\Wbem\ Repository\Cim.rep. WMI учитывает параметры реестра (включая различ ные внутренние параметры в Windows 2000 вроде расположения резерв ных копий файлов CIMOM и интервалов между их созданием), которые хранятся в разделе HKLM\SOFTWARE\Microsoft\WBEM\CIMOM. Для обмена данными с WMI и приема команд от него драйверы ус тройств используют специальные интерфейсы под общим названием WMI System Control Commands. Эти межплатформенные интерфейсы являются частью WDM (см. главу 9). WMIC В состав Windows XP и Windows Server 2003 входит утилита Wmic.exe, позволяющая взаимодействовать с WMI из оболочки командной стро ки с поддержкой WMI. Через эту оболочку доступны все WMIобъек ты и их свойства и методы, что превращает WMIC в консоль расши ренного управления системами.
266 ГЛ А В А 4 БЕЗОПАСНОСТЬ Защита WMI WMI реализует защиту на уровне пространства имен. Если управляющее приложение успешно подключилось к пространству имен, оно получает доступ к любым свойствам всех объектов этого пространства имен. Для уп равления доступом пользователей к пространству имен администратор мо жет задействовать приложение WMI Control. Для запуска WMI Control пос ледовательно откройте в меню Start (Пуск) подменю Programs (Программы) и Administrative Tools (Администрирование), а затем выберите команду Com puter Management (Управление компьютером). Далее раскройте узел Services And Applications (Службы и приложения), щелкните правой кнопкой мыши строку WMI Control (Управляющий элемент WMI) и выберите команду Pro perties (Свойства) для вывода диалогового окна WMI Control Properties (Свой ства: Управляющий элемент WMI), которое показано на рис. 422. Для на стройки параметров защиты пространства имен перейдите на вкладку Se curity (Безопасность), выберите пространство имен и щелкните кнопку Secu rity (Безопасность). Другие вкладки диалогового окна WMI Control Properties позволяют изменять сохраняемые в реестре настройки, которые относятся к функционированию WMI и резервному копированию. Рис. 4-22. Параметры защиты WMI Резюме К этому моменту мы уже рассмотрели общую структуру Windows, базовые системные механизмы, на которые опирается эта структура, и основные механизмы управления. Заложив такой фундамент, можно переходить к бо лее подробному изучению процесса загрузки и индивидуальных компонен тов исполнительной системы.
Г Л А В А 5 Запуск и завершение работы системы В этой главе описываются стадии загрузки Windows, а также параметры, влия ющие на процесс ее запуска. Понимание тонкостей процесса загрузки по может вам в диагностике проблем, возникающих при загрузке Windows. Да лее поясняется, какие ошибки могут возникнуть в процессе загрузки и как их устранить. В заключение мы рассмотрим, что происходит при коррект ном завершении работы системы. Процесс загрузки Описание процесса загрузки мы начнем с рассмотрения установки Windows, а затем исследуем выполнение загрузочных файлов. Поскольку драйверы ус тройств играют ключевую роль в процессе загрузки, будет уделено внима ние и тому, как они контролируют собственную загрузку и инициализацию. Далее мы поясним, как инициализируются компоненты исполнительной системы и как ядро запускает пользовательскую часть Windows, активизируя процессы Session Manager (Smss.exe) и Winlogon, а также подсистему Win dows. Попутно вы узнаете, что происходит внутри системы на момент вы вода тех или иных текстовых сообщений, появляющихся на экране в про цессе загрузки. Ранние стадии процесса загрузки на платформах x86 и x64 сильно отли чаются от таковых на платформе IA64. В следующих разделах описываются стадии, специфичные для x86 и x64, а потом поясняются стадии, специфич ные для IA64. Что предшествует загрузке на платформах x86 и x64 Процесс загрузки Windows начинается не при включении компьютера или нажатии кнопки Reset, а еще при установке этой системы на компьютер. На одном из этапов работы программы установки Windows (Windows Setup) происходит подготовка основного жесткого диска системы: на нем разме щается код, в дальнейшем участвующий в процессах загрузки. Прежде чем рассказывать, что делает этот код, мы покажем, как и в какой области жест кого диска он размещается.
268 ГЛ А В А 5 БЕЗОПАСНОСТЬ Стандарт разбиения физических жестких дисков на тома существует в сис темах типа x86 со времен первых версий MSDOS. Операционные системы Microsoft разбивают жесткие диски на дискретные области, называемые разде лами (partitions). После форматирования с использованием файловых систем (типа FAT и NTFS) разделы образуют тома. На жестком диске может быть до четырех главных разделов (primary partitions). Поскольку это ограничило бы количество томов на одном диске, данная схема предусматривает особый тип раздела — дополнительный (extended partition), что дает до четырех дополни тельных разделов в главном разделе. Дополнительные разделы могут содержать другие дополнительные разделы, те в свою очередь — третьи дополнительные разделы и т. д. Так что диск можно разбить практически на бесконечное число томов. Пример разбиения жесткого диска на разделы показан на рис. 51, а ком поненты, участвующие в процессе загрузки, перечислены в таблице 51. (Под робнее о разбиении жестких дисков в Windows см. главу 10.) Таблица 5-1. Компоненты, участвующие в процессе загрузки на платформах x86 и x64 Компонент Режим работы Описание Код главной загрузоч 16разрядный реальный ной записи (master boot record, MBR) Считывает в память загрузоч ные секторы раздела Загрузочный сектор 16разрядный реальный Считывает корневой каталог для загрузки Ntldr Ntldr 16разрядный реальный и 32 или 64разрядный защищен ный (активизирует поддержку подкачки страниц) Считывает Boot.ini, выводит загрузочное меню, загружает Ntoskrnl.exe, Bootvid.dll, Hal.dll и драйверы устройств, необ ходимые для загрузки и по следующего запуска системы. Если загружается 32разряд ная система, переключает в 32разрядный защищенный режим, а если загружается 64 разрядная система — в 64раз рядный защищенный режим Ntdetect.com 16разрядный реальный Обеспечивает распознавание устройств для Ntldr Ntbootdd.sys Защищенный Драйвер устройства, применя емый для дисковых операций вводавывода в системах со SCSI и ATA (Advanced Techno logy Attachment), где BIOS не используется Ntoskrnl.exe Защищенный с поддержкой подкачки страниц Инициализирует компоненты исполнительной системы, драйверы, необходимые для загрузки и запуска системы, подготавливает систему к вы полнению встроенных прило жений и запускает Smss.exe
ГЛАВА 9 Запуск и завершение работы системы 269 Таблица 5-1. (окончание) Компонент Режим работы Smss Встроенное приложение Загружает подсистему Win dows, включая Win32k.sys и Csrss.exe, и запускает про цесс Winlogon Winlogon Встроенное приложение Загружает SCM, подсистему локальной аутентификации (LSASS) и выводит на экран диалоговое окно для входа в систему Диспетчер управления Встроенное приложение сервисами (service control manager, SCM) Рис. 5-1. Загружает и инициализирует автоматически запускаемые драйверы устройств и серви сы Windows Пример структуры разделов жесткого диска Единицей адресации физических дисков является сектор. Типичный раз мер сектора жесткого диска на IBMсовместимом PC — 512 байтов. Такие утилиты, как Fdisk в MSDOS или программа Windows Setup, позволяющие создавать на жестком диске тома, записывают в первый сектор жесткого диска специальные данные, создавая таким образом главную загрузочную запись (MBR) диска (детали см. в главе 10). Размер MBR фиксирован. Она состоит из набора машинных команд (загрузочный код) и таблицы разде лов с четырьмя записями, которые определяют расположение главных раз делов на диске. Первый код, выполняемый при загрузке IBMсовместимого компьютера, называется BIOS, — он хранится в ПЗУ компьютера. BIOS вы
270 ГЛ А В А 5 БЕЗОПАСНОСТЬ бирает загрузочное устройство, считывает его MBR в память и передает уп равление ее загрузочному коду. MBR начинает со сканирования таблицы разделов в поисках раздела, по меченного особым флагом. Этот флаг сигнализирует, что данный раздел яв ляется загрузочным. Как только MBR обнаружит хотя бы один такой флаг, она считывает в память код из первого сектора раздела, помеченного флагом, и передает ему управление. Такой раздел называется загрузочным, как и его пер вый сектор, а том, определенный для загрузочного раздела, — системным. Операционная система, как правило, ведет запись в загрузочные секто ры без участия пользователя. Например, Windows Setup при записи MBR од новременно создает в первом загрузочном разделе жесткого диска свой заг рузочный сектор. Перед этим программа установки проверяет, является ли он сейчас загрузочным сектором MSDOS. Если да, Windows Setup сначала копирует содержимое загрузочного сектора в файл Bootsect.dos, помещая его в корневой каталог раздела. Перед записью в загрузочный сектор Windows Setup проверяет совмес тимость текущей файловой системы этого раздела с Windows. В любом слу чае она может отформатировать данный раздел с использованием выбран ной вами файловой системы (FAT, FAT32 или NTFS). Если раздел уже отфор матирован, вы можете пропустить этот этап. После того как загрузочный раздел отформатирован, Setup копирует на него файлы Windows, в том числе два стартовых файла, Ntldr и Ntdetect.com. Еще одна задача программы установки — создание файла загрузочного меню, Boot.ini, в корневом каталоге системного тома. В этом файле содер жатся параметры запуска устанавливаемой версии Windows, а также сведе ния обо всех системах, установленных до Windows. Если файл Bootsect.dos содержит загрузочный сектор MSDOS, в Boot.ini добавляется запись, позво ляющая загружать MSDOS. Ниже приведен пример файла Boot.ini с поддер жкой двухвариантной загрузки для компьютера, на котором перед установ кой Windows XP была установлена MSDOS. [boot loader] timeout=30 default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS [operating systems] multi(0)disk(0)rdisk(0)partition(1) \WINDOWS="Microsoft Windows XP Professional " /fastdetect C:\="Microsoft Windows" Заметьте, что в этом примере путь к каталогу Windows задан по специаль ному синтаксису, отвечающему соглашению по именованию Advanced RISC Computing (ARC). В Windows используется три вида такого синтаксиса. Пер вый, синтаксис multi(), показан в примере; он указывает Windows загружать системные файлы через функции прерывания INT 13, предоставляемые BIOS. Таким образом, синтаксис multi() применяется, когда у диска, на котором на ходится загрузочный том, есть контроллер с поддержкой прерывания INT 13. Синтаксис multi() имеет следующий формат:
ГЛАВА 9 Запуск и завершение работы системы 271 multi(W)disk(X)rdisk(Y)partition(Z) где W — номер дискового контроллера (также называемый порядковым но мером), обычно равный 0, X — всегда 0 в синтаксисе multi(), а Y указывает физический жесткий диск, подключенный к контроллеру W. Для ATAкон троллеров значение Y, как правило, укладывается в диапазон от 0 до 3, для SCSIконтроллеров — 0–15. Z сообщает номер раздела на физическом дис ке, соответствующего загрузочному тому. Первому разделу присваивается значение 1. ARCсинтаксис scsi() сообщает Windows, что для доступа к файлам на заг рузочном томе нужно задействовать сервисы дискового вводавывода, пре доставляемые Ntbootdd.sys (о нем чуть позже). Синтаксис scsi() выглядит так: scsi(W)disk(X)rdisk(Y)partition(Z) Здесь W — номер контроллера, X — физический жесткий диск, подклю ченный к этому контроллеру (обычно равен 0–15). Y указывает SCSI LUN номер (logical unit number) диска, содержащего загрузочный том, и, как пра вило, равен 0. Наконец, Z — это раздел, соответствующий загрузочному тому с нумерацией, начинающейся от 1. Наконец, в Windows применяется третий вид синтаксиса — signature(). Он указывает Windows найти диск с сигнатурой, соответствующей первому зна чению в скобках, независимо от номера контроллера, сопоставленного с этим диском, и использовать Ntbootdd.sys для доступа к загрузочному тому. Сигнатура диска (disk signature) — это глобально уникальный идентифика тор (GUID), извлекаемый Windows Setup из информации в MBR и записыва емый на диск. Синтаксис signature() выглядит так: signature(V)disk(X)rdisk(Y)partition(Z) где V — 32битная сигнатура диска в шестнадцатеричной форме, идентифи цирующая диск, X — физический жесткий диск со специфической сигнату рой, который может быть подключен к любому контроллеру в системе, Y — всегда 0, а Z — номер раздела, на котором находится загрузочный том. Windows использует синтаксис signature(), если: 쐽 размер загрузочного тома больше 7,8 Гб, а BIOSфункции расширенного прерывания INT 13 (которые применяются для доступа к частям диска за пределами 7,8 Гб) не могут обращаться ко всему тому; 쐽 BIOS не поддерживает расширенное прерывание INT 13. Загрузочный сектор и Ntldr на платформах x86 и x64 Перед тем как произвести запись в загрузочный сектор, программа установ ки должна выяснить формат раздела, поскольку от него зависит содержимое загрузочного сектора. Если это раздел FAT, Windows записывает в загрузоч ный сектор код, поддерживающий файловую систему FAT. Если раздел от форматирован под NTFS, в загрузочный сектор записывается код, соответ
272 ГЛ А В А 5 БЕЗОПАСНОСТЬ ствующий NTFS. Задача кода загрузочного сектора — предоставлять Windows информацию о структуре и формате тома и считывать из его корневого ка талога файл Ntldr. После считывания Ntldr в память код загрузочного сектора передает управление в точку входа Ntldr. Если код загрузочного сектора не может найти Ntldr в корневом каталоге тома, он выводит сообщение об ошибке: «BOOT: Couldn’t find NTLDRP» (в FAT) или «NTLDR is missing» (в NTFS). Ntldr начинает свою работу, когда система функционирует в реальном режиме (real mode) x86. В реальном режиме трансляция между виртуальны ми и физическими адресами не осуществляется, поэтому программы, ис пользующие какиелибо адреса памяти, интерпретируют их как физические. В этом режиме доступен лишь первый мегабайт физической памяти компь ютера; в нем выполняются простые программы MSDOS. Однако первое, что делает Ntldr, — переключает систему в защищенный режим (protected mode). На этой стадии трансляция между виртуальными адресами и физическими попрежнему отсутствует, но становится доступным полный объем памяти. Переключив систему в защищенный режим, Ntldr может работать со всей физической памятью. После того как он создает таблицы страниц, число которых достаточно для доступа к нижним 16 Мб памяти с подкачкой, Ntldr включает поддержку подкачки страниц. Защищенный режим с подкачкой страниц является нормальным режимом работы Windows. С этого момента Ntldr может работать в полнофункциональном режиме. Но при доступе к IDEдискам и дисплею Ntldr все еще зависит от функций загрузочного кода, которые на непродолжительное время отключают под качку страниц и возвращают процессор в режим, позволяющий выполнять сервисы BIOS. Если диск, содержащий загрузочный или системный том, яв ляется SCSIустройством и недоступен через BIOS, Ntldr загружает файл Ntbootdd.sys и использует его функции доступа к диску вместо аналогичных функций загрузочного кода. Ntbootdd.sys — это экземпляр минипортдрай вера SCSI, применяемый Windows для полноценного доступа к загрузочно му диску. (О дисковых драйверах см. главу 10.) Затем Ntldr с помощью встро енного кода файловой системы считывает из корневого каталога файл Boot.ini. В отличие от кода загрузочного сектора код Ntldr способен читать и подкаталоги. Далее Ntldr очищает экран. Если в корневом каталоге системного тома при сутствует допустимый файл Hiberfil.sys, Ntldr считывает его содержимое в па мять и передает управление коду в ядре, восстанавливающему спящую (hiberna ted) систему. Этот код отвечает за перезапуск драйверов, которые были актив ны на момент выключения системы. Hiberfil.sys считается допустимым, только если при последнем выключении компьютер был переведен в спящий режим. (О спящем режиме см. раздел «Диспетчер электропитания» главы 11.) Если в файле Boot.ini имеется более одной записи о доступных для загруз ки операционных системах, Ntldr выводит загрузочное меню. (Если в файле Boot.ini только одна запись, Ntldr пропускает загрузочное меню и сразу вы водит стартовый индикатор прогресса загрузки.) Информация из Boot.ini ад ресует Ntldr к разделу, в котором находится системный каталог Windows
ГЛАВА 9 Запуск и завершение работы системы 273 (обычно \Windows). Этим разделом может быть как загрузочный, так и дру гой главный раздел. Если запись Boot.ini ссылается на MSDOS, Ntldr считывает в память со держимое файла Bootsect.dos, переключается обратно в 16разрядный реаль ный режим и вызывает из Bootsect.dos код MBR. В результате код из Boot sect.dos выполняется аналогично коду, считанному MBR с диска. Код из Boot sect.dos инициирует процесс загрузки, специфичный для MSDOS. Так же происходит загрузка Microsoft Windows Me, Windows 98 или Windows 95, если они установлены вместе с Windows. Записи Boot.ini могут включать ряд необязательных параметров, интер претируемых Ntldr и другими компонентами в процессе загрузки. Полный список этих параметров приводится в таблице 52. Утилита Bootcfg.exe, впервые появившаяся в Windows XP, предоставляет удобный интерфейс для задания ряда параметров. Любые параметры, включаемые в Boot.ini, сохра няются в параметре реестра HKLM\System\CurrentControlSet\Control\System StartOptions. Таблица 5-2. Параметры в Boot.ini Параметр Описание /3GB только для 32разрядных систем) Увеличивает пользовательскую часть адресного пространства процессов с 2 до 3 Гб, тем самым уменьшая размер системной части пространства с 2 до 1 Гб. Позволяет повысить производи тельность приложений, интенсивно использующих виртуаль ную память (например, серверов баз данных), предоставляя им большее адресное пространство. Но здесь нужно соблюсти еще два условия: система должна работать под управлением Win dows XP, Windows Server 2003, Windows 2000 Advanced Server или Datacenter Server, а в исполняемом файле приложения дол жен присутствовать флаг, указывающий на поддержку 3гига байтного пользовательского адресного пространства (см. раз дел «Структура адресного пространства» главы 7) /BASEVIDEO Заставляет Windows использовать стандартный драйвер VGA видеоадаптера для работы в GUIрежиме /BAUDRATE= Включает отладку в режиме ядра и позволяет изменить устанав ливаемую по умолчанию скорость передачи по соединению с удаленным хостом, используемым для отладки ядра (19200). Например: /BAUDRATE=115200 /BOOTLOG Заставляет Windows вести журнал загрузки и записывать его в файл %SystemRoot%\Ntbtlog.txt /BOOTLOGO Позволяет отображать собственный экранзаставку при загруз ке Windows XP или Windows Server 2003 вместо стандартного. Для этого сначала создайте 16цветное (любые 16 цветов) рас тровое изображение размером 640x480 и сохраните его в ката логе Windows под именем Boot.bmp. Затем добавьте /bootlogo/ noguiboot в boot.ini (там, где осуществляется выбор) см. след. стр.
274 ГЛ А В А 5 Таблица 5-2. БЕЗОПАСНОСТЬ (продолжение) Параметр Описание /BREAK Вызывает остановку HAL на точке прерывания в процессе ини циализации. Первое, что делает ядро Windows, — инициализи рует HAL. Так что данная точка прерывания является первой из возможных. HAL может неопределенно долго ждать соединения с удаленным отладчиком ядра. При использовании этого пара метра без /DEBUG появляется «синий экран» со стопкодом 0x00000078 (PHASE0_EXCEPTION) /BURNMEMORY= Указывает объем памяти, запрещаемой для использования опе рационной системой Windows (по аналогии с параметром /MAXMEM). Значение задается в мегабайтах. Например, /BURNMEMORY=128 означает, что 128 Мб физической памяти компьютера недоступны Windows /CHANNEL= Используется в сочетании с /DEBUGPORT=1394, чтобы задать канал IEEE 1394, через который осуществляется коммуникаци онное взаимодействие при удаленной отладке ядра. Принимает любое значение из диапазона 0–62 и по умолчанию (если не указано конкретное значение) равен 0 /CLKLVL Перенастраивает стандартную многопроцессорную версию HAL для систем типа x86 (Halmps.dll) на распознавание сигна лов системного таймера по потенциалу, а не по фронту /CMDCONS Передается при загрузке консоли восстановления (Recovery Console) /CRASHDEBUG При загрузке системы загружает и отладчик ядра, который оста ется неактивным до момента краха. Этот параметр освобождает последовательный порт, который иначе был бы постоянно за действован отладчиком. Пока не произошел крах, порт может использоваться системой (параметр /DEBUG, напротив, застав ляет отладчик ядра постоянно занимать последовательный порт) /DEBUG Включает отладку в режиме ядра /DEBUGPORT= Включает отладку в режиме ядра и назначает последовательный порт для подключения удаленного хоста с отладчиком ядра, от личный от заданного по умолчанию (обычно COM2 в системах минимум с двумя последовательными портами). Windows XP и Windows Server 2003 поддерживают удаленную отладку и че рез порты IEEE 1394. Например: /DEBUGPORT=COM2, /DEBUGPORT=1394 /EXECUTE Отключает защиту «запрет исполнения», см. также /NOEXECUTE /FASTDETECT Параметр загрузки Windows по умолчанию. Заменяет /NOSERIALMICE, применяемый в Windows NT 4. Введен для под держки модулем NTDETECT альтернативной загрузки Windows NT 4. В Windows устройства, подключенные к параллельным и последовательным портам, определяются PnPдрайверами уст ройств, тогда как в Windows NT 4 эти функции возлагаются на NTDETECT. Параметр /FASTDETECT заставляет NTDETECT про пускать перечисление устройств, подключенных к параллель ным и последовательным портам (не требуемое при загрузке Windows). А в отсутствие этого параметра NTDETECT перечис ляет такие устройства, что необходимо для загрузки NT 4
ГЛАВА 9 Запуск и завершение работы системы 275 Таблица 5-2. (продолжение) Параметр Описание /INTAFFINITY Указывает стандартной многопроцессорной версии HAL для систем типа x86 (Halmps.dll) так настроить привязку прерыва ний, чтобы лишь один процессор (с наибольшим порядковым номером) принимал запросы на прерывания. В отсутствие это го параметра (по умолчанию) HAL разрешает принимать запро сы на прерывания всем процессорам /KERNEL= /HAL= Позволяет задавать имена файлов образа ядра и/или HAL, от личные от используемых по умолчанию (Ntoskrnl.exe и Hal.dll). Эти параметры предназначены для переключения между прове рочными (отладочными) и рабочими версиями ядра, а также для выбора HAL вручную. Если вы хотите загрузить отладочную среду, состоящую только из проверочных версий ядра и HAL (этого, как правило, достаточно для тестирования драйверов), выполните следующие операции. 1. Скопируйте отладочные версии ядра с дистрибутивного компактдиска в каталог \Windows\System32, изменив при этом их имена. Например, на однопроцессорной системе скопируйте Ntoskrnl.exe в Ntoschk.exe и Ntkrnlpa.exe в Ntoschkpa.exe, а на многопроцессорной — Ntkrnlmp.exe в Ntoschk.exe и Ntkrpamp.exe в Ntoschkpa.exe. Файлу ядра нужно присвоить краткое имя в формате «8.3». 2. Скопируйте с дистрибутивного компактдиска \I386\Driver.cab подходящую проверочную версию HAL в файл Halchk.dll в каталоге \Windows\System32. Чтобы узнать, какую именно версию HAL нужно скопировать, найдите в \Windows\Re pair\Setup.log строку с Hal.dll. Она выглядит примерно так: \Windows\system32\hal.dll=«halacpi.dll», «1d8a1». Искомое имя файла HAL находится сразу после знака равенства. Файлу HAL нужно присвоить краткое имя в формате «8.3». 3. Сделайте копию строк, присутствовавших в файле Boot.ini по умолчанию. 4. В строку с определением элементов загрузочного меню до бавьте новый элемент для отладочной среды (например «Windows XP Professional Checked»). 5. В конец нового элемента добавьте /KERNEL=NTOSCHK.EXE /HAL= HALCHK.DLL. Учтите, что теперь в загрузочном меню доступны два элемента: новый — для загрузки отладочной среды и старый — для загруз ки рабочей среды /LASTKNOWN GOOD Заставляет систему загружаться так, будто в загрузочном меню была выбрана команда загрузки последней удачной конфигура ции /MAXMEM= Ограничивает объем памяти, доступный Windows. Физическая память, лежащая за пределами указанного значения, системой игнорируется (не используется). Значение задается в мегабай тах. Например, при /MAXMEM=32 система использует только первые 32 Мб физической памяти см. след. стр.
276 ГЛ А В А 5 Таблица 5-2. БЕЗОПАСНОСТЬ (продолжение) Параметр Описание /MAXPROCSPER CLUSTER= При использовании стандартной многопроцессорной версии HAL для систем x86 (Halmps.dll) включает кластерный режим адресации контроллера прерываний APIC. Не поддерживается при использовании внешнего APICконтроллера 82489DX /MININT Этот параметр используется Windows PE (Preinstallation Envi ronment) и заставляет диспетчер конфигурации загрузить куст реестра SYSTEM как изменяемый (volatile), чтобы его изменения в памяти не сохранялись в соответствующем образе на диске /NODEBUG Запрещает инициализацию отладки режима ядра. Имеет боль ший приоритет, чем остальные параметры, применяемые для отладки (/DEBUG, /DEBUGPORT и /BAUDRATE) /NOEXECUTE Доступен только в 32разрядных версиях Windows при выпол нении на процессорах AMD64 и только при включенной под держке PAE (см. также /PAE). Включает защиту «запрет исполне ния» (noexecute protection), что заставляет диспетчер памяти помечать страницы с данными как не исполняемые, чтобы их нельзя было выполнять как код. Это полезно для предотвраще ния попыток зловредного кода использовать ошибки с пере полнением буферов для запуска произвольного кода. Такая за щита всегда включена в 64разрядных версиях Windows на про цессорах AMD64. Существует 4 модификатора, которые можно указать в /NOEXECUTE: =OPTIN, =OPTOUT, =ALWAYSON, =ALWAYSOFF. Подробности см. в главе 7 /NOGUIBOOT Запрещает Windows инициализацию VGAдрайвера, ответствен ного за вывод растровой графики в процессе загрузки. Этот драйвер используется для вывода информации о ходе загрузки, поэтому при его отключении Windows не будет выводить эту информацию /NOLOWMEM Применяется только с параметром /PAE и только при наличии в системе более 4 Гб физической памяти. Если эти условия со блюдены, PAEверсия ядра Windows, Ntkrnlpa.exe, не использует первые 4 Гб физической памяти. Для загрузки драйверов и при ложений, а также для создания всех пулов памяти используется область выше этой границы. Данный параметр предназначен для тестирования драйверов на совместимость с системами, в которых установлено более 4 Гб памяти /NOPAE Заставляет Ntldr загружать версию ядра, не поддерживающую PAE (Physical Address Extensions) даже в том случае, когда x86 система поддерживает такой механизм и имеет более 4 Гб фи зической памяти /NOSERIALMICE= Устаревший спецификатор Windows NT 4, замененный на [COMx | COMx,y,z...] /FASTDETECT. Отключает распознавание мыши на указанных COMпортах. Применяется в том случае, если к последователь ному порту подключено устройство, отличное от мыши. При использовании /NOSERIALMICE без указания порта распознава ние мыши отключается для всех COMпортов. См. также статью Q131976 в Microsoft Knowledge Base
ГЛАВА 9 Запуск и завершение работы системы 277 Таблица 5-2. (продолжение) Параметр Описание /NUMPROC= Указывает число процессоров, которые Windows может исполь зовать в многопроцессорной системе. Например, указав /NUMP ROC=2 в четырехпроцессорной системе, вы запретите исполь зование двух из четырех процессоров /ONECPU В многопроцессорных системах заставляет Windows работать только с одним процессором /PAE Указывает Ntldr загрузить Ntkrnlpa.exe, версию ядра (для х86 процессоров), использующую преимущества PAE. PAE обеспечи вает 64разрядную адресацию драйверами устройств. Этот па раметр предназначен для тестирования драйверов на совмести мость с системами с большим объемом памяти /PCILOCK Запрещает Windows динамически назначать PCIустройствам IRQ и другие ресурсы для вводавывода. При этом используются настройки, заданные в BIOS. Подробности см. в статье Q148501 в Microsoft Knowledge Base /RDPATH= Указывает путь к файлу System Disk Image (SDI), который может находиться в сети и который система должна использовать для загрузки. Часто применяется в сочетании с флагом /RDIMAGE OFFSET=, сообщающим NTLDR, где в этом файле начинается об раз системы /REDIRECT Введен в Windows Server 2003. Заставляет Windows включить поддержку сервисов аварийного управления (Emergency Mana gement Services, EMS), которые выводят информацию о процес се загрузки и принимают команды системного управления че рез последовательный порт. Этот порт и параметр baudrate, ис пользуемые в сочетании с EMS, указываются в строках redirect= и redirectbaudrate= в разделе [boot loader] файла Boot.ini /SAFEBOOT: Задает параметры загрузки в безопасном режиме. Никогда не указывайте этот параметр вручную, так как Ntldr сам задает его при использовании меню, открываемого нажатием клавиши F8. (При загрузке Windows в безопасном режиме загружаются толь ко драйверы и сервисы, указанные в подразделах реестра Mini mal или Network, которые находятся в HKLM\SYSTEM\Current ControlSet\Control\SafeBoot.) После двоеточия можно указать один из трех дополнительных параметров: MINIMAL, NETWORK или DSREPAIR. Параметр MINIMAL соответствует безопасной загрузке без сетевой поддержки, NETWORK — безопасной за грузке с сетевой поддержкой. DSREPAIR (Directory Services Re pair) предназначен для такой загрузки Windows, при которой Active Directory находится в автономном состоянии (offline), а база данных этой службы не открывается. Это позволяет адми нистратору выполнять диагностику, исправлять или восстанав ливать базу данных. Можно использовать еще один дополни тельный параметр, ALTERNATESHELL, — тогда вместо оболочки по умолчанию (Windows Explorer) загружается то, что указано в разделе реестра HKLM\System\CurrentControlSet\SafeBoot \AlternateShell см. след. стр.
278 ГЛ А В А 5 БЕЗОПАСНОСТЬ Таблица 5-2. (окончание) Параметр Описание /SCSIORDINAL: Указывает идентификатор SCSIконтроллера для Windows яв ным образом. (Добавление нового SCSIустройства в систему с интегрированным SCSIконтроллером может привести к сме не идентификатора этого контроллера.) Подробности см. в ста тье Q103625 в Microsoft Knowledge Base /SDIBOOT= Применяется в системах Windows XP Embedded, чтобы Win dows загружалась с образа RAMдиска, хранящегося в указанном файле System Disk Image (SDI) /SOS Заставляет Windows перечислять на экране список помеченных к загрузке драйверов устройств, а затем показывать номер вер сии системы (включая номер сборки), объем физической памя ти и число процессоров /TIMERES= В системах со стандартной многопроцессорной x86версией HAL (Halmps.dll) задает разрешение системного таймера. Аргу ментом является значение в сотнях наносекунд, но частота ус танавливается в соответствии с ближайшим меньшим значени ем, поддерживаемым HAL (см. ниже). Сотни наносекунд Миллисекунды (мс) 97660,98 390633,90 195322,00 781257,80 Разрешение по умолчанию — 7,8 мс. Разрешение системного таймера влияет на разрешение ожидаемых таймеров. Например, параметр /TIMERES=21000 установит разрешение таймера рав ным 2,0 мс /USERVA= (только для 32разрядных систем) Поддерживается только в Windows XP и Windows Server 2003. Как и параметр /3GB, предоставляет приложениям большее ад ресное пространство. Указывается в мегабайтах, значение долж но укладываться в диапазон от 2048 до 3072. Этот параметр предъявляет к приложениям те же требования, что и параметр /3GB; используется только в сочетании с /3GB /WIN95 Указывает Ntldr загрузить содержимое файла Bootsect.w40, в ко тором хранится загрузочный сектор Windows 9x. Применим, только если на компьютере установлены три операционные системы (Windows, Windows 9х и MSDOS). Подробности см. в статье Q157992 в Microsoft Knowledge Base /WIN95DOS Указывает Ntldr использовать загрузочный сектор MSDOS, хра нящийся в файле Bootsect.w40. Применим, только если на ком пьютере установлены три операционные системы (Windows, Windows 9х и MSDOS). Подробности см. в статье Q157992 в Microsoft Knowledge Base /YEAR= Указывает Windows игнорировать значение года, сообщаемое системными часами компьютера, и использовать заданное зна чение. Этот параметр влияет на все программное обеспечение, в том числе на ядро Windows. Пример: /YEAR=2001. (Этот пара метр предназначался для тестирования на совместимость с да тами 2000 года)
ГЛАВА 9 Запуск и завершение работы системы 279 Если до истечения периода ожидания, указанного в Boot.ini, пользователь не выбрал ни одной команды загрузочного меню, Ntldr выбирает вариант по умолчанию, который соответствует самой верхней записи в Boot.ini и содер жит путь, совпадающий с путем в строке «default=». После выбора одного из вариантов Ntldr загружает и запускает Ntdetect.com, 16разрядную програм му реального режима, которая получает от BIOS сведения о базовых устрой ствах и конфигурации компьютера: 쐽 время и дату, хранящиеся в энергонезависимой памяти CMOS; 쐽 типы шин в системе (например, ISA, PCI, EISA, MCA) и идентификаторы устройств, подключенных к этим шинам; 쐽 число, емкость и тип дисков, присутствующих в системе; 쐽 тип подключенной мыши; 쐽 число и тип параллельных портов, сконфигурированных в системе; 쐽 типы видеоадаптеров, присутствующих в системе. Эти сведения, записываемые во внутренние структуры данных, на более поздних этапах загрузки будут сохранены в разделе реестра HKLM\HARD WARE\DESCRIPTION. Далее Ntldr в Windows 2000 очищает экран и выводит индикатор прогресса загрузки с надписью «Starting Windows» («Запуск Windows»). Индикатор оста ется на нулевой отметке до начала загрузки драйверов устройств (см. п. 5 в следующем списке). Под индикатором появляется сообщение: «For trouble shooting and advanced startup options for Windows 2000, press F8» («Для выбо ра особых вариантов загрузки Windows 2000 нажмите F8»). При нажатии кла виши F8 выводится дополнительное загрузочное меню, предлагающее выб рать особые варианты загрузки — последнюю удачную конфигурацию, безо пасный или отладочный режим и т. д. В Windows XP и Windows Server 2003 Ntldr выводит экранзаставку вместо индикатора прогресса загрузки. Если Ntldr выполняется в x64системе и в загрузочном меню выбран эле мент, указывающий на запуск ядра для x64, то Ntldr переключает процессор в режим, в котором «родной» размер слова составляет 64 бита. Затем Ntldr начинает загружать необходимые для инициализации ядра файлы. Загрузоч ным является том, соответствующий разделу, на котором находится систем ный каталог (обычно \Windows) загружаемой системы. Ниже описываются операции, выполняемые Ntldr. 1. Загружает соответствующие образы ядра и HAL (по умолчанию — Ntosk rnl.exe и Hal.dll). Если Ntldr не удается загрузить какойлибо из этих фай лов, он выводит сообщение «Windows could not start because the following file was missing or corrupt» («Не удается запустить Windows изза испор ченного или отсутствующего файла»), за которым следует имя файла. 2. Для поиска драйверов устройств, которые нужно загрузить, считывает в память содержимое куста реестра SYSTEM, \Windows\System32\Config\ System. Куст — это файл, содержащий поддерево реестра. Подробнее о реестре см. главу 4.
280 ГЛ А В А 5 БЕЗОПАСНОСТЬ 3. Сканирует загруженный в память куст реестра SYSTEM и находит все заг рузочные драйверы устройств (это драйверы, обязательные для запуска системы). Они отмечены в реестре флагом SERVICE_BOOT_START (0). Каждому драйверу устройства в реестре соответствует подраздел HKLM\ SYSTEM\CurrentControlSet\Services. Например, драйверу диспетчера логи ческих дисков (Logical Disk Manager) в разделе Services соответствует под раздел Dmio, показанный на рис. 52. (Подробное описание содержимо го Services см. в разделе «Сервисы» главы 4.) Рис. 5-2. Параметры драйвера диспетчера логических дисков 4. Вносит в список загрузочных драйверов устройств драйвер файловой системы, отвечающий за реализацию кода для конкретного типа разде ла (FAT, FAT32 или NTFS), на котором находится системный каталог. Ntldr должен загрузить этот драйвер именно сейчас, иначе ядро будет требо вать от драйверов их же загрузки, и получится замкнутый круг. 5. Загружает драйверы, обязательные для запуска системы. Ход загрузки от ражается индикатором «Starting Windows». Полоска на индикаторе про двигается вперед по мере загрузки драйверов (число загрузочных драй веров считается равным 80, поэтому после успешной загрузки каждого драйвера полоска продвигается на 1,25%). Если в Boot.ini указан параметр /SOS, то вместо индикатора Ntldr выводит имя файла каждого загрузоч ного драйвера. Учтите, что на этом этапе драйверы лишь загружаются, а их инициализация происходит позже. 6. Подготавливает регистры процессора для выполнения Ntoskrnl.exe. На этом участие Ntldr в процессе загрузки заканчивается. Для инициали зации системы Ntldr вызывает главную функцию из Ntoskrnl.exe. Процесс загрузки на платформе IA64 Файлы, участвующие в процессе загрузки на платформе IA64 перечислены в таблице 53. Системы IA64 соответствуют спецификации Extensible Firm ware Interface (EFI), определенной Intel. В EFIсовместимой системе имеет ся микрокод, который запускает стартовый загрузчик (загрузочный код), записываемый Windows Setup в системную NVRAM (nonvolatile RAM). Загру
ГЛАВА 9 Запуск и завершение работы системы 281 зочный код считывает содержимое IA64эквивалента Boot.ini, который так же хранится в NVRAM. Средства Microsoft EFI можно запускать в консоли EFI, а Bootcfg.exe (утилита, поставляемая с Windows) позволяет модифицировать параметры и варианты загрузки из NVRAM. Далее происходит распознавание оборудования, в ходе которого старто вый загрузчик использует интерфейсы EFI для определения числа и типов следующих устройств: 쐽 сетевых адаптеров; 쐽 видеоадаптеров; 쐽 клавиатур; 쐽 дисковых контроллеров; 쐽 накопителей. Так же, как и Ntldr в системах x86 и x64, стартовый загрузчик выводит меню с вариантами загрузки. Как только пользователь выбирает один из ва риантов, загрузчик переходит в подкаталог в разделе EFI System, соответству ющий выбранному варианту, и загружает несколько других файлов, необхо димых для продолжения загрузки: Fpswa.efi и Ia64ldr.efi. Спецификация EFI требует, чтобы в системе был раздел, обозначенный как EFI System; он фор матируется под файловую систему FAT и может быть размером от 100 Мб до 1 Гб (или до 1% от общего размера диска). Для каждой установленной Win dowsсистемы выделяется свой подкаталог в разделе EFI System (в каталоге EFI\Microsoft). Первой системе назначается подкаталог Winnt50, второй — Winnt50.1 и т. д. Ia64ldr.efi отвечает за загрузку Ntoskrnl.exe, Hal.dll и драйве ров, применяемых на этапе загрузки. Далее процесс загрузки идет так же, как и на платформе x86 или x64. Таблица 5-3. Компоненты, участвующие в процессе загрузки на платформе IA64 Компонент Местонахождение Описание Fpswa.efi EFI\Microsoft\Winnt50.x в разделе EFI System Файл с кодом поддержки операций с плавающей точкой Ia64ldr.efi EFI\Microsoft\Winnt50.x в разделе EFI System Загружает Ntoskrnl.exe, Hal.dll и драй веры, используемые на этапе загрузки Ntoskrnl.exe \Windows\System32 Инициализирует подсистемы испол нительной системы, а также драйве ры устройств, используемые на этапе загрузки и при запуске системы (boot and systemstart device drivers), подготавливает систему к запуску встроенных приложений и запускает Smss.exe Hal.dll \Windows\System32 DLL режима ядра, предоставляющая интерфейс к оборудованию для Ntoskrnl и драйверов Диспетчер управле \Windows\System32 ния сервисами (SCM) Загружает и инициализирует автома тически запускаемые драйверы уст ройств и сервисы Windows см. след. стр.
282 ГЛ А В А 5 БЕЗОПАСНОСТЬ Таблица 5-3. (окончание) Компонент Местонахождение Описание Smss \Windows\System32 Загружает подсистему Windows, в том числе Win32k.sys и Csrss.exe, а затем запускает процесс Winlogon Winlogon \Windows\System32 Запускает диспетчер управления сер висами (SCM), подсистему Local Se curity Authority Subsystem (LSASS) и выводит диалоговое окно для ин терактивного входа в систему Инициализация ядра и компонентов исполнительной системы Вызывая Ntoskrnl.exe, Ntldr передает структуру данных с копией строки из Boot.ini (представляющей выбранный вариант загрузки), с указателем на таб лицы памяти (сгенерированные Ntldr для описания физической памяти в данной системе), с указателем на загруженные в память копии кустов реес тра HARDWARE и SYSTEM и с указателем на список загруженных драйверов. Ntoskrnl начинает первую из двух фаз процесса инициализации (они нумеруются от 0). Большинство компонентов исполнительной системы име ет инициализирующую функцию, которая принимает параметр, определя ющий текущую фазу. В фазе 0 прерывания отключены. Предназначение этой фазы в том, что бы сформировать рудиментарные структуры, необходимые для вызова сер висов в фазе 1. Главная функция Ntoskrnl вызывает KiSystemStartup, которая в свою очередь вызывает HalInitializeProcessor и KiInitializeKernel для каждо го процессора. Работая на стартовом процессоре, KiInitializeKernel выполня ет общесистемную инициализацию ядра, в том числе всех внутренних струк тур данных, разделяемых всеми процессорами. Затем каждый экземпляр KiInitializeKernel вызывает функцию ExpInitializeExecutive, отвечающую за управление фазой 0. ExpInitializeExecutive начинает с вызова HALфункции HalInitSystem, позво ляющей HAL взять управление инициализацией системы на себя. Одной из задач HalInitSystem является подготовка системного контроллера прерыва ний каждого процессора к обработке прерываний и конфигурирование тай мера, используемого для учета распределяемого процессорного времени (подробнее на эту тему см. раздел «Учет квантов времени» главы 6). Лишь на стартовом процессоре ExpInitializeExecutive не просто вызыва ет HalInitSystem, но и выполняет другие операции по инициализации. Когда HalInitSystem возвращает управление, функция ExpInitializeExecutive, выпол няемая на стартовом процессоре, обрабатывает параметр /BURNMEMORY файла Boot.ini (если таковой указан и действителен для данного варианта загрузки). В соответствии с этим параметром ExpInitializeExecutive исключает указанный объем памяти.
ГЛАВА 9 Запуск и завершение работы системы 283 Далее ExpInitializeExecutive вызывает процедуры инициализации для дис петчера памяти, диспетчера объектов, монитора состояния защиты, диспет чера процессов и диспетчера Plug and Play. Эти компоненты выполняют сле дующие инициализирующие операции. 1. Диспетчер памяти формирует таблицы страниц и внутренние структуры данных, необходимые для предоставления базовых сервисов, связанных с памятью. Кроме того, он создает и резервирует пространство для кэша файловой системы, а также выделяет области для пулов подкачиваемой и неподкачиваемой памяти. Другие компоненты исполнительной систе мы, ядро и драйверы устройств пользуются этими пулами, выделяя память под собственные структуры данных. 2. При инициализации диспетчера объектов определяются объекты, необ ходимые для создания его пространства имен, чтобы другие компонен ты могли помещать в него свои объекты. Также создается таблица описа телей для поддержки учета ресурсов. 3. Монитор состояния защиты инициализирует объект типа «маркер досту па» и использует его для создания и подготовки первого маркера по учет ной записи локальной системы, назначаемого начальному процессу (об учетной записи локальной системы см. главу 8). 4. Диспетчер процессов производит бóльшую часть своей инициализации в фазе 0, определяя типы объектов «процесс» и «поток» и создавая спис ки для отслеживания активных процессов и потоков. Он также создает объект «процесс» для начального процесса и присваивает ему имя Idle. Наконец, диспетчер процессов создает процесс System и системный по ток для выполнения процедуры Phase1Initialization. Этот поток не запус кается сразу после создания, поскольку прерывания пока запрещены. 5. Далее наступает фаза 0 в инициализации диспетчера Plug and Play, в ходе которой просто инициализируется ресурс исполнительной системы, ис пользуемый для синхронизации ресурсов шин. Когда на каждом процессоре управление возвращается к функции KiIni tializeKernel, она передает его циклу Idle. В результате системный поток, соз данный, как было описано в п. 4 предыдущего списка, начинает фазу 1. До полнительные процессоры ждут начала своей инициализации до п. 5 фазы 1 (см. список ниже). В фазе 1 выполняются следующие операции. (На экране заставке, выводимом при загрузке Windows 2000, отображается индикатор прогресса, поэтому в списке упоминаются операции, связанные с обновле нием этого индикатора.) 1. Для подготовки системы к приему прерываний от устройств и для разре шения прерываний вызывается HalInitSystem. 2. Вызывается загрузочный видеодрайвер (\Windows\System32\Bootvid.dll), который выводит экранзаставку, показываемую в процессе запуска Win dows. (В Windows XP и Windows Server 2003 этот драйвер отображает ту картинку, которую Ntldr ранее вывел на экран.)
284 ГЛ А В А 5 БЕЗОПАСНОСТЬ 3. Инициализируется диспетчер электропитания. 4. Инициализируются системные часы (вызовом HalQueryRealTimeClock), текущее значение которых сохраняется как время загрузки системы. 5. В многопроцессорной системе инициализируются остальные процессо ры и начинается выполнение команд. 6. Индикатор прогресса загрузки устанавливается на отметку 5%. 7. Диспетчер объектов создает корневой каталог пространства имен (\), каталог \ObjectTypes и каталог сопоставлений DOSимен устройств (\?? в Windows 2000 или \Global?? в Windows XP и Windows Server 2003), а так же символьную ссылку в каталоге сопоставлений DOSимен устройств. 8. Вызывается исполнительная система для создания своих типов объектов, включая семафор, мьютекс, событие и таймер. 9. Ядро инициализирует структуры данных планировщика (диспетчера) и таблицу диспетчеризации системных сервисов. 10. Монитор состояния защиты создает в пространстве имен диспетчера объектов каталог \Security и инициализирует структуры данных аудита (если аудит системы разрешен). 11. Индикатор прогресса загрузки устанавливается на отметку 10%. 12. Для создания объекта «раздел» и системных рабочих потоков вызывает ся диспетчер памяти (см. главу 7). 13. На системное адресное пространство проецируются таблицы NLS (Natio nal Language Support). 14. На системное адресное пространство проецируется Ntdll.dll. 15. Диспетчер кэша инициализирует структуры данных кэша файловой си стемы и создает свои рабочие потоки. 16. Диспетчер конфигурации создает в пространстве имен объект «раздел реестра» \Registry и копирует переданные Ntldr начальные данные в кус ты реестра HARDWARE и SYSTEM. 17. Инициализируются структуры данных драйвера файловой системы. 18. Диспетчер Plug and Play вызывает PnP BIOS. 19. Индикатор прогресса загрузки устанавливается на отметку 20%. 20. Подсистема LPC инициализирует объект типа «порт LPC». 21. Если система запущена с протоколированием загрузки (/BOOTLOG), ини циализируется файл протокола загрузки. 22. Индикатор прогресса загрузки устанавливается на отметку 25%. 23. Наступает момент инициализации диспетчера вводавывода. Согласно показаниям индикатора, эта стадия запуска системы занимает 50% време ни. После успешной загрузки каждого драйвера диспетчер вводавывода продвигает полоску на индикаторе на 2% (если загружается более 25 драйверов, индикатор останавливается на отметке 75%).
ГЛАВА 9 Запуск и завершение работы системы 285 Диспетчер вводавывода прежде всего инициализирует различные внутренние структуры и создает типы объектов «устройство» и «драйвер». Затем он вызывает диспетчер Plug and Play, диспетчер электропитания и HAL, чтобы начать динамическое перечисление и инициализацию уст ройств. (Подробнее этот сложный процесс, специфичный для конкрет ной подсистемы вводавывода, рассматривается в главе 9.) Далее иници ализируется подсистема WMI (Windows Management Instrumentation), которая предоставляет WMIподдержку драйверам устройств. (Подробнее о WMI см. раздел «Windows Management Instrumentation» главы 4.) После этого вызываются все загрузочные драйверы, которые осуществляют свою инициализацию. Также загружаются и инициализируются драйве ры, необходимые для запуска системы (см. главу 9). Наконец, в простран стве имен диспетчера объектов создаются имена устройств MSDOS в виде символьных ссылок. 24. Индикатор прогресса загрузки устанавливается на отметку 75%. 25. Если система загружается в безопасном режиме, этот факт отмечается в реестре. 26. Включается подкачка страниц для кода режима ядра (в Ntkrnl и драйве рах), если она явно не запрещена в реестре. 27. Индикатор прогресса загрузки устанавливается на отметку 80%. 28. Вызывается диспетчер электропитания для инициализации своих струк тур данных. 29. Индикатор прогресса загрузки устанавливается на отметку 85%. 30. Вызывается монитор состояния защиты для создания потока Command Server, взаимодействующего с LSASS (см. раздел «Компоненты системы защиты» главы 8). 31. Индикатор прогресса загрузки устанавливается на отметку 90%. 32. На завершающем этапе создается процесс Smss диспетчера сеансов (ба зовые сведения об Smss см. в главе 2). Smss отвечает за создание среды пользовательского режима, которая предоставляет визуальный интер фейс Windows. Об инициализации Smss см. следующий раздел. 33. Индикатор прогресса загрузки устанавливается на отметку 100%. Перед завершением инициализации компонентов исполнительной сис темы и ядра поток инициализации фазы 1 в течение пяти секунд ждет осво бождения описателя процесса Smss. Если этот процесс завершается до ис течения пяти секунд, происходит крах системы с кодом SESSION5_INITIA LIZATION_FAILED. По истечении пяти секунд запуск диспетчера сеансов считается успеш ным, и вызывается функция потока обнуления страниц диспетчера памяти (см. главу 7).
286 ГЛ А В А 5 БЕЗОПАСНОСТЬ Smss, Csrss и Winlogon Smss похож на любой другой процесс пользовательского режима, но имеет два существенных отличия. Вопервых, Windows считает его доверяемой (trusted) частью системы. Вовторых, Smss является встроенным (native) приложением. Как доверяемый компонент Smss может выполнять операции, доступные лишь немногим процессам, например создавать маркеры защи ты. А как встроенное приложение Smss использует не Windows API, а базо вые APIфункции исполнительной системы, в совокупности называемые Windows Native API. Smss не обращается к Windows API, поскольку при его запуске подсистема Windows еще не функционирует. Запуск подсистемы Windows и является одной из его первых задач. Затем Smss вызывает диспетчер конфигурации, который завершает ини циализацию реестра, заполняя все его разделы. Диспетчер конфигурации запрограммирован так, что ему известно местонахождение всех кустов ре естра на диске, кроме содержащих пользовательские параметры. Пути ко всем загружаемым им кустам реестра записываются в раздел HKLM\SYS TEM\CurrentControlSet\Control\Hivelist. Основной поток Smss выполняет следующие инициализирующие операции. 1. Создает объект «порт LPC» (\SmApiPort) и два потока, ожидающие клиентские запросы (например, на загрузку новой подсистемы или на создание сеанса). 2. Определяет символьные ссылки на имена устройств MSDOS (вроде COM1 и LPT1). 3. Если установлены Terminal Services, создает в пространстве имен диспет чера объектов каталог \Sessions (для нескольких сеансов). 4. Запускает программы, указанные в HKLM\SYSTEM\CurrentControlSet\Con trol\Session Manager\BootExecute. Как правило, в нем содержится одна ко манда на запуск Autochk (версия Chkdsk, работающая на этапе загрузки). 5. Выполняет отложенные действия по переименованию и удалению фай лов, указанные в разделах HKLM\SYSTEM\CurrentControlSet\Control\Ses sion Manager\PendingFileRenameOperations и HKLM\SYSTEM\CurrentCont rolSet\Control\Session Manager\PendingFileRenameOperations2. 6. Открывает известные DLL и создает для них объекты «раздел» в каталоге \Knowndlls пространства имен диспетчера объектов. Список DLL, считае мых известными, находится в разделе HKEY_LOCAL_MACHINE\SYSTEM\ CurrentControlSet\Control\Session Manager\KnownDLLs, а путь к каталогу, где расположены эти DLL, хранится в параметре Dlldirectory этого разде ла. Об использовании разделов Known DLLs при загрузке DLL см. главу 6. 7. Создает дополнительные страничные файлы. Их конфигурация хранит ся в разделе HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\ Session Manager\Memory Management\PagingFiles. 8. Инициализирует реестр. Диспетчер конфигурации заполняет реестр, за гружая кусты HKLM\SAM, HKLM\SECURITY и HKLM\SOFTWARE. Хотя ин
ГЛАВА 9 Запуск и завершение работы системы 287 формация о местонахождении файлов кустов содержится в разделе HKLM\ SYSTEM\CurrentControlSet\Control\Hivelist, диспетчер конфигурации ищет эти файлы в каталоге \Windows\System32\Config. 9. Создает системные переменные окружения, определенные в HKLM\Sys tem\CurrentControlSet\Session Manager\Environment. 10. Загружает часть подсистемы Windows, работающую в режиме ядра (Win32k.sys). Smss определяет местонахождение Win32k.sys и других загру жаемых им компонентов по путям, хранящимся в HKLM\SYSTEM\Current ControlSet\Control\Session Manager. Инициализирующий код в Win32k.sys использует видеодрайвер для переключения экрана в разрешение, опреде ленное в профиле по умолчанию. Таким образом, в этот момент видеоадап тер переключается с VGAрежима, используемого загрузочным видеодрай вером, в выбранное для данной системы разрешение. 11. Запускает процессы подсистем, в том числе Csrss. (Как говорилось в главе 2, подсистемы POSIX и OS/2 в Windows 2000 запускаются по требованию.) 12. Запускает процесс Winlogon. Этапы запуска Winlogon кратко описывают ся ниже. 13. Создает порты LPC для сообщений об отладочных событиях (DbgSsApiPort и DbgUiApiPort) и потоки, прослушивающие эти порты. Отложенные действия по переименованию файлов Тот факт, что исполняемые образы и DLL при использовании проеци руются в память, делает невозможным обновление базовых системных файлов по окончании загрузки Windows. APIфункция MoveFileEx позво ляет указать, что перемещение файла должно быть отложено до следу ющей загрузки. Пакеты обновлений и критические исправления, кото рым нужно обновлять уже используемые файлы, проецируемые в па мять, устанавливают заменяющие файлы во временные каталоги и вы зывают функцию MoveFileEx именно так, как говорилось чуть выше. В этом случае MoveFileEx просто записывает команды в параметры Pen dingFileRenameOperations и PendingFileRenameOperations2 в разделе ре естра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager. Эти параметры имеют тип MULTI_SZ, и каждая операция указывается пара ми имен файлов: первое имя — источник, а второе — приемник. В опе рациях удаления вместо приемника задается пустая строка. Чтобы про смотреть зарегистрированные отложенные команды переименования и удаления, используйте утилиту Pendmoves с сайта www.sysinternals.com. После выполнения вышеперечисленных операций основной поток Smss переходит к бесконечному ожиданию описателей процессов Csrss и Win logon. Поскольку от этих процессов зависит функционирование Windows, в случае их неожиданного завершения Smss вызывает крах системы. (В Win dows XP и выше, если Csrss по какойто причине завершается, крах системы вызывается ядром, а не Smss.)
288 ГЛ А В А 5 БЕЗОПАСНОСТЬ Далее Winlogon продолжает инициализацию, выполняя такие операции, как создание начального объекта WindowStation и объектов рабочего сто ла. Если в HKLM\Software\Microsoft\Windows NT\Current Version\WinLogon\ GinaDLL указана какаянибудь DLL, Winlogon использует ее в качестве GINA; в ином случае применяется GINA по умолчанию от Microsoft, Msgina (\Win dows\System32\Msgina.dll), которая отображает стандартное диалоговое ок но входа в Windows. Затем Winlogon создает процесс SCM (диспетчера уп равления сервисами) (\Windows\System32\Services.exe), который загружает все сервисы и драйверы устройств, помеченные для автоматического запус ка, а также запускает процесс LSASS (подсистемы локальной аутентифика ции) (\Windows\System32\Lsass.exe). Подробнее о запуске Winlogon и LSASS см. раздел «Инициализация Winlogon» главы 8. После того как SCM инициализирует автоматически запускаемые серви сы и драйверы устройств, а пользователь успешно зарегистрируется в сис теме, загрузка считается успешно завершенной. Параметры в разделе HKLM\ SYSTEM\Select\LastKnownGood обновляются в соответствии со значениями параметров последней удачной конфигурации (\CurrentControlSet). ПРИМЕЧАНИЕ Если на неинтерактивном сервере не бывает интерак тивного входа, раздел LastKnownGood, отражающий набор управления (control set), который позволил выполнить успешную загрузку, не об новляется. Вы можете заменить определение успешной загрузки. Для этого ус тановите HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlo gon\ReportBootOk в 0, напишите свою программу, проверяющую успеш ность загрузки, и укажите путь к ней в HKLM\System\CurrentControlSet\ Control\BootVerificationProgram. Такая программа должна вызывать API функцию NotifyBootConfigStatus, если загрузка прошла успешно. Запустив SCM, Winlogon ждет уведомления об интерактивном входе от GINA. Получив такое уведомление и проверив вход (об этом процессе см. в главе 8), Winlogon загружает куст реестра из профиля зарегистрировавше гося пользователя и отображает его на HKCU. Затем он настраивает перемен ные окружения для данного пользователя, хранящиеся в HKCU\Environment, и направляет уведомления о входе компонентам, зарегистрированным в HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Notify. Затем Winlogon сообщает GINA запустить оболочку. В ответ на этот зап рос Msgina запускает исполняемый файл (или исполняемые файлы), указан ный в параметре HKLM\Software\Microsoft\Windows NT\CurrentVersion\Win Logon\Userinit (несколько исполняемых файлов перечисляются через запя тые), который по умолчанию указывает на \Windows\System32\Userinit.exe. Userinit.exe выполняет следующие операции. 1. Обрабатывает пользовательские сценарии, указанные в HKCU\Software\ Policies\Microsoft\Windows\System\Scripts, и машинные сценарии входа, заданные в HKLM\Software\Policies\Microsoft\Windows\System\Scripts.
ГЛАВА 9 Запуск и завершение работы системы 289 (Так как машинные сценарии выполняются после пользовательских, они могут переопределять пользовательские настройки.) 2. Если политика группы задает какуюлибо квоту в профиле пользователя, Userinit.exe запускает \Windows\System32\Proquota.exe для ее применения. 3. Запускает оболочку (или оболочки), указанную в HKCU\Software\Micro soft\Windows NT\CurrentVersion\Winlogon\Shell. Если этого параметра нет, Userinit.exe запускает оболочку (или оболочки), определенные в HKLM\Software\Microsoft\Windows NT\CurrentVersion\Winlogon\Shell (по умолчанию — Explorer.exe). Далее Winlogon уведомляет зарегистрированные провайдеры сетей о вхо де пользователя. Провайдер сети Microsoft, маршрутизатор многосетевого доступа (Multiple Provider Router, MPR) (\Windows\System32\Mpr.dll), восста навливает постоянные подключения к сетевому диску и принтерам, установ ленные пользователем; эти сопоставления хранятся в HCU\Network и HKCU\ Printers соответственно. На рис. 53 показано дерево процессов, которое ото бражается в Process Explorer при входе до завершения Userinit. Рис. 5-3. Дерево процессов при входе Автоматически запускаемые образы Помимо параметров Userinit и Shell в разделе Winlogon, существует много других разделов в реестре и каталогов, проверяемых и обрабатываемых си стемными компонентами для автоматического запуска процессов при за грузке и входе. Утилита Msconfig (в Windows XP и Windows Server 2003 это \Windows\System32\Msconfig.exe) показывает образы, сконфигурированные в нескольких местах. Но утилита Autoruns от Sysinternals (www.sysinternals. com), представленная на рис. 54, анализирует больше разделов реестра и каталогов, чем Msconfig, и выводит больше информации об образах, настро енных на автоматический запуск. По умолчанию Autoruns показывает толь
290 ГЛ А В А 5 БЕЗОПАСНОСТЬ ко те места, где задается автоматический запуск хотя бы одного образа, но команда Include Empty Locations в меню View заставляет Autoruns отображать все проверяемые ею разделы реестра и каталоги. В меню View можно настро ить Autoruns на отображение сведений о других типах автоматически запус каемых образов, например служб Windows и надстроек Explorer. Рис. 5-4. Утилита Autoruns от www.sysinternals.com ЭКСПЕРИМЕНТ: утилита Autoruns Многие пользователи даже не представляют, сколько программ вы полняется в процессе их входа. OEM (original equipment manufacturers) часто конфигурируют свои системы с помощью дополнительных ути лит, которые выполняются в фоновом режиме и обычно не видны. Чтобы увидеть, какие программы настроены на автоматический запуск на вашем компьютере, запустите утилиту Autoruns; ее можно скачать с сайта www.sysinternals.com. Сравните полученный в Autoruns список с тем, что показывается Msconfig (доступной в Windows XP и Windows Server 2003), и обратите внимание на различия. Потом попробуйте разобраться в предназначении каждой программы. Анализ проблем при загрузке и запуске системы В этом разделе представлены подходы к решению проблем, возможных в про цессе запуска Windows изза повреждения жесткого диска и файлов, отсут ствия какихлибо файлов и ошибок в сторонних драйверах. Сначала мы опи шем три режима восстановления Windows при возникновении проблем с заг рузкой: последняя удачная конфигурация, безопасный режим и консоль вос становления (Recovery Console). Затем мы расскажем о наиболее распростра ненных проблемах при загрузке, об их причинах и способах устранения.
ГЛАВА 9 Запуск и завершение работы системы 291 Последняя удачная конфигурация Последняя удачная конфигурация (last known good, LKG) — полезный меха низм для возврата системы, рухнувшей в процессе загрузки, в загружаемое состояние. Поскольку параметры системной конфигурации хранятся в HKLM\System\CurrentControlSet\Control, конфигурация драйверов и серви сов — в HKLM\System\CurrentControlSet\Services, изменения этих частей ре естра могут привести к тому, что система станет незагружаемой. Например, если вы установили драйвер устройства с ошибкой, изза которой происхо дит крах системы при загрузке, то можете нажать клавишу F8 в момент заг рузки и выбрать из меню последнюю удачную конфигурацию. Система от мечает набор управления, использовавшийся при загрузке как неудачный, устанавливая параметр Failed в HKLM\System\Select и заменяя значение па раметра HKLM\System\Select\Current на значение параметра HKLM\System\ Select\LastKnownGood. Она также обновляет символьную ссылку HKLM\Sys tem\CurrentControlSet так, чтобы она указывала на набор управления Last KnownGood. Поскольку для нового драйвера нет подраздела в разделе Ser vices набора управления LastKnownGood, система успешно загрузится. Безопасный режим Наиболее распространенная причина, по которой системы Windows стано вятся незагружаемыми, заключается в том, что какойто драйвер устройства приводит к краху при загрузке. Поскольку со временем программноаппа ратная конфигурация системы может измениться, скрытые до этого ошиб ки в драйверах могут проявиться в любой момент. Windows предоставляет администратору способ решения подобных проблем: загрузку в безопасном режиме (safe mode). Понятие безопасного режима в Windows заимствовано из потребительских версий Windows и представляет собой конфигурацию с минимальным набором драйверов и сервисов. Используя только самые необходимые драйверы, Windows избегает загрузки сторонних драйверов, способных вызывать крах системы. Нажав клавишу F8 в начале загрузки Windows 2000, вы открываете допол нительное загрузочное меню, в котором присутствуют три варианта загруз ки в безопасном режиме: Safe Mode (Безопасный режим), Safe Mode With Networking (Безопасный режим с загрузкой сетевых драйверов) и Safe Mode With Command Prompt (Безопасный режим с поддержкой командной стро ки). Стандартный безопасный режим подразумевает использование мини мума необходимых для успешной загрузки драйверов. В безопасном режи ме с сетевой поддержкой дополнительно загружаются сетевые драйверы и сервисы. Наконец, единственное отличие безопасного режима с поддержкой командной строки от стандартного заключается в том, что Windows вместо обычной оболочки Windows Explorer, позволяющей работать в GUIрежиме, запускает оболочку командной строки (Cmd.exe). В Windows предусмотрен и четвертый безопасный режим — Directory Services Restore (Восстановление службы каталогов), который применяется
292 ГЛ А В А 5 БЕЗОПАСНОСТЬ для загрузки системы с отключенной службой каталогов Active Directory и без открытия ее базы данных. Это позволяет администратору исправить повреж денную базу данных или восстановить ее с резервной копии. В этом режиме загружается весь набор драйверов и сервисов, кроме Active Directory. В тех случаях, в которых вам не удается войти в систему изза повреждения базы данных Active Directory, этот режим дает возможность устранить неполадки. Загрузка драйверов в безопасном режиме Как Windows определяет набор драйверов для загрузки в стандартном безо пасном режиме и безопасном режиме с сетевой поддержкой? Ответ следует искать в содержимом раздела реестра HKLM\SYSTEM\CurrentControlSet\ Control\SafeBoot. В нем присутствуют подразделы Minimal и Network. Каж дый подраздел в свою очередь содержит подразделы с именами драйверов, сервисов или их групп. Так, подраздел vga.sys определяет драйвер видеоадап тера VGA, который поддерживает базовый набор графических сервисов стандартного видеоадаптера для IBMсовместимого компьютера. Этот драй вер используется системой в безопасном режиме вместо драйверов, которые позволяют задействовать все преимущества куда более совершенных видео адаптеров, но способны помешать успешной загрузке системы. Каждому подразделу в разделе SafeBoot соответствует параметр по умолчанию, опи сывающий, что именно идентифицирует данный подраздел. Например, в подразделе vga.sys параметр по умолчанию — Driver. Параметром по умолчанию для подраздела файловой системы является Driver Group. При создании сценария установки для драйвера устройства разработчик может указать, что он относится к какойлибо группе драйве ров. Группы драйверов, определенные в системе, перечисляются в парамет ре List раздела реестра HKLM\SYSTEM\CurrentControlSet\Control\ServiceGro upOrder. Разработчик приписывает драйвер к той или иной группе, чтобы указать Windows, на каком этапе загрузки следует запускать данный драйвер. Главное предназначение раздела ServiceGroupOrder — определение поряд ка загрузки групп драйверов. Некоторые группы драйверов нужно загружать до или после других. Параметр Group в подразделе реестра со сведениями о конфигурации драйвера, сопоставляет его с определенной группой. Под разделы со сведениями о конфигурации драйверов и сервисов находятся в разделе HKLM\SYSTEM\CurrentControlSet\Services. Взглянув на его содержи мое, вы найдете раздел VgaSave для драйвера видеоадаптера VGA, который принадлежит к группе Video Save. Любой драйвер файловой системы, необ ходимый Windows для обращения к системному диску, находится в группе Boot File System. Если файловой системой такого диска является NTFS, то в группу входит драйвер NTFS; в ином случае в группу входит драйвер Fastfat (поддерживающий диски FAT12, FAT16 и FAT32). Другие драйверы файловой системы входят в группу File System, которая также включена в конфигура ции Safe Mode и Safe Mode With Networking. При загрузке в безопасном режиме Ntldr передает ядру (Ntoskrnl.exe) вме сте с другими параметрами, указанными в Boot.ini для текущего варианта
ГЛАВА 9 Запуск и завершение работы системы 293 загрузки, параметр командной строки /SAFEBOOT:, добавляя к нему одну или несколько строк в зависимости от выбранного типа безопасного режима. Для стандартного безопасного режима Ntldr добавляет MINIMAL, для Safe Mode With Networking — NETWORK, для Safe Mode With Command Prompt — MINIMAL(ALTERNATESHELL), а для Directory Services Restore — DSREPAIR. Ядро Windows сканирует параметры загрузки в поисках спецификаторов безопасного режима и устанавливает значение внутренней переменной InitSafeBootMode в соответствии с результатом поиска. Значение этой пере менной также записывается в раздел HKLM\SYSTEM\CurrentControlSet\Cont rol\SafeBoot\Option\OptionValue, что позволяет компонентам пользователь ского режима (например, SCM) определять режим загрузки системы. Кроме того, при выборе Safe Mode With Command Prompt, ядро присваивает зна чение 1 параметру UseAlternateShell в разделе реестра HKLM\SYSTEM\Cur rentControlSet\Control\SafeBoot\Option. Кроме того, ядро записывает пара метры, переданные Ntldr, в раздел HKLM\SYSTEM\CurrentControlSet\Control\ SystemStartOptions. Когда диспетчер вводавывода загружает драйверы устройств, указанные в разделе HKLM\SYSTEM\CurrentControlSet\Services, он выполняет функцию IopLoadDriver. А когда диспетчер Plug and Play обнаруживает новое устрой ство и хочет динамически загрузить драйвер для этого устройства, он вызы вает функцию IopCallDriverAddDevice. Обе эти функции перед загрузкой драйвера обращаются к функции IopSafeBootDriverLoad. Последняя проверя ет значение переменной InitSafeBootMode и определяет, можно ли загрузить данный драйвер. Так, если система загружается в стандартном безопасном режиме, IopSafeBootDriverLoad ищет группу этого драйвера (если таковая есть) в подразделе Minimal. Найдя ее, IopSafeBootDriverLoad уведомляет выз вавшую функцию о том, что этот драйвер можно загрузить. В ином случае IopSafeBootDriverLoad ищет в том же подразделе имя драйвера. Если оно есть в списке, драйвер может быть загружен. Если IopSafeBootDriverLoad не нахо дит в списке группу или имя данного драйвера, его загрузка запрещается. При загрузке системы в безопасном режиме с сетевой поддержкой IopSafe BootDriverLoad ведет поиск в подразделе Network, а в случае загрузки систе мы в нормальном режиме IopSafeBootDriverLoad разрешает загрузку всех драйверов. Однако Ntldr загружает все драйверы, у которых в соответствующих раз делах реестра значение Start равно 0, что указывает на необходимость их загрузки при запуске системы. Поскольку Ntldr не проверяет раздел SafeBoot (считая, что любой драйвер с нулевым значением параметра Start необхо дим для успешного старта системы), он загружает все загрузочные драйве ры, которые впоследствии запускаются Ntoskrnl. Программное обеспечение с поддержкой безопасного режима SCM (Services.exe), проводя инициализацию при загрузке, проверяет пара метр OptionValue в разделе реестра HKLM\SYSTEM\CurrentControlSet\Cont rol\SafeBoot\Option, чтобы выяснить, загружается ли система в безопасном
294 ГЛ А В А 5 БЕЗОПАСНОСТЬ режиме. Если да, SCM зеркально воспроизводит действия IopSafeBootDriver Load. Он обрабатывает все сервисы, перечисленные в HKLM\SYSTEM\Cur rentControlSet\Services, но загружает лишь отмеченные в соответствующем подразделе реестра для загрузки в безопасном режиме. Подробнее об ини циализации SCM см. раздел «Сервисы» главы 4. Userinit (\Windows\System32\Userinit.exe) — другой компонент пользова тельского режима, которому нужно знать, загружается ли система в безопас ном режиме. Userinit, инициализирующий среду для пользователя при его входе в систему, проверяет значение HKLM\SYSTEM\CurrentControlSet\Cont rol\SafeBoot\UseAlternateValue. Если это значение установлено, в качестве пользовательской оболочки он запускает не Explorer.exe, а программу, ука занную в HKLM\SYSTEM\CurrentControlSet\Control\SafeBoot\AlternateShell. Когда вы устанавливаете Windows на компьютер, параметру AlternateShell присваивается значение Cmd.exe, и командная строка Windows становится оболочкой по умолчанию для безопасного режима с командной строкой. Но, даже если текущей оболочкой является командная строка, из нее можно за пустить Windows Explorer, введя команду Explorer.exe. Аналогичным образом из командной строки можно запустить любую GUIпрограмму. А как приложения узнают о загрузке системы в безопасном режиме? Вы зовом Windowsфункции GetSystemMetrics(SM_CLEANBOOT). Пакетные сцена рии, выполняющие некоторые действия при загрузке системы в безопасном режиме, проверяют наличие переменной окружения SAFEBOOT_OPTION, так как система определяет ее только при загрузке в безопасном режиме. Ведение протокола при загрузке в безопасном режиме Если вы загружаете систему в безопасном режиме, Ntldr передает ядру Win dows вместе с параметрами, устанавливающими безопасный режим, и пара метр /BOOTLOG. При инициализации ядро проверяет наличие параметра /BOOTLOG независимо от того, задан ли безопасный режим. Если ядро об наруживает соответствующую строку, оно протоколирует все свои действия при загрузке каждого драйвера. Так, если функция IopSafeBootDriverLoad зап рещает загрузку какоголибо драйвера, диспетчер вводавывода вызывает функцию IopBootLog, регистрируя, что данный драйвер не загружен. Анало гичным образом после успешной загрузки драйвера, входящего в конфигу рацию безопасного режима, IopLoadDriver вызывает IopBootLog для внесения записи о загрузке этого драйвера. Изучив файлы протокола загрузки, мож но выяснить, какие драйверы являются частью данной конфигурации. Поскольку ядро избегает изменения данных на диске до запуска Chkdsk, который происходит на более позднем этапе загрузки, IopBootLog не может просто сбрасывать записи в файл. Вместо этого она записывает их в раздел реестра HKLM\SYSTEM\CurrentControlSet\BootLog. Диспетчер сеансов (Smss), первый загружаемый компонент пользовательского режима, запускает Chkdsk для проверки целостности системного диска, а потом завершает инициали зацию реестра, вызывая NtInitializeRegistry. Этот вызов указывает ядру, что уже можно безопасно открыть на диске файл протокола, что и делается вызовом
ГЛАВА 9 Запуск и завершение работы системы 295 IopCopyBootLogRegistryToFile. Эта функция создает в системном каталоге Win dows (по умолчанию — \Windows) файл Ntbtlog.txt и копирует в него содер жимое раздела реестра BootLog. IopCopyBootLogRegistryToFile также устанавли вает флаг, сигнализирующий IopBootLog о возможности записи непосред ственно в файл протокола. Ниже показан фрагмент образца такого файла. Service Pack 1 3 30 2004 14:05:21.500 Loaded driver \WINDOWS\system32\ntoskrnl.exe Loaded driver \WINDOWS\system32\hal.dll Loaded driver \WINDOWS\system32\KDCOM.DLL Loaded driver \WINDOWS\system32\BOOTVID.dll Loaded driver ACPI.sys Loaded driver \WINDOWS\System32\DRIVERS\WMILIB.SYS Loaded driver pci.sys Loaded driver isapnp.sys Loaded driver intelide.sys Loaded driver \WINDOWS\System32\DRIVERS\PCIIDEX.SYS Loaded driver MountMgr.sys Loaded driver ftdisk.sys Loaded driver dmload.sys Loaded driver dmio.sys Microsoft (R)Windows 2000 (R)Version 5.0 (Build 2195) 2 11 2000 10:53:27.500 Loaded driver \WINNT \System32 \ntoskrnl.exe Loaded driver \WINNT \System32 \hal.dll Loaded driver \WINNT \System32 \BOOTVID.DLL Loaded driver ACPI.sys Loaded driver \WINNT \System32 \DRIVERS \WMILIB.SYS Loaded driver pci.sys Loaded driver isapnp.sys Loaded driver compbatt.sys Loaded driver \WINNT \System32 \DRIVERS \BATTC.SYS Loaded driver intelide.sys Loaded driver \WINNT \System32 \DRIVERS \PCIIDEX.SYS Loaded driver pcmcia.sys Loaded driver ftdisk.sys Loaded driver Diskperf.sys Loaded driver dmload.sys Loaded driver dmio.sys ... Did not load driver \SystemRoot\System32\Drivers\lbrtfdc.SYS Did not load driver \SystemRoot\System32\Drivers\Sfloppy.SYS Did not load driver \SystemRoot\System32\Drivers\i2omgmt.SYS Did not load driver Media Control Devices Did not load driver Communications Port Did not load driver Audio Codecs ...
296 ГЛ А В А 5 БЕЗОПАСНОСТЬ Консоль восстановления В безопасном режиме обычно удается восстановить систему, ставшую неза гружаемой в нормальном режиме изза неправильной работы какоголибо драйвера устройства. Однако в некоторых ситуациях это не помогает: сис тема все равно не загружается. Так, если сбойный драйвер входит в группу Safe, загрузиться в безопасном режиме не удастся. Другая ситуация, когда загрузка в безопасном режиме не помогает, — сбои в загрузочном драйвере стороннего поставщика, например в драйвере антивирусного сканера, по скольку загрузочные драйверы стартуют независимо от режима загрузки системы. Аналогичная ситуация возникает при повреждении файлов систем ных модулей или драйверов, входящих в конфигурацию безопасного режи ма, а также главной загрузочной записи (MBR) системного диска. Эти про блемы можно решить с помощью Recovery Console (Консоль восстановле ния). Консоль восстановления позволяет загрузить компактную оболочку командной строки с дистрибутивного компактдиска Windows (или ранее подготовленных загрузочных дискет) и восстановить систему без загрузки компьютера с жесткого диска. При загрузке системы с дистрибутивного компактдиска Windows появ ляется экран, на котором можно выбрать между установкой Windows и вос становлением существующей системы. При выборе второго варианта пред лагается вставить дистрибутивный компактдиск Windows (если он не встав лен в CDпривод). Далее вы должны выбрать один из двух вариантов восста новления: запустить консоль восстановления или начать процесс аварийно го восстановления. Если при появлении экрана Setup Welcome (Вас привет ствует программа установки) вы нажмете клавишу F10, это меню выводить ся не будет, а сразу запустится консоль восстановления. После запуска консоль восстановления сканирует жесткие диски и фор мирует список систем Windows NT и Windows на данном компьютере (если они есть). Выбрав нужную систему, вы должны ввести пароль, соответству ющий учетной записи администратора для данной системы. Если регистра ция прошла успешно, система предоставляет вам командную оболочку, ана логичную среде MSDOS. Гибкий набор команд позволяет выполнять про стые операции с файлами (вроде копирования, переименования и удаления), включать и отключать службы и драйверы и даже восстанавливать MBR и загрузочные записи. Однако консоль восстановления обеспечивает доступ лишь к корневому каталогу, к каталогу, в котором установлена система и в котором вы сейчас зарегистрировались, и к каталогам на сменных дисках, например на компактдисках или 3,5дюймовых дискетах (если это разре шено локальной политикой безопасности, чьи параметры хранятся в кусте SECURITY реестра текущей системы). Эти ограничения диктуются требова ниями защиты данных, право на доступ к которым может отсутствовать у администратора одной из систем. Вы можете переопределить эти ограни чения, используя редактор локальной политики безопасности (secpol.msc) для настройки параметров Recovery Console (Консоль восстановления) в
ГЛАВА 9 Запуск и завершение работы системы 297 папке Security Options (Параметры безопасности) в Local Policies (Локальные политики) при нормальной загрузке системы. Для поддержки таких команд файлового вводавывода, как Cd, Rename или Move, консоль восстановления использует встроенный интерфейс сис темных вызовов Windows. Команды Enable и Disable, позволяющие изменять режимы запуска драйверов устройств и сервисов (служб), работают иначе. Например, когда вы командуете консоли восстановления отключить какой либо драйвер, она обращается к разделу реестра Services и присваивает па раметру Start в подразделе для соответствующего драйвера значение SER VICE_DISABLED. В результате при следующей загрузке системы данный драй вер загружаться не будет. Консоль также загружает куст реестра SYSTEM (\Windows\System32\Config\System) для текущей системы, где в разделе HKLM\SYSTEM\CurrentControlSet\Services хранится нужная информация. Когда вы загружаете систему с дистрибутивного компактдиска Windows или загрузочных дискет, к моменту появления экрана, предлагающего выбор между установкой или восстановлением Windows, происходит загрузка с компактдиска стартовой копии ядра Windows и всех драйверов поддержки (например, драйверов NTFS, FAT, SCSI и видеоадаптера). На компьютерах с процессорами типа x86 загрузка с компактдиска управляется файлом Txt setup.sif из каталога I386. В нем содержится список файлов, подлежащих заг рузке, с указанием их местонахождения на компактдиске. Как и при загрузке Windows с жесткого диска, первой запускаемой программой пользователь ского режима является диспетчер сеансов (Smss.exe), расположенный в ка талоге I386\System32. Диспетчер сеансов, используемый программой уста новки Windows, отличается от стандартного в уже установленной системе. Эта версия диспетчера сеансов предоставляет меню, позволяющие устано вить или восстановить Windows, а также выбрать тип восстановления. В про цессе установки Windows этот компонент также помогает выбрать раздел для установки системы и копирует файлы на жесткий диск. После запуска консоли восстановления диспетчер сеансов загружает и за пускает два драйвера устройств, реализующие эту консоль: Spcmdcon.sys и Setupdd.sys. Первый предоставляет интерактивную командную строку и обра батывает высокоуровневые команды. Второй является драйвером поддержки, предоставляющим Spcmdcon.sys набор функций для управления разделами диска, загрузки кустов реестра и управления видеовыводом. Setupdd.sys так же взаимодействует с драйверами дисковых устройств для управления раз делами и выводит на экран сообщения, используя базовую видеоподдержку, встроенную в ядро Windows. Консоль восстановления, приняв от вас пароль для входа в выбранную сис тему, должна проверить его, даже несмотря на то что подсистема защиты Windows сейчас не функционирует. Таким образом, проверка пароля возла гается исключительно на консоль восстановления. Для этого консоль преж де всего загружает с жесткого диска (через Setupdd.sys) куст реестра диспет чера учетных записей безопасности (Security Accounts Manager, SAM) данной системы, где хранится информация о паролях. Куст SAM находится в ката
298 ГЛ А В А 5 БЕЗОПАСНОСТЬ логе \Windows\System32\Config\Sam. После загрузки этого куста консоль восстановления находит в реестре системный ключ для расшифровки копии SAM в памяти. Шифрование куста SAM введено, начиная с Windows NT 4 Service Pack 3, для защиты от попыток взлома из MSDOS. Далее консоль восстановления (Spcmdcon.sys) отыскивает в SAM пароль для учетной записи Administrator (Администратор). На заключительном эта пе проверки консоль хэширует пароль по алгоритму MD5, а затем сравни вает полученный хэш с зашифрованным хэшем из SAM. Если они совпада ют, консоль восстановления считает, что вы успешно вошли в систему, в ином случае консоль восстановления отказывает вам в доступе. Решение распространенных проблем загрузки В этом разделе описываются проблемы, которые могут возникнуть в процес се загрузки, их симптомы, причины и подходы к решению. Повреждение MBR 쐽 Симптомы Система с поврежденной главной загрузочной записью (Master Boot Record, MBR) пройдет тест самодиагностики при включении, выполняемый BIOS (poweron self test, POST), выведет на экран информа цию о версии BIOS или модели компьютера, затем экран станет черным, и компьютер зависнет. В зависимости от типа повреждения MBR вы мо жете увидеть одно из следующих сообщений: «Invalid Partition Table» (не допустимая таблица разделов), «Error Loading Operating System» (ошибка при загрузке операционной системы) или «Missing Operating System» (операционная система не найдена). 쐽 Причина MBR может быть повреждена изза ошибок жесткого диска, в результате ошибки одного из драйверов в процессе работы Windows или изза деструктивной деятельности какоголибо вируса. 쐽 Решение Загрузите консоль восстановления и запустите команду fixmbr. Эта команда заменяет исполняемый код в MBR. К сожалению, она не испра вит таблицу разделов. Единственный способ это сделать — восстановить поврежденную таблицу разделов из резервной копии или использовать сторонний инструмент для устранения повреждений на диске. Повреждение загрузочного сектора 쐽 Симптомы Повреждение загрузочного сектора выглядит как повреж дение MBR, когда система зависает с черным экраном после прохожде ния BIOS POST, либо на черном экране появляется сообщение: «A disk read error occurred» (ошибка чтения с диска), «NTLDR is missing» (NTLDR не найден) или «NTLDR is compressed» (NTLDR заархивирован). 쐽 Причина Загрузочная запись может быть повреждена изза ошибок же сткого диска, в результате ошибки одного из драйверов в процессе рабо ты Windows или изза деструктивной деятельности какоголибо вируса.
ГЛАВА 9 Запуск и завершение работы системы 299 쐽 Решение Загрузите консоль восстановления и запустите команду fix boot. Эта команда перепишет загрузочный сектор указанного вами тома. Вы должны выполнить такую команду применительно к системному и загрузочному томам, если они разные. Неправильная конфигурация Boot.ini 쐽 Симптом После BIOS POST вы видите сообщение, которое начинается как «Windows could not start because of a computer disk hardware con figuration problem» (Windows не удалось запустить изза проблемы с кон фигурацией дискового устройства), «Could not read from selected boot disk» (не удалось считать данные с выбранного загрузочного диска) или «Check boot path and disk hardware» (проверьте путь к загрузочному дис ку и дисковое устройство). 쐽 Причина Файл Boot.ini удален, поврежден или больше не ссылается на загрузочный том изза добавления раздела, которое привело к изменению ARCимени тома (Advanced RISC Computing). 쐽 Решение Загрузите консоль восстановления и запустите команду bootcfg /rebuild. Эта команда заставит консоль восстановления просканировать каждый том в поисках установленных систем Windows. Обнаружив первую из них, она спросит, следует ли добавить ее в Boot.ini как вариант загруз ки и под каким названием отображать ее в загрузочном меню. Повреждение системных файлов 쐽 Симптомы Повреждение системных файлов (в том числе драйверов и DLL) может проявляться поразному. Один из вариантов — сообщение на черном экране после прохождения BIOS POST, в котором говорится «Win dows could not start because the following file is missing or corrupt» (Win dows не удалось запустить изза отсутствия или повреждения следующе го файла). Далее выводится имя файла и запрос на его переустановку. Еще один вариант — синий экран в результате краха при загрузке с текстом «STOP: 0xC0000135 {Unable to Locate Component}». 쐽 Причины Том, на котором находится системный файл, поврежден, один или несколько системных файлов удалены либо повреждены. 쐽 Решение Загрузите консоль восстановления и запустите команду chkdsk. Эта команда попытается устранить повреждение тома. Если Chkdsk не со общит о какихлибо проблемах, возьмите резервную копию нужного сис темного файла. Одно из мест, где можно найти такие копии, — каталог \Windows\System32\DllCache, в котором Windows хранит копии многих системных файлов для использования Windows File Protection (см. врезку «Windows File Protection» далее в этом разделе). Если вам не удалось найти копию файла в этом каталоге, поищите ее на другом компьютере в сети. Заметьте, что резервная копия файла должна быть от того же пакета обнов лений или критического исправления, что и заменяемый файл.
300 ГЛ А В А 5 БЕЗОПАСНОСТЬ В некоторых случаях может быть удалено или повреждено много систем ных файлов, поэтому процесс восстановления потребует неоднократных пе резагрузок, пока вы поочередно не замените все файлы. Если вы считаете, что повреждения системных файлов слишком обширны, подумайте о восстанов лении системы с резервного образа, который генерируется, например, Auto mated System Recovery (ASR). Запустив Windows Backup (Архивация данных) [эта программа находится в папке System (Служебные) в группе Accessories (Стандартные) меню Start (Пуск)], вы можете сгенерировать резервный ASR образ, который включает все файлы на системном и загрузочном томах, плюс дискету, на которой сохраняется информация о дисках и томах в системе. Чтобы восстановить систему из ASR, загрузите компьютер с дистрибутива Windows и нажмите F2, когда появится соответствующий запрос. Если у вас нет резервной копии, остается последнее средство — запуск программы установки Windows в режиме исправления: загрузите компьютер с дистрибутива Windows и следуйте указаниям мастера. Мастер спросит вас, хотите ли вы исправить существующую систему или установить новую. Как только вы выберете первый вариант, Setup переустановит все системные файлы, сохранив данные ваших приложений и параметры реестра. Windows File Protection Помимо своих основных задач, Winlogon также поддерживает функ циональность защиты файлов Windows (Windows File Protection, WFP). WFP, которая реализована в виде двух DLL (\Windows\System32\Sfc.dll и \Windows\System32\Sfc_os.dll), отслеживает несколько каталогов на предмет изменения ключевых драйверов, исполняемых файлов и DLL, в том числе большинство подкаталогов в \Windows. При этом она ис пользует версию ReadDirectoryChangesW для Native API. Когда WFP об наруживает изменение в одном из системных файлов, список которых «зашит» в \Windows\System32\Sfcfiles.dll (с помощью утилиты Strings от www.sysinternals.com вы можете получить этот список), она проверяет, подписан ли данный файл цифровой подписью Microsoft (об этом процессе см. раздел «Установка драйверов» главы 9). Если подписан, WFP разрешает изменение и копирует файл в свой резервный каталог. По умолчанию это \Windows\System32\DllCache, но его можно пере определить, изменив параметр реестра HKLM\Software\Microsoft\Win dows NT\CurrentVersion\Winlogon\SFCDllCacheDir. Критические ис правления и пакеты обновлений всегда устанавливают системные фай лы, подписанные Microsoft. Если в результате модификации появляется файл, не подписанный Microsoft, WFP заменяет его резервной версией из подкаталога DLL Cache. Если Winlogon не удается найти резервную версию в этом под каталоге, он проверяет сетевой путь установки или дистрибутив (в этом случае предлагается вставить компактдиск).
ГЛАВА 9 Запуск и завершение работы системы 301 Повреждение куста System 쐽 Симптомы Если куст реестра System (сведения об этом кусте см. в раз деле «Реестр» главы 4) отсутствует или поврежден, NTLDR выводит на чер ном экране после BIOS POST сообщение «Windows could not start because the following file is missing or corrupt: \WINDOWS\SYSTEM32\CONFIG\SYS TEM» (Windows не удалось запустить изза отсутствия или повреждения следующего файла: \WINDOWS\SYSTEM32\CONFIG\SYSTEM). 쐽 Причины Куст реестра System, который содержит конфигурационную информацию, необходимую для загрузки системы, поврежден или удален. 쐽 Решение Загрузите консоль восстановления и запустите команду chkdsk применительно к загрузочному тому, чтобы исправить любые возможные его повреждения. Если это не решило проблему, возьмите резервную ко пию куста System. Если вы делали резервные ASRкопии системы или ис пользовали утилиту Windows Backup для создания резервных копий со стояния системы (это один из вариантов, предлагаемых в ее UI), то ско пируйте кусты реестра из самой последней резервной копии, которые хранятся в каталоге \Windows\Repair, в частности скопируйте файл Sys tem в \Windows\System32\Config. Если вы используете Windows XP и средство System Restore (Восстанов ление системы) включено (о System Restore см. в главе 12), то можете полу чить резервные копии кустов реестра, в том числе System, из самой после дней точки восстановления. Однако не исключено, что консоль восстанов ления не позволит вам обратиться к каталогу, где хранятся точки восстанов ления, — \System Volume Information. Версия консоли восстановления из Windows XP Service Pack 1 разрешает доступ к этому каталогу, а более ста рые версии — нет (если только это не разрешено локальной политикой бе зопасности). Чтобы обойти это ограничение, используйте Local Security Policy Editor (Редактор локальной политики безопасности) для изменения параметров консоли восстановления, как уже пояснялось ранее. Вы также можете применить сторонние утилиты для доступа к другим каталогам. По лучив доступ к каталогу точек восстановления, выполните следующие опе рации, чтобы получить файлы кустов реестра. 1. Перейдите в каталоге \System Volume Information на загрузочном томе в подкаталог, имя которого начинается с «_restore». 2. Найдите подкаталог RP с самым большим числом (например, RP173). 3. Скопируйте файл с именем _REGISTRY_MACHINE_SYSTEM в файл \Win dows\System32\Config\System. 4. Перезагрузите систему. Другой вариант — попробовать исправить повреждение с помощью ути литы Microsoft ChkReg. Она пытается делать это автоматически и запускает ся с дискет, подготовленных в программе установки Windows XP Setup. Эту утилиту и инструкции по ее применению вы найдете по ссылке http://www. microsoft.com/downloads/details.aspx?displaylang=en&familyid=56d3c2012c68 4de89229ca494362419c.
302 ГЛ А В А 5 БЕЗОПАСНОСТЬ Если у вас нет резервных копий, нет доступа к точкам восстановления и утилита ChkReg не помогла, используйте копию куста System из \Windows \Repair как последнее средство. Windows Setup делает копию куста System по окончании установки, поэтому вы потеряете все изменения в конфигурации системы и драйверов устройств, произошедшие с того момента. Крах или зависание после вывода экрана-заставки 쐽 Симптомы К этой категории относятся проблемы, которые возникают после отображения экраназаставки Windows, вывода рабочего стола или входа в систему. Они могут проявляться как крах с отображением сине го экрана или зависание, при котором замораживается вся система (либо сохраняется возможность перемещать по экрану курсор мыши, но сис тема ни на что не реагирует). 쐽 Причины Эти проблемы почти всегда являются следствием ошибки в драйвере устройства, но иногда могут быть результатом повреждения ку ста реестра, отличного от System. 쐽 Решение Вы можете попытаться устранить такую проблему. Первое, что стоит попробовать, — последнюю удачную конфигурацию (last known good, LKG), о которой уже рассказывалось в этой главе и в разделе «Сер висы» главы 4. Она состоит из набора управления реестром (registry cont rol set), с помощью которого в последний раз удалось успешно загрузить систему. Поскольку этот набор включает базовую системную конфигура цию и регистрационную базу данных драйверов устройств и сервисов, он не отражает самые последние изменения в составе драйверов устройств или сервисов, что часто помогает обойти источник проблемы. Для дос тупа к последней удачной конфигурации нажмите клавишу F8 на самой ранней стадии процесса загрузки и в появившемся загрузочном меню выберите этот вариант. Как уже говорилось в этой главе, когда вы загружаете LKG, система сохра няет набор управления, от которого вы тем самым отказываетесь, и помечает его как неудачный. Если LKG позволит сделать систему загружаемой, вы смо жете экспортировать содержимое текущего и неудачного наборов управле ния в .regфайлы и, сравнив их, определить, что стало причиной неудачной загрузки системы. Для этого используйте поддержку экспорта в Regedit, до ступную в меню File (Файл) [или Registry (Реестр), если вы работаете с Win dows 2000]. 1. Запустите Regedit и выберите HKLM\System\CurrentControlSet. 2. Выберите Export (Экспорт) из меню File (Файл) и сохраните содержимое в файл с именем good.reg. 3. Откройте HKLM\System\Select, посмотрите значение параметра Failed и выберите подраздел HKLM\System\ControlXXX, где XXX — значение па раметра Failed. 4. Экспортируйте содержимое этого набора управления в файл bad.reg.
ГЛАВА 9 Запуск и завершение работы системы 303 5. Используйте Wordpad для глобальной замены всех вхождений «Current ControlSet» в good.reg на «ControlSet». 6. С помощью Wordpad замените все вхождения «ControlXXX» (вместо XXX должно быть значение параметра Failed) в bad.reg на «ControlSet». 7. Запустите Windiff из Support Tools и сравните два файла. Различия между неудачным и удачным наборами управления могут быть весьма значительными, поэтому вы должны сосредоточиться на изменениях в подразделе Control, а также в подразделах Parameters каждого драйвера и сер виса, зарегистрированного в подразделе Services. Различия в подразделах Enum разделов для драйверов в ветви Services набора управления игнорируйте. Если проблема вызвана драйвером или сервисом, который присутствовал в системе до последней успешной загрузки, LKG не сделает систему загру жаемой. LKG не поможет и в том случае, если изменившийся проблематич ный параметр конфигурации находится вне набора управления или если он был изменен до последней успешной загрузки. В таких случаях следующий шаг — попробовать загрузиться в безопасном режиме (о нем уже рассказы валось в этом разделе). Если система успешно загружается в безопасном ре жиме и вам известно, какой драйвер привел к провалу нормальной загруз ки, вы можете отключить его через диспетчер устройств, доступный с вклад ки Hardware (Оборудование) апплета System (Система). Для этого укажите проблемный драйвер и выберите Disable (Отключить) из меню Action (Дей ствие). Если вы используете Windows XP или Windows Server 2003, недавно обновили драйвер и считаете, что в обновленной версии есть какаято ошиб ка, то можете выбрать откат драйвера к его предыдущей версии, что также делается в диспетчере устройств. Чтобы восстановить предыдущую версию драйвера, дважды щелкните нужный драйвер для открытия его окна свойств и нажмите кнопку Roll Back Driver (Откатить) на вкладке Drivers (Драйвер). В Windows XP при включенном System Restore предлагается вариант от ката состояния всей системы к предыдущей точке (определенной средством System Restore), когда LKG ничего не дала. Безопасный режим распознает наличие точек восстановления и, если они есть, спрашивает, что вы хоти те — войти в систему и вручную выполнить диагностику и исправление или запустить мастер восстановления системы. Попытка сделать систему загру жаемой с помощью System Restore — хороший вариант, когда вы знаете при чину проблемы и хотите автоматически ее устранить или когда причина вам не известна, но вы не желаете тратить время на ее поиск. Если System Restore вас не устраивает или если вам нужно определить причину краха при нормальной загрузке, когда в безопасном режиме сис тема успешно загружается, то попробуйте вести журнал в ходе неудачной загрузки. Для этого выберите соответствующий вариант в загрузочном меню, которое открывается нажатием клавиши F8 на самой ранней стадии загруз ки. Как уже говорилось в этой главе, диспетчер сеансов (\Windows\System32\ Smss.exe) сохраняет журнал загрузки в \Windows\ntbtlog.txt; в нем отмеча ются как загруженные, так и незагруженные системой драйверы устройств,
304 ГЛ А В А 5 БЕЗОПАСНОСТЬ поэтому вы получите такой журнал, только если крах или зависание проис ходит после инициализации диспетчера сеансов. После перезагрузки в бе зопасный режим система добавит в существующий журнал загрузки новые записи. Отделите части журнала, относящиеся к неудачной попытке загруз ки и к загрузке в безопасный режим, и сохраните их в разных файлах. Уда лите строки с текстом «Did not load driver», а затем сравните эти файлы с помощью утилиты наподобие Windiff. Поочередно отключайте драйверы, загружавшиеся при нормальной загрузке, но не в безопасном режиме, пока система вновь не будет загружаться в нормальном режиме. (После чего вновь включите драйверы, не связанные с проблемой.) Если вам не удается получить журнал при нормальной загрузке (напри мер, изза того, что крах системы происходит до инициализации диспетче ра сеансов), если система рушится и при загрузке в безопасном режиме или если при сравнении двух частей журнала не обнаруживается значимых раз личий, то остается лишь прибегнуть к утилите Driver Verifier в сочетании с анализом аварийного дампа. (Более подробные сведения по этой тематике см. в главе 14.) Завершение работы системы Если в систему ктото вошел и некий процесс инициирует завершение ра боты системы, вызывая Windowsфункцию ExitWindowsEx, Csrss получает сообщение о необходимости завершения системы. Тогда Csrss в интересах инициатора завершения системы посылает скрытому окну, которое принад лежит Winlogon, Windowsсообщение с требованием завершить работу си стемы. Winlogon, олицетворяющий зарегистрированного в данный момент пользователя (чей контекст защиты может совпадать, а может и не совпадать с контекстом защиты пользователя процесса, инициировавшего завершение работы), вызывает ExitWindowsEx с набором специальных внутренних фла гов. В результате Csrss получает еще одно сообщение с запросом на завер шение системы. На этот раз Csrss видит, что запрос поступил от Winlogon, и перебирает все процессы в сеансе интерактивного пользователя (а не того, кто иници ировал завершение системы). Вызвав SetProcessShutdownParameters, процесс может указать уровень завершения (shutdown level), который сообщает сис теме, когда этому процессу нужно завершиться по отношению к другим про цессам. Допустимые уровни укладываются в диапазон 0–1023 (по умолча нию — 640). Explorer, например, устанавливает свой уровень в 2, а Task Ma nager — в 1. Для каждого процесса, владеющего окном верхнего уровня, Csrss посылает сообщения WM_QUERYENDSESSION всем его потокам с циклом выборки Windowsсообщений. Если поток возвращает TRUE, процесс завер шения работы системы продолжается. Тогда Csrss посылает потоку сообще ние WM_ENDSESSION с требованием завершить свою работу. Csrss ждет за вершения потока в течение времени, указанного в HKCU\Control Panel\ Desk top\HungAppTimeout (по умолчанию — 5000 мс).
ГЛАВА 9 Запуск и завершение работы системы 305 Если в течение указанного времени поток не завершается, Csrss открывает диалоговое окно, показанное на рис. 55. (Вывод этого окна можно отклю чить, присвоив параметру HKCU\Control Panel\Desktop\AutoEndTasks значе ние, равное 1.) Диалоговое окно уведомляет пользователя о том, что коррек тное завершение данной программы невозможно, и предлагает принуди тельно завершить процесс или отменить завершение работы системы (тайм аут для этого диалогового окна не предусмотрен, а значит, на этом этапе зап рос на завершение может ждать бесконечно долго). Рис. 5-5. Диалоговое окно для принудительного закрытия программы Если поток успевает завершиться до истечения указанного времени, Csrss посылает пары сообщений WM_QUERYENDSESSION/WM_ENDSESSION дру гим потокам процесса с окнами верхнего уровня. Как только все его пото ки завершаются, Csrss завершает выполнение этого процесса и переходит к следующему процессу в интерактивном сеансе. ЭКСПЕРИМЕНТ: проверка HungAppTimeout Вы можете проверить, как используется параметр реестра HungAppTime out, запустив Notepad, введя в него какойнибудь текст и выйдя из систе мы. По истечении времени, заданного в HungAppTimeout, Csrss.exe откро ет диалоговое окно с запросом о том, хотите ли вы закрыть процесс Note pad, который еще не завершился. Notepad ждет, когда вы сообщите ему, надо ли сохранить введенный вами текст. Если вы нажмете Cancel в этом диалоговом окне, Csrss.exe отменит завершение работы системы. Обнаружив консольное приложение, Csrss вызывает обработчик консоли, посылая событие CTRL_LOGOFF_EVENT (при завершении работы системы только процессы сервисов получают события CTRL_SHUTDOWN_ EVENT). Если обработчик возвращает FALSE, Csrss уничтожает процесс. Если обработ чик возвращает TRUE или не отвечает в течение времени, указанного в HKCU\ Control Panel\Desktop\WaitToKillAppTimeout (по умолчанию — 20000 мс), Csrss выводит диалоговое окно, показанное на рис. 55. Далее Winlogon вызывает функцию ExitWindowsEx, чтобы Csrss завершил лю бые COMпроцессы, являющиеся частью сеанса интерактивного пользователя. К этому моменту выполнение всех процессов в сеансе уже завершено. Winlogon снова вызывает функцию ExitWindowsEx, на этот раз в контексте
306 ГЛ А В А 5 БЕЗОПАСНОСТЬ системного процесса, и та посылает Csrss сообщение. Csrss просматривает все процессы, принадлежащие контексту системы и рассылает сообщения WM_QUERYENDSESSION/WM_ENDSESSION всем GUIпотокам. Но консоль ным приложениям с зарегистрированными обработчиками Csrss посылает не CTRL_LOGOFF_EVENT, а CTRL_SHUTDOWN_EVENT. Заметьте, что SCM яв ляется консольной программой, которой регистрируется свой обработчик. Получив запрос на завершение, SCM рассылает соответствующие сообщения всем сервисам, которые зарегистрированы на уведомление о завершении работы. Подробнее о завершении работы сервисов (в том числе о таймауте для SCM) см. раздел «Сервисы» главы 4. Хотя при завершении системных процессов действуют те же таймауты, что и для пользовательских процессов, Csrss не выводит никаких диалоговых окон и не завершает их принудительно. (Значения таймаутов завершения системных процессов берутся из профиля пользователя по умолчанию.) Смысл этих тай маутов только в том, чтобы системные процессы корректно завершились до выключения системы. Но многие системные процессы вроде Smss, Winlogon, SCM и LSASS на самом деле еще выполняются при выключении системы. Как только Csrss заканчивает рассылку уведомлений системным процес сам о завершении работы, Winlogon вызывает функцию исполнительной системы NtShutdownSystem. Она в свою очередь вызывает функцию NtSet SystemPowerState, управляющую завершением драйверов и остальных компо нентов исполнительной системы (диспетчеров Plug and Play, электропита ния, вводавывода, конфигурации и памяти). Например, NtSetSystemPowerState вызывает диспетчер вводавывода для рассылки пакетов завершения вводавывода всем драйверам устройств, зап росившим уведомление о завершении системы. Это позволяет драйверам подготовить свои устройства к завершению работы Windows. Диспетчер конфигурации сбрасывает на диск все измененные данные реестра, а дис петчер памяти записывает все измененные страницы с файловыми данны ми обратно в соответствующие файлы. Диспетчер памяти производит очи стку страничного файла (если это указано в настройках). Далее вновь вызы вается диспетчер вводавывода, который информирует драйверы файловой системы о завершении Windows. Процесс завершения работы заканчивает ся на диспетчере электропитания, дальнейшие действия которого зависят от пользовательских настроек (выключение компьютера, перезагрузка или переход в ждущий режим). Резюме В этой главе мы подробно исследовали процессы загрузки и завершения работы Windows в нормальном режиме и при возникновении сбоев. К это му моменту мы уже рассмотрели общую структуру Windows и базовые сис темные механизмы, обеспечивающие запуск, работу и в конечном счете вы ключение системы. Заложив такой фундамент, можно переходить к более подробному изучению отдельных компонентов исполнительной системы, начиная с процессов и потоков.
Г Л А В А 6 Процессы, потоки и задания В этой главе мы рассмотрим структуры данных и алгоритмы, связанные с процессами, потоками и заданиями в Microsoft Windows. В первом разделе основное внимание уделяется внутренним структурам данных, из которых состоит процесс. Во втором разделе поясняются этапы создания процесса (и его первичного потока). Далее поясняются внутреннее устройство потоков и их планирование. Завершается глава описанием объекта «задание» (job object). В процессе изложения материала мы будем упоминать соответствующие счетчики производительности или переменные ядра. Хотя программирова& ние под Windows не является предметом этой книги, в ней перечисляются Windows&функции, связанные с процессами, потоками и заданиями, — это даст вам представление о том, как они используются. Внутреннее устройство процессов В этом разделе описываются ключевые структуры данных процессов Win& dows. Также поясняются основные переменные ядра, счетчики производи& тельности, функции и утилиты, имеющие отношение к процессам. Структуры данных Каждый процесс в Windows представлен блоком процесса, создаваемым ис& полнительной системой (EPROCESS). Кроме многочисленных атрибутов, относящихся к процессу, в блоке EPROCESS содержатся указатели на неко& торые структуры данных. Так, у каждого процесса есть один или более по& токов, представляемых блоками потоков исполнительной системы (ETH& READ) (см. раздел «Внутреннее устройство потоков» далее в этой главе). Блок EPROCESS и связанные с ним структуры данных — за исключением блока переменных окружения процесса (process environment block, PEB) — суще& ствуют в системном пространстве. PEB находится в адресном пространстве процесса, так как содержит данные, модифицируемые кодом пользователь& ского режима. Для каждого процесса, выполняющего Windows&программу, процесс под& системы Windows (Csrss) поддерживает в дополнение к блоку EPROCESS па& раллельную структуру данных. Кроме того, часть подсистемы Windows, ра& ботающая в режиме ядра (Win32k.sys), поддерживает структуру данных для каждого процесса, которая создается при первом вызове потоком любой функции USER или GDI, реализованной в режиме ядра.
308 ГЛ А В А 6 БЕЗОПАСНОСТЬ На рис. 6&1 показана упрощенная схема структур данных процесса и по& тока. Каждая из этих структур детально рассматривается далее в этой главе. Рис. 6-1. Структуры данных, сопоставляемые с процессами и потоками Сначала рассмотрим блок процесса. (Изучение блока потока мы отложим до раздела «Внутреннее устройство потоков».) Ключевые поля EPROCESS показаны на рис. 6&2. Рис. 6-2. Блок процесса (EPROCESS), создаваемый исполнительной системой
ГЛАВА 9 Процессы, потоки и задания 309 ЭКСПЕРИМЕНТ: исследуем формат блока EPROCESS Список полей, составляющих блок EPROCESS, и их смещения в шест& надцатеричной форме, можно увидеть с помощью команды dt eprocess отладчика ядра (подробнее об отладчике ядра см. главу 1). Вот что дает эта команда (вывод обрезан для экономии места): lkd> dt _eprocess nt!_EPROCESS +0x000 Pcb : _KPROCESS +0x06c ProcessLock : _EX_PUSH_LOCK +0x070 CreateTime : _LARGE_INTEGER +0x078 ExitTime : _LARGE_INTEGER +0x080 RundownProtect : _EX_RUNDOWN_REF +0x084 UniqueProcessId : Ptr32 Void +0x088 ActiveProcessLinks : _LIST_ENTRY +0x090 QuotaUsage : [3] Uint4B +0x09c QuotaPeak : [3] Uint4B +0x0a8 CommitCharge : Uint4B +0x0ac PeakVirtualSize : Uint4B +0x0b0 VirtualSize : Uint4B +0x0b4 SessionProcessLinks : _LIST_ENTRY +0x0bc DebugPort : Ptr32 Void +0x0c0 ExceptionPort : Ptr32 Void +0x0c4 ObjectTable : Ptr32 _HANDLE_TABLE +0x0c8 Token : _EX_FAST_REF +0x0cc WorkingSetLock : _FAST_MUTEX +0x0ec WorkingSetPage : Uint4B +0x0f0 AddressCreationLock : _FAST_MUTEX +0x110 HyperSpaceLock : Uint4B +0x114 ForkInProgress : Ptr32 _ETHREAD +0x118 HardwareTrigger : Uint4B Заметьте, что первое поле (Pcb) на самом деле является подструк& турой — блоком процесса, принадлежащим ядру (KPROCESS). Именно здесь хранится информация, используемая при планировании. Для вывода формата блока процесса KPROCESS введите dt_kprocess: lkd> dt _kprocess nt!_KPROCESS +0x000 Header : +0x010 ProfileListHead : +0x018 DirectoryTableBase +0x020 LdtDescriptor : +0x028 Int21Descriptor : +0x030 IopmOffset : +0x032 Iopl : +0x033 Unused : +0x034 ActiveProcessors : _DISPATCHER_HEADER _LIST_ENTRY : [2] Uint4B _KGDTENTRY _KIDTENTRY Uint2B UChar UChar Uint4B см. след. стр.
310 ГЛ А В А 6 +0x038 +0x03c +0x040 +0x048 +0x04c +0x050 +0x058 +0x05c +0x060 +0x062 +0x063 +0x064 +0x065 +0x066 +0x067 +0x068 +0x069 +0x06a +0x06b БЕЗОПАСНОСТЬ KernelTime UserTime ReadyListHead SwapListEntry VdmTrapcHandler ThreadListHead ProcessLock Affinity StackCount BasePriority ThreadQuantum AutoAlignment State ThreadSeed DisableBoost PowerState DisableQuantum IdealNode Spare : : : : : : : : : : : : : : : : : : : Uint4B Uint4B _LIST_ENTRY _SINGLE_LIST_ENTRY Ptr32 Void _LIST_ENTRY Uint4B Uint4B Uint2B Char Char UChar UChar UChar UChar UChar UChar UChar UChar Другой способ просмотра KPROCESS (и прочих подструктур в EPROCESS) — использовать ключ рекурсии (–r) в команде dt. Напри& мер, введя dt _eprocess –r1, вы увидите все подструктуры с глубиной вложения, равной 1. Команда dt показывает формат блока процесса, но не его содержи& мое. Чтобы вывести экземпляр самого процесса, можно указать адрес структуры EPROCESS в качестве аргумента команды dt. Команда !process 0 0 позволяет получить адрес всех блоков EPROCESS в системе. При& мер вывода этой команды будет приведен далее в этой главе. Некоторые поля, показанные в предыдущем эксперименте, поясняются в таблице 6&1. Процессы и потоки — неотъемлемая часть Windows, о которой нельзя рассказать, не упомянув множество других компонентов системы. Но, чтобы эта глава не слишком разбухла, мы поясняем механизмы, связанные с процессами и потоками (вроде управления памятью, защиты, объектов и описателей), в других главах. Таблица 6-1. Содержимое блока EPROCESS Элемент Описание Блок процесса ядра (KPROCESS) Общий заголовок объекта диспетчера, указа& тель на каталог страниц процесса, список блоков потоков ядра (KTHREAD), принадле& жащих процессу, базовый приоритет по умол& чанию, выделяемый квант процессорного времени, маска привязки к процессорам, а также суммарное время работы потоков в режиме ядра и пользовательском режиме Дополнительные ссылки Раздел «Плани& рование пото& ков» далее в этой главе
ГЛАВА 9 Процессы, потоки и задания 311 Таблица 6-1. (продолжение) Дополнительные ссылки Элемент Описание Идентификация процесса Уникальный идентификатор процесса, иден& тификатор процесса&создателя, имя выполня& емого образа, имя WindowStation&объекта для данного процесса Блок квот Лимиты на пулы подкачиваемой и неподкачи& ваемой памяти, а также на использование страничного файла плюс текущее и пиковое использование пулов подкачиваемой и непод& качиваемой памяти процесса. Некоторые про& цессы могут разделять эту структуру: все сис& темные процессы ссылаются на один обще& системный блок квот по умолчанию, а все процессы интерактивного сеанса используют один блок квот, определяемый Winlogon Дескрипторы виртуальных адресов (virtual address descriptors, VAD) Наборы структур данных, описывающих статус частей адресного пространства, кото& рые существуют в процессе Глава 7 Информация о рабочем наборе Указатель на список рабочего набора (струк& тура MMWSL); текущий, пиковый, минималь& ный и максимальный размеры рабочего на& бора; время последнего усечения (last trim time); счетчик числа ошибок страниц; при& оритет памяти; некоторые специфические флаги; хронология ошибок страниц Глава 7 Информация о виртуальной памяти Текущий и пиковый размер виртуальной па& Глава 7 мяти, использование страничного файла, элемент аппаратной таблицы страниц, указы& вающий на каталог страниц процесса LPC&порт исключений Канал межпроцессной связи, по которому диспетчер процессов посылает сообщение, если один из потоков этого процесса вызы& вает исключение Отладочный LPC&порт Канал межпроцессной связи, по которому Раздел «LPC» диспетчер процессов посылает сообщение, главы 3 если один из потоков этого процесса генери& рует событие отладки Маркер доступа (ACCESS_TOKEN) Объект исполнительной системы, описываю& Глава 8 щий профиль защиты данного процесса Таблица описателей Адрес таблицы описателей, принадлежащей процессу Раздел «Диспет& черизация исклю& чений» главы 3 Раздел «Описате& ли объектов и таблица описа& телей, принадле& жащая процессу» главы 3 см. след. стр.
312 ГЛ А В А 6 БЕЗОПАСНОСТЬ Таблица 6-1. (окончание) Элемент Описание Дополнительные ссылки Карта устройств Адрес каталога объектов для разрешения ссылок на устройства по именам (поддержи& вается несколько пользователей) Раздел «Диспет& чер объектов» главы 3 Блок переменных окружения про& цесса (PEB) Информация об образе исполняемого файла Далее в этой (базовый адрес, номера версий, список моду& главе лей), информация о куче процесса и TLS&па& мяти (указатели на кучи процесса начинают& ся с первого байта после PEB) Блок процесса подсистемы Windows (W32PROCESS) Дополнительная информация о процессе, необходимая той части подсистемы Windows, которая работает в режиме ядра Блок KPROCESS, входящий в блок EPROCESS, и PEB, на который указывает EPROCESS, содержат дополнительные сведения об объекте «процесс». Блок KPROCESS, иногда называемый блоком управления процессом (process control block, PCB), показан на рис. 6&3. Он содержит базовую информацию, нужную ядру Windows для планирования потоков. (О каталогах страниц см. главу 7.) PEB, размещаемый в адресном пространстве пользовательского процес& са, содержит информацию, необходимую загрузчику образов, диспетчеру кучи и другим системным DLL&модулям Windows для доступа из пользова& тельского режима. (Блоки EPROCESS и KPROCESS доступны только из режи& ма ядра.) Базовая структура PEB, показанная на рис. 6&4, подробнее объясня& ется далее в этой главе. Рис. 6-3. Блок процесса исполнительной системы
ГЛАВА 9 Рис. 6-4. Процессы, потоки и задания 313 Поля в блоке PEB ЭКСПЕРИМЕНТ: исследуем PEB Дамп структуры PEB можно получить с помощью команды !peb отлад& чика ядра. Чтобы узнать адрес PEB, используйте команду !process так: lkd> !process PROCESS 8575f030 SessionId: 0 Cid: 08d0 Peb: 7ffdf000 ParentCid: 0360 DirBase: 1a81b000 ObjectTable: e12bd418 HandleCount: 66. Image: windbg.exe Затем укажите этот адрес в команде !peb: lkd> !peb 7ffdf000 PEB at 7ffdf000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No ImageBaseAddress: 01000000 Ldr 00181e90 Ldr.Initialized: Yes Ldr.InInitializationOrderModuleList: 00181f28 . 00183188 Ldr.InLoadOrderModuleList: 00181ec0 . 00183178 Ldr.InMemoryOrderModuleList: 00181ec8 . 00183180 Base TimeStamp Module 1000000 40478dbd Mar 04 15:12:45 2004 C:\Program Files\Debugging Tools for Windows\windbg.exe 77f50000 3eb1b41a May 01 19:56:10 2003 C:\WINDOWS\System32\ntdll.dll 77e60000 3d6dfa28 Aug 29 06:40:40 2002 C:\WINDOWS\system32\kernel32.dll 2000000 40476db2 Mar 04 12:56:02 2004 C:\Program Files\Debugging Tools for Windows\dbgeng.dll . см. след. стр.
314 ГЛ А В А 6 БЕЗОПАСНОСТЬ SubSystemData: 00000000 ProcessHeap: 00080000 ProcessParameters: 00020000 WindowTitle: 'C:\Documents and Settings\All Users\Start Menu\Programs\Debugging Tools for Windows\WinDbg.lnk' ImageFile: 'C:\Program Files\Debugging Tools for Windows\windbg.exe' CommandLine: '"C:\Program Files\Debugging Tools for Windows\windbg.exe" ' DllPath: 'C:\Program Files\Debugging Tools for Windows;C:\WINDOWS\System32;C:\WINDOWS\system;C:\WINDOWS;.;C:\Program Files\Windows Resource Kits\Tools\;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files\Support Tools\;c:\sysint;C:\Program Files\ATI Technologies\ATI Control Panel;C:\Program Files\Resource Kit\;C:\PROGRA~1\CA\Common\SCANEN~1;C:\PROGRA~1\CA\eTrust\ANTIVI~1;C:\Program Files\Common Files\Roxio Shared\DLLShared;C:\SFU\common\' Environment: 00010000 =::=::\ ALLUSERSPROFILE=C:\Documents and Settings\All Users APPDATA=C:\Documents and Settings\dsolomon\Application Data ... Переменные ядра В таблице 6&2 перечислено несколько важнейших глобальных переменных ядра, связанных с процессами. На эти переменные мы будем ссылаться по ходу изложения материала, в частности при описании этапов создания процесса. Таблица 6-2. Переменные ядра, связанные с процессами Переменная Тип Описание PsActiveProcessHead Заголовок очереди Заголовок списка блоков процесса PsIdleProcess EPROCESS Блок процесса Idle PsInitialSystemProcess Указатель на EPROCESS Указатель на блок начального системно& го процесса (с идентификатором 2), ко& торый содержит системные потоки PspCreateProcess NotifyRoutine Массив указателей Указатели на процедуры (максимум 8), вызываемые при создании и удалении процесса PspCreateProcess NotifyRoutineCount DWORD Счетчик зарегистрированных процедур уведомления о создании процесса PspLoadImageNotify Routine Массив указателей Указатели на процедуры, вызываемые при загрузке образа исполняемого файла PspLoadImageNotify RoutineCount DWORD Счетчик зарегистрированных процедур уведомления о загрузке образа PspCidTable Указатель на HAND& Таблица описателей для клиентских LE_TABLE идентификаторов процесса и потока
ГЛАВА 9 Процессы, потоки и задания 315 Счетчики производительности Windows поддерживает несколько счетчиков, которые позволяют отслежи& вать процессы, выполняемые в системе; данные этих счетчиков можно счи& тывать программно или просматривать с помощью оснастки Performance. В таблице 6&3 перечислены счетчики производительности, имеющие отноше& ние к процессам (кроме счетчиков, связанных с управлением памятью и вво& дом&выводом, которые описываются в главах 7 и 9 соответственно). Таблица 6-3. Счетчики производительности, связанные с процессами Объект: счетчик Описание Process: % Privileged Time (Процесс: % работы в привилеги& рованном режиме) Процентная доля времени, в течение которого потоки данного процесса выполнялись в режи& ме ядра Process: % Processor Time (Процесс: % загруженности процессора) Процентная доля процессорного времени, ис& пользованная потоками процесса за опреде& ленный период времени; вычисляется как сумма % Privileged Time и % User Time Process: % User Time (Процесс: % работы в пользовательском режиме) Процентная доля времени, в течение которого потоки данного процесса выполнялись в пользовательском режиме Process: Elapsed Time (Процесс: Прошло времени) Суммарное время (в секундах), прошедшее с момента создания процесса Process: ID Process (Процесс: Идентификатор процесса) Идентификатор процесса; полученное таким образом значение действительно лишь на вре& мя выполнения процесса, поскольку иденти& фикаторы могут использоваться повторно Process: Creating Process ID [Процесс: Код (ID) создавшего процесса] Идентификатор родительского процесса; его значение не обновляется после завершения родительского процесса Process: Thread Count (Процесс: Счетчик потоков) Число потоков в процессе Process: Handle Count (Процесс: Счетчик дескрипторов) Число открытых процессом описателей Сопутствующие функции В таблице 6&4 приведена информация по некоторым Windows&функциям, связанным с процессами. Более подробные сведения см. в документации Windows API в MSDN Library. Таблица 6-4. Функции, связанные с процессами Функция Описание CreateProcess Создает новый процесс и поток с использованием идентификации защиты вызывающего процесса CreateProcessAsUser Создает новый процесс и поток с указанным альтер& нативным маркером защиты см. след. стр.
316 ГЛ А В А 6 БЕЗОПАСНОСТЬ Таблица 6-4. (окончание) Функция Описание CreateProcessWithLogonW Создает новый процесс и поток для выполнения под учетной записью, соответствующей указанным имени и паролю пользователя CreateProcessWithTokenW Создает новый процесс и поток с указанным альтер& нативным маркером защиты и поддерживает допол& нительные возможности, например разрешает загруз& ку профиля пользователя OpenProcess Возвращает описатель указанного объекта «процесс» ExitProcess Завершает процесс с уведомлением всех подключен& ных DLL TerminateProcess Завершает процесс без уведомления подключенных DLL FlushInstructionCache Опустошает кэш команд указанного процесса GetProcessTimes Получает временные параметры процесса, описываю& щие, сколько времени процесс провел в режиме ядра и в пользовательском режиме GetExitCodeProcess Возвращает код завершения процесса, указывающий, как и почему завершился этот процесс GetCommandLine Возвращает указатель на командную строку, передан& ную текущему процессу GetCurrentProcess Возвращает псевдоописатель текущего процесса GetCurrentProcessId Возвращает идентификатор текущего процесса GetProcessVersion Возвращает старший и младший номера версии Windows, необходимой для запуска указанного процесса GetStartupInfo Возвращает содержимое структуры STARTUPINFO, заданное при вызове CreateProcess GetEnvironmentStrings Возвращает адрес блока переменных окружения GetEnvironmentVariable Возвращает значение указанной переменной окружения GetProcessShutdownPara meters и SetProcessShutdown Parameters Определяет приоритет завершения и число попыток для текущего процесса GetGuiResources Возвращает число открытых описателей USER и GDI ЭКСПЕРИМЕНТ: применение команды !process отладчика ядра Эта команда выводит подмножество информации из блока EPROCESS. Ее вывод для каждого процесса делится на две части. Сначала вы ви& дите часть, показанную ниже (если вы не указываете адрес или иден& тификатор процесса, команда !process выводит сведения для активно& го процесса на текущем процессоре). lkd> !process PROCESS 8575f030 SessionId: 0 Cid: 08d0 ParentCid: 0360 Peb: 7ffdf000
ГЛАВА 9 Процессы, потоки и задания 317 DirBase: 1a81b000 ObjectTable: e12bd418 HandleCount: 65. Image: windbg.exe VadRoot 857f05e0 Vads 71 Clone 0 Private 1152. Modified 98. Locked 1. DeviceMap e1e96c88 Token e1f5b8a8 ElapsedTime 1:23:06.0219 UserTime 0:00:11.0897 KernelTime 0:00:07.0450 QuotaPoolUsage[PagedPool] 38068 QuotaPoolUsage[NonPagedPool] 2840 Working Set Sizes (now,min,max) (2552, 50, 345) (10208KB, 200KB, 1380KB) PeakWorkingSetSize 2715 VirtualSize 41 Mb PeakVirtualSize 41 Mb PageFaultCount 3658 MemoryPriority BACKGROUND BasePriority 8 CommitCharge 1566 Вслед за базовой информацией о процессе появляется список его потоков. Данная часть поясняется в эксперименте «Применение ко& манды !thread отладчика ядра» далее в этой главе. Еще одна команда, позволяющая получить информацию о процессе, — !handle. Она созда& ет дамп таблицы описателей, принадлежащей процессу (см. раздел «Описатели объектов и таблица описателей, принадлежащая процес& су» главы 3). Структуры защиты процессов и потоков описываются в главе 8. Что делает функция CreateProcess К этому моменту мы уже рассмотрели структуры, которые являются частью процесса, и API&функции, позволяющие вам (и операционной системе) ма& нипулировать процессами. Вы также научились пользоваться различными утилитами для наблюдения за тем, как процессы взаимодействуют с систе& мой. Но как эти процессы появляются на свет и как они завершаются, выпол& нив задачи, для которых они предназначались? В следующих разделах вы узнаете, как порождаются Windows&процессы. Создание Windows&процесса осуществляется вызовом одной из таких функций, как CreateProcess, CreateProcessAsUser, CreateProcessWithTokenW или CreateProcessWithLogonW, и проходит в несколько этапов с участием трех компонентов операционной системы: Kernel32.dll (библиотеки клиентской части Windows), исполнительной системы и процесса подсистемы окруже& ния Windows (Csrss). Поскольку архитектура Windows поддерживает не& сколько подсистем окружения, операции, необходимые для создания объек& та «процесс» исполнительной системы (которым могут пользоваться и дру&
318 ГЛ А В А 6 БЕЗОПАСНОСТЬ гие подсистемы окружения), отделены от операций, требуемых для создания Windows&процесса. Поэтому часть действий Windows&функции CreateProcess специфична для семантики, привносимой подсистемой Windows. В приведенном ниже списке перечислены основные этапы создания про& цесса Windows&функцией CreateProcess. Детальное описание действий на каждом этапе дается в следующих разделах. ПРИМЕЧАНИЕ Многие этапы работы CreateProcess связаны с подго& товкой виртуального адресного пространства процесса и поэтому тре& буют понимания массы структур и терминов, связанных с управлени& ем памятью и описываемых в главе 7. 1. Открывается файл образа (EXE), который будет выполняться в процессе. 2. Создается объект «процесс» исполнительной системы. 3. Создается первичный поток (стек, контекст и объект «поток» исполни& тельной системы). 4. Подсистема Windows уведомляется о создании нового процесса и потока. 5. Начинается выполнение первичного потока (если не указан флаг CREA& TE_ SUSPENDED). 6. В контексте нового процесса и потока инициализируется адресное про& странство (например, загружаются требуемые DLL) и начинается выпол& нение программы. Общая схема создания процесса в Windows показана на рис. 6&5. Прежде чем открыть исполняемый образ для выполнения, CreateProcess делает следующее. 쐽 При вызове CreateProcess класс приоритета указывается в параметре Crea tionFlags, и, вызывая CreateProcess, вы можете задать сразу несколько клас& сов приоритета. Windows выбирает самый низкий из них. 쐽 Когда для нового процесса не указывается класс приоритета, по умолча& нию принимается Normal, если только класс приоритета процесса&созда& теля не равен Idle или Below Normal. В последнем случае новый процесс получает тот же класс приоритета, что и у родительского процесса. 쐽 Если для нового процесса указан класс приоритета Real&time, а создатель не имеет привилегии Increase Scheduling Priority, устанавливается класс приоритета High. Иначе говоря, функция CreateProcess завершается ус& пешно, даже если у того, кто ее вызвал, недостаточно привилегий для со& здания процессов с классом приоритета Real&time, — просто класс при& оритета нового процесса будет ниже Real&time. 쐽 Все окна сопоставляются с объектами «рабочий стол», которые являются графическим представлением рабочего пространства. Если при вызове CreateProcess не указан конкретный объект «рабочий стол», новый процесс сопоставляется с текущим объектом «рабочий стол» процесса&создателя.
ГЛАВА 9 Рис. 6-5. Процессы, потоки и задания 319 Основные этапы создания процесса Этап 1: открытие образа, подлежащего выполнению Как показано на рис. 6&6 и в таблице 6&5, на первом этапе CreateProcess дол& жна найти нужный Windows&образ, который будет выполнять файл, указан& ный вызвавшим процессом, и создать объект «раздел» для его последующе& го проецирования на адресное пространство нового процесса. Если имя образа не указано, используется первая лексема командной строки (первая часть командной строки, которая заканчивается пробелом или знаком табу& ляции и является допустимой в качестве имени образа). В Windows XP и Windows Server 2003 CreateProcess проверяет, не запре& щает ли политика безопасности на данной машине запуск этого образа (см. главу 8). Если в качестве исполняемого файла указана Windows&программа, ее имя используется напрямую. А если исполняемый файл является не Windows&при& ложением, а программой MS&DOS, Win16 или POSIX, то CreateProcess ищет образ поддержки (support image) для запуска этой программы. Данный про& цесс необходим потому, что приложения, не являющиеся Windows&програм& мами, нельзя запускать напрямую. Вместо этого Windows использует один из нескольких специальных образов поддержки, которые и отвечают за запуск
320 ГЛ А В А 6 БЕЗОПАСНОСТЬ приложений, отличных от Windows&программ. Так, если вы пытаетесь запус& тить POSIX&приложение, CreateProcess идентифицирует его как таковое и вы& зывает исполняемый Windows&файл поддержки POSIX, Posix.exe. А если вы запускаете программу MS&DOS или Win16, стартует исполняемый Windows& файл поддержки Ntvdm.exe. Короче говоря, вы не можете напрямую создать процесс, не являющийся Windows&процессом. Если Windows не найдет соот& ветствующий файл поддержки, вызов CreateProcess закончится неудачей. Рис. 6-6. Выбор активизируемого Windows-образа Таблица 6-5. Дерево решений CreateProcess на первом этапе Если файл относится к Запускается образ поддержки POSIX Posix.exe Возврат к первому этапу CreateProcess MS&DOS (в случае файла с расширением EXE, COM или PIF) Ntvdm.exe Возврат к первому этапу CreateProcess Win16 Ntvdm.exe Возврат к первому этапу CreateProcess К командной оболочке (в случае файла с расши& рением BAT или CMD) Cmd.exe Возврат к первому этапу CreateProcess И происходит Конкретное решение о запуске того или иного файла поддержки Create Process принимает так. 쐽 Если исполняемый файл — программа MS&DOS с расширением EXE, COM или PIF, подсистеме Windows посылается сообщение, чтобы она прове& рила, не создан ли уже процесс поддержки MS&DOS (Ntvdm.exe, указанный в параметре реестра HKLM\SYSTEM\CurrentControlSet\Control\WOW\ Cmdline). Если да, этот процесс используется для запуска программы MS& DOS — подсистема Windows посылает виртуальной DOS&машине (Virtual
ГЛАВА 9 Процессы, потоки и задания 321 DOS Machine, VDM) сообщение для запуска новой программы, — после чего управление возвращается к CreateProcess. Если нет, запускается Ntvdm.exe и повторно выполняется первый этап CreateProcess. 쐽 Если исполняемый файл — командный файл с расширением BAT или CMD, запускается Cmd.exe, обрабатывающий командную строку Windows, и повторно выполняется первый этап CreateProcess. (Имя командного файла передается Cmd.exe как первый параметр.) 쐽 Если исполняемый файл — приложение Win16 (Windows 3.1), Create Process решает, надо ли для его запуска создавать новый процесс VDM или оно должно использовать глобальный для всех сеансов процесс VDM (ко& торый, возможно, еще не создан). Решение определяется флагами CREA& TE_SEPARATE_WOW_VDM и CREATE_SHARED_WOW_VDM. Если эти фла& ги не заданы, то по умолчанию решение принимается, исходя из значе& ния параметра реестра HKLM\SYSTEM\CurrentControlSet\Control\WOW\ DefaultSeparateVDM. Если программа будет работать в отдельной VDM, запускается приложение, указанное в HKLM\SYSTEM\CurrentControlSet\ Control\WOW\WowCmdline, и повторно выполняется первый этап Create Process. В ином случае подсистема Windows посылает сообщение для про& верки возможности использования общего процесса VDM. (Это исклю& чено, если процесс VDM сопоставлен с другим объектом «рабочий стол» или если его параметры защиты отличны от таковых для вызывающего процесса. Тогда нужно создавать новый процесс VDM.) Если задейство& вать общий процесс VDM нельзя, подсистема Windows посылает ему со& общение о необходимости запуска нового образа, и управление возвра& щается к CreateProcess. Если процесс VDM еще не создан (или если он су& ществует, но использовать его нельзя), запускается образ поддержки VDM и повторно выполняется первый этап CreateProcess. К этому моменту CreateProcess успешно открывает допустимый исполня& емый файл Windows и создает для него объект «раздел». Этот объект еще не спроецирован на память, но уже открыт. Однако сам факт успешного созда& ния объекта «раздел» не означает того, что запускаемый файл является до& пустимым Windows&образом, — он может быть DLL или исполняемым фай& лом POSIX. Если это исполняемый файл POSIX, запускается Posix.exe, и Crea teProcess заново выполняет действия первого этапа. А если это DLL, вызов CreateProcess заканчивается неудачей. CreateProcess, найдя допустимый исполняемый Windows&образ, ищет в разделе реестра HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ Image File Execution Options подраздел с именем и расширением запускае& мого образа (но без указания пути к нему, например Image.exe). Если такой подраздел есть, CreateProcess ищет в нем параметр Debugger. Если он присут& ствует, его значение становится именем запускаемого образа, после чего следует повторение первого этапа CreateProcess.
322 ГЛ А В А 6 БЕЗОПАСНОСТЬ СОВЕТ Вы можете извлечь выгоду из такого поведения CreateProcess. Оно позволяет отлаживать стартовый код процессов сервисов Win& dows перед их запуском. Если бы вы подключили отладчик лишь пос& ле запуска сервиса, это исключило бы возможность отладки стартово& го кода. Этап 2: создание объекта «процесс» К началу второго этапа функция CreateProcess уже открыла допустимый ис& полняемый файл Windows и создала объект «раздел» для его проецирования на адресное пространство нового процесса. После этого она создает объект «процесс», чтобы запустить образ вызовом внутренней функции NtCreate Process. Создание объекта «процесс» исполнительной системы включает сле& дующие подэтапы: 쐽 формируется блок EPROCESS; 쐽 создается начальное адресное пространство процесса; 쐽 инициализируется блок процесса ядра (KPROCESS); 쐽 инициализируется адресное пространство процесса (в том числе список рабочего набора и дескрипторы виртуального адресного пространства), а также проецируется образ на это пространство; 쐽 формируется блок PEB; 쐽 завершается инициализация объекта «процесс» исполнительной системы. ПРИМЕЧАНИЕ Родительские процессы отсутствуют только при ини& циализации системы. Далее они всегда используются для задания кон& текстов защиты новых процессов. Этап 2A: формирование блока EPROCESS Этот подэтап включает девять операций. 1. Создается и инициализируется блок EPROCESS. 2. От родительского процесса наследуется маска привязки к процессорам. 3. Минимальный и максимальный размеры рабочего набора процесса ус& танавливаются равными значениям переменных PsMinimumWorkingSet и PsMaximumWorkingSet. 4. Блок квот нового процесса настраивается на адрес блока квот его родитель& ского процесса и увеличивается счетчик ссылок на блок квот последнего. 5. Наследуется пространство имен устройств Windows (в том числе опре& деление букв дисков, COM&портов и т. д.). 6. В поле InheritedFromUniqueProcessId нового объекта «процесс» сохраня& ется идентификатор родительского процесса. 7. Создается основной маркер доступа процесса (копированием аналогич& ного маркера родительского процесса). Новый процесс наследует про&
ГЛАВА 9 Процессы, потоки и задания 323 филь защиты своих родителей. Если используется функция CreateProcess AsUser, чтобы задать для нового процесса другой маркер доступа, он со& ответственно модифицируется. 8. Инициализируется таблица описателей, принадлежащая процессу. Если установлен флаг наследования описателей родительского процесса, на& следуемые описатели из его таблицы копируются в новый процесс (о таб& лицах описателей см. главу 3). 9. Статус завершения нового процесса устанавливается как STATUS_PEN& DING. Этап 2B: создание начального адресного пространства процесса Начальное адресное пространство процесса состоит из следующих страниц: 쐽 каталога страниц (этих каталогов может быть больше одного в системах, где таблицы страниц имеют более двух уровней, например в x86&систе& мах в режиме PAE или в 64&разрядных системах); 쐽 страницы гиперпространства; 쐽 списка рабочего набора. Для создания этих страниц выполняются операции, перечисленные ниже. 1. В соответствующих таблицах страниц формируются записи, позволяю& щие проецировать эти начальные страницы. Количество страниц вычи& тается из переменной ядра MmTotalCommittedPages и добавляется к пере& менной ядра MmProcessCommit. 2. Из MmResidentAvailablePages вычитается минимальный размер рабочего набора по умолчанию (PsMinimumWorkingSet). 3. На адресное пространство процесса проецируются страницы таблицы страниц для неподкачиваемой части системного пространства и систем& ного кэша. Этап 2C: создание блока процесса ядра На этом подэтапе работы CreateProcess инициализируется блок KPROCESS, содержащий указатель на список потоков ядра. (Ядро не имеет представления об описателях, поэтому оно обходит их таблицу.) Блок процесса ядра также указывает на каталог таблицы страниц процесса (используемый для отслежи& вания виртуального адресного пространства процесса) и содержит суммар& ное время выполнения потоков процесса, базовый приоритет процесса по умолчанию (он начинается с Normal, или 8, если только его значение у ро& дительского процесса не равно Idle или Below Normal; в последнем случае приоритет просто наследуется), привязку потоков к процессорам по умолча& нию и начальный квант процессорного времени, выделяемый процессу по умолчанию. Последнее значение принимается равным PspForegroundQuan tum[0], первому элементу общесистемной таблицы величин квантов.
324 ГЛ А В А 6 БЕЗОПАСНОСТЬ ПРИМЕЧАНИЕ Начальный квант по умолчанию в клиентских и сер& верных версиях Windows неодинаков. Подробнее о квантах см. раздел «Планирование потоков» далее в этой главе. Этап 2D: инициализация адресного пространства процесса Подготовка адресного пространства нового процесса довольно сложна, по& этому разберем ее отдельно по каждой операции. Для максимального усво& ения материала этого раздела вы должны иметь представление о внутрен& нем устройстве диспетчера памяти Windows (см. главу 7). 쐽 Диспетчер виртуальной памяти присваивает времени последнего усече& ния (last trim time) для процесса текущее время. Диспетчер рабочих на& боров, выполняемый в контексте системного потока диспетчера настрой& ки баланса (balance set manager), использует это значение, чтобы опре& делить, когда нужно инициировать усечение рабочего набора. 쐽 Диспетчер памяти инициализирует список рабочего набора процесса, после чего становится возможной генерация ошибок страниц. 쐽 Раздел (созданный при открытии файла образа) проецируется на адрес& ное пространство нового процесса, и базовый адрес раздела процесса приравнивается базовому адресу образа. 쐽 На адресное пространство процесса проецируется Ntdll.dll. 쐽 На адресное пространство процесса проецируются общесистемные таб& лицы NLS (national language support). ПРИМЕЧАНИЕ Процессы POSIX клонируют адресное пространство своих родителей, поэтому для них не нужны все вышеперечисленные операции создания нового адресного пространства. В случае прило& жений POSIX базовый адрес раздела нового процесса приравнивает& ся тому же базовому адресу родительского процесса, а родительский PEB просто копируется. Этап 2E: формирование блока PEB CreateProcess выделяет страницу под PEB и инициализирует некоторые поля, описанные в таблице 6&6. Таблица 6-6. Начальные значения полей PEB Поле Начальное значение ImageBaseAddress Базовый адрес раздела NumberOfProcessors Значение переменной ядра KeNumberProcessors NtGlobalFlag Значение переменной ядра NtGlobalFlag CriticalSectionTimeout Значение переменной ядра MmCriticalSectionTimeout HeapSegmentReserve Значение переменной ядра MmHeapSegmentReserve HeapSegmentCommit Значение переменной ядра MmHeapSegmentCommit HeapDeCommitTotalFree Threshold Значение переменной ядра MmHeapDeCommitTotal FreeThreshold
ГЛАВА 9 Процессы, потоки и задания 325 Таблица 6-6. (окончание) Поле Начальное значение HeapDeCommitFreeBlock Threshold Значение переменной ядра MmHeapDeCommitFreeBlock Threshold NumberOfHeaps 0 MaximumNumberOfHeaps (Размер страницы – размер PEB) / 4 ProcessHeaps Первый байт после PEB OSMajorVersion Значение переменной ядра NtMajorVersion OSMinorVersion Значение переменной ядра NtMinorVersion OSBuildNumber Значение переменной ядра NtBuildNumber & 0x3FFF OSPlatformId 2 Если в файле явно указаны значения версии Windows, эти данные замеща& ют соответствующие начальные значения, показанные в таблице 6&6. Связь полей версии из заголовка образа с полями PEB описывается в таблице 6&7. Таблица 6-7. Windows-значения, заменяющие начальные значения полей PEB Имя поля Значение из заголовка образа OSMajorVersion НеобязательныйЗаголовок.НомерВерсииWin32 & 0xFF OSMinorVersion (НеобязательныйЗаголовок.НомерВерсииWin32 >> 8) & 0xFF OSBuildNumber (НеобязательныйЗаголовок.НомерВерсииWin32 >> 16) & 0x3FFF OSPlatformId (НеобязательныйЗаголовок.НомерВерсииWin32 >> 30) ^ 0x2 Этап 2F: завершение инициализации объекта «процесс» исполнительной системы Перед возвратом описателя нового процесса выполняется несколько завер& шающих операций. 1. Если общесистемный аудит процессов разрешен (через локальную поли& тику безопасности или политику группы, вводимую контроллером доме& на), факт создания процесса отмечается в журнале безопасности. 2. Если родительский процесс входил в задание, новый процесс тоже вклю& чается в это задание (о заданиях — в конце главы). 3. Если в заголовке образа задан флаг IMAGE_FILE_UP_SYSTEM_ONLY (ко& торый указывает, что данную программу можно запускать только в одно& процессорной системе), для выполнения всех потоков процесса выбира& ется один процессор. Выбор осуществляется простым перебором доступ& ных процессоров: при каждом запуске следующей программы такого типа выбирается следующий процессор. Благодаря этому подобные про& граммы равномерно распределяются между процессорами. 4. Если в образе явно указана маска привязки к процессорам (например, в поле конфигурационного заголовка), ее значение копируется в PEB и впоследствии устанавливается как маска привязки к процессорам по умолчанию.
326 ГЛ А В А 6 БЕЗОПАСНОСТЬ 5. CreateProcess помещает блок нового процесса в конец списка активных процессов (PsActiveProcessHead). 6. Устанавливается время создания процесса, и вызвавшей функции (Create Process в Kernel32.dll) возвращается описатель нового процесса. Этап 3: создание первичного потока, его стека и контекста К началу третьего этапа объект «процесс» исполнительной системы полно& стью инициализирован. Однако у него еще нет ни одного потока, поэтому он не может ничего делать. Прежде чем создать поток, нужно создать стек и контекст, в котором он будет выполняться. Эта операция и является целью данного этапа. Размер стека первичного потока берется из образа — друго& го способа задать его размер нет. Далее создается первичный поток вызовом NtCreateThread. Параметр по& тока — это адрес PEB (данный параметр нельзя задать при вызове Create Process — только при вызове CreateThread). Этот параметр используется ко& дом инициализации, выполняемым в контексте нового потока (см. этап 6). Однако поток по&прежнему ничего не делает — он создается в приостанов& ленном состоянии и возобновляется лишь по завершении инициализации процесса (см. этап 5). NtCreateThread вызывает PspCreateThread (функцию, которая используется и при создании системных потоков) и выполняет сле& дующие операции. 1. Увеличивается счетчик потоков в объекте «процесс». 2. Создается и инициализируется блок потока исполнительной системы (ETHREAD). 3. Генерируется идентификатор нового потока. 4. В адресном пространстве пользовательского режима формируется TEB. 5. Стартовый адрес потока пользовательского режима сохраняется в блоке ETHREAD. В случае Windows&потоков это адрес системной стартовой функции потока в Kernel32.dll (BaseProcessStart для первого потока в про& цессе и BaseThreadStart для дополнительных потоков). Стартовый адрес, указанный пользователем, также хранится в ETHREAD, но в другом его месте; это позволяет системной стартовой функции потока вызвать поль& зовательскую стартовую функцию. 6. Для подготовки блока KTHREAD вызывается KeInitThread. Начальный и текущий базовые приоритеты потока устанавливаются равными базово& му приоритету процесса; привязка к процессорам и значение кванта так& же устанавливаются по соответствующим параметрам процесса. Кроме того, функция определяет идеальный процессор для первичного потока. (О том, как происходит выбор идеального процессора см. раздел «Иде& альный и последний процессоры» далее в этой главе.) Затем KeInitThread создает стек ядра для потока и инициализирует его аппаратно&зависимый контекст, включая фреймы ловушек и исключений. Контекст потока на& страивается так, чтобы выполнение этого потока началось в режиме ядра
ГЛАВА 9 Процессы, потоки и задания 327 в KiThreadStartup. Далее KeInitThread устанавливает состояние потока в Initialized (инициализирован) и возвращает управление PspCreateThread. 7. Вызываются общесистемные процедуры, зарегистрированные на уведом& ление о создании потока. 8. Маркер доступа потока настраивается как указатель на маркер доступа процесса. Затем вызывающая программа проверяется на предмет того, имеет ли она право создавать потоки. Эта проверка всегда заканчивает& ся успешно, если поток создается в локальном процессе, но может дать отрицательный результат, если поток создается в другом процессе через функцию CreateRemoteThread и у создающего процесса нет привилегии отладки. 9. Наконец, поток готов к выполнению. Этап 4: уведомление подсистемы Windows о новом процессе Если заданы соответствующие правила, для нового процесса создается мар& кер с ограниченными правами доступа. К этому моменту все необходимые объекты исполнительной системы созданы, и Kernel32.dll посылает подсис& теме Windows сообщение, чтобы она подготовилась к выполнению нового процесса и потока. Сообщение включает следующую информацию: 쐽 описатели процесса и потока; 쐽 флаги создания; 쐽 идентификатор родительского процесса; 쐽 флаг, который указывает, относится ли данный процесс к Windows&прило& жениям (что позволяет Csrss определить, показывать ли курсор запуска). Получив такое сообщение, подсистема Windows выполняет следующие операции. 1. CreateProcess дублирует описатели процесса и потока. На этом этапе счет& чик числа пользователей процесса увеличивается с 1 (начального значе& ния, установленного в момент создания процесса) до 2. 2. Если класс приоритета процесса не указан, CreateProcess устанавливает его в соответствии с алгоритмом, описанным ранее. 3. Создается блок процесса Csrss. 4. Порт исключений нового процесса настраивается как общий порт функ& ций для подсистемы Windows, которая может таким образом получать сообщения при возникновении в процессе исключений (об обработке исключений см. главу 3). 5. Если в данный момент процесс отлаживается (т. е. подключен к процес& су отладчика), в качестве общего порта функций выбирается отладочный порт. Такой вариант позволяет Windows пересылать события отладки в новом процессе (генерируемые при создании и удалении потоков, при исключениях и т. д.) в виде сообщений подсистеме Windows, которая
328 ГЛ А В А 6 БЕЗОПАСНОСТЬ затем доставляет их процессу, выступающему в роли отладчика нового процесса. 6. Создается и инициализируется блок потока Csrss. 7. CreateProcess включает поток в список потоков процесса. 8. Увеличивается счетчик процессов в данном сеансе. 9. Уровень завершения процесса (process shutdown level) устанавливается как 0x280 (это значение по умолчанию; его описание ищите в докумен& тации MSDN Library по ключевому слову SetProcessShutdownParameters). 10. Блок нового процесса включается в список общесистемных Windows& процессов. 11. Создается и инициализируется структура данных (W32PROCESS), инди& видуальная для каждого процесса и используемая той частью подсисте& мы Windows, которая работает в режиме ядра. 12. Выводится курсор запуска в виде стрелки с песочными часами. Тем самым Windows говорит пользователю: «Я запускаю какую&то программу, но ты все равно можешь пользоваться курсором.» Если в течение двух секунд процесс не делает GUI&вызова, курсор возвращается к стандартному виду. А если за это время процесс обратился к GUI, CreateProcess ждет откры& тия им окна в течение пяти секунд и после этого восстанавливает исход& ную форму курсора. Этап 5: запуск первичного потока К началу этого этапа окружение процесса уже определено, его потокам вы& делены ресурсы, у процесса есть поток, а подсистеме Windows известен факт существования нового процесса. Поэтому для завершения инициализации нового процесса (см. этап 6) возобновляется выполнение его первичного потока, если только не указан флаг CREATE_SUSPENDED. Этап 6: инициализация в контексте нового процесса Новый поток начинает свою жизнь с выполнения стартовой процедуры по& тока режима ядра, KiThreadStartup, которая понижает уровень IRQL потока с «DPC/dispatch» до «APC», а затем вызывает системную стартовую процеду& ру потока, PspUserThreadStartup. Параметром этой процедуры является поль& зовательский стартовый адрес потока. В Windows 2000 PspUserThreadStartup сначала разрешает расширение рабочего набора. Если создаваемый процесс является отлаживаемой про& граммой, все его потоки (которые могли быть созданы на этапе 3) приоста& навливаются. В отладочный порт процесса (порт функций подсистемы Windows, так как это Windows&процесс) посылается сообщение о создании процесса, чтобы подсистема доставила событие отладки CREATE_PROCESS_ DEBUG_INFO соответствующему отладчику. Далее PspUserThreadStartup ждет пересылки подсистемой Windows ответа отладчика (через функцию Conti
ГЛАВА 9 Процессы, потоки и задания 329 nueDebugEvent). Как только такой ответ приходит, выполнение всех потоков возобновляется. В Windows XP и Windows Server 2003 PspUserThreadStartup проверяет, раз& решена ли в системе предварительная выборка для приложений (application prefetching), и, если да, вызывает модуль логической предвыборки (logical prefetcher) для обработки файла команд предвыборки (prefetch instruction file) (если таковой есть), а затем выполняет предвыборку страниц, на кото& рые процесс ссылался в течение первых десяти секунд при последнем запус& ке. Наконец, PspUserThreadStartup ставит APC пользовательского режима в очередь для запуска процедуры инициализации загрузчика образов (LdrIni tializeThunk из Ntdll.dll). APC будет доставлен, когда поток попытается вер& нуться в пользовательский режим. Когда PspUserThreadStartup возвращает управление KiThreadStartup, та возвращается из режима ядра, доставляет APC и обращается к LdrInitialize Thunk. Последняя инициализирует загрузчик, диспетчер кучи, таблицы NLS, массив локальной памяти потока (thread&local storage, TLS) и структуры кри& тической секции. После этого она загружает необходимые DLL и вызывает их точки входа с флагом DLL_PROCESS_ATTACH. Наконец, когда процедура инициализации загрузчика возвращает управ& ление диспетчеру APC пользовательского режима, начинается выполнение образа в пользовательском режиме. Диспетчер APC вызывает стартовую функ& цию потока, помещенную в пользовательский стек в момент доставки APC. Сборки, существующие в нескольких версиях Одна из проблем, уже давно изводившая пользователей Windows, — так называемый «DLL hell». Вы создаете этот ад, устанавливая прило& жение, которое заменяет одну или более базовых системных DLL, со& держащих, например, стандартные элементы управления, исполняю& щую среду Microsoft Visual Basic или MFC. Программы установки при& ложений делают такую замену, чтобы приложения работали коррект& но, но обновленные DLL могут оказаться несовместимыми с уже уста& новленными приложениями. Эта проблема в Windows 2000 была отчасти решена, где модифи& кация базовых системных DLL предотвращалась средством Windows File Protection, а приложениям разрешалось использовать собственные экземпляры этих DLL. Чтобы задействовать свой экземпляр какой&либо DLL вместо того, который находится в системном каталоге, у прило& жения должен быть файл Application.exe.local (где Application — имя исполняемого файла приложения); этот файл указывает загрузчику сначала проверить DLL&модули в каталоге приложения. Такой вид пе& реадресации DLL позволяет избежать проблем несовместимости меж& ду приложениями и DLL, но больно бьет по принципу разделения DLL, ради которого DLL изначально и разрабатывались. Кроме того, любые DLL, загруженные из списка KnownDLLs (они постоянно проецируются см. след. стр.
330 ГЛ А В А 6 БЕЗОПАСНОСТЬ в память) или, наоборот, загруженные ими, нельзя переадресовывать по такому механизму. Продолжая работу над решением этой проблемы, Microsoft ввела в Windows XP общие сборки (shared assemblies). Сборка (assembly) со& стоит из группы ресурсов, в том числе DLL и XML&файла манифеста, который описывает сборку и ее содержимое. Приложение ссылается на сборку через свой XML&манифест. Манифестом может быть файл в каталоге приложения с тем же именем, что и само приложение, но с добавленным расширением «.manifest» (например application.exe.ma& nifest), либо он может быть включен в приложение как ресурс. Мани& фест описывает приложение и его зависимости от сборок. Существует два типа сборок: закрытые (private) и общие (shared). Общие сборки отличаются тем, что они подписываются цифровой подписью; это позволяет обнаруживать их повреждение или модифи& кацию. Помимо этого, общие сборки хранятся в каталоге \Windows\ Winsxs, тогда как закрытые — в каталоге приложения. Таким образом, с общими сборками сопоставлен файл каталога (.cat), содержащий информацию о цифровых подписях. Общие сборки могут содержать несколько версий какой&либо DLL, чтобы приложения, зависимые от определенной версии этой DLL, всегда могли использовать именно ее. Обычно файлу манифеста сборки присваивается имя, которое включает имя сборки, информацию о версии, некий текст, представ& ляющий уникальную сигнатуру, и расширение .manifest. Манифесты хранятся в каталоге \Windows\Winsxs\Manifests, а остальные ресурсы сборки — в подкаталогах \Windows\Winsxs с теми же именами, что и у соответствующих файлов манифестов, но без расширения .manifest. Пример общей сборки — 6&я версия DLL стандартных элементов управления Windows, comctl32.dll, которая является новинкой Win& dows XP. Ее файл манифеста называется \Windows\Winsxs\Manifest\ x86_Microsoft. Windows.CommonControls_6595b64144ccf1df_6.0.0.0_x& ww_1382d70a.manifest. С ним сопоставлен файл каталога (с тем же именем, но с расширением .cat) и подкаталог в Winsxs, включающий comctl32.dll. Comctl32.dll версии 6 обеспечивает интеграцию с темами Windows XP и из&за того, что приложения, написанные без учета поддержки тем, могут неправильно выглядеть на экране при использовании этой но& вой DLL, она доступна только тем приложениям, которые явно ссыла& ются на ее общую сборку. Версия Comctl32.dll, установленная в \Win& dows\System32, — это экземпляр версии 5.x, не поддерживающей темы. Загружая приложение, загрузчик ищет его манифест и, если таковой есть, загружает DLL&модули из указанной сборки. DLL, не включенные в сборки, на которые ссылается манифест, загружаются традицион& ным способом. Поэтому унаследованные приложения связываются с версией в \Windows\System32, а новые приложения с поддержкой тем могут ссылаться на новую версию в своих манифестах.
ГЛАВА 9 Процессы, потоки и задания 331 Чтобы увидеть, какой эффект дает манифест, указывающий систе& ме задействовать новую библиотеку стандартных элементов управле& ния в Windows XP, запустите User State Migration Wizard (\Windows\Sys& tem32\Usmt\Migwiz.exe) с файлом манифеста и без него. 1. Запустите этот мастер и обратите внимание на темы Windows XP на кнопках в мастере. 2. Откройте файл манифеста в Notepad и найдите упоминание 6&й версии библиотеки стандартных элементов управления. 3. Переименуйте Migwiz.exe.manifest в Migwiz.exe.manifest.bak. 4. Вновь запустите мастер и обратите внимание на кнопки без тем. 5. Восстановите исходное имя файла манифеста. И еще одно преимущество общих сборок. Издатель может указать конфигурацию, которая заставит все приложения, использующие оп& ределенную сборку, работать с ее обновленной версией. Издатели по& ступают так, когда хотят сохранить обратную совместимость, пока занимаются устранением каких&то ошибок. Однако благодаря гибко& сти модели сборок приложение может игнорировать новые настрой& ки и по&прежнему использовать более старую версию. Внутреннее устройство потоков Теперь, изучив анатомию процессов, рассмотрим структуру потоков. Там, где явно не сказано обратное, считайте, что весь материал этого раздела в рав& ной мере относится как к обычным потокам пользовательского режима, так и к системным потокам режима ядра (описанным в главе 3). Структуры данных На уровне операционной системы поток представляется блоком потока, принадлежащим исполнительной системе (ETHREAD). Структура этого бло& ка показана на рис. 6&7. Блок ETHREAD и все структуры данных, на которые он ссылается, существуют в системном адресном пространстве, кроме бло& ка переменных окружения потока (thread environment block, TEB) — он раз& мещается в адресном пространстве процесса. Помимо этого, процесс под& системы Windows (Csrss) поддерживает параллельную структуру для каждо& го потока, созданного в Windows&процессе. Часть подсистемы Windows, ра& ботающая в режиме ядра (Win32k.sys), также поддерживает для каждого по& тока, вызывавшего USER& или GDI&функцию, структуру W32THREAD, на ко& торую указывает блок ETHREAD.
332 Рис. 6-7. ГЛ А В А 6 БЕЗОПАСНОСТЬ Блок потока исполнительной системы Поля блока потока, показанные на рис. 6&7, в большинстве своем не тре& буют дополнительных пояснений. Первое поле — это блок потока ядра (KTH& READ). За ним следуют идентификационные данные потока и процесса (вклю& чая указатель на процесс — владелец данного потока, что обеспечивает дос& туп к информации о его окружении), затем информация о защите в виде ука& зателя на маркер доступа и сведения, необходимые для олицетворения (под& мены одного процесса другим), а также поля, связанные с сообщениями LPC и незавершенными запросами на ввод&вывод. В таблице 6&8 даны ссылки на другие части книги, где некоторые из наиболее важных полей описываются подробнее. Чтобы получить более детальные сведения о внутренней структу& ре блока ETHREAD, используйте команду dt отладчика ядра. Таблица 6-8. Ключевые поля блока потока Элемент Описание KTHREAD См. таблицу 6&9 Временные пока& затели потока Время создания и завершения потока Идентификаци& онные данные процесса Идентификатор процесса и указатель на блок EPROCESS процесса, которому принадлежит данный поток Дополнительная ссылка Стартовый адрес Адрес стартовой процедуры потока Информация об олицетворении Маркер доступа и уровень олицетворе& ния (если поток олицетворяет, или подменяет, клиент) Глава 8 Информация LPC Идентификатор и адрес сообщения, ожидаемого потоком Раздел «LPC» главы 3 Информация, связанная с вводом&выводом Список необработанных пакетов запро& Глава 9 сов на ввод&вывод (I/O request packets, IRP)
ГЛАВА 9 Процессы, потоки и задания 333 Давайте повнимательнее присмотримся к двум ключевым структурам по& тока, упомянутым выше, — к блокам KTHREAD и TEB. Первый содержит ин& формацию, нужную ядру Windows для планирования потоков и их синхрони& зации с другими потоками. Схема блока KTHREAD показана на рис. 6&8. Рис. 6-8. Схема блока потока ядра Ключевые поля блока KTHREAD кратко рассмотрены в таблице 6&9. Таблица 6-9. Ключевые поля блока KTHREAD Элемент Описание Заголовок диспетчера Поскольку поток — это объект, на кото& ром можно ждать, он запускается со стандартным заголовком объекта диспетчера ядра Дополнительная ссылка Раздел «Объекты дис& петчера ядра» главы 3 Время выполнения Суммарное время выполнения (в режиме ядра и в пользовательском режиме) Указатель на инфор& Базовый и верхний адреса стека ядра мацию стека ядра Глава 7 Указатель на таб& лицу системных сервисов В начале выполнения каждого потока Раздел «Диспетчери& указатель в данном поле ссылается на зация системных сер& главную таблицу системных сервисов висов» главы 3 (KeServiceDescriptorTable); когда поток впервые вызывает GUI&сервис Windows, текущей таблицей системных сервисов становится та, которая включает сервисы GDI и USER в Win32k.sys Информация, связанная с пла& нированием Базовый и текущий приоритеты, значе& Раздел «Планирова& ние кванта, маска привязки к процессо& ние потоков» далее рам, идеальный процессор, статус плани& в этой главе рования, счетчики числа замораживаний (freeze count) и приостановок (suspend count) см. след. стр.
334 ГЛ А В А 6 БЕЗОПАСНОСТЬ Таблица 6-9. (окончание) Дополнительная ссылка Элемент Описание Блоки ожидания В блоке потока содержится четыре встро& Раздел «Синхрониза& енных блока ожидания, поэтому их не ция» главы 3 нужно создавать и инициализировать при каждом переходе потока в состоя& ние ожидания какого&либо объекта (один блок ожидания принадлежит таймерам) Информация об ожидании Список объектов, ожидаемых потоком, причина ожидания и время перехода потока в состояние ожидания Раздел «Синхрониза& ция» главы 3 Список мутантов Список принадлежащих потоку объектов «мутант» Раздел «Синхрониза& ция» главы 3 Очереди APC Список незавершенных APC режима ядра Раздел «APC» главы 3 и пользовательского режима, а также флаг оповещения (alertable flag) Блок таймера Встроенный блок таймера (а также со& ответствующий блок ожидания) Список очередей Указатель на сопоставленный с потоком Раздел «Синхрониза& объект очереди ция» главы 3 Указатель на TEB Идентификатор потока, данные TLS, указатель на PEB, информация, связанная с GDI и OpenGL ЭКСПЕРИМЕНТ: просмотр структур ETHREAD и KTHREAD Структуры ETHREAD и KTHREAD можно просмотреть с помощью коман& ды dt отладчика ядра. В следующем выводе показан формат ETHREAD: lkd> dt nt!_ethread nt!_ETHREAD +0x000 Tcb : _KTHREAD +0x1c0 CreateTime : _LARGE_INTEGER +0x1c0 NestedFaultCount : Pos 0, 2 Bits +0x1c0 ApcNeeded : Pos 2, 1 Bit +0x1c8 ExitTime : _LARGE_INTEGER +0x1c8 LpcReplyChain : _LIST_ENTRY +0x1c8 KeyedWaitChain : _LIST_ENTRY +0x1d0 ExitStatus : Int4B +0x1d0 OfsChain : Ptr32 Void +0x1d4 PostBlockList : _LIST_ENTRY +0x1dc TerminationPort : Ptr32 _TERMINATION_PORT +0x1dc ReaperLink : Ptr32 _ETHREAD +0x1dc KeyedWaitValue : Ptr32 Void +0x1e0 ActiveTimerListLock : Uint4B +0x1e4 ActiveTimerListHead : _LIST_ENTRY +0x1ec Cid : _CLIENT_ID +0x1f4 LpcReplySemaphore : _KSEMAPHORE
ГЛАВА 9 +0x1f4 +0x208 +0x208 +0x20c +0x210 +0x218 +0x21c +0x220 +0x224 +0x228 +0x228 +0x22c +0x234 +0x238 +0x23c +0x240 +0x244 +0x248 +0x248 +0x248 +0x248 +0x248 +0x248 +0x248 +0x248 +0x248 +0x248 +0x24c +0x24c +0x24c +0x24c +0x250 +0x250 +0x250 +0x250 +0x254 +0x255 Процессы, потоки и задания 335 KeyedWaitSemaphore : _KSEMAPHORE LpcReplyMessage : Ptr32 Void LpcWaitingOnPort : Ptr32 Void ImpersonationInfo : Ptr32 _PS_IMPERSONATION_INFORMATION IrpList : _LIST_ENTRY TopLevelIrp : Uint4B DeviceToVerify : Ptr32 _DEVICE_OBJECT ThreadsProcess : Ptr32 _EPROCESS StartAddress : Ptr32 Void Win32StartAddress : Ptr32 Void LpcReceivedMessageId : Uint4B ThreadListEntry : _LIST_ENTRY RundownProtect : _EX_RUNDOWN_REF ThreadLock : _EX_PUSH_LOCK LpcReplyMessageId : Uint4B ReadClusterSize : Uint4B GrantedAccess : Uint4B CrossThreadFlags : Uint4B Terminated : Pos 0, 1 Bit DeadThread : Pos 1, 1 Bit HideFromDebugger : Pos 2, 1 Bit ActiveImpersonationInfo : Pos 3, 1 Bit SystemThread : Pos 4, 1 Bit HardErrorsAreDisabled: Pos 5, 1 Bit BreakOnTermination : Pos 6, 1 Bit SkipCreationMsg : Pos 7, 1 Bit SkipTerminationMsg : Pos 8, 1 Bit SameThreadPassiveFlags : Uint4B ActiveExWorker : Pos 0, 1 Bit ExWorkerCanWaitUser : Pos 1, 1 Bit MemoryMaker : Pos 2, 1 Bit SameThreadApcFlags : Uint4B LpcReceivedMsgIdValid: Pos 0, 1 Bit LpcExitThreadCalled : Pos 1, 1 Bit AddressSpaceOwner : Pos 2, 1 Bit ForwardClusterOnly : UChar DisablePageFaultClustering : UChar Для просмотра KTHREAD предназначена аналогичная команда: lkd> dt nt!_kthread nt!_KTHREAD +0x000 Header +0x010 MutantListHead +0x018 InitialStack +0x01c StackLimit +0x020 Teb +0x024 TlsArray +0x028 KernelStack +0x02c DebugActive : : : : : : : : _DISPATCHER_HEADER _LIST_ENTRY Ptr32 Void Ptr32 Void Ptr32 Void Ptr32 Void Ptr32 Void UChar см. след. стр.
336 ГЛ А В А 6 +0x02d +0x02e +0x030 +0x031 +0x032 +0x033 +0x034 +0x04c +0x050 +0x051 +0x054 БЕЗОПАСНОСТЬ State Alerted Iopl NpxState Saturation Priority ApcState ContextSwitches IdleSwapBlock Spare0 WaitStatus : : : : : : : : : : : UChar [2] UChar UChar UChar Char Char _KAPC_STATE Uint4B UChar [3] UChar Int4B ЭКСПЕРИМЕНТ: использование команды !thread отладчика ядра Команда !thread отладчика ядра выдает дамп подмножества информа& ции из структур данных потока. Отладчик ядра выводит ряд важных данных, не показываемых любыми другими утилитами: адреса внут& ренних структур, детальные сведения о приоритетах, данные стека, список незавершенных запросов на ввод&вывод и список ожидаемых объектов для тех потоков, которые находятся в состоянии ожидания. Чтобы получить информацию о потоке, используйте либо коман& ду !process (которая выводит все блоки потоков после блока процес& са), либо команду !thread (которая сообщает сведения только об ука& занном потоке). Ниже дан пример информации о потоке с пояснени& ем ее важнейших полей.
ГЛАВА 9 Процессы, потоки и задания 337 ЭКСПЕРИМЕНТ: просмотр информации о потоке Утилита Tlist из Windows Debugging Tools позволяет получить подробную информацию о процессе, пример которой приведен ниже. Заметьте, что в списке потоков указывается «Win32StartAddress». Это адрес, передавае& мый функции CreateThread приложением. Остальные утилиты, кроме Pro& cess Explorer, показывающие стартовый адрес потока, выводят его истин& ный стартовый адрес, а не стартовый адрес, заданный приложением. C:\> tlist winword 155 WINWORD.EXE Document1  Microsoft Word CWD: C:\book\ CmdLine: ”C:\Program Files\Microsoft Office\Office\WINWORD.EXE” VirtualSize: 64448 KB PeakVirtualSize: 106748 KB WorkingSetSize: 1104 KB PeakWorkingSetSize: 6776 KB NumberOfThreads: 2 156 Win32StartAddr:0x5032cfdb LastErr:0x00000000 State:Waiting 167 Win32StartAddr:0x00022982 LastErr:0x00000000 State:Waiting 0x50000000 WINWORD.EXE 5.0.2163.1 shp 0x77f60000 ntdll.dll 5.0.2191.1 shp 0x77f00000 KERNEL32.dll ... список DLL, загруженных в процесс... В отличие от других структур данных, описываемых в этом разделе, только блок TEB, показанный на рис. 6&9, присутствует в адресном пространстве про& цесса, а не системы. В TEB хранится контекстная информация загрузчика об& разов и различных Windows DLL. Поскольку эти компоненты выполняются в пользовательском режиме, им нужны структуры данных, доступные для запи& си из этого режима. Вот почему TEB размещается в адресном пространстве процесса, а не системы, где он был бы доступен для записи только из режима ядра. Адрес TEB можно найти с помощью команды !thread отладчика ядра. Рис. 6-9. Поля блока переменных окружения потока
338 ГЛ А В А 6 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: исследуем TEB Вы можете получить дамп структуры TEB, используя команду !teb от& ладчика ядра. Ее вывод выглядит так: kd> !teb TEB at 7ffde000 ExceptionList: StackBase: StackLimit: SubSystemTib: FiberData: ArbitraryUserPointer: Self: EnvironmentPointer: ClientId: RpcHandle: Tls Storage: PEB Address: LastErrorValue: LastStatusValue: Count Owned Locks: 0006b540 00070000 00065000 00000000 00001e00 00000000 7ffde000 00000000 00000254 . 000007ac 00000000 00000000 7ffdf000 2 c0000034 0 HardErrorMode: 0 Переменные ядра Как и в случае процессов, ряд переменных ядра Windows контролирует вы& полнение потоков. Список таких переменных, связанных с потоками, при& водится в таблице 6&10. Таблица 6-10. Переменные ядра, относящиеся к потокам Переменная Тип Описание PspCreateThread NotifyRoutine Массив указателей Массив указателей на процедуры (мак& симум 8), вызываемых при создании и удалении потока PspCreateThread NotifyRoutineCount DWORD Счетчик зарегистрированных процедур уведомления потока PspCreateProcess NotifyRoutine Массив указателей Массив указателей на процедуры (мак& симум 8), вызываемых при создании и удалении процесса Счетчики производительности Большая часть важной информации в структурах данных потоков экспор& тируется в виде счетчиков производительности, перечисленных в табли& це 6&11. Даже используя только оснастку Performance, вы можете получить довольно много сведений о внутреннем устройстве потоков.
ГЛАВА 9 Процессы, потоки и задания 339 Таблица 6-11. Счетчики производительности для потоков Объект: счетчик Описание Process: Priority Base (Процесс: Базовый приоритет) Возвращает текущий базовый приоритет процес& са; это начальный приоритет для потоков, созда& ваемых в данном процессе Thread: % Privileged Time (Поток: % работы в привилеги& рованном режиме) Процентная доля времени, в течение которого поток выполнялся в режиме ядра Thread: % Processor Time (Поток: % загруженности процессора) Процентная доля процессорного времени, исполь& зованная потоком за определенный период вре& мени; вычисляется как сумма % Privileged Time и % User Time Thread: % User Time (Поток: % работы в пользовательском режиме Процентная доля времени, в течение которого поток выполнялся в пользовательском режиме Thread: Context Switches/Sec (Поток: Контекстных переклю& чений/сек) Число переключений контекстов в секунду в системе Thread: Elapsed Time (Поток: Прошло времени) Процессорное время (в секундах), использован& ное потоком Thread: ID Process (Поток: Идентификатор процесса) Идентификатор процесса — владельца потока; действителен лишь на время существования процесса, так как идентификаторы процессов подлежат повторному использованию Thread: ID Thread (Поток: Идентификатор потока) Идентификатор потока; действителен лишь на время существования потока, так как иденти& фикаторы потоков подлежат повторному исполь& зованию Thread: Priority Base (Поток: Базовый приоритет) Текущий базовый приоритет потока; его значение может отличаться от начального базового при& оритета Thread: Priority Current (Поток: Текущий приоритет) Текущий динамический приоритет потока Thread: Start Address (Поток: Начальный адрес) Стартовый виртуальный адрес потока (у большин& ства потоков этот адрес одинаков) Thread: Thread State (Поток: Состояние потока) Текущее состояние потока — значение в интерва& ле от 0 до 7 Thread: Thread Wait Reason (Поток: Причина состояния ожидания для потока) Причина перехода потока в состояние ожида& ния — значение в интервале от 0 до 19 Сопутствующие функции В таблице 6&12 перечислены Windows&функции, позволяющие создавать потоки и манипулировать ими. Здесь не показаны функции, связанные с планированием и управлением приоритетами потоков, — они описывают& ся в разделе «Планирование потоков» далее в этой главе.
340 ГЛ А В А 6 Таблица 6-12. БЕЗОПАСНОСТЬ Функции Windows, относящиеся к потокам Функция Описание CreateThread Создает новый поток CreateRemoteThread Создает поток в другом процессе ExitThread Нормально завершает поток TerminateThread Аварийно завершает поток GetExitCodeThread Получает код завершения другого потока GetThreadTimes Возвращает временные характеристики другого потока GetCurrentThread Возвращает псевдоописатель текущего потока GetCurrentThreadId Возвращает идентификатор текущего потока GetThreadId Возвращает идентификатор указанного потока GetThreadContext SetThreadContext Возвращает или изменяет регистры процессора для данного потока GetThreadSelectorEntry Возвращает элемент таблицы дескрипторов другого потока (только для систем типа x86) Рождение потока Жизненный цикл потока начинается при его создании программой. Запрос на его создание в конечном счете поступает исполнительной системе Win& dows, где диспетчер процессов выделяет память для объекта «поток» и вы& зывает ядро для инициализации блока потока ядра. Ниже перечислены основные этапы создания потока Windows&функцией CreateThread (которая находится в Kernel32.dll). 1. CreateThread создает стек пользовательского режима в адресном про& странстве процесса. 2. CreateThread инициализирует аппаратный контекст потока, специфич& ный для конкретной архитектуры процессора. (Подробнее о блоке кон& текста потока см. раздел справочной документации Windows API по структуре CONTEXT.) 3. Для создания объекта «поток» исполнительной системы вызывается Nt CreateThread. Он создается в приостановленном состоянии. Описание операций, выполняемых NtCreateThread, см. в разделе «Что делает функ& ция CreateProcess» (этапы 3 и 6) ранее в этой главе. 4. CreateThread уведомляет подсистему Windows о создании нового потока, и та выполняет некоторые подготовительные операции. 5. Вызвавшему коду возвращаются описатель и идентификатор потока (сге& нерированный на этапе 3). 6. Выполнение потока возобновляется, и ему может быть выделено процес& сорное время, если только он не был создан с флагом CREATE_SUSPEN& DED. Перед вызовом по пользовательскому стартовому адресу поток вы& полняет операции, описанные в разделе «Этап 3: создание первичного потока, его стека и контекста» ранее в этой главе.
ГЛАВА 9 Процессы, потоки и задания 341 Наблюдение за активностью потоков Не только оснастка Performance, но и другие утилиты (таблица 6&13) позво& ляют получать сведения о состоянии потоков в Windows. (Утилиты, показы& вающие информацию о планировании потоков, перечисляются в разделе «Планирование потоков» далее в этой главе.) ПРИМЕЧАНИЕ Чтобы получить информацию о потоке с помощью Tlist, введите tlist xxx, где xxx — имя образа процесса или заголовок окна (можно использовать символы подстановки). Таблица 6-13. Утилиты для исследования потоков и их функций Process Explorer позволяет наблюдать за активностью потоков в процес& се. Это особенно важно, когда вы пытаетесь понять, почему процесс зависа& ет или запускается какой&то процесс, служащий хостом для множества сер& висов (например, Svchost.exe, Dllhost.exe, Inetinfo.exe или System). Для просмотра потоков в процессе выберите этот процесс и откройте окно его свойств двойным щелчком. Потом перейдите на вкладку Threads. На этой вкладке отображается список потоков в процессе. Для каждого потока показывается процентная доля использованного процессорного времени (с
342 ГЛ А В А 6 БЕЗОПАСНОСТЬ учетом заданного интервала обновления), число переключений контекста для данного потока и его стартовый адрес. Поддерживается сортировка по любому из этих трех столбцов. Новые потоки выделяются зеленым, а существующие — красным. (Дли& тельность подсветки настраивается в Options.) Это помогает обнаруживать создание лишних потоков в процессе. (Как правило, потоки должны созда& ваться при запуске процесса, а не при каждой обработке какого&либо зап& роса внутри процесса.) Когда вы поочередно выбираете потоки в списке, Process Explorer отобра& жает их идентификаторы, время запуска, состояние, счетчики использова& ния процессорного времени, число переключений контекстов, а также ба& зовый и текущий приоритеты. Кнопка Kill позволяет принудительно завер& шать индивидуальные потоки, но пользоваться ею следует с крайней осто& рожностью. Разница в числе переключений контекста (context switch delta) отража& ет, сколько раз потоки начинали работать в течение периода обновления, указанного в Process Explorer. Это еще один способ определения активнос& ти потоков. В некоторых отношениях он даже лучше, так как многие пото& ки выполняются в течение лишь очень короткого времени и поэтому край& не редко попадают в список текущих потоков. Например, если вы добавите столбец с разницей в числе переключений контекстов к тому, что показы& вается для процесса и отсортируете по этому столбцу, то увидите процессы, в которых потоки выполняются, но используют очень мало процессорного времени или вообще его не используют. Стартовый адрес потока выводится в виде «module!function», где module — имя EXE или DLL. Имя функции извлекается из файла символов для данного модуля (см. эксперимент «Просмотр детальных сведений о процессах с по& мощью Process Explorer» в главе 1). Если вы точно не знаете, что это за мо& дуль, нажмите кнопку Module, и появится окно свойств модуля, где содержит& ся данная функция. ПРИМЕЧАНИЕ Для потоков, созданных Windows&функцией Create Thread, Process Explorer показывает функцию, переданную в Create Thread, а не истинную стартовую функцию потока. Это связано с тем, что все Windows&потоки запускаются в общей стартовой функции& оболочке для процессов или потоков (BaseProcessStart либо BaseThre adStart в Kernel32.dll). Если бы Process Explorer выводил истинный стартовый адрес, то казалось бы, что большинство потоков в процес& се были запущены по одному адресу, а это вряд ли помогло бы понять, какой код выполняется потоком. Однако одного стартового адреса потока может оказаться недостаточно для того, чтобы выяснить, что именно делает поток и какой компонент внут& ри процесса отвечает за использование процессорного времени этим пото& ком. Это особенно верно, если стартовый адрес потока относится к универ& сальной стартовой функции (например, если имя функции не указывает на
ГЛАВА 9 Процессы, потоки и задания 343 то, что делает данный поток). Тогда может помочь изучение стека потока. Для его просмотра дважды щелкните интересующий вас поток (или выберите этот поток и нажмите кнопку Stack). Process Explorer покажет стек потока (пользо& вательского режима и режима ядра, если поток был в последнем режиме). ПРИМЕЧАНИЕ Отладчики пользовательского режима (Windbg, Ntsd и Cdb) тоже позволяют подключаться к процессу и просматривать стек потока, но Process Explorer выводит стек как пользовательского режи& ма, так и режима ядра простым нажатием одной кнопки. Стеки пользо& вательского режима и режима ядра можно просмотреть и с помощью Livekd от www.sysinternals.com, но эта утилита гораздо сложнее в ис& пользовании. Кстати, при работе Windbg в режиме локальной отлад& ки ядра, поддерживаемом только в Windows XP и Windows Server 2003, увидеть содержимое стеков потоков нельзя. Просмотр стека потока полезен и при поиске причины зависания про& цесса. Например, на одной системе Microsoft PowerPoint зависал при запус& ке на минуту. Чтобы понять причину этого зависания, с помощью Process Explorer изучили стек одного из потоков в процессе. Результат приведен на рис. 6&10. Рис. 6-10. Стек зависшего потока в PowerPoint Как видите, PowerPoint (строка 10) вызвал функцию в Mso.dll (основной Microsoft Office DLL), которая обратилась к функции OpenPrinterW в Win& spool.drv (DLL, используемой для подключения к принтерам). Затем Win& spool.drv пересылает запрос функции OpenPrinterRPC, а та вызывает функ& цию в DLL исполняющей среды RPC, сообщая, что запрос посылается удален& ному принтеру. Вот так, не зная деталей внутреннего устройства PowerPoint, по именам модулей и функций в стеке потока можно понять, что поток ждет соединения с сетевым принтером. В данной системе был сетевой принтер, который не отвечал, что и объясняет задержку в запуске PowerPoint. (При& ложения Microsoft Office соединяются со всеми сконфигурированными принтерами при запуске.) Соединение с тем принтером было удалено из пользовательской системы, и проблема исчезла.
344 ГЛ А В А 6 БЕЗОПАСНОСТЬ Планирование потоков Здесь описываются стратегии и алгоритмы планирования в Windows. В пер& вом разделе этой части материалов рассматриваются принципы планиро& вания в Windows и даются определения ключевых терминов. Уровни при& оритета обсуждаются с точки зрения как Windows API, так и ядра. После об& зора сопутствующих Windows&функций и утилит подробно анализируют& ся — сначала в однопроцессорных системах, а затем и в многопроцессор& ных — алгоритмы и структуры данных, используемые подсистемой плани& рования Windows. Обзор планирования в Windows В Windows реализована подсистема вытесняющего планирования на осно& ве уровней приоритета, в которой всегда выполняется поток с наибольшим приоритетом, готовый к выполнению. Однако выбор потока для выполне& ния может быть ограничен набором процессоров, на которых он может ра& ботать. Это явление называется привязкой к процессорам (processor affinity). По умолчанию поток выполняется на любом доступном процессоре, но вы можете изменить привязку к процессорам через Windows&функции плани& рования, перечисленные в таблице 6&14 (см. далее в этой главе), или задани& ем маски привязки в заголовке образа. ЭКСПЕРИМЕНТ: просмотр потоков, готовых к выполнению Список потоков, готовых к выполнению, можно увидеть с помощью команды !ready отладчика ядра. Она выводит поток или список пото& ков, готовых к выполнению (на каждом уровне приоритета отдельно). В следующем примере к выполнению готовы два потока с приорите& том 10 и шесть потоков — с приоритетом 8. Поскольку эта информа& ция получена в однопроцессорной системе с использованием LiveKd, текущим потоком всегда является отладчик ядра (Kd или WinDbg). kd> !ready 1 Ready Threads at THREAD 810de030 THREAD 81110030 Ready Threads at THREAD 811fe790 THREAD 810bec70 THREAD 8003a950 THREAD 85ac2db0 THREAD 827318d0 THREAD 8117adb0 priority 10 Cid 490.4a8 Cid 490.48c priority 8 Cid 23c.274 Cid 23c.50c Cid 23c.550 Cid 23c.5e4 Cid 514.560 Cid 2d4.338 Teb: 7ffd9000 Win32Thread: e297e008 READY Teb: 7ffde000 Win32Thread: e29425a8 READY Teb: Teb: Teb: Teb: Teb: Teb: 7ffdb000 7ffd9000 7ffda000 7ffd8000 7ffd9000 7ffaf000 Win32Thread: Win32Thread: Win32Thread: Win32Thread: Win32Thread: Win32Thread: e258cda8 e2ccf748 e29a7ae8 e297a9e8 00000000 00000000 READY READY READY READY READY READY Выбранный для выполнения поток работает в течение некоего периода, называемого квантом. Квант определяет, сколько времени будет выполнять&
ГЛАВА 9 Процессы, потоки и задания 345 ся поток, пока не наступит очередь другого потока с тем же приоритетом (или более высоким, что возможно в многопроцессорной системе). Длитель& ность квантов зависит от трех факторов: конфигурационных параметров системы (длинные или короткие кванты), статуса процесса (активный или фоновый) и использования объекта «задание» для изменения длительности квантов. (Подробнее о квантах см. раздел «Квант» далее в этой главе.) Одна& ко поток может не полностью использовать свой квант. Поскольку в Win& dows реализован вытесняющий планировщик, то происходит вот что. Как только другой поток с более высоким приоритетом готов к выполнению, текущий поток вытесняется, даже если его квант еще не истек. Фактически поток может быть выбран следующим для выполнения и вытеснен, не успев воспользоваться своим квантом! Код Windows, отвечающий за планирование, реализован в ядре. Посколь& ку этот код рассредоточен по ядру, единого модуля или процедуры с назва& нием «планировщик» нет. Совокупность процедур, выполняющих эти обя& занности, называется диспетчером ядра (kernel’s dispatcher). Диспетчериза& ция потоков может быть вызвана любым из следующих событий. 쐽 Поток готов к выполнению — например, он только что создан или вышел из состояния ожидания. 쐽 Поток выходит из состояния Running (выполняется), так как его квант истек или поток завершается либо переходит в состояние ожидания. 쐽 Приоритет потока изменяется в результате вызова системного сервиса или самой Windows. 쐽 Изменяется привязка к процессорам, из&за чего поток больше не может работать на процессоре, на котором он выполнялся. В любом случае Windows должна определить, какой поток выполнять сле& дующим. Выбрав новый поток, Windows переключает контекст. Эта опе& рация заключается в сохранении параметров состояния машины, связанных с выполняемым потоком, и загрузке аналогичных параметров для другого потока, после чего начинается выполнение нового потока. Как уже говорилось, планирование в Windows осуществляется на уровне потоков. Этот подход станет понятен, если вы вспомните, что сами процес& сы не выполняются, а лишь предоставляют ресурсы и контекст для выпол& нения потоков. Поскольку решения, принимаемые в ходе планирования, ка& саются исключительно потоков, система не обращает внимания на то, како& му процессу принадлежит тот или иной поток. Так, если у процесса А есть 10, у процесса В — 2 готовых к выполнению потока, и все 12 имеют одина& ковый приоритет, каждый из потоков теоретически получит 1/12 процес& сорного времени, потому что Windows не станет поровну делить процессор& ное время между двумя процессами. Чтобы понять алгоритмы планирования потоков, вы должны сначала ра& зобраться в уровнях приоритета, используемых Windows.
346 ГЛ А В А 6 БЕЗОПАСНОСТЬ Уровни приоритета Как показано на рис. 6&11, в Windows предусмотрено 32 уровня приорите& та — от 0 до 31. Эти значения группируются так: 쐽 шестнадцать уровней реального времени (16–31); 쐽 пятнадцать варьируемых (динамических) уровней (1–15); 쐽 один системный уровень (0), зарезервированный для потока обнуления страниц (zero page thread). Рис. 6-11. Уровни приоритета потоков Уровни приоритета потока назначаются с учетом двух разных точек зре& ния — Windows API и ядра Windows. Windows API сначала упорядочивает процессы по классам приоритета, назначенным при их создании [Real&time (реального времени), High (высокий), Above Normal (выше обычного), Nor& mal (обычный), Below Normal (ниже обычного) и Idle (простаивающий)], а затем — по относительному приоритету индивидуальных потоков в рамках этих процессов [Time&critical (критичный по времени), Highest (наивысший), Above&normal (выше обычного), Normal (обычный), Below&normal (ниже обычного), Lowest (наименьший) и Idle (простаивающий)]. Базовый приоритет каждого потока в Windows API устанавливается, ис& ходя из класса приоритета его процесса и относительного приоритета са& мого потока. Связь между приоритетами Windows API и внутренними при& оритетами ядра Windows (в числовой форме) показана на рис. 6&12. Если у процесса только одно значение приоритета (базовое), то у каждого потока их два: текущее и базовое. Решения, связанные с планированием, при& нимаются на основе текущего приоритета. Как поясняется в следующем раз& деле, в определенных обстоятельствах система может на короткое время повышать приоритеты потоков в динамическом диапазоне (1–15). Windows никогда не изменяет приоритеты потоков в диапазоне реального времени (16–31), поэтому у таких потоков базовый приоритет идентичен текущему.
ГЛАВА 9 Рис. 6-12. Процессы, потоки и задания 347 Взаимосвязь приоритетов в ядре и Windows API Начальный базовый приоритет потока наследуется от базового приори& тета процесса, а тот наследует его от родительского процесса. Это поведе& ние можно изменить при вызове Windows&функции CreateProcess или коман& ды START. Приоритет процесса можно изменить и после его создания, ис& пользуя функцию SetPriorityClass или различные утилиты, предоставляющие доступ к этой функции через UI, например диспетчер задач и Process Explo& rer. В частности, вы можете понизить приоритет процесса, интенсивно ис& пользующего процессорное время, чтобы он не мешал обычным операци& ям в системе. Смена приоритета процесса влечет за собой смену приорите& тов всех его потоков, но их относительные приоритеты остаются прежни& ми. Но изменение приоритетов индивидуальных потоков внутри процесса обычно не имеет смысла, потому что вы не знаете, чем именно занимается каждый из них (если только сами не пишете программу или не располагае& те исходным кодом); так что изменение относительных приоритетов пото& ков может привести к неадекватному поведению этого приложения. Обычно базовый приоритет процесса (а значит, и базовый приоритет пер& вичного потока) по умолчанию равен значению из середины диапазонов при&
348 ГЛ А В А 6 БЕЗОПАСНОСТЬ оритетов процессов (24, 13, 10, 8, 6 или 4). Однако базовый приоритет неко& торых системных процессов (например, диспетчера сеансов, контроллера сервисов и сервера локальной аутентификации) несколько превышает значе& ние по умолчанию для класса Normal (8). Более высокий базовый приоритет по умолчанию обеспечивает запуск потоков этих процессов с приоритетом выше 8. Чтобы изменить свой начальный базовый приоритет, такие систем& ные процессы используют внутреннюю функцию NtSetInformationProcess. Функции Windows API, связанные с планированием Эти функции перечислены в таблице 6&14 (более подробную информацию см. в справочной документации Windows API). Таблица 6-14. API-функции планирования и их назначение API-функция Описание SuspendThread ResumeThread Приостанавливает/возобновляет поток GetPriorityClass SetPriorityClass Возвращает/устанавливает класс приоритета процесса (базовый приоритет) GetThreadPriority SetThreadPriority Возвращает/устанавливает приоритет потока (относи& тельный базовому приоритету его процесса) GetProcessAffinityMask SetProcessAffinityMask Возвращает/устанавливает маску привязки процесса к процессорам SetThreadAffinityMask Устанавливает маску привязки потока (которая должна быть подмножеством маски привязки процесса) к кон& кретному набору процессоров, ограничивая доступные для выполнения этого потока процессоры SetInformationJobObject Задает атрибуты для задания; некоторые из них влияют на планирование, изменяя, например, привязку к процес& сорам и приоритет (описание объекта «задание» см. в разделе «Объекты&задания» далее в этой главе) GetLogicalProcessor Information Возвращает детальные сведения о конфигурации про& цессоров [для систем с поддержкой логических процес& соров (hyperthreaded systems) и NUMA] GetThreadPriorityBoost SetThreadPriorityBoost Возвращает информацию о динамическом повышении приоритета потока или разрешает такое повышение приоритета (только для потоков с приоритетами из динамического диапазона) SetThreadIdealProcessor Задает предпочтительный процессор для данного пото& ка, но не ограничивает им набор процессоров, доступ& ных этому потоку GetProcessPriorityBoost SetProcessPriorityBoost Возвращает/устанавливает статус динамического повы& шения приоритета данного процесса по умолчанию (ис& пользуется для установки этого статуса при создании потока) SwitchToThread Переключает процессор на выполнение другого потока (с приоритетом от 1 и выше), готового к выполнению на текущем процессоре
ГЛАВА 9 Процессы, потоки и задания 349 Таблица 6-14. (окончание) API-функция Описание Sleep Переводит текущий поток в состояние ожидания на ука& занное время (в мс); нулевое значение отбирает у потока остаток его кванта SleepEx Переводит текущий поток в состояние ожидания до тех пор, пока не закончится операция ввода&вывода, пока не истечет указанный временной интервал или пока в очереди потока не появится APC Сопутствующие утилиты В следующей таблице перечислены утилиты, сообщающие информацию о пла& нировании потоков. Базовый приоритет процесса можно увидеть (и изменить) с помощью диспетчера задач, Process Explorer, Pview или Pviewer. Заметьте, что Process Explorer позволяет уничтожать отдельные потоки в любых процессах. Но, конечно же, этой возможностью следует пользоваться с крайней осторожностью. Приоритеты потоков можно просмотреть в оснастке Performance (Про& изводительность), а также с помощью утилит Process Explorer, Plist, Pview, Pviewer и Pstat. Хотя повышение или понижение приоритета процесса мо& жет оказаться весьма полезным, изменение приоритетов индивидуальных потоков внутри процесса, как правило, не имеет смысла, потому что посто& роннему человеку не известно, что делают эти потоки и почему важны имен& но такие их относительные приоритеты. Единственный способ задать начальный класс приоритета для процес& са — использовать команду start в командной строке Windows. Если вы хо& тите, чтобы некая программа каждый раз запускалась с определенным при& оритетом, то можете создать для нее ярлык и указать команду запуска, пред& варив ее cmd /c. Это приведет к появлению окна командной строки, выпол& нению команды и последующему закрытию этого окна. Например, чтобы за& пустить Notepad в процессе с низким приоритетом, в свойствах ярлыка дол& жна быть задана команда cmd /c start /low notepad.exe. ЭКСПЕРИМЕНТ: исследуем и задаем приоритеты процессов и потоков Попробуйте провести такой эксперимент. 1. Наберите в командной строке start /realtime notepad. На экране появится окно Notepad. см. след. стр.
350 ГЛ А В А 6 БЕЗОПАСНОСТЬ 2. Запустите утилиту Process Explorer или Process Viewer (Pviewer.exe) из Support Tools и выберите Notepad.exe из списка процессов, как показано ниже. Заметьте, что динамический приоритет потока No& tepad равен 24. Это значение совпадает со значением приоритета реального времени на рис. 6&12. 3. Аналогичную информацию можно получить в диспетчере задач. Для его запуска нажмите клавиши Ctrl+Shift+Esc и перейдите на вкладку Processes (Процессы). Щелкните правой кнопкой мыши процесс Notepad.exe и выберите команду Set Priority (Приоритет). Вы увидите, что класс приоритета потока относится к Realtime (Ре& ального времени), как показано на следующей иллюстрации.
ГЛАВА 9 Процессы, потоки и задания 351 Диспетчер системных ресурсов Windows В Windows Server 2003 Enterprise Edition и Windows Server 2003 Data& center Edition включен необязательный компонент, который называ& ется диспетчером системных ресурсов Windows (Windows System Re& source Manager, WSRM). Он позволяет администратору настраивать правила политики, указывающие для процессов использование про& цессорного времени, параметры привязки к процессорам и лимиты на физическую и виртуальную память. Кроме того, WSRM может генери& ровать отчеты по использованию ресурсов, удобные для учета и про& верки уровня обслуживания по договорам с пользователями. Такие правила могут быть применены к конкретным приложениям, пользователям или группам и действовать в определенные периоды или постоянно. После того как вы сформировали политику выделения ресурсов для управления определенными процессами, служба WSRM будет вести мо& ниторинг потребления ими процессорного времени и регулировать их базовые приоритеты, если эти процессы будут использовать процессор& ного времени больше или меньше, чем было установлено вами. Ограничение физической памяти достигается заданием макси& мального размера рабочего набора через функцию SetProcessWorking SetSizeEx, а ограничение виртуальной памяти реализуется самой служ& бой (о лимитах на объемы физической и виртуальной памяти см. гла& ву 7). Если заданный лимит превышен, WSRM — в зависимости от на& строек — может уничтожать процессы или создавать соответствую& щую запись в журнале событий. Последнее позволяет выявить процесс с утечкой памяти до того, как он займет всю переданную виртуальную память в системе. Заметьте, что лимиты на память, установленные в WSRM, не применяются к памяти Address Windowing Extensions (AWE), памяти больших страниц (large page memory) или памяти ядра (пулу подкачиваемых или неподкачиваемых страниц). Приоритеты реального времени Вы можете повысить или понизить приоритет потока любого приложения в динамическом диапазоне; однако, чтобы задать значение из диапазона реального времени, у вас должна быть привилегия Increase Scheduling Priority. Учтите, что многие важные системные потоки режима ядра выполняются в диапазоне приоритетов реального времени. Поэтому, если потоки слишком долго выполняются с приоритетом этого диапазона, они могут блокировать критичные системные функции (например в диспетчере памяти, диспетче& ре кэша или драйверах устройств).
352 ГЛ А В А 6 БЕЗОПАСНОСТЬ ПРИМЕЧАНИЕ Как показано на следующей иллюстрации, где изобра& жены уровни запросов прерываний (Interrupt Request Levels, IRQL) на платформе x86, в Windows имеется набор приоритетов, называемых при& оритетами реального времени, но они не являются таковыми в общепри& нятом смысле этого термина, так как Windows не относится к операци& онным системам реального времени. Подробнее на эту тему см. врезку «Windows и обработка данных в реальном времени» в главе 3, а также статью «Real&Time Systems and Microsoft Windows NT» в MSDN Library. Уровни прерываний и уровни приоритета Как показано на следующей иллюстрации, потоки обычно выполня& ются при IRQL, равном 0 или 1. (Описание уровней прерываний в Windows см. в главе 3.) Потоки пользовательского режима всегда вы& полняются при IRQL, равном 0. Ввиду этого ни один поток пользова& тельского режима независимо от его приоритета не в состоянии бло& кировать аппаратные прерывания (хотя потоки с высоким приорите& том из диапазона реального времени способны блокировать важные системные потоки). При IRQL, равном 1, работают только APC режи& ма ядра, поскольку они прерывают выполнение потоков (об APC см. главу 3). Кроме того, потоки, выполняемые в режиме ядра, могут по& вышать IRQL, например при обработке системного вызова, требующе& го диспетчеризации потоков. Состояния потоков Прежде чем перейти к алгоритмам планирования потоков, вы должны разоб& раться, в каких состояниях могут находиться потоки в процессе выполнения
ГЛАВА 9 Процессы, потоки и задания 353 в Windows 2000 и Windows XP. Соответствующая схема дана на рис. 6&13 [числовые значения отражают показатели счетчика производительности Thread: thread state (Поток: Состояние потока)]. Рис. 6-13. Состояния потоков в Windows 2000 и Windows XP Вот что представляют собой состояния потока. 쐽 Ready (готов) Поток в состоянии готовности ожидает выполнения. Вы& бирая следующий поток для выполнения, диспетчер принимает во вни& мание только пул потоков, готовых к выполнению. 쐽 Standby (простаивает) Поток в этом состоянии уже выбран следующим для выполнения на конкретном процессоре. В подходящий момент диспет& чер переключает контекст на этот поток. В состоянии Standby может нахо& диться только один поток для каждого процессора в системе. Заметьте, что поток может быть вытеснен даже в этом состоянии (если, например, до на& чала выполнения потока, который пока находится в состоянии Standby, к вы& полнению будет готов поток с более высоким приоритетом). 쐽 Running (выполняется) Поток переходит в это состояние и начина& ет выполняться сразу после того, как диспетчер переключает на него кон& текст. Выполнение потока прекращается, как только он завершается, вы& тесняется потоком с более высоким приоритетом, переключает контекст на другой поток, самостоятельно переходит в состояние ожидания или истекает выделенный ему квант процессорного времени (и другой поток с тем же приоритетом готов к выполнению). 쐽 Waiting (ожидает) Поток входит в состояние Waiting несколькими способами. Он может самостоятельно начать ожидание на синхронизи& рующем объекте или его вынуждает к этому подсистема окружения. По окончании ожидания поток — в зависимости от приоритета — либо не& медленно начинает выполняться, либо переходит в состояние Ready.
354 ГЛ А В А 6 БЕЗОПАСНОСТЬ 쐽 Transition (переходное состояние) Поток переходит в это состоя& ние, если он готов к выполнению, но его стек ядра выгружен из памяти. Как только этот стек загружается в память, поток переходит в состояние Ready. 쐽 Terminated (завершен) Заканчивая выполнение, поток переходит в состояние Terminated. После этого блок потока исполнительной системы (структура данных в пуле неподкачиваемой памяти, описывающая дан& ный поток) может быть удален, а может быть и не удален — это уже оп& ределяется диспетчером объектов. 쐽 Initialized (инициализирован) цессе своего создания. В это состояние поток входит в про& ЭКСПЕРИМЕНТ: изменение состояний потоков при планировании Вы можете понаблюдать за изменением этих состояний с помощью оснастки Performance. Она может оказаться полезной в отладке мно& гопоточных приложений, если вам нужно проверить состояние пото& ков, выполняемых в вашем процессе. 1. Запустите стандартную программу Notepad (Блокнот) (Notepad.exe). 2. Запустите оснастку Performance (Производительность), открыв в меню Start (Пуск) подменю Programs (Программы) и Administrative Tools (Администрирование), а затем выбрав команду Performance (Производительность). 3. Выберите режим просмотра диаграмм (если установлен какой&то другой). 4. Щелкните график правой кнопкой мыши и выберите команду Pro& perties (Свойства). 5. Откройте вкладку Graph (График) и установите максимальное зна& чение вертикальной шкалы равным 7. (Состояниям потоков соот& ветствуют числа от 0 до 7). Щелкните кнопку ОК. 6. Щелкните на панели инструментов кнопку Add (Добавить), чтобы открыть диалоговое окно Add Counters (Добавить счетчики). 7. Выберите в списке объект Thread (Поток), а затем — счетчик Thread State (Состояние потока). Определение его значений вы увидите, щелкнув кнопку Explain (Объяснение), как показано ниже. 8. Прокрутите список вхождений до строки notepad/0 (это процесс Notepad), выделите его и щелкните кнопку Add (Добавить). 9. Прокрутите список назад до процесса Mmc (это процесс Microsoft Management Console, в котором выполняется ActiveX&элемент Sys& tem Monitor), выберите все его потоки (mmc/0, mmc/1 и т. д.) и до&
ГЛАВА 9 Процессы, потоки и задания 355 бавьте их на график, щелкнув кнопку Add. Прежде чем щелкнуть кнопку Add, вы должны увидеть диалоговое окно, аналогичное по& казанному ниже. 10. Теперь закройте диалоговое окно Add Counters, щелкнув кнопку Close (Закрыть). 11. Вы должны увидеть, что поток Notepad (верхняя линия графика) находится в состоянии 5. Как вы уже знаете, значение 5 соответ& ствует состоянию Waiting. (В данном случае поток ждет GUI&ввода.) 12. Заметьте, что один из потоков процесса Mmc (выполняющий осна& стку Performance) находится в состоянии Running (значение 2). Этот поток всегда выполняется, так как постоянно запрашивает состояние других потоков. 13. Вы никогда не увидите процесс Notepad в состоянии Running (если только не используете многопроцессорную систему), поскольку в этом состоянии всегда находится Mmc, собирая данные о состоя& нии отслеживаемых потоков.
356 ГЛ А В А 6 БЕЗОПАСНОСТЬ Схема состояний потоков в Windows Server 2003 показана на рис. 6&14. Обратите внимание на новое состояние Deferred Ready (готов, отложен). Это состояние используется для потоков, выбранных для выполнения на кон& кретном процессоре, но пока не запланированных к выполнению. Это но& вое состояние предназначено для того, чтобы ядро могло свести к миниму& му срок применения общесистемной блокировки к базе данных планирова& ния (scheduling database). (Этот процесс подробно описывается в разделе «База данных диспетчера ядра в многопроцессорной системе».) Рис. 6-14. Состояния потоков в Windows Server 2003 База данных диспетчера ядра Для принятия решений при планировании потоков ядро поддерживает на& бор структур данных, в совокупности известных как база данных диспет чера ядра (dispatcher database) (рис. 6&15). Эта база данных позволяет отсле& живать потоки, ждущие выполнения, и потоки, выполняемые на тех или иных процессорах. ПРИМЕЧАНИЕ База данных диспетчера ядра в однопроцессорной сис& теме имеет ту же структуру, что и в многопроцессорных системах Windows 2000 и Windows XP, но отличается от структуры такой базы данных в системах Windows Server 2003. Эти различия, а также иной алгоритм выбора потоков для выполнения в многопроцессорных сис& темах поясняются в разделе «Многопроцессорные системы».
ГЛАВА 9 Процессы, потоки и задания 357 Рис. 6-15. База данных диспетчера ядра (однопроцессорная и многопроцессорная в Windows 2000/XP) Очереди готовых потоков (ready queues) диспетчера ядра включают по& токи в состоянии Ready, ожидающие выделения им процессорного времени. Для каждого из 32 уровней приоритета существует по одной очереди. Для ускорения выбора потока, подлежащего выполнению или вытеснению, Win& dows поддерживает 32&битную маску, называемую сводкой готовности (rea& dy summary) (KiReadySummary). Каждый установленный в ней бит указыва& ет на присутствие одного или более потоков в очереди готовых потоков для данного уровня приоритета (бит 0 соответствует приоритету 0, бит 1 — при& оритету 1 и т. д.). В таблице 6&15 перечислены переменные ядра, связанные с планирова& нием потоков в однопроцессорных системах. Таблица 6-15. Переменные ядра, связанные с планированием потоков Переменная Тип Описание KiReadySummary 32&битная маска Битовая маска уровней приоритета, имеющихся у одного или нескольких готовых потоков KiDispatcherReady ListHead Массив из 32 записей Список заголовков для 32 очередей готовых потоков В однопроцессорных системах база данных диспетчера ядра синхрони& зируется повышением IRQL до уровня «DPC/dispatch» и SYNCH_LEVEL (оба определены как уровень 2). (Об уровнях приоритета прерываний см. раздел «Диспетчеризация ловушек» главы 3.) Такое повышение IRQL не дает другим потокам прервать диспетчеризацию потоков, так как потоки обычно выпол&
358 ГЛ А В А 6 БЕЗОПАСНОСТЬ няются при IRQL 0 или 1. В многопроцессорных системах одного повыше& ния IRQL мало, потому что каждый процессор может одновременно увели& чить IRQL до одного уровня и попытаться обратиться к базе данных диспет& чера ядра. Как Windows синхронизирует доступ к этой базе данных в мно& гопроцессорных системах, поясняется в разделе «Многопроцессорные сис& темы» далее в этой главе. Квант Как уже говорилось, квант — это интервал процессорного времени, отведен& ный потоку для выполнения. По его окончании Windows проверяет, ожида& ет ли выполнения другой поток с таким же уровнем приоритета. Если на момент истечения кванта других потоков с тем же уровнем приоритета нет, Windows выделяет текущему потоку еще один квант. По умолчанию в Windows 2000 Professional и Windows XP потоки выпол& няются в течение 2 интервалов таймера (clock intervals), а в системах Win& dows Server — 12. (Как изменить эти значения, мы объясним позже.) В сер& верных системах величина кванта увеличена для того, чтобы свести к мини& муму переключение контекста. Получая больший квант, серверные приложе& ния, которые пробуждаются при получении клиентского запроса, имеют больше шансов выполнить запрос и вернуться в состояние ожидания до ис& течения выделенного кванта. Длительность интервала таймера зависит от аппаратной платформы и определяется HAL, а не ядром. Например, этот интервал на большинстве од& нопроцессорных x86&систем составляет 10 мс, а на большинстве многопро& цессорных x86&систем — около 15 мс. (Как проверить реальный интервал системного таймера, см. в следующем эксперименте.) ЭКСПЕРИМЕНТ: определяем величину интервала системного таймера Windows&функция GetSystemTimeAdjustment возвращает величину ин& тервала системного таймера. Для ее определения запустите програм& му Clockres с www.sysinternals.com. Вот что это программа выводит на однопроцессорной x86&системе: C:\>clockres ClockRes  View the system clock resolution By Mark Russinovich SysInternals  www.sysinternals.com The system clock interval is 10.014400 ms Учет квантов времени Величина кванта для каждого процесса хранится в блоке процесса ядра. Это значение используется, когда потоку предоставляется новый квант. Когда поток выполняется, его квант уменьшается по истечении каждого интерва&
ГЛАВА 9 Процессы, потоки и задания 359 ла таймера, и в конечном счете срабатывает алгоритм обработки заверше& ния кванта. Если имеется другой поток с тем же приоритетом, ожидающий выполнения, происходит переключение контекста на следующий поток в очереди готовых потоков. Заметьте: когда системный таймер прерывает DPC или процедуру обработки другого прерывания, квант выполнявшегося по& тока все равно уменьшается, даже если этот поток не успел отработать пол& ный интервал таймера. Если бы это было не так и если бы аппаратное пре& рывание или DPC появилось непосредственно перед прерыванием таймера, квант потока мог бы вообще никогда не уменьшиться. Внутренне величина кванта хранится как число тактов таймера, умножен& ное на 3. То есть в Windows 2000 и Windows XP потоки по умолчанию полу& чают квант величиной 6 (2 * 3), в Windows Server — 36 (12 * 3). Всякий раз, когда возникает прерывание таймера, процедура его обработки вычитает из кванта потока постоянную величину (3). Почему квант внутренне хранится как величина, кратная трем квантовым единицам за один такт системного таймера? Это сделано для того, чтобы можно было уменьшать значение кванта по завершении ожидания. Когда поток с текущим приоритетом ниже 16 и базовым приоритетом ниже 14 запускает функцию ожидания (WaitForSingleObject или WaitForMultipleObjects) и его запрос на доступ удовлетворяется немедленно (например, он не пере& ходит в состояние ожидания), его квант уменьшается на одну единицу. Бла& годаря этому кванты ожидающих потоков в конечном счете заканчиваются. Если запрос на доступ не удовлетворяется немедленно, кванты потоков с приоритетом ниже 16 тоже уменьшаются на одну единицу (кроме случая, когда поток пробуждается для выполнения APC ядра). Но перед такой опе& рацией квант потока с приоритетом 14 или выше сбрасывается. Это делает& ся и для потоков с приоритетом менее 14, если они не выполняются при специально повышенном приоритете (как, например, в случае фоновых процессов или при недостаточном выделении процессорного времени) и если их приоритет повышен в результате выхода из состояния ожидания (unwait operation). (Динамическое повышение приоритета поясняется в сле& дующем разделе.) Управление величиной кванта Вы можете изменить квант для потоков всех процессов, но выбор ограни& чен всего двумя значениями: короткий квант (2 такта таймера, использует& ся по умолчанию для клиентских компьютеров) или длинный (12 тактов тай& мера, используется по умолчанию для серверных систем). ПРИМЕЧАНИЕ Используя объект «задание» в системе с длинными квантами, вы можете указать другие величины квантов для процессов в задании. Более подробную информацию об объектах «задание» см. в разделе «Объекты&задания» далее в этой главе. Для изменения величины кванта в Windows 2000 щелкните правой кноп& кой мыши My Computer (Мой компьютер), выберите Properties (Свойства),
360 ГЛ А В А 6 БЕЗОПАСНОСТЬ перейдите на вкладку Advanced (Дополнительно), а затем щелкните кнопку Performance Options (Параметры быстродействия). Вы увидите диалоговое окно, показанное на рис. 6&16. Рис. 6-16. Задание кванта в Windows 2000 Для изменения величины кванта в Windows XP или Windows Server 2003 щелкните правой кнопкой мыши My Computer (Мой компьютер), выберите Properties (Свойства), перейдите на вкладку Advanced (Дополнительно), щел& кните кнопку Settings (Параметры) в разделе Performance (Быстродействие), а затем перейдите на вкладку Advanced (Дополнительно). Соответствующие диалоговые окна в Windows XP и Windows Server 2003 немного различают& ся. Они показаны на рис. 6&17. Рис. 6-17. Задание кванта в Windows XP и Windows Server 2003 Параметр Programs (Программ), который в Windows 2000 назывался App& lications (Приложений), соответствует использованию коротких квантов
ГЛАВА 9 Процессы, потоки и задания 361 переменной величины — этот вариант действует для Windows 2000 Profes& sional и Windows XP по умолчанию. Если вы установите Terminal Services в систему Windows Server и настроите ее как сервер приложений, то и в такой системе будет выбран именно этот параметр, чтобы пользователи сервера терминала получали одинаковые кванты, как и в клиентских или персональ& ных системах. Работая с Windows Server как с персональной операционной системой, вы также могли бы вручную выбрать этот параметр. Параметр Background Services (Фоновых служб) подразумевает примене& ние длинных квантов фиксированного размера, что предлагается по умол& чанию в системах Windows Server. Единственная причина, по которой име& ло бы смысл выбрать этот параметр на рабочей станции, — ее использова& ние в качестве серверной системы. Еще одно различие между параметрами Programs и Background Services заключается в том, какой эффект они оказывают на кванты потоков в актив& ном процессе. Об этом рассказывается в следующем разделе. Динамическое увеличение кванта До Windows NT 4.0, когда на рабочей станции или в клиентской системе ка& кое&то окно становилось активным, приоритет всех потоков активного про& цесса (которому принадлежит поток, владеющий окном в фокусе ввода) ди& намически повышался на 2. Повышенный приоритет действовал до тех пор, пока любому потоку процесса принадлежало активное окно. Проблема с этим подходом была в том, что, если вы запустили длительный процесс, ин& тенсивно использующий процессор (например, начали пересчет электрон& ной таблицы), и переключились на другой процесс, требующий больших вычислительных ресурсов (скажем, на одну из программ CAD, графический редактор или какую&нибудь игру), то первый процесс, ставший теперь фо& новым, получит лишь очень малую часть процессорного времени (или во& обще не получит его). А все дело в том, что приоритет потоков активного процесса повышается на 2 (здесь предполагается, что базовый приоритет потоков обоих процессов был одинаковым). Это поведение по умолчанию изменилось с появлением Windows NT 4.0 Workstation — кванты потоков активного процесса стали увеличиваться в 3 раза. Таким образом, по умолчанию на рабочих станциях их квант достигал 6 тактов таймера, а у потоков остальных процессов — 2 тактов. Благодаря этому, когда процесс, интенсивно использующий процессорные ресурсы, оказывается фоновым, новый активный процесс получает пропорциональ& но большее процессорное время (и вновь предполагается, что приоритеты потоков одинаковы как в активном, так и в фоновом процессе). Заметьте, что это изменение квантов относится лишь к процессам с приори& тетом выше Idle в системах с установленным параметром Programs (или Applica& tions в Windows 2000) в диалоговом окне Performance Options (Параметры бы& стродействия), как пояснялось в предыдущем разделе. Кванты потоков актив& ного процесса в системах с установленным параметром Background Services (настройка по умолчанию в системах Windows Server) не изменяются.
362 ГЛ А В А 6 БЕЗОПАСНОСТЬ Параметр реестра для настройки кванта Пользовательский интерфейс, позволяющий изменить относительную вели& чину кванта, модифицирует в реестре параметр HKLM\SYSTEM\CurrentCont& rolSet\Control\PriorityControl\Win32PrioritySeparation. Этот же параметр оп& ределяет, можно ли динамически увеличивать (и, если да, то насколько) кван& ты потоков, выполняемых в активном процессе. Данный параметр содержит 3 двухбитных поля (рис. 6&18). Рис. 6-18. Поля параметра Win32PrioritySeparation 쐽 Короткие или длинные Значение 1 указывает на длинные кванты, а 2 — на короткие. Если это поле равно 0 или 3, используются кванты по умолчанию (короткие в Windows 2000 Professional или Windows XP и длинные в системах Windows Server). 쐽 Переменные или фиксированные Если задано значение 1, кванты потоков активного процесса могут варьироваться, а если задано значение 2 — нет. Если это поле равно 0 или 3, используется настройка по умолча& нию (переменные в Windows 2000 Professional или Windows XP и фикси& рованные в системах Windows Server). 쐽 Динамическое приращение кванта потока активного процесса Это поле (хранящееся в переменной ядра PsPrioritySeparation) может быть равно 0, 1 или 2 (значение 3 недопустимо и интерпретируется как 2) и представляет собой индекс в трехэлементном байтовом массиве (Psp ForegroundQuantum), используемом для расчета квантов потоков актив& ного процесса. Кванты потоков фоновых процессов определяются пер& вым элементом этого массива. Возможные значения в PspForeground Quantum перечислены в таблице 6&16. Таблица 6-16. Величины квантов Короткие Длинные Переменные 6 12 18 12 24 36 Фиксированные 18 18 18 36 36 36 Заметьте, что при использовании диалогового окна Performance Options (Параметры быстродействия) доступны лишь две комбинации: короткие кванты с утроением в активном процессе или длинные без изменения в та& ком процессе. Но прямое редактирование параметра Win32PrioritySeparation в реестре позволяет выбирать и другие комбинации. Сценарии планирования Известно, что вопрос «Какому потоку отдать процессорное время?» Windows 2000 решает, исходя из приоритетов. Но как этот подход работает на прак&
ГЛАВА 9 Процессы, потоки и задания 363 тике? Следующие разделы иллюстрируют, как вытесняющая многозадач& ность, управляемая на основе приоритетов, действует на уровне потоков. Самостоятельное переключение Во&первых, поток может самостоятельно освободить процессор, перейдя в состояние ожидания на каком&либо объекте (например, событии, мьютек& се, семафоре, порте завершения ввода&вывода, процессе, потоке, оконном со& общении и др.) путем вызова одной из многочисленных Windows&функций ожидания (скажем, WaitForSingleObject или WaitForMultipleObjects). Ожидание на объектах было рассмотрено в главе 3. На рис. 6&19 показано, как поток входит в состояние ожидания и как Windows выбирает новый поток для выполнения. Рис. 6-19. Самостоятельное переключение На рис. 6&19 поток (верхний блок) самостоятельно освобождает процес& сор, в результате чего к процессору подключается другой поток из очереди (отмеченный кольцом в колонке Running). Исходя из этой схемы, можно подумать, что приоритет потока, освобождающего процессор, снижается, но это не так — он просто переводится в очередь ожидания выбранных им объектов. А что происходит с оставшейся частью кванта этого потока? Ког& да поток входит в состояние ожидания, квант не сбрасывается. Как уже го& ворилось, после успешного завершения ожидания квант потока уменьшает& ся на одну единицу, что эквивалентно трети интервала таймера (исключе& ние составляют потоки с приоритетом от 14 и выше, у которых после ожи& дания квант сбрасывается).
364 ГЛ А В А 6 БЕЗОПАСНОСТЬ Вытеснение В этом сценарии поток с более низким приоритетом вытесняется готовым к выполнению потоком с более высоким приоритетом. Такая ситуация мо& жет быть следствием двух обстоятельств: 쐽 завершилось ожидание потока с более высоким приоритетом (т. е. про& изошло событие, которого он ждал); 쐽 приоритет потока увеличился или уменьшился. В любом из этих случаев Windows решает, продолжить выполнение теку& щего потока или вытеснить его потоком с более высоким приоритетом. ПРИМЕЧАНИЕ Потоки пользовательского режима могут вытеснять потоки режима ядра. Tо есть режим выполнения потока значения не имеет — определяющим фактором является его приоритет. Когда поток вытесняется, он помещается в начало очереди готовых по& токов соответствующего уровня приоритета. Эту ситуацию иллюстрирует рис. 6&20. Рис. 6-20. Планирование потоков с вытеснением На рис. 6&20 поток с приоритетом 18 выходит из состояния ожидания и вновь захватывает процессор, вытесняя выполняемый в этот момент поток (с приоритетом 16) в очередь готовых потоков. Заметьте, что вытесненный поток помещается не в конец, а в начало очереди. После завершения вытес& нившего потока вытесненный сможет отработать остаток своего кванта. Завершение кванта Когда поток израсходует свой квант процессорного времени, Windows дол& жна решить, следует ли понизить его приоритет и подключить к процессо& ру другой поток.
ГЛАВА 9 Процессы, потоки и задания 365 Снизив приоритет потока, Windows ищет более подходящий для выпол& нения поток (таким потоком, например, будет любой из очереди готовых потоков с приоритетом выше нового приоритета текущего потока). Если Windows оставляет приоритет потока прежним и в очереди готовых пото& ков есть другие потоки с тем же приоритетом, она выбирает из очереди сле& дующий поток с тем же приоритетом, а выполнявшийся до этого поток пе& ремещает в хвост очереди (задавая ему новую величину кванта и переводя его из состояния Running в состояние Ready). Этот случай иллюстрирует рис. 6&21. Если ни один поток с тем же приоритетом не готов к выполнению, текущему потоку выделяется еще один квант процессорного времени. Рис. 6-21. Планирование потоков в момент завершения кванта текущего потока Завершение потока Завершаясь (после возврата из основной процедуры и вызова ExitThread или из&за уничтожения вызовом TerminateThread), поток переходит в состояние Terminated. Если в этот момент ни один описатель его объекта «поток» не открыт, поток удаляется из списка потоков процесса, и соответствующие структуры данных освобождаются. Переключение контекста Контекст потока и процедура его переключения зависят от архитектуры процессора. В типичном случае переключение контекста требует сохране& ния и восстановления следующих данных: 쐽 указателя команд; 쐽 указателей на стек ядра и пользовательский стек; 쐽 указателя на адресное пространство, в котором выполняется поток (ка& талог таблиц страниц процесса). Ядро сохраняет эту информацию, заталкивая ее в текущий стек ядра, об& новляя указатель стека и сохраняя его в блоке KTHREAD потока. Далее ука& затель стека ядра устанавливается на стек ядра нового потока и загружается контекст этого потока. Если новый поток принадлежит другому процессу, в
366 ГЛ А В А 6 БЕЗОПАСНОСТЬ специальный регистр процессора загружается адрес его каталога таблиц страниц, в результате чего адресное пространство этого процесса становит& ся доступным (о трансляции адресов см. в главе 7). При наличии отложен& ной APC ядра запрашивается прерывание IRQL уровня 1. В ином случае уп& равление передается загруженному для нового потока указателю команд, и выполнение этого потока возобновляется. Поток простоя Если нет ни одного потока, готового к выполнению на процессоре, Windows подключает к данному процессору поток простоя (процесса Idle). Для каж& дого процессора создается свой поток простоя. Разные утилиты для просмотра процессов в Windows по&разному назы& вают процесс Idle. Диспетчер задач и Process Explorer обозначают его как «System Idle Process», Process Viewer — как «Idle», Pstat — как «Idle Process», Process Explode и Tlist — как «System Process», а Qslice — как «SystemProcess». Windows сообщает, что приоритет потока простоя равен 0. Но на самом деле у него вообще нет уровня приоритета, поскольку он выполняется лишь в отсутствие других потоков. (Вспомните, что на нулевом уровне приоритета в Windows работает лишь поток обнуления страниц; см. главу 7.) Холостой цикл, работающий при IRQL уровня «DPC/dispatch», просто зап& рашивает задания, например на доставку отложенных DPC или на поиск потоков, подлежащих диспетчеризации. Хотя последовательность работы потока простоя зависит от архитектуры, он все равно выполняет следующие действия. 1. Включает и отключает прерывания (тем самым давая возможность дос& тавить отложенные прерывания). 2. Проверяет, нет ли у процессора незавершенных DPC (см. главу 3). Если таковые есть, сбрасывает отложенное программное прерывание и достав& ляет эти DPC. 3. Проверяет, выбран ли какой&нибудь поток для выполнения на данном процессоре, и, если да, организует его диспетчеризацию. 4. Вызывает из HAL процедуру обработки процессора в простое (если нуж& но выполнить какие&либо функции управления электропитанием). В Windows Server 2003 поток простоя также проверяет наличие потоков, ожидающих выполнения на других процессорах, но об этом пойдет речь в разделе по планированию потоков в многопроцессорных системах. Динамическое повышение приоритета Windows может динамически повышать значение текущего приоритета по& тока в одном из пяти случаев: 쐽 после завершения операций ввода&вывода; 쐽 по окончании ожидания на событии или семафоре исполнительной си& стемы;
ГЛАВА 9 Процессы, потоки и задания 367 쐽 по окончании операции ожидания потоками активного процесса; 쐽 при пробуждении GUI&потоков из&за операций с окнами; 쐽 если поток, готовый к выполнению, задерживается из&за нехватки про& цессорного времени. Динамическое повышение приоритета предназначено для оптимизации общей пропускной способности и отзывчивости системы, а также для уст& ранения потенциально «нечестных» сценариев планирования. Однако, как и любой другой алгоритм планирования, динамическое повышение приори& тета — не панацея, и от него выигрывают не все приложения. ПРИМЕЧАНИЕ Windows никогда не увеличивает приоритет потоков в диапазоне реального времени (16–31). Поэтому планирование таких потоков по отношению к другим всегда предсказуемо. Windows считает: тот, кто использует приоритеты реального времени, знает, что делает. Динамическое повышение приоритета после завершения ввода-вывода Windows временно повышает приоритет потоков по окончании определен& ных операций ввода&вывода, поэтому у потоков, ожидавших завершения та& ких операций, больше шансов немедленно возобновить выполнение и об& работать полученные данные. Вспомните: после пробуждения потока остав& шийся у него квант уменьшается на одну единицу, так что потоки, ожидав& шие завершения ввода&вывода, не получают неоправданных преимуществ. Хотя рекомендованные приращения в результате динамического повышения приоритета определены в заголовочных файлах DDK (ищите строки «#define IO» в Wdm.h или Ntddk.h; эти же значения перечислены в табли& це 6&17), реальное приращение определяется драйвером устройства. Именно драйвер устройства указывает — через функцию ядра IoCompleteRequest — на необходимость динамического повышения приоритета после выполнения запроса на ввод&вывод. Заметьте, что для запросов на ввод&вывод, адресован& ных устройствам, которые гарантируют меньшее время отклика, предусмат& риваются бóльшие приращения приоритета. Таблица 6-17. Рекомендованные приращения приоритета Устройство Приращение приоритета Диск, CD&ROM, параллельный порт, видео 1 Сеть, почтовый ящик, именованный канал, последовательный порт 2 Клавиатура, мышь 6 Звуковая плата 8 Приоритет потока всегда повышается относительно базового, а не теку& щего уровня. Как показано на рис. 6&22, после динамического повышения приоритета поток в течение одного кванта выполняется с повышенным уровнем приоритета, после чего приоритет снижается на один уровень и потоку выделяется еще один квант. Этот цикл продолжается до тех пор, пока
368 ГЛ А В А 6 БЕЗОПАСНОСТЬ приоритет не снизится до базового. Поток с более высоким приоритетом все равно может вытеснить поток с повышенным приоритетом, но прерванный поток должен полностью отработать свой квант с повышенным приорите& том до того, как этот приоритет начнет понижаться. Рис. 6-22. Динамическое изменение приоритета Как уже отмечалось, динамическое повышение приоритета применяется только к потокам с приоритетом динамического диапазона (0–15). Незави& симо от приращения приоритет потока никогда не будет больше 15. Иначе говоря, если к потоку с приоритетом 14 применить динамическое повыше& ние на 5 уровней, его приоритет возрастет лишь до 15. Если приоритет по& тока равен 15, он остается неизменным при любой попытке его повышения. Динамическое повышение приоритета по окончании ожидания событий и семафоров Когда ожидание потока на событии исполнительной системы или объекте «семафор» успешно завершается (из&за вызова SetEvent, PulseEvent или Relea seSemaphore), его приоритет повышается на 1 уровень (см. значения EVENT_ INCREMENT и SEMAPHORE_INCREMENT в заголовочных файлах DDK). При& чина повышения приоритета потоков, закончивших ожидание событий или семафоров, та же, что и для потоков, ожидавших окончания операций вво& да&вывода: потокам, блокируемым на событиях, процессорное время требу& ется реже, чем остальным. Такая регулировка позволяет равномернее распре& делять процессорное время. В данном случае действуют те же правила динамического повышения приоритета, что и при завершении операций ввода&вывода (см. предыдущий раздел). К потокам, которые пробуждаются в результате установки события вызо& вом специальных функций NtSetEventBoostPriority (используется в Ntdll.dll для критических секций) и KeSetEventBoostPriority (используется для ресурсов исполнительной системы и блокировок с заталкиванием указателя) повыше& ние приоритета применяется особым образом. Если поток с приоритетом
ГЛАВА 9 Процессы, потоки и задания 369 13 или ниже, ждущий на событии, пробуждается в результате вызова специ& альной функции, его приоритет повышается до приоритета потока, устано& вившего событие, плюс 1. Если длительность его кванта меньше 4 единиц, она приравнивается 4 единицам. Исходный приоритет восстанавливается по истечении этого кванта. Динамическое повышение приоритета потоков активного процесса после выхода из состояния ожидания Всякий раз, когда поток в активном процессе завершает ожидание на объек& те ядра, функция ядра KiUnwaitThread динамически повышает его текущий (не базовый) приоритет на величину текущего значения PsPrioritySeparation. (Какой процесс является активным, определяет подсистема управления ок& нами.) Как было сказано в разделе «Управление величиной кванта» ранее в этой главе, PsPrioritySeparation представляет собой индекс в таблице квантов (байтовом массиве), с помощью которой выбираются величины квантов для потоков активных процессов. Однако в данном случае PsPrioritySeparation используется как значение, на которое повышается приоритет. Это увеличивает отзывчивость интерактивного приложения по оконча& нии ожидания. В результате повышаются шансы на немедленное возобнов& ление его потока — особенно если в фоновом режиме выполняется несколь& ко процессов с тем же базовым приоритетом. В отличие от других видов динамического повышения приоритета этот поддерживается всеми системами Windows, и его нельзя отключить даже через Windows&функцию SetThreadPriorityBoost. ЭКСПЕРИМЕНТ: наблюдение за динамическим изменением приоритета потока активного процесса Увидеть механизм повышения приоритета в действии позволяет ути& лита CPU Stress (входит в состав ресурсов и Platform SDK). 1. В окне Control Panel (Панель управления) откройте апплет System (Система) или щелкните правой кнопкой мыши значок My Com& puter (Мой компьютер), выберите команду Properties (Свойства) и перейдите на вкладку Advanced (Дополнительно). Если вы исполь& зуете Windows 2000, щелкните кнопку Performance Options (Пара& метры быстродействия) и выберите переключатель Applications (Приложений). В случае Windows XP или Windows Server 2003 щел& кните кнопку Options (Параметры) в разделе Performance (Быстро& действие), откройте вкладку Advanced (Дополнительно) и выбери& те переключатель Programs (Программ). В итоге PsPrioritySeparation получит значение 2. 2. Запустите Cpustres.exe. 3. Запустите Windows NT 4 Performance Monitor (Perfmon4.exe на ком& пакт&диске ресурсов Windows 2000). Для эксперимента нужна имен& см. след. стр.
370 ГЛ А В А 6 БЕЗОПАСНОСТЬ но эта устаревшая версия, поскольку она способна запрашивать значения счетчиков производительности с более высокой часто& той, чем оснастка Performance (Производительность), которая зап& рашивает такие значения не чаще, чем раз в секунду. 4. Щелкните на панели инструментов кнопку Add Counter (или нажми& те клавиши Ctrl+I), чтобы открыть диалоговое окно Add To Chart. 5. Выберите объект Thread и счетчик Priority Current. 6. Пролистайте список Instance и найдите процесс Cpustres. Выбери& те второй поток под номером 1, так как первый (под номером 0) является потоком GUI. 7. Щелкните кнопку Add, затем — кнопку Done. 8. Из меню Options выберите команду Chart. Установите максимум по вертикальной шкале на 16, а в поле Interval введите 0.010 и щелк& ните кнопку ОК. 9. Теперь активизируйте процесс Cpustres. В результате приоритет потока Cpustres должен повыситься на 2 уровня, а потом снизить& ся до базового, как показано на следующей иллюстрации.
ГЛАВА 9 Процессы, потоки и задания 371 10. Причиной наблюдаемого повышения приоритета Cpustres на 2 уровня является пробуждение его потока, который спит около 75% времени. Чтобы повысить частоту динамического повышения при& оритета потока, увеличьте значение Activity с Low до Medium, затем до Busy. Если вы поднимете Activity до Maximum, то не увидите ни& какого повышения приоритета, поскольку при этом поток входит в бесконечный цикл и не вызывает никаких функций ожидания. А значит, его приоритет будет оставаться неизменным. 11. Закончив эксперимент, закройте Performance Monitor и CPU Stress. Динамическое повышение приоритета после пробуждения GUI-потоков Приоритет потоков, владеющих окнами, дополнительно повышается на 2 уровня после их пробуждения из&за активности подсистемы управления ок& нами, например при получении оконных сообщений. Подсистема управле& ния окнами (Win32k.sys) повышает приоритет, вызывая KeSetEvent для уста& новки события, пробуждающего GUI&поток. Приоритет повышается по той же причине, что и в предыдущем случае, — для создания преимуществ ин& терактивным приложениям. ЭКСПЕРИМЕНТ: наблюдаем динамическое повышение приоритета GUI-потоков Чтобы увидеть, как подсистема управления окнами повышает на 2 уров& ня приоритет GUI&потоков, пробуждаемых для обработки оконных со& общений, понаблюдайте за текущим приоритетом GUI&приложения, перемещая мышь в пределах его окна. Для этого сделайте вот что. 1. В окне Control Panel (Панель управления) откройте апплет System (Система) или щелкните правой кнопкой мыши значок My Compu& см. след. стр.
372 ГЛ А В А 6 БЕЗОПАСНОСТЬ ter (Мой компьютер), выберите команду Properties (Свойства) и перейдите на вкладку Advanced (Дополнительно). Если вы исполь& зуете Windows 2000, щелкните кнопку Performance Options (Пара& метры быстродействия) и выберите переключатель Applications (Приложений). В случае Windows XP или Windows Server 2003 щел& кните кнопку Options (Параметры) в разделе Performance (Быстро& действие), откройте вкладку Advanced (Дополнительно) и выбери& те переключатель Programs (Программы). В итоге PsPrioritySepara tion получит значение 2. 2. Запустите Notepad, выбрав из меню Start (Пуск) команды Programs (Программы), Accessories (Стандартные) и Notepad (Блокнот). 3. Запустите Windows NT 4 Performance Monitor (Perfmon4.exe на ком& пакт&диске ресурсов Windows 2000). Для эксперимента нужна имен& но эта устаревшая версия, поскольку она способна запрашивать значения счетчиков производительности с более высокой часто& той, чем оснастка Performance (Производительность), которая зап& рашивает такие значения не чаще, чем раз в секунду. 4. Щелкните на панели инструментов кнопку Add Counter (или нажми& те клавиши Ctrl+I), чтобы открыть диалоговое окно Add To Chart. 5. Выберите объект Thread и счетчик Priority Current. 6. Пролистайте список Instance и найдите процесс Notepad. Выбери& те поток 0, щелкните кнопку Add, а затем — кнопку Done. 7. Как и в предыдущем эксперименте, выберите из меню Options ко& манду Chart. Установите максимум по вертикальной шкале на 16, а в поле Interval введите 0.010 и щелкните кнопку ОК. 8. В итоге вы должны увидеть, как колеблется приоритет нулевого потока Notepad (от 8 до 10). Поскольку Notepad — вскоре после повышения его приоритета (как потока активного процесса) на 2 уровня — перешел в состояние ожидания, его приоритет мог не успеть снизиться с 10 до 9 или до 8. 9. Активизировав окно Performance Monitor, подвигайте курсор мыши в окне Notepad (но сначала расположите эти окна на рабочем сто& ле так, чтобы они оба были видны). Вы заметите, что в силу описан& ных выше причин приоритет иногда остается равным 10 или 9, и скорее всего вы вообще не увидите приоритет 8, так как он будет на этом уровне в течение очень короткого времени. 10. Теперь сделайте активным окно Notepad. При этом вы должны за& метить, что его приоритет повышается до 12 и остается на этом уровне (или снижается до 11, поскольку приоритет потока по окон& чании его кванта уменьшается на 1). Почему приоритет потока Notepad достигает такого значения? Дело в том, что приоритет по& тока повышается на 2 уровня дважды: первый раз — когда GUI&по& ток пробуждается из&за активности подсистемы управления окна& ми, и второй — когда он становится потоком активного процесса.
ГЛАВА 9 Процессы, потоки и задания 373 11. Если после этого вы снова подвигаете курсор мыши в окне Notepad (пока оно активно), то, возможно, заметите падение приоритета до 11 (или даже до 10) из&за динамического снижения приоритета потока по истечении кванта. Но приоритет этого потока все рав& но превышает базовый на 2 уровня, так как процесс Notepad оста& ется активным до тех пор, пока активно его окно. 12. Закончив эксперимент, закройте Performance Monitor и Notepad. Динамическое повышение приоритета при нехватке процессорного времени Представьте себе такую ситуацию: поток с приоритетом 7 постоянно вытес& няет поток с приоритетом 4, не давая ему возможности получить процессор& ное время; при этом поток с приоритетом 11 ожидает какой&то ресурс, заб& локированный потоком с приоритетом 4. Но, поскольку поток с приорите& том 7 занимает все процессорное время, поток с приоритетом 4 никогда не получит процессорное время, достаточное для завершения и освобождения ресурсов, нужных потоку с приоритетом 11. Что же делает Windows в подоб& ной ситуации? Раз в секунду диспетчер настройки баланса (balance set mana& ger), системный поток, предназначенный главным образом для выполнения функций управления памятью (см. главу 7), сканирует очереди готовых по& токов и ищет потоки, которые находятся в состоянии Ready в течение при& мерно 4 секунд. Обнаружив такой поток, диспетчер настройки баланса по& вышает его приоритет до 15. В Windows 2000 и Windows XP квант потока удваивается относительно кванта процесса. В Windows Server 2003 квант ус& танавливается равным 4 единицам. Как только квант истекает, приоритет потока немедленно снижается до исходного уровня. Если этот поток не ус& пел закончить свою работу и если другой поток с более высоким приорите& том готов к выполнению, то после снижения приоритета он возвращается в очередь готовых потоков. В итоге через 4 секунды его приоритет может быть снова повышен. На самом деле диспетчер настройки баланса не сканирует при каждом запуске все потоки, готовые к выполнению. Чтобы свести к минимуму рас& ход процессорного времени, он сканирует лишь 16 готовых потоков. Если таких потоков с данным уровнем приоритета более 16, он запоминает тот поток, перед которым он остановился, и в следующий раз продолжает ска& нирование именно с него. Кроме того, он повышает приоритет не более чем у 10 потоков за один проход. Обнаружив 10 потоков, приоритет которых следует повысить (что говорит о необычайно высокой загруженности сис& темы), он прекращает сканирование. При следующем проходе сканирование возобновляется с того места, где оно было прервано в прошлый раз. Всегда ли данный алгоритм решает проблемы, связанные с приоритета& ми? Вовсе нет — он тоже не совершенен. Но со временем потоки, страдаю& щие от нехватки процессорного времени, обязательно получают время, до& статочное для завершения обработки текущих данных и возврата в состоя& ние ожидания.
374 ГЛ А В А 6 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: динамическое повышение приоритетов при нехватке процессорного времени Утилита CPU Stress (она входит в состав ресурсов и Platform SDK) по& зволяет наблюдать, как работает механизм динамического повышения приоритетов. В этом эксперименте мы увидим, как изменяется интен& сивность использования процессора при повышении приоритета по& тока. Для этого проделайте следующие операции. 1. Запустите Cpustres.exe. Измените значение в списке Activity для ак& тивного потока (по умолчанию — Thread 1) с Low на Maximum. Да& лее смените приоритет потока с Normal на Below Normal. При этом окно утилиты должно выглядеть так: 2. Запустите Windows NT 4 Performance Monitor (Perfmon4.exe на ком& пакт&диске ресурсов Windows 2000). Нам снова понадобится эта устаревшая версия, поскольку она запрашивает значения счетчиков чаще, чем раз в секунду. 3. Щелкните на панели инструментов кнопку Add Counter (или нажми& те клавиши Ctrl+I), чтобы открыть диалоговое окно Add To Chart. 4. Выберите объект Thread и счетчик % Processor Time. 5. Пролистайте список Instance и найдите процесс Cpustres. Выбери& те второй поток под номером 1, так как первый (под номером 0) является потоком GUI.
ГЛАВА 9 Процессы, потоки и задания 375 6. Щелкните кнопку Add, затем — кнопку Done. 7. Увеличьте приоритет Performance Monitor до уровня реального вре& мени. Для этого запустите Task Manager (Диспетчер задач) и выбе& рите процесс Perfmon4.exe на вкладке Processes (Процессы). Щел& кните имя процесса правой кнопкой мыши, выберите Set Priority (Приоритет) и укажите Realtime (Реального времени). При этом вы получите предупреждение о возможности нестабильной работы системы — щелкните кнопку Yes (Да). 8. Запустите еще один экземпляр CPU Stress. Измените в нем параметр Activity для Thread 1 с Low на Maximum. 9. Теперь переключитесь обратно в Performance Monitor. Вы должны наблюдать всплески активности процессора примерно каждые 4 секунды, так как приоритет потока возрос до 15. Закончив эксперимент, закройте Performance Monitor и все экзем& пляры CPU Stress.
376 ГЛ А В А 6 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: «прослушивание» динамического повышения приоритета Чтобы «услышать» эффект динамического повышения приоритета потока при нехватке процессорного времени, в системе со звуковой платой выполните следующие операции. 1. Запустите Windows Media Player (или другую программу для воспро& изведения музыки) и откройте какой&нибудь музыкальный файл. 2. Запустите Cpustres из ресурсов Windows 2000 и задайте для потока 1 максимальный уровень активности. 3. Повысьте приоритет потока 1 с Normal до Time Critical. 4. Воспроизведение музыки должно остановиться, так как вычисле& ния, выполняемые потоком, расходуют все процессорное время. 5. Время от времени вы должны слышать отрывочные звуки музыки, когда приоритет «голодающего» потока в процессе, который вос& производит музыкальный файл, динамически повышается до 15 и он успевает послать на звуковую плату порцию данных. 6. Закройте Cpustres и Windows Media Player. Многопроцессорные системы В однопроцессорной системе алгоритм планирования относительно прост: всегда выполняется поток с наивысшим приоритетом, готовый к выполне& нию. В многопроцессорной системе планирование усложняется, так как Windows пытается подключать поток к наиболее оптимальному для него процессору, учитывая предпочтительный и предыдущий процессоры для этого потока, а также конфигурацию многопроцессорной системы. Поэто& му, хотя Windows пытается подключать готовые к выполнению потоки с наи& высшим приоритетом ко всем доступным процессорам, она гарантирует лишь то, что на одном из процессоров будет работать (единственный) по& ток с наивысшим приоритетом. Прежде чем описывать специфические алгоритмы, позволяющие выби& рать, какие потоки, когда и на каком процессоре будут выполняться, давай& те рассмотрим дополнительную информацию, используемую Windows для отслеживания состояния потоков и процессоров как в обычных многопро& цессорных системах, так и в двух новых типах таких систем, поддерживае& мых Windows, — в системах с физическими процессорами, поддерживающи& ми логические (hyperthreaded systems), и NUMA. База данных диспетчера ядра в многопроцессорной системе Как уже говорилось в разделе «База данных диспетчера ядра» ранее в этой главе, в такой базе данных хранится информация, поддерживаемая ядром и необходимая для планирования потоков. В многопроцессорных системах Windows 2000 и Windows XP (рис. 6&15) очереди готовых потоков и сводка готовых потоков имеют ту же структуру, что и в однопроцессорных систе&
ГЛАВА 9 Процессы, потоки и задания 377 мах. Кроме того, Windows поддерживает две битовые маски для отслежива& ния состояния процессоров в системе. (Как используются эти маски, см. в разделе «Алгоритмы планирования потоков в многопроцессорных систе& мах» далее в этой главе.) Вот что представляют собой эти маски. 쐽 Маска активных процессоров (KeActiveProcessors), в которой устанавли& ваются биты для каждого используемого в системе процессора. (Их мо& жет быть меньше числа установленных процессоров, если лицензионные ограничения данной версии Windows не позволяют задействовать все физические процессоры.) 쐽 Сводка простоя (idle summary) (KiIdleSummary), в которой каждый уста& новленный бит представляет простаивающий процессор. Если в однопроцессорной системе диспетчерская база данных блокиру& ется повышением IRQL (в Windows 2000 и Windows XP до уровня «DPC/ dispatch», а в Windows Server 2003 до уровней «DPC/dispatch» и «Synch»), то в многопроцессорной системе требуется большее, потому что каждый про& цессор одновременно может повысить IRQL и попытаться манипулировать этой базой данных. (Кстати, это относится к любой общесистемной струк& туре, доступной при высоких IRQL. Общее описание синхронизации режи& ма ядра и спин&блокировок см. в главе 3.) В Windows 2000 и Windows XP для синхронизации доступа к информации о диспетчеризации потока приме& няется две спин&блокировки режима ядра: спинблокировка диспетчера ядра (dispatcher spinlock) (KiDispatcherLock) и спинблокировка обмена кон текста (context swap spinlock) (KiContextSwapLock). Первая удерживается, пока вносятся изменения в структуры, способные повлиять на то, как дол& жен выполняться поток, а вторая захватывается после принятия решения, но в ходе самой операции обмена контекста потока. Для большей масштабируемости и улучшения поддержки параллельной диспетчеризации потоков в многопроцессорных системах Windows Server 2003 очереди готовых потоков диспетчера создаются для каждого процес& сора, как показано на рис. 6&23. Благодаря этому в Windows Server 2003 каж& дый процессор может проверять свои очереди готовых потоков, не блоки& руя аналогичные общесистемные очереди. Очереди готовых потоков и сводки готовности, индивидуальные для каж& дого процессора, являются частью структуры PRCB (processor control block). (Чтобы увидеть поля этой структуры, введите dt nt!_prcb в отладчике ядра.) Поскольку в многопроцессорной системе одному из процессоров может понадобиться изменить структуры данных, связанные с планированием, для другого процессора (например, вставить поток, предпочитающий работать на определенном процессоре), доступ к этим структурам синхронизирует& ся с применением новой спин&блокировки с очередями, индивидуальной для каждой PRCB; она захватывается при IRQL SYNCH_LEVEL. (Возможные зна& чения SYNCH_LEVEL см. в таблице 6&18.) Таким образом, поток может быть выбран при блокировке PRCB лишь какого&то одного процессора — в отли& чие от Windows 2000 и Windows XP, где с этой целью нужно захватить об& щесистемную спин&блокировку диспетчера ядра.
378 ГЛ А В А 6 БЕЗОПАСНОСТЬ Рис. 6-23. База данных диспетчера ядра в многопроцессорной системе Windows Server 2003 Таблица 6-18. IRQL SYNCH_LEVEL в многопроцессорных системах Версия Windows Количество процессоров Windows 2000 2 Windows XP на x86 2 Windows Server 2003 на x86 27 Windows XP на x64 12 Windows XP на IA&64 2 Windows Server 2003 на x64 и IA&64 12 Для каждого процессора создается и список потоков в готовом, но отло& женном состоянии (deferred ready state). Это потоки, готовые к выполнению, но операция, уведомляющая в результате об их готовности, отложена до бо& лее подходящего времени. Поскольку каждый процессор манипулирует толь& ко своим списком отложенных готовых потоков, доступ к этому списку не синхронизируется по спин&блокировке PRCB. Список отложенных готовых потоков обрабатывается до выхода из диспетчера потоков, до переключения контекста и после обработки DPC. Потоки в этом списке либо немедленно диспетчеризуются, либо перемещаются в одну из индивидуальных для каж& дого процессора очередей готовых потоков (в зависимости от приоритета).
ГЛАВА 9 Процессы, потоки и задания 379 Заметьте, что общесистемная спин&блокировка диспетчера ядра по&пре& жнему существует и используется в Windows Server 2003, но она захватыва& ется лишь на период, необходимый для модификации общесистемного со& стояния, которое может повлиять на то, какой поток будет выполняться сле& дующим. Например, изменения в синхронизирующих объектах (мьютексах, событиях и семафорах) и их очередях ожидания требуют захвата блокиров& ки диспетчера ядра, чтобы предотвратить попытки модификации таких объектов (и последующей операции перевода потоков в состояние готовно& сти к выполнению) более чем одним процессором. Другие примеры — из& менение приоритета потока, срабатывание таймера и обмен содержимого стеков ядра для потоков. Наконец, в Windows Server 2003 улучшена сихронизация переключения контекста потоков, так как теперь оно синхронизируется с применением спин&блокировки, индивидуальной для каждого потока, а в Windows 2000 и Windows XP переключение контекста синхронизировалось захватом обще& системной спин&блокировки обмена контекста. Системы с поддержкой Hyperthreading Как уже говорилось в разделе «Симметричная многопроцессорная обработ& ка» главы 2, Windows XP и Windows Server 2003 поддерживают многопроцес& сорные системы, использующие технологию Hyperthreading (аппаратная реализация логических процессоров на одном физическом). 1. Логические процессоры не подпадают под лицензионные ограничения на число физических процессоров. Так, Windows XP Home Edition, кото& рая по условиям лицензии может использовать только один процессор, задействует оба логических процессора в однопроцессорной системе с поддержкой Hyperthreading. 2. Если все логические процессоры какого&либо физического процессора простаивают, для выполнения потока выбирается один из логических процессоров этого физического процессора, а не того, у которого один из логических процессоров уже выполняет другой поток. ЭКСПЕРИМЕНТ: просмотр информации, связанной с Hyperthreading Изучить такую информацию позволяет команда !smt отладчика ядра. Следующий вывод получен в системе с двумя процессорами Xeon с технологией Hyperthreading (четыре логических процессора): lkd> !smt SMT Summary: —————— KeActiveProcessors: KiIdleSummary: No PRCB Set Master 0 ffdff120 Master 1 f771f120 Master ****—————————————— (0000000f) ***—————————————— (0000000e) SMT Set **—————————————— (00000005) 2 00 **—————————————— (0000000a) 2 06 #LP IAID см. след. стр.
380 ГЛ А В А 6 БЕЗОПАСНОСТЬ 2 f7727120 ffdff120 3 f772f120 f771f120 **—————————————— (00000005) 2 01 **—————————————— (0000000a) 2 07 Number of licensed physical processors: 2 Логические процессоры 0 и 1 находятся на разных физических процессорах (на что указывает ключевое слово «Master»). Системы NUMA Другой тип многопроцессорных систем, поддерживаемый Windows XP и Win& dows Server 2003, — архитектуры памяти с неунифицированным доступом (nonuniform memory access, NUMA). В NUMA&системе процессоры группиру& ются в узлы. В каждом узле имеются свои процессоры и память, и он подклю& чается к системе соединительной шиной с когерентным кэшем (cache&cohe& rent interconnect bus). Доступ к памяти в таких системах называется неунифи& цированным потому, что у каждого узла есть локальная высокоскоростная память. Хотя любой процессор в любом узле может обращаться ко всей па& мяти, доступ к локальной для узла памяти происходит гораздо быстрее. Ядро поддерживает информацию о каждом узле в NUMA&системе в струк& турах данных KNODE. Переменная ядра KeNodeBlock содержит массив ука& зателей на структуры KNODE для каждого узла. Формат структуры KNODE можно просмотреть командой dt отладчика ядра: lkd> dt nt!_knode nt!_KNODE +0x000 ProcessorMask : Uint4B +0x004 Color : Uint4B +0x008 MmShiftedColor : Uint4B +0x00c FreeCount : [2] Uint4B +0x018 DeadStackList : _SLIST_HEADER +0x020 PfnDereferenceSListHead : _SLIST_HEADER +0x028 PfnDeferredList : Ptr32 _SINGLE_LIST_ENTRY +0x02c Seed : UChar +0x02d Flags : _flags ЭКСПЕРИМЕНТ: просмотр информации, относящейся к NUMA Вы можете исследовать информацию, поддерживаемую Windows для каждого узла в NUMA&системе, с помощью команды !numa отладчика ядра. Ниже приведен фрагмент вывода, полученный в 32&процессор& ной NUMA&системе производства NEC с 4 процессорами в каждом узле: 21: kd> !numa NUMA Summary: —————— Number of NUMA nodes : 8 Number of Processors : 32
ГЛАВА 9 MmAvailablePages KeActiveProcessors (00000000ffffffff) Процессы, потоки и задания 381 : 0x00F70D2C : ********************************———————————————— NODE 0 (E00000008428AE00): ProcessorMask : ****—————————————————————————————— Color : 0x00000000 MmShiftedColor : 0x00000000 Seed : 0x00000000 Zeroed Page Count: 0x00000000001CF330 Free Page Count : 0x0000000000000000 NODE 1 (E00001597A9A2200): ProcessorMask : ——****———————————————————————————— Color : 0x00000001 MmShiftedColor : 0x00000040 Seed : 0x00000006 Zeroed Page Count: 0x00000000001F77A0 Free Page Count : 0x0000000000000004 А это фрагмент вывода, полученный в 64&процессорной NUMA&си& стеме производства Hewlett Packard с 4 процессорами в каждом узле: 26: kd> !numa NUMA Summary: —————— Number of NUMA nodes : 16 Number of Processors : 64 MmAvailablePages : 0x03F55E67 KeActiveProcessors : ************************************************************** ** (ffffffffffffffff) NODE 0 (E000000084261900): ProcessorMask : ****—————————————————————————————— Color : 0x00000000 MmShiftedColor : 0x00000000 Seed : 0x00000001 Zeroed Page Count: 0x00000000003F4430 Free Page Count : 0x0000000000000000 NODE 1 (E0000145FF992200): ProcessorMask : ——****———————————————————————————— Color : 0x00000001 MmShiftedColor : 0x00000040 Seed : 0x00000007 Zeroed Page Count: 0x00000000003ED59A Free Page Count : 0x0000000000000000
382 ГЛ А В А 6 БЕЗОПАСНОСТЬ Приложения, которым нужно выжать максимум производительности из NUMA&систем, могут устанавливать маски привязки процесса к процессорам в определенном узле. Получить эту информацию позволяют функции, пере& численные в таблице 6&19. (Функции, с помощью которых можно изменять привязку потоков к процессорам, были перечислены в таблице 6&14.) Таблица 6-19. Функции, связанные с NUMA Функция Описание GetNumaHighestNodeNumber Возвращает узел с наивысшим в данный момент номером GetNumaNodeProcessorMask Возвращает маску процессоров для указанного узла GetNumaProcessorNode Возвращает номер узла для указанного процессора О том, как алгоритмы планирования учитывают особенности NUMA&сис& тем, см. в разделе «Алгоритмы планирования потоков в многопроцессорных системах» далее в этой главе (а об оптимизациях в диспетчере памяти для использования преимуществ локальной для узла памяти см. в главе 7). Привязка к процессорам У каждого потока есть маска привязки к процессорам (affinity mask), указыва& ющая, на каких процессорах можно выполнять данный поток. Потоки насле& дуют маску привязки процесса. По умолчанию начальная маска для всех про& цессов (а значит, и для всех потоков) включает весь набор активных процес& соров в системе, т. е. любой поток может выполняться на любом процессоре. Однако для повышения пропускной способности и/или оптимизации рабочих нагрузок на определенный набор процессоров приложения могут изменять маску привязки потока к процессорам. Это можно сделать на не& скольких уровнях. 쐽 Вызовом функции SetThreadAffinityMask, чтобы задать маску привязки к процессорам для индивидуального потока; 쐽 Вызовом функции SetProcessAffinityMask, чтобы задать маску привязки к процессорам для всех потоков в процессе. Диспетчер задач и Process Explorer предоставляют GUI&интерфейс к этой функции: щелкните про& цесс правой кнопкой мыши и выберите Set Affinity (Задать соответствие). Утилита Psexec (с сайта www.sysinternals.com) предоставляет к той же функ& ции интерфейс командной строки (см. ключ –a). 쐽 Включением процесса в задание, в котором действует глобальная для за& дания маска привязки к процессорам, установленная через функцию SetInformationJobObject (о заданиях см. раздел «Объекты&задания» далее в этой главе.) 쐽 Определением маски привязки к процессорам в заголовке образа с помо& щью, например, утилиты Imagecfg из Windows 2000 Server Resource Kit Supplement 1. (О формате образов в Windows см. статью «Portable Execu& table and Common Object File Format Specification» в MSDN Library.)
ГЛАВА 9 Процессы, потоки и задания 383 В образе можно установить и «однопроцессорный» флаг (используя в Imagecfg ключ –u). Если этот флаг установлен, система выбирает один про& цессор в момент создания процесса и закрепляет его за этим процессом; при этом процессоры меняются от первого и до последнего по принципу кару& сели. Например, в двухпроцессорной системе при первом запуске образа, помеченного как однопроцессорный, он закрепляется за процессором 0, при втором — за процессором 1, при третьем — за процессором 0, при чет& вертом — за процессором 1 и т. д. Этот флаг полезен, когда нужно времен& но обойти ошибку в программе, связанную с неправильной синхронизаци& ей потоков, но проявляющуюся только в многопроцессорных системах. ЭКСПЕРИМЕНТ: просмотр и изменение привязки процесса к процессорам В этом эксперименте вы модифицируете привязку процесса к процес& сорам и убедитесь, что привязка наследуется новыми процессами. 1. Запустите окно командной строки (cmd.exe). 2. Запустите диспетчер задач или Process Explorer и найдите cmd.exe в списке процессов. 3. Щелкните этот процесс правой кнопкой мыши и выберите коман& ду Set Affinity (Задать соответствие). Должен появиться список про& цессоров. Например, в двухпроцессорной системе вы увидите окно, как на следующей иллюстрации. 4. Выберите подмножество доступных процессоров в системе и на& жмите OK. Теперь потоки процесса будут работать только на выб& ранных вами процессорах. 5. Запустите Notepad.exe из окна командной строки (набрав note pad.exe). 6. Вернитесь в диспетчер задач или Process Explorer и найдите новый процесс Notepad. Щелкните его правой кнопкой мыши и выбери& те Set Affinity. Вы должны увидеть список процессоров, выбранных вами для процесса cmd.exe. Это вызвано тем, что процессы насле& дуют привязки к процессорам от своего родителя.
384 ГЛ А В А 6 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: изменение маски привязки образа В этом эксперименте (который потребует доступа к многопроцессорной системе) вы измените маску привязки к процессорам для какой&нибудь программы, чтобы заставить ее работать на первом процессоре. 1. Создайте копию Cpustres.exe (эта утилита содержится в ресурсах Windows 2000). Например, если у вас есть каталог c:\temp, то в ко& мандной строке введите: copy c:\program files\resource kit\cpustres.exe c:\temp\cpustres.exe 2. Задайте маску привязки так, чтобы она заставляла потоки процес& са выполняться на процессоре 0. Для этого в командной строке (предполагается, что путь к ресурсам прописан в переменной ок& ружения PATH) введите: imagecfg a 1 c:\temp\cpustres.exe 3. Теперь запустите модифицированную Cpustres из каталога c:\temp. 4. Включите два рабочих потока и установите уровень активности обоих потоков в Maximum (не Busy). Окно Cpustres должно выгля& деть следующим образом. 5. Найдите процесс Cpustres в Process Explorer или диспетчере задач, щелкните его правой кнопкой мыши и выберите Set Affinity. Вы дол& жны увидеть, что процесс привязан к процессору 0. 6. Посмотрите общесистемное использование процессора, выбрав Show, System Information (в Process Explorer) или открыв вкладку Performance (в диспетчере задач). Если в системе нет других про& цессов, занятых интенсивными вычислениями, общая процентная
ГЛАВА 9 Процессы, потоки и задания 385 доля использования процессорного времени должна составить примерно 1/(число процессоров) (скажем, около 50% в двухпро& цессорной системе или около 25% в четырехпроцессорной), пото& му что оба потока в Cpustres привязаны к одному процессору и ос& тальные процессоры простаивают. 7. Наконец, измените маску привязки процесса Cpustres так, чтобы разрешить ему выполнение на всех процессорах. Снова проверьте общесистемное использование процессорного времени. Теперь оно должно быть 100% в двухпроцессорной системе, 50% в четы& рехпроцессорной и т. д. Windows не перемещает уже выполняемый поток с одного процессора на второй, чтобы готовый поток с маской привязки именно к первому процес& сору немедленно начал на нем работать. Рассмотрим, например, такой сце& нарий: к процессору 0 подключен поток с приоритетом 8, который может работать на любом процессоре, а к процессору 1 — поток с приоритетом 4, который тоже может выполняться на любом процессоре. Но вот готов по& ток с приоритетом 6, привязанный только к процессору 0. Что произойдет? Windows не станет переключать поток с приоритетом 8 на процессор 1 (вы& тесняя при этом поток с приоритетом 4), и поток с приоритетом 6 будет ждать освобождения процессора 0. Следовательно, изменение маски привязки для процесса или потока мо& жет привести к тому, что потоки будут получать меньше процессорного вре& мени, чем обычно, поскольку это ограничивает Windows в выборе процес& соров для данного потока. А значит, задавать маску привязки нужно с край& ней осторожностью — в большинстве ситуаций оптимальнее оставить вы& бор за самой Windows. Идеальный и последний процессоры В блоке потока ядра каждого потока хранятся номера двух особых процес& соров: 쐽 идеального (ideal processor) — предпочтительного для выполнения дан& ного потока; 쐽 последнего (last processor) — на котором поток работал в прошлый раз. Идеальный процессор для потока выбирается случайным образом при его создании с использованием зародышевого значения (seed) в блоке про& цесса. Это значение увеличивается на 1 всякий раз, когда создается новый поток, поэтому создаваемые потоки равномерно распределяются по набо& ру доступных процессоров. Например, первый поток в первом процессе в системе закрепляется за идеальным процессором 0, второй поток того же процесса — за идеальным процессором 1. Однако у следующего процесса в системе идеальный процессор для первого потока устанавливается в 1, для второго — в 2 и т. д. Благодаря этому потоки внутри каждого процесса рав& номерно распределяются между процессорами.
386 ГЛ А В А 6 БЕЗОПАСНОСТЬ Заметьте: здесь предполагается, что потоки внутри процесса выполняют равные объемы работы. Но в многопоточном процессе это обычно не так; в нем есть, как правило, один или более «служебных» потоков (housekeeping threads) и несколько рабочих. Поэтому, если в многопоточном приложении нужно задействовать все преимущества многопроцессорной платформы, целесообразно указывать номера идеальных процессоров для потоков вы& зовом функции SetThreadIdealProcessor. В системах с Hyperthreading следующим идеальным процессором являет& ся первый логический процессор на следующем физическом. Например, в двухпроцессорной системе с Hyperthreading логических процессоров — 4; если для первого потока идеальным процессором назначен логический про& цессор 0, то для второго потока имело бы смысл назначить таковым логи& ческий процессор 2, для третьего — логический процессор 1, для четверто& го — логический процессор 3 и т. д. Тогда потоки равномерно распределя& лись бы по физическим процессорам. В NUMA&системах идеальный узел для процесса выбирается при его (про& цесса) создании. Первому процессу назначается узел 0, второму — 1 и т. д. Затем идеальные процессоры для потоков процесса выбираются из идеаль& ного узла. Идеальным процессором для первого потока в процессе назнача& ется первый процессор в узле. По мере создания дополнительных потоков в процессе за ними закрепляется тот же идеальный узел; следующий процес& сор в этом узле становится идеальным для следующего потока и т. д. Алгоритмы планирования потоков в многопроцессорных системах Теперь, описав типы многопроцессорных систем, поддерживаемых Win& dows, а также привязку потоков к процессорам и выбор идеального процес& сора, мы готовы объяснить вам применение этой информации при опреде& лении того, какие потоки выполняются и на каких процессорах. При этом система принимает два базовых решения: 쐽 выбор процессора для потока, который готов к выполнению; 쐽 выбор потока для конкретного процессора. Выбор процессора для потока при наличии простаивающих процессоров Как только поток готов к выполнению, Windows сначала пытается подклю& чить его к простаивающему процессору. Если таких процессоров несколь& ко, предпочтение отдается сначала идеальному процессору для данного по& тока, затем предыдущему, а потом текущему (т. е. процессору, на котором работает код, отвечающий за планирование). В Windows 2000, если все эти процессоры заняты, выбирается первый простаивающий процессор, на ко& тором может работать данный поток, для чего сканируется маска свободных процессоров в направлении убывания их номеров. В Windows XP и Windows Server 2003 выбор простаивающего процессо& ра не так прост. Во&первых, выделяются простаивающие процессоры из чис&
ГЛАВА 9 Процессы, потоки и задания 387 ла тех, на которых маска привязки разрешает выполнение данного потока. Если система имеет архитектуру NUMA и в узле, где находится идеальный процессор для потока, есть простаивающие процессоры, то список всех простаивающих процессоров уменьшается до этого набора. Если в резуль& тате такой операции в списке не останется простаивающих процессоров, список не сокращается. Затем, если в системе работают процессоры с тех& нологией Hyperthreading и имеется физический процессор, все логические процессоры которого свободны, список простаивающих процессоров умень& шается до этого набора. И вновь, если в результате такой операции в списке не останется простаивающих процессоров, список не сокращается. Если текущий процессор (тот, который пытается определить, что делать с потоком, готовым к выполнению) относится к набору оставшихся проста& ивающих процессоров, поток планируется к выполнению именно на этом процессоре. А если текущий процессор не входит в список оставшихся про& стаивающих процессоров, если это система с технологией Hyperthreading и если есть простаивающий логический процессор на физическом, который содержит идеальный процессор для данного потока, то список простаива& ющих процессоров ограничивается этим набором. В ином случае система проверяет, имеются ли простаивающие логические процессоры на физичес& ком, который содержит предыдущий процессор потока. Если такой набор не пуст, список простаивающих процессоров уменьшается до этого набора. Из оставшегося набора простаивающих процессоров исключаются все процессоры, находящиеся в состоянии сна. (Эта операция не выполняется, если в ее результате такой список опустел бы.) Наконец, поток подключает& ся к процессору с наименьшим номером в оставшемся списке. Независимо от версии Windows, как только процессор выбран, соответ& ствующий поток переводится в состояние Standby, и PRCB простаивающего процессора обновляется так, чтобы указывать на этот поток. При выполне& нии на этом процессоре цикл простоя обнаруживает, что поток выбран и подключает его к процессору. Выбор процессора для потока в отсутствие простаивающих процессоров Если простаивающих процессоров нет в момент, когда готовый к выполне& нию поток переведен в состояние Standby, Windows проверяет приоритет выполняемого потока (или того, который находится в состоянии Standby) и идеальный процессор для него, чтобы решить, следует ли вытеснить вы& полняемый. В Windows 2000 маска привязки может исключить идеальный процессор. (В Windows XP такое не допускается.) Если этот процессор не входит в маску привязки потока, Windows выбирает для потока процессор с наибольшим номером. Если для идеального процессора уже выбран поток, ожидающий в состо& янии Standby выделения процессорного времени, и его приоритет ниже, чем потока, готовящегося к выполнению, последний вытесняет первый и стано& вится следующим выполняемым на данном процессоре. Если к процессору уже подключен какой&то поток, Windows сравнивает приоритеты текущего
388 ГЛ А В А 6 БЕЗОПАСНОСТЬ и нового потока. Если приоритет текущего меньше, чем нового, первый по& мечается как подлежащий вытеснению, и Windows ставит в очередь межпро& цессорное прерывание, чтобы целевой процессор вытеснил текущий поток в пользу нового. ПРИМЕЧАНИЕ Windows сравнивает приоритеты текущего и следую& щего потоков не на всех процессорах, а только на одном, выбранном по только что описанным правилам. Если вытеснение подключенно& го к данному процессору потока невозможно, новый поток помеща& ется в очередь готовых потоков, соответствующую его уровню при& оритета, где он и ждет выделения процессорного времени. Поэтому Windows не гарантирует первоочередное выполнение всех потоков с наивысшим приоритетом, но всегда выполняет один поток с таким приоритетом. Как мы уже сказали, если готовый поток нельзя выполнить немедленно, он помещается в очередь готовых потоков и ждет выделения процессорно& го времени. Однако в Windows Server 2003 потоки всегда помещаются в оче& реди готовых потоков на своих идеальных процессорах. Выбор потока для выполнения на конкретном процессоре (Windows 2000 и Windows XP) В некоторых случаях (например, когда поток входит в состояние ожидания, снижает свой приоритет, изменяет привязку, откладывает выполнение или передает управление) Windows нужно найти новый поток для подключения к процессору, на котором работал текущий поток. Как уже говорилось, в од& нопроцессорной системе Windows просто выбирает первый поток из непу& стой очереди готовых потоков с наивысшим приоритетом. Но в многопро& цессорной системе Windows 2000 или Windows XP должно быть соблюде& но одно из дополнительных условий: 쐽 поток уже выполнялся в прошлый раз на данном процессоре; 쐽 данный процессор должен быть идеальным для этого потока; 쐽 поток провел в состоянии Ready более трех тактов системного таймера; 쐽 поток имеет приоритет не менее 24. Таким образом, потоки с жесткой привязкой, в маску которых данный процессор не входит, очевидно, пропускаются. Если потоков, отвечающих одному из условий, нет, Windows отберет поток из начала той очереди го& товых потоков, с которой она начинает поиск. Почему так важно подключить поток именно к тому процессору, на ко& тором он выполнялся в прошлый раз? Как обычно, все дело в быстродей& ствии — процессор, на котором поток выполнялся в прошлый раз, скорее всего еще хранит его данные в своем кэше второго уровня.
ГЛАВА 9 Процессы, потоки и задания 389 Выбор потока для выполнения на конкретном процессоре (Windows Server 2003) Поскольку в Windows Server 2003 у каждого процессора собственный спи& сок потоков, ждущих выполнения на этом процессоре, то по окончании выполнения текущего потока процессор просто проверяет свою очередь готовых потоков. Если его очереди пусты, к процессору подключается по& ток простоя. Затем этот поток начинает сканировать очереди готовых по& токов при других процессорах и ищет потоки, которые можно было бы вы& полнять на данном процессоре. Заметьте, что в NUMA&системах поток про& стоя проверяет процессоры сначала в своем узле, а потом в других узлах. Объекты-задания Объект «задание» (job object) — это именуемый, защищаемый и разделяемый объект ядра, обеспечивающий управление одним или несколькими процес& сами как группой. Процесс может входить только в одно задание. По умол& чанию его связь с объектом «задание» нельзя разрушить, и все процессы, создаваемые данным процессом и его потомками, будут сопоставлены с тем же заданием. Объект «задание» также регистрирует базовую учетную инфор& мацию всех включенных в него процессов, в том числе уже завершившихся. Windows&функции, предназначенные для создания объектов&заданий и ма& нипулирования ими, перечислены в таблице 6&20. Таблица 6-20. Функции Windows API для заданий Функция Описание CreateJobObject Создает объект&задание (с необязательным именем) OpenJobObject Открывает существующий объект&задание по имени AssignProcessToJobObject Включает процесс в задание TerminateJobObject Завершает все процессы в задании SetInformationJobObject Устанавливает ограничения на процессы задания QueryInformationJobObject Возвращает информацию о задании — количество использованного процессорного времени, счетчик числа ошибок страниц, число процессов, список идентификаторов процессов, квоты и лимиты защиты Ниже кратко поясняются некоторые ограничения, которые можно нала& гать на задания. 쐽 Максимальное число активных процессов новременно выполняемых процессов задания. Ограничивает число од& 쐽 Общий лимит на процессорное время в пользовательском ре жиме Ограничивает максимальное количество процессорного времени, потребляемого процессами задания (с учетом завершившихся) в поль& зовательском режиме. Как только этот лимит будет исчерпан, все процес& сы задания завершатся с сообщением об ошибке, а создание новых про& цессов в задании станет невозможным (если лимит не будет переустанов&
390 ГЛ А В А 6 БЕЗОПАСНОСТЬ лен). Объект&задание будет переведен в свободное состояние, и все ожи& давшие его потоки освободятся. Это поведение системы по умолчанию можно изменить через функцию EndOfJobTimeAction. 쐽 Индивидуальный лимит на процессорное время пользователь ского режима для каждого процесса Ограничивает максимальное количество процессорного времени, потребляемого каждым процессом в задании. По достижении этого лимита процесс завершается (не полу& чая шанса на очистку). 쐽 Класс планирования задания Устанавливает длительность кванта для потоков процессов, входящих в задание. Этот параметр применим только в системах, использующих длинные фиксированные кванты (в системах Windows Server по умолчанию). Длительность кванта определя& ется классом планирования задания, как показано в следующей таблице. Класс планирования Число квантовых единиц 0 6 1 12 2 18 3 24 4 30 5 36 6 42 7 48 8 54 9 Бесконечное для приоритета реального времени; в остальных случаях — 60 쐽 Привязка задания к процессорам Устанавливает маску привязки к процессорам для каждого процесса задания. (Отдельные потоки могут из& менять свои привязки на любое подмножество привязок задания, но про& цессы этого делать не могут.) 쐽 Класс приоритета для всех процессов задания Определяет класс приоритета для каждого процесса в задании. Потоки не могут повышать свой приоритет относительно класса (как они это обычно делают). Все по& пытки повышения приоритета игнорируются. (При вызове SetThreadPrio rity ошибка не генерируется, но и приоритет не повышается.) 쐽 Минимальный и максимальный размеры рабочего набора по умолчанию Устанавливает указанные минимальный и максимальный размеры рабочего набора для каждого процесса задания. (У каждого про& цесса свой рабочий набор, но с одинаковыми максимальным и мини& мальным размерами.) 쐽 Лимит на виртуальную память, передаваемую процессу или зада нию Указывает максимальный размер виртуального адресного простран& ства, который можно передать либо одному процессу, либо всему заданию.
ГЛАВА 9 Процессы, потоки и задания 391 Задания можно настроить на отправку в очередь объекта «порт заверше& ния ввода&вывода» какого&либо элемента, который могут ждать другие пото& ки через Windows&функцию GetQueuedCompletionStatus. Задание также позволяет накладывать на включенные в него процессы ограничения, связанные с защитой. Например, вы можете сделать так, что& бы все процессы в задании использовали один и тот же маркер доступа или не имели права олицетворять (подменять) другие процессы либо создавать процессы с маркерами доступа, включающими привилегии группы локаль& ных администраторов. Кроме того, допускается применение фильтров защи& ты, предназначенных, например, для следующих ситуаций: когда потоки процессов задания олицетворяют клиентские потоки, из их маркера олицет& ворения можно избирательно исключать некоторые привилегии и иденти& фикаторы защиты (SID). Наконец, вы можете задавать ограничения для пользовательского интер& фейса процессов задания, например запрещать открытие процессами опи& сателей окон, которыми владеют потоки, не входящие в это задание, огра& ничивать операции с буфером обмена или блокировать изменение многих параметров пользовательского интерфейса системы с помощью Windows& функции SystemParametersInfo. В Windows 2000 Datacenter Server имеется утилита Process Control Mana& ger, позволяющая администратору определять объекты «задание», устанавли& вать для них различные квоты и лимиты, а также указывать процессы, кото& рые следует включать в то или иное задание при запуске. Заметьте, что эта утилита больше не поставляется с Windows Server 2003 Datacenter Edition, но останется в системе при обновлении Windows 2000 Datacenter Server до Windows Server 2003 Datacenter Edition. ЭКСПЕРИМЕНТ: просмотр объекта «задание» Вы можете просматривать именованные объекты «задание» в оснастке Performance (Производительность). Для просмотра неименованных за& даний нужно использовать команду !job или dt nt!_ejob отладчика ядра. Выяснить, сопоставлен ли данный процесс с заданием, позволяет команда !process отладчика ядра или — в Windows XP и Windows Server 2003 — утилита Process Explorer. Чтобы создать неименованный объект «задание» и понаблюдать за ним, придерживайтесь следующей схемы. 1. Введите команду runas для создания процесса командной строки (Cmd.exe). Например, наберите runas /user:<домен>\<имя_поль зователя> cmd. Далее введите свой пароль, и на экране появится окно командной строки. Windows&сервис, выполняющий команду runas, создаст неименованное задание, включающее все процессы (они будут завершены в момент вашего выхода из системы). 2. Из командной строки запустите Notepad.exe. 3. Запустите Process Explorer и обратите внимание на то, что процес& сы Cmd.exe и Notepad.exe выделяются как часть задания. Эти два процесса показаны на следующей иллюстрации. см. след. стр.
392 ГЛ А В А 6 БЕЗОПАСНОСТЬ 4. Дважды щелкните либо процесс Cmd.exe, либо процесс Notepad.exe, чтобы открыть окно свойств. В этом окне вы увидите вкладку Job. 5. Перейдите на вкладку Job для просмотра детальных сведений о за& дании. В нашем случае с заданием не сопоставлены никакие кво& ты — в него просто включены два процесса. 6. Теперь запустите отладчик ядра в работающей системе (либо Win& Dbg в режиме локальной отладки ядра, либо LiveKd, если вы исполь& зуете Windows 2000), выведите на экран список процессов коман& дой !process и найдите в нем только что созданный процесс Cmd.exe. Затем просмотрите содержимое блока процесса, введя команду !process <идентификатор_процесса>, и найдите адрес объекта «задание». Наконец, исследуйте объект «задание» с помо& щью команды !job. Ниже приведен фрагмент вывода отладчика для этих команд в работающей системе: lkd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** ... PROCESS 8567b758 SessionId: 0 Cid: 0fc4 Peb: 7ffdf000 ParentCid: 00b0 DirBase: 1b3fb000 ObjectTable: e18dd7d0 HandleCount: 19. Image: cmd.exe PROCESS 856561a0 SessionId: 0 Cid: 0d70 Peb: 7ffdf000 ParentCid: 0fc4 DirBase: 2e341000 ObjectTable: e19437c8
ГЛАВА 9 HandleCount: 16. Процессы, потоки и задания 393 Image: notepad.exe lkd> !process 0fc4 Searching for Process with Cid == fc4 PROCESS 8567b758 SessionId: 0 Cid: 0fc4 Peb: 7ffdf000 ParentCid: 00b0 DirBase: 1b3fb000 ObjectTable: e18dd7d0 HandleCount: 19. Image: cmd.exe BasePriority ... Job lkd> !job 85557988 Job at 85557988 TotalPageFaultCount TotalProcesses ActiveProcesses TotalTerminatedProcesses LimitFlags MinimumWorkingSetSize MaximumWorkingSetSize ActiveProcessLimit PriorityClass UIRestrictionsClass SecurityLimitFlags Token 8 85557988 0 2 2 0 0 0 0 0 0 0 0 00000000 7. Наконец, используйте команду dt для просмотра объекта&задания и обратите внимание на дополнительные поля: lkd> dt nt!_ejob 85557988 nt!_EJOB +0x000 Event : _KEVENT +0x010 JobLinks : _LIST_ENTRY [ 0x805455c8  0x85797888 ] +0x018 ProcessListHead : _LIST_ENTRY [ 0x8567b8dc  0x85656324 ] +0x020 JobLock : _ERESOURCE +0x058 TotalUserTime : _LARGE_INTEGER 0x0 +0x060 TotalKernelTime : _LARGE_INTEGER 0x0 +0x068 ThisPeriodTotalUserTime : _LARGE_INTEGER 0x0 +0x070 ThisPeriodTotalKernelTime : _LARGE_INTEGER 0x0 +0x078 TotalPageFaultCount : 0 +0x07c TotalProcesses : 2 +0x080 ActiveProcesses : 2 +0x084 TotalTerminatedProcesses : 0 +0x088 PerProcessUserTimeLimit : _LARGE_INTEGER 0x0 +0x090 PerJobUserTimeLimit : _LARGE_INTEGER 0x0 +0x098 LimitFlags : 0 +0x09c MinimumWorkingSetSize : 0 +0x0a0 MaximumWorkingSetSize : 0 см. след. стр.
394 ГЛ А В А 6 +0x0a4 +0x0a8 +0x0ac +0x0b0 +0x0b4 +0x0b8 +0x0bc +0x0c0 +0x0c4 +0x0c8 +0x0cc +0x0d0 +0x0d8 +0x0e0 +0x0e8 +0x0f0 +0x0f8 +0x100 +0x108 +0x138 +0x13c +0x140 +0x144 +0x148 +0x14c +0x16c +0x174 БЕЗОПАСНОСТЬ ActiveProcessLimit : 0 Affinity : 0 PriorityClass : 0 ‘’ UIRestrictionsClass : 0 SecurityLimitFlags : 0 Token : (null) Filter : (null) EndOfJobTimeAction : 0 CompletionPort : 0x8619d8c0 CompletionKey : (null) SessionId : 0 SchedulingClass : 5 ReadOperationCount : 0 WriteOperationCount : 0 OtherOperationCount : 0 ReadTransferCount : 0 WriteTransferCount : 0 OtherTransferCount : 0 IoInfo : _IO_COUNTERS ProcessMemoryLimit : 0 JobMemoryLimit : 0 PeakProcessMemoryUsed : 0x256 PeakJobMemoryUsed : 0x1f6 CurrentJobMemoryUsed : 0x1f6 MemoryLimitsLock : _FAST_MUTEX JobSetLinks : _LIST_ENTRY [ 0x85557af4  0x85557af4 ] MemberLevel : 0 +0x178 JobFlags : 0 Резюме Мы изучили структуру процессов, потоков и заданий, узнали, как они созда& ются, а также познакомились с алгоритмами распределения процессорно& го времени в Windows. В этой главе было много ссылок на материалы, связанные с управлени& ем памятью. Поскольку потоки выполняются в адресном пространстве про& цессов, следующим предметом рассмотрения станет управление виртуаль& ной и физической памятью в Windows. Этому и посвящена глава 7.
Г Л А В А 7 Управление памятью В этой главе вы узнаете, как реализована виртуальная память в Microsoft Windows и как осуществляется управление той частью виртуальной памяти, которая находится в физической. Мы также опишем внутреннюю структу" ру диспетчера памяти и его компоненты, в том числе ключевые структуры данных и алгоритмы. Прежде чем изучать механизмы управления памятью, давайте рассмотрим базовые сервисы, предоставляемые диспетчером памя" ти, и основные концепции, такие как зарезервированная (reserved memory), переданная (committed memory) и разделяемая память (shared memory). Введение в диспетчер памяти По умолчанию виртуальный размер процесса в 32"разрядной Windows — 2 Гб. Если образ помечен как поддерживающий большое адресное пространство и система загружается со специальным ключом (о нем мы расскажем позже), 32"разрядный процесс может занимать до 3 Гб в 32"разрядной Windows и до 4 Гб в 64"разрядной. Размер виртуального адресного пространства процесса в 64"разрядной Windows составляет 7152 Гб на платформе IA64 и 8192 Гб на платформе x64. (Это значение может увеличиться в следующих выпусках 64" разрядной Windows.) Как вы видели в главе 2 (особенно в таблице 2"4), максимальный объем физической памяти, поддерживаемый Windows, варьируется от 2 до 1024 Гб в зависимости от версии и редакции Windows. Так как виртуальное адресное пространство может быть больше или меньше объема физической памяти в компьютере, диспетчер управления памятью решает две главные задачи. 쐽 Трансляция, или проецирование (mapping), виртуального адресного про" странства процесса на физическую память. Это позволяет ссылаться на корректные адреса физической памяти, когда потоки, выполняемые в кон" тексте процесса, читают и записывают в его виртуальном адресном про" странстве. Физически резидентное подмножество виртуального адресно" го пространства процесса называется рабочим набором (working set). 쐽 Подкачка части содержимого памяти на диск, когда потоки или систем" ный код пытаются задействовать больший объем физической памяти, чем тот, который имеется в наличии, и загрузка страниц обратно в физичес" кую память по мере необходимости.
396 ГЛ А В А 7 БЕЗОПАСНОСТЬ Кроме управления виртуальной памятью диспетчер памяти предоставля" ет базовый набор сервисов, на которые опираются различные подсистемы окружения Windows. К этим сервисам относится поддержка файлов, проеци" руемых в память (memory"mapped files) [их внутреннее название — объекты разделы (section objects)], памяти, копируемой при записи, и приложений, использующих большие разреженные адресные пространства. Диспетчер памяти также позволяет процессу выделять и использовать большие объе" мы физической памяти, чем можно спроецировать на виртуальное адресное пространство процесса (например, в 32"разрядных системах, в которых ус" тановлено более 4 Гб физической памяти). Соответствующий механизм по" ясняется в разделе «Address Windowing Extensions» далее в этой главе. Компоненты диспетчера памяти Диспетчер памяти является частью исполнительной системы Windows, со" держится в файле Ntoskrnl.exe и включает следующие компоненты. 쐽 Набор сервисов исполнительной системы для выделения, освобождения и управления виртуальной памятью; большинство этих сервисов доступ" но через Windows API или интерфейсы драйверов устройств режима ядра. 쐽 Обработчики ловушек трансляции недействительных адресов (transla" tion"not"valid) и нарушений доступа для разрешения аппаратно обнару" живаемых исключений, связанных с управлением памятью, а также заг" рузки в физическую память необходимых процессу страниц. 쐽 Несколько ключевых компонентов, работающих в контексте шести раз" личных системных потоков режима ядра. 쐽 Диспетчер рабочих наборов (working set manager) с приоритетом 16. Диспетчер настройки баланса (системный поток, создаваемый ядром) вызывает его раз в секунду или при уменьшении объема свободной памяти ниже определенного порогового значения. Он реализует об" щие правила управления памятью, например усечение рабочего набо" ра, старение и запись модифицированных страниц. 쐽 Поток загрузки и выгрузки стеков (process/stack swapper) с приори" тетом 23. Выгружает (outswapping) и загружает (inswapping) стеки процесса и потока. При необходимости операций со страничным файлом этот поток пробуждается диспетчером рабочих наборов и кодом ядра, отвечающим за планирование. 쐽 Подсистема записи модифицированных страниц (modified page writer) с приоритетом 17. Записывает измененные страницы, зарегистрирован" ные в списке модифицированных страниц, обратно в соответствующие страничные файлы. Этот поток пробуждается, когда возникает необхо" димость в уменьшении размера списка модифицированных страниц. 쐽 Подсистема записи спроецированных страниц (mapped page writer) с приоритетом 17. Записывает измененные страницы спроецирован" ных файлов на диск. Пробуждается, когда нужно уменьшить размер
ГЛАВА 9 Управление памятью 397 списка модифицированных страниц или когда страницы модифици" рованных файлов находятся в этом списке более 5 минут. Этот второй поток записи модифицированных страниц требуется потому, что он может генерировать ошибки страниц, в результате которых выдают" ся запросы на свободные страницы. Если бы в системе был лишь один поток записи модифицированных страниц, она могла бы перейти в бесконечное ожидание свободных страниц. 쐽 Поток сегмента разыменования (dereference segment thread) с при" оритетом 18. Отвечает за уменьшение размеров системного кэша и изменение размеров страничного файла. 쐽 Поток обнуления страниц (zero page thread) с приоритетом 0. Запол" няет нулями страницы, зарегистрированные в списке свободных стра" ниц. (В некоторых случаях обнуление памяти выполняется более ско" ростной функцией MiZeroInParallel.) Внутренняя синхронизация Как и другие компоненты исполнительной системы Windows, диспетчер памяти полностью реентерабелен и поддерживает одновременное выполне" ние в многопроцессорных системах, управляя тем, как потоки захватывают ресурсы. С этой целью диспетчер памяти контролирует доступ к собствен" ным структурам данным, используя внутренние механизмы синхронизации, например спин"блокировку и ресурсы исполнительной системы (о синхро" низирующих объектах см. главу 3). Диспетчер памяти должен синхронизировать доступ к таким общесис" темным ресурсам, как база данных номеров фреймов страниц (PFN) (конт" роль через спин"блокировку), объекты «раздел» и системный рабочий набор (контроль через спин"блокировку с заталкиванием указателя) и страничные файлы (контроль через объекты «мьютекс»). В Windows XP и Windows Server 2003 ряд таких блокировок был либо удален, либо оптимизирован, что по" зволило резко снизить вероятность конкуренции. Например, в Windows 2000 для синхронизации изменений в системном адресном пространстве и при передаче памяти применялись спин"блокировки, но, начиная с Windows XP, эти спин"блокировки были удалены, чтобы повысить масштабируемость. Индивидуальные для каждого процесса структуры данных управления памя" тью, требующие синхронизации, включают блокировку рабочего набора (удерживаемую на время внесения изменений в список рабочего набора) и блокировку адресного пространства (удерживаемую в период его измене" ния). Синхронизация рабочего набора в Windows 2000 реализована с помо" щью мьютекса, но в Windows XP и более поздних версиях применяется бо" лее эффективная блокировка с заталкиванием указателя, которая поддержи" вает как разделяемый, так и монопольный доступ. К другим операциям, в которых больше не используется захват блокиро" вок, относятся контроль квот на пулы подкачиваемой и неподкачиваемой памяти, управление передачей страниц, а также выделение и проецирование
398 ГЛ А В А 7 БЕЗОПАСНОСТЬ физической памяти через функции поддержки AWE (Address Windowing Extensions). Кроме того, блокировка, синхронизирующая доступ к структу" рам, которые описывают физическую память (база данных PFN), теперь зах" ватывается реже и удерживается в течение меньшего времени. Эти измене" ния особенно важны в многопроцессорных системах, где они позволили уменьшить частоту блокировки диспетчера памяти на период модификации со стороны другого процессора какой"либо глобальной структуры или во" обще исключить такую блокировку. Конфигурирование диспетчера памяти Как и большинство компонентов Windows, диспетчер памяти старается ав" томатически оптимизировать работу систем различных масштабов и конфи" гураций при разных уровнях загруженности. Некоторые стандартные на" стройки можно изменить через параметры в разделе реестра HKLM\SYSTEM\ CurrentControlSet\Control\Session Manager\Memory Management, но, как пра" вило, они оптимальны в большинстве случаев. Многие пороговые значения и лимиты, от которых зависит политика принятия решений диспетчером памяти, вычисляются в период загрузки системы на основе доступной памяти и типа продукта (Windows 2000 Profes" sional, Windows XP Professional и Windows XP Home Edition оптимизируется для интерактивного использования в качестве персональной системы, а си" стемы Windows Server — для поддержки серверных приложений). Эти зна" чения записываются в различные переменные ядра и впоследствии исполь" зуются диспетчером памяти. Некоторые из них можно найти поиском в Ntoskrnl.exe глобальных переменных с именами, которые начинаются с Mm и содержат слово «maximum» или «minimum». ВНИМАНИЕ Не изменяйте значения этих переменных. Как показывают результаты тестирования, автоматически вычисляемые значения обеспе" чивают оптимальное быстродействие. Их модификация может привес" ти к непредсказуемым последствиям вплоть до зависания и даже краха. Исследование используемой памяти Объекты счетчиков производительности Memory (Память) и Process (Про" цесс) открывают доступ к большей части сведений об использовании памя" ти системой и процессами. В этой главе мы нередко упоминаем счетчики, относящиеся к рассматриваемым компонентам. Кроме оснастки Performance (Производительность) информацию об ис" пользовании памяти выводят некоторые утилиты из Windows Support Tools и ресурсов Windows. Мы включили ряд примеров и экспериментов, иллюс" трирующих их применение. Но предупреждаем: одна и та же информация по"разному называется в разных утилитах. Это демонстрирует следующий эксперимент (определения упоминаемых в нем терминов будут даны в дру" гих разделах).
ГЛАВА 9 Управление памятью 399 ЭКСПЕРИМЕНТ: просмотр информации о системной памяти Базовую информацию о системной памяти можно получить на вклад" ке Performance (Быстродействие) в Task Manager (Диспетчер задач), как показано ниже (здесь используется Windows XP). Эти сведения явля" ются подмножеством информации о памяти, предоставляемой счет" чиками производительности. Как Pmon.exe (из Windows Support Tools), так и Pstat.exe (из Platform SDK) выводят сведения о памяти системы и процессов. Взгляните на об" разец вывода Pstat (определения некоторых терминов см. в таблице 7"15). см. след. стр.
400 ГЛ А В А 7 БЕЗОПАСНОСТЬ Для просмотра использованного объема памяти подкачиваемого и неподкачиваемого пулов по отдельности используйте утилиту Pool" mon, описанную в разделе «Мониторинг использования пулов». Наконец, команда !vm отладчика ядра выводит базовые сведения об управлении памятью, доступные через соответствующие счетчики производительности. Эта команда может быть полезна при изучении аварийного дампа или зависшей системы. Пример вывода этой коман" ды приводится ниже. kd> !vm *** Virtual Memory Usage *** Physical Memory: 32620 ( 130480 Page File: \??\C:\pagefile.sys Current: 204800Kb Free Space: Minimum: 204800Kb Maximum: Available Pages: 3604 ( 14416 ResAvail Pages: 24004 ( 96016 Modified Pages: 768 ( 3072 NonPagedPool Usage: 1436 ( 5744 NonPagedPool Max: 12940 ( 51760 PagedPool 0 Usage: 6817 ( 27268 PagedPool 1 Usage: 982 ( 3928 PagedPool 2 Usage: 984 ( 3936 PagedPool Usage: 8783 ( 35132 PagedPool Maximum: 26624 ( 106496 Shared Commit: 1361 ( 5444 Special Pool: 0 ( 0 Free System PTEs: 189291 ( 757164 Shared Process: 3165 ( 12660 PagedPool Commit: 8783 ( 35132 Driver Commit: 1098 ( 4392 Committed pages: 45113 ( 180452 Commit limit: 79556 ( 318224 Total Private: IEXPLORE.EXE svchost.exe WINWORD.EXE POWERPNT.EXE Acrobat.exe winlogon.exe explorer.exe livekd.exe hh.exe ... 30536 3028 2128 1971 1905 1761 1361 1300 1015 960 Kb) 101052Kb 204800Kb Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) ( 122144 Kb) ( 12112 Kb) ( 8512 Kb) ( 7884 Kb) ( 7620 Kb) ( 7044 Kb) ( 5444 Kb) ( 5200 Kb) ( 4060 Kb) ( 3840 Kb)
ГЛАВА 9 Управление памятью 401 ЭКСПЕРИМЕНТ: учет использованной физической памяти Комбинируя данные от счетчиков производительности и выходную информацию команд отладчика ядра, можно получить довольно пол" ное представление об использовании физической памяти компьюте" ра под управлением Windows. Соответствующие счетчики производи" тельности доступны через оснастку Performance. (Вам будет удобнее, если вы установите максимальное значение для вертикальной шкалы равным 1000.) 쐽 Суммарный размер рабочих наборов процессов Для про" смотра этих данных выберите объект Process (Процесс) и счетчик Working Set (Рабочее множество) для экземпляра _Total. Показыва" емое значение превышает реальный объем используемой памяти, так как разделяемые страницы учитываются в каждом рабочем на" боре процесса, использующего эти страницы. Более точную карти" ну использования памяти процессами вы получите, вычтя из обще" го объема физической памяти следующие показатели: размер сво" бодной памяти, объем памяти, занятой операционной системой (неподкачиваемый пул, резидентная часть подкачиваемого пула и резидентный код операционной системы и драйверов), а также раз" мер списка модифицированных страниц. Оставшаяся часть соот" ветствует памяти, используемой процессами. Сравнив ее размер с размером рабочего набора процесса, показываемым оснасткой Performance, можно получить намек на объем разделяемой памяти. Хотя исследование использованной физической памяти — дело весьма увлекательное, гораздо важнее знать, сколько закрытой вир" туальной памяти передано процессам, — утечки памяти проявляют" ся как увеличение объема закрытой виртуальной памяти, а не раз" мера рабочего набора. На каком"то этапе диспетчер памяти оста" новит чрезмерные аппетиты процесса, но размер виртуальной па" мяти может расти, пока не достигнет общесистемного лимита (мак" симально возможного в данной системе объема закрытой передан" ной памяти) либо лимита, установленного для задания или процес" са (если процесс включен в задание); см. раздел «Страничные фай" лы» далее в этой главе. 쐽 Суммарный размер системного рабочего набора Эти дан" ные можно увидеть, выбрав объект Memory (Память) и счетчик Cache Bytes (Байт кэш"памяти). Как поясняется в разделе «Системный ра" бочий набор», суммарный размер системного рабочего набора оп" ределяется не только размером кэша, но и подмножеством пула под" качиваемой памяти и объемом резидентного кода операционной системы и драйверов, находящегося в этом рабочем наборе. 쐽 Размер пула неподкачиваемой памяти Для просмотра этого значения выберите счетчик Memory: Pool Nonpaged Bytes (Память: Байт в невыгружаемом страничном пуле). см. след. стр.
402 ГЛ А В А 7 БЕЗОПАСНОСТЬ 쐽 Размер списков простаивающих, свободных и обнуленных страниц Общий размер этих списков сообщает счетчик Memory: Available Bytes (Память: Доступно байт). Если вы хотите узнать раз" мер каждого из списков, используйте команду !memusage отладчи" ка ядра. Теперь на графике (или в отчете) должна присутствовать информа" ция обо всей физической памяти, кроме двух элементов, о которых счетчики производительности не сообщают: 쐽 неподкачиваемого кода операционной системы и драйверов; 쐽 списка модифицированных страниц и списка модифицированных, но не записываемых страниц (modified"no"write paging list). Хотя размеры двух последних списков легко узнать с помощью ко" манды !memusage отладчика ядра, выяснить размер резидентного кода операционной системы и драйверов не так просто. Сервисы диспетчера памяти Диспетчер памяти предоставляет набор системных сервисов для выделения и освобождения виртуальной памяти, разделения памяти между процесса" ми, проецирования файлов в память, сброса виртуальных страниц на диск, получения информации о диапазоне виртуальных страниц, изменения ат" рибутов защиты виртуальных страниц и блокировки в памяти. Как и другие сервисы исполнительной системы, сервисы управления па" мятью требуют при вызове передачи описателя того процесса, с виртуаль" ной памятью которого будут проводиться операции. Таким образом, вызы" вающая программа может управлять как собственной памятью, так и памя" тью других процессов (при наличии соответствующих прав). Например, если один процесс порождает другой, у первого по умолчанию остается пра" во на манипуляции с виртуальной памятью второго. Впоследствии родитель" ский процесс может выделять и освобождать память, считывать и записывать в нее данные через сервисы управления виртуальной памятью, передавая им в качестве аргумента описатель дочернего процесса. Подсистемы использу" ют эту возможность для управления памятью своих клиентских процессов; она же является ключевой для реализации отладчиков, так как им нужен до" ступ к памяти отлаживаемого процесса для чтения и записи. Большинство этих сервисов предоставляется через Windows API. В него входят три группы прикладных функций управления памятью: для операций со страницами виртуальной памяти (Virtualxxx), проецирования файлов в память (CreateFileMapping, MapViewOfFile) и управления кучами (Heapxxx, а также функции из старых версий интерфейса — Localxxx и Globalxxx). Диспетчер памяти поддерживает такие сервисы, как выделение и осво" бождение физической памяти, блокировка страниц в физической памяти для передачи данных другим компонентам исполнительной системы режи" ма ядра и драйверам устройств через DMA. Имена этих функций начинают"
ГЛАВА 9 Управление памятью 403 ся с префикса Mm. Кроме того, существуют процедуры поддержки исполни" тельной системы, имена которых начинаются с Ex. Не являясь частью дис" петчера памяти в строгом смысле этого слова, они применяются для выде" ления и освобождения памяти из системных куч (пулов подкачиваемой и неподкачиваемой памяти), а также для манипуляций с ассоциативными списками. Мы затронем эту тематику в разделе «Системные пулы памяти» далее в этой главе. Несмотря на упоминание Windows"функций управления памятью в режи" ме ядра и выделения памяти для драйверов устройств, мы будем рассматри" вать не столько интерфейсы и особенности их программирования, сколь" ко внутренние принципы работы этих функций. Полное описание доступ" ных функций и их интерфейсов см. в документации Platform SDK и DDK. Большие и малые страницы Виртуальное адресное пространство делится на единицы, называемые стра" ницами. Это вызвано тем, что аппаратный блок управления памятью транс" лирует виртуальные адреса в физические по страницам. Поэтому страни" ца — наименьшая единица защиты на аппаратном уровне. (Различные пара" метры защиты страниц описываются в разделе «Защита памяти» далее в этой главе.) Страницы бывают двух размеров: малого и большого. Реальный раз" мер зависит от аппаратной платформы (см. таблицу 7"1). Таблица 7-1. Размеры страниц Архитектура Размер малой страницы Размер большой страницы x86 4 Кб 4 Мб (2 Мб в PAE"системах) x64 4 Кб 2 Мб IA64 8 Кб 16 Мб Преимущество больших страниц — скорость трансляции адресов для ссылок на другие данные в большой странице. Дело в том, что первая ссыл" ка на любой байт внутри большой страницы заставляет аппаратный ассоци" ативный буфер трансляции (translation look"aside buffer, TLB) (см. раздел «Ассоциативный буфер трансляции» далее в этой главе) загружать в свой кэш информацию, необходимую для трансляции ссылок на любые другие бай" ты в этой большой странице. При использовании малых страниц для того же диапазона виртуальных адресов требуется больше элементов TLB, что заставляет чаще обновлять элементы по мере трансляции новых виртуаль" ных адресов. А это в свою очередь требует чаще обращаться к структурам таблиц страниц при ссылках на виртуальные адреса, выходящие за преде" лы данной малой страницы. TLB — очень маленький кэш, и поэтому боль" шие страницы обеспечивают более эффективное использование этого ог" раниченного ресурса. Чтобы задействовать преимущества больших страниц в системах с доста" точным объемом памяти (см. минимальные размеры памяти в таблице 7"2), Windows проецирует на такие страницы базовые образы операционной сис"
404 ГЛ А В А 7 БЕЗОПАСНОСТЬ темы (Ntoskrnl.exe и Hal.dll) и базовые системные данные (например, началь" ную часть пула неподкачиваемой памяти и структуры данных, описывающие состояние каждой страницы физической памяти). Windows также автомати" чески проецирует на большие страницы запросы объемного ввода"вывода (драйверы устройств вызывают MmMapIoSpace), если запрос удовлетворяет длине и выравниванию для большой страницы. Наконец, Windows разреша" ет приложениям проецировать на такие страницы свои образы, закрытые области памяти и разделы, поддерживаемые страничным файлом (pagefile" backed sections). (См. описание флага MEM_LARGE_PAGE функции VirtualAlloc.) Вы можете указать, чтобы и другие драйверы устройств проецировались на большие страницы, добавив многострочный параметр реестра HKLM\SYS" TEM\CurrentControlSet\Control\Session Manager\Memory Management\Large" PageDrivers и задав имена драйверов как отдельные строки с нулем в конце. Таблица 7-2. Минимальные объемы физической памяти, при которых включается поддержка больших страниц Операционная система Минимальная физическая память Windows 2000 >127 Мб Windows XP, Windows Server 2003 >255 Мб Один из побочных эффектов применения больших страниц заключает" ся в следующем. Так как аппаратная защита памяти оперирует страницами как наименьшей единицей, то, если на большой странице содержатся код только для чтения и данные для записи/чтения, она должна быть помечена как доступная для чтения и записи, т. е. код станет открытым для записи. А значит, драйверы устройств или другой код режима ядра мог бы в резуль" тате скрытой ошибки модифицировать код операционной системы или драйверов, изначально предполагавшийся только для чтения, и не вызвать нарушения доступа к памяти. Однако при использовании малых страниц для проецирования ядра части NTOSKRNL.EXE и HAL.DLL только для чтения бу" дут спроецированы именно как страницы только для чтения. Хотя это сни" жает эффективность трансляции адресов, зато при попытке драйвера уст" ройства (или другого кода режима ядра) модифицировать доступную толь" ко для чтения часть операционной системы произойдет немедленный крах с указанием на неверную инструкцию. Поэтому, если вы подозреваете, что источник ваших проблем связан с повреждением кода ядра, включите Driver Verifier — это автоматически отключит использование больших страниц. Резервирование и передача страниц Страницы в адресном пространстве процесса могут быть свободными (free), зарезервированными (reserved) или переданными (committed). Приложения могут резервировать (reserve) адресное пространство и передавать память (commit) зарезервированным страницам по мере необходимости. Резерви" ровать страницы и передавать им память можно одним вызовом. Эти серви" сы предоставляются через Windowsфункции VirtualAlloc и VirtualAllocEx.
ГЛАВА 9 Управление памятью 405 Резервирование адресного пространства позволяет потоку резервировать диапазон виртуальных адресов для последующего использования. Попытка доступа к зарезервированной памяти влечет за собой нарушение доступа, так как ее страницы не спроецированы на физическую память. При попытке доступа адреса переданных страниц в конечном счете транс" лируются в допустимые адреса страниц физической памяти. Переданные стра" ницы могут быть закрытыми (не предназначенными для разделения с други" ми процессами) или спроецированными на представление объекта"раздела (на которое в свою очередь могут проецировать страницы другие процессы). Закрытые страницы процесса, к которым еще не было обращения, созда" ются при первой попытке доступа как обнуленные. Закрытые переданные страницы могут впоследствии записываться операционной системой в стра" ничный файл (в зависимости от текущей ситуации). Такие страницы недо" ступны другим процессам, если только они не используют функции Read ProcessMemory или WriteProcessMemory. Если переданные страницы спрое" цированы на часть проецируемого файла, их скорее всего придется загрузить с диска — при условии, что они не были считаны раньше из"за обращения к ним того же или другого процесса, на который спроецирован этот файл. Страницы записываются на диск по обычной процедуре записи модифи" цированных страниц, которые перемещаются из рабочего набора процес" са в список модифицированных страниц и в конечном счете на диск (о ра" бочих наборах и списке модифицированных страниц — чуть позже). Стра" ницы проецируемого файла можно сбросить на диск явным вызовом функ" ции FlushViewOfFile. Для возврата страниц (decommitting) и/или освобождения виртуальной памяти предназначена функция VirtualFree или VirtualFreeEx. Различия меж" ду возвратом и освобождением страниц такие же, как между резервировани" ем и передачей: возвращенная память все еще зарезервирована, тогда как освобожденная память действительно свободна и не является ни передан" ной, ни зарезервированной. Такой двухэтапный процесс (резервирование и передача) помогает сни" зить нагрузку на память, откладывая передачу страниц до реальной необ" ходимости в них. Резервирование памяти — операция относительно быст" рая и не требующая большого количества ресурсов, поскольку в данном слу" чае не расходуется ни физическая память (драгоценный системный ресурс), ни квота процесса на ресурсы страничного файла (число страниц, переда" ваемых процессу из страничного файла). При этом нужно создать или об" новить лишь сравнительно небольшие внутренние структуры данных, отра" жающие состояние адресного пространства процесса. (Об этих структурах данных, называемых дескрипторами виртуальных адресов, или VAD, мы рас" скажем потом.) Резервирование памяти с последующей ее передачей особенно эффек" тивно для приложений, нуждающихся в потенциально большой и непрерыв" ной области виртуальной памяти: зарезервировав требуемое адресное про" странство, они могут передавать ему страницы порциями, по мере необхо"
406 ГЛ А В А 7 БЕЗОПАСНОСТЬ димости. Эта методика применяется и для организации стека пользователь" ского режима для каждого потока. Такой стек резервируется при создании потока. (Его размер по умолчанию — 1 Мб; другой размер стека для конкрет" ного потока можно указать при вызове CreateThread. Если вы хотите изме" нить его для всех потоков процесса, укажите при сборке программы флаг /STACK.) По умолчанию стеку передается только начальная страница, а сле" дующая страница просто помечается как сторожевая (guard page). За счет этой страницы, которая служит своего рода ловушкой для перехвата ссылок за ее пределы, стек расширяется только по мере заполнения. Блокировка памяти В целом, принятие решений о том, какие страницы следует оставить в фи" зической памяти, лучше сохранить за диспетчером памяти. Однако в особых обстоятельствах можно подкорректировать работу диспетчера памяти. Су" ществует два способа блокировки страниц в памяти. 쐽 Windows"приложения могут блокировать страницы в рабочем наборе своего процесса через функцию VirtualLock. Максимальное число стра" ниц, которые процесс может блокировать, равно минимальному разме" ру его рабочего набора за вычетом восьми страниц. Следовательно, если процессу нужно блокировать большее число страниц, он может увели" чить минимальный размер своего рабочего набора вызовом функции SetProcessWorkingSetSize (см. раздел «Управление рабочим набором» далее в этой главе). 쐽 Драйверы устройств могут вызывать функции режима ядра MmProbeAnd LockPages, MmLockPagableCodeSection и MmLockPagableSectionByHandle. Блокированные страницы остаются в памяти до снятия блокировки. Хотя число блокируемых страниц не ограничивается, драйвер не может бло" кировать их больше, чем это позволяет счетчик доступных резидентных страниц. Гранулярность выделения памяти Windows выравнивает начало каждого региона зарезервированного адресно" го пространства в соответствии с гранулярностью выделения памяти (allo" cation granularity). Это значение можно получить через Windows"функцию GetSystemInfo. В настоящее время оно равно 64 Кб. Такая величина выбрана из соображений поддержки будущих процессоров с бóльшим размером страниц памяти (до 64 Кб) или виртуально индексируемых кэшей (virtually indexed caches), требующих общесистемного выравнивания между физическими и виртуальными страницами (physical"to"virtual page alignment). Благодаря это" му уменьшается риск возможных изменений, которые придется вносить в приложения, полагающиеся на определенную гранулярность выделения па" мяти. (Это ограничение не относится к коду Windows режима ядра — исполь" зуемая им гранулярность выделения памяти равна одной странице.)
ГЛАВА 9 Управление памятью 407 Windows также добивается, чтобы размер и базовый адрес зарезервиро" ванного региона адресного пространства всегда был кратен размеру стра" ницы. Например, системы типа x86 используют страницы размером 4 Кб, и, если вы попытаетесь зарезервировать 18 Кб памяти, на самом деле будет за" резервировано 20 Кб. А если вы укажете базовый адрес 3 Кб для 18"килобайт" ного региона, то на самом деле будет зарезервировано 24 Кб. Разделяемая память и проецируемые файлы Как и большинство современных операционных систем, Windows поддер" живает механизм разделения памяти. Разделяемой (shared memory) называ" ется память, видимая более чем одному процессу или присутствующая в вир" туальном адресном пространстве более чем одного процесса. Например, если два процесса используют одну и ту же DLL, есть смысл загрузить ее код в физическую память лишь один раз и сделать ее доступной всем процессам, проецирующим эту DLL (рис. 7"1). Рис. 7-1. Разделение памяти процессами Каждый процесс поддерживает закрытые области памяти для хранения собственных данных, но программные инструкции и страницы немодифи" цируемых данных в принципе можно использовать совместно с другими процессами. Как вы еще увидите, такой вид разделения реализуется автома"
408 ГЛ А В А 7 БЕЗОПАСНОСТЬ тически, поскольку страницы кода в исполняемых образах проецируются с атрибутом «только для выполнения», а страницы, доступные для записи, — с атрибутом «копирование при записи» (copy"on"write) (см. раздел «Копиро" вание при записи» далее в этой главе). Для реализации разделяемой памяти используются примитивы диспетче" ра памяти, объекты «раздел», которые в Windows API называются объектами «проекция файла» (file mapping objects). Внутренняя структура и реализация этих объектов описывается в разделе «Объекты"разделы» далее в этой главе. Этот фундаментальный примитив диспетчера памяти применяется для проецирования виртуальных адресов в основной памяти, страничном фай" ле или любых других файлах, к которым приложение хочет обращаться так, будто они находятся в памяти. Раздел может быть открыт как одним процес" сом, так и несколькими; иначе говоря, объекты «раздел» вовсе не обязатель" но представляют разделяемую память. Объект «раздел» может быть связан с открытым файлом на диске (кото" рый в этом случае называется проецируемым) или с переданной памятью (для ее разделения). Разделы, проецируемые на переданную память, называ" ются разделами, поддерживаемыми страничными файлами (page file backed sections), так как при нехватке памяти их страницы перемещаются в стра" ничный файл. (Однако Windows может работать без страничного файла, и тогда эти разделы «поддерживаются» физической памятью.) Разделяемые переданные страницы, как и любые другие страницы, видимые в пользова" тельском режиме (например, закрытые переданные страницы), всегда обну" ляются при первом обращении к ним. Для создания объекта «раздел» используется Windows"функция Create FileMapping, которой передается описатель проецируемого файла (или IN" VALID_ HANDLE_VALUE в случае раздела, поддерживаемого страничным фай" лом), а также необязательные имя и дескриптор защиты. Если разделу при" своено имя, его может открыть другой процесс вызовом OpenFileMapping. Кроме того, вы можете предоставить доступ к объектам «раздел» через на" следование описателей (определив при открытии или создании описателя, что он является наследуемым) или их дублирование (с помощью Duplicate Handle). Драйверы также могут манипулировать объектами «раздел» через функции ZwOpenSection, ZwMapViewOfSection и ZwUnmapViewOfSection. Объект «раздел» может ссылаться на файлы, длина которых намного пре" вышает размер адресного пространства процесса. (Если раздел поддержи" вается страничным файлом, в нем должно быть достаточно места для раз" мещения всего раздела.) Используя очень большой объект «раздел», процесс может проецировать лишь необходимую ему часть этого объекта, которая называется представлением (view) и создается вызовом функции MapView OfFile с указанием проецируемого диапазона. Это позволяет процессам эко" номить адресное пространство, так как на память проецируется только пред" ставление объекта «раздел». Windows"приложения могут использовать проецирование файлов для упрощения ввода"вывода в файлы на диске, просто делая их доступными в
ГЛАВА 9 Управление памятью 409 своем адресном пространстве. Приложения — не единственные потребите" ли объектов «раздел»: загрузчик образов использует их для проецирования в память исполняемых образов, DLL и драйверов устройств, а диспетчер кэ" ша — для доступа к данным кэшируемых файлов. (Об интеграции диспетче" ра кэша с диспетчером памяти см. в главе 11.) О реализации разделов совме" стно используемой памяти мы расскажем потом. ЭКСПЕРИМЕНТ: просмотр файлов, проецируемых в память Просмотреть спроецированные в память файлы для какого"либо про" цесса позволяет утилита Process Explorer от Sysinternals. Для этого на" стройте нижнюю секцию ее окна на режим отображения DLL. (Выбе" рите View, Lower Pane View, DLLs.) Заметьте, что это не просто список DLL, — здесь представлены все спроецированные в память файлы в адресном пространстве процесса. Некоторые являются DLL, один из них — файлом выполняемого образа (EXE), а другие элементы списка могут представлять файлы данных, проецируемые в память. Например, на следующей иллюстрации показан вывод Process Explorer примени" тельно к процессу Microsoft PowerPoint, в адресное пространство ко" торого загружен документ PowerPoint. Для поиска спроецированных в память файлов щелкните Find, DLL. Это удобно, когда нужно определить, какие процессы используют DLL, которую вы пытаетесь заменить. Наконец, сравнение списка DLL, загруженных в процесс, с анало" гичным списком другого экземпляра той же программы в другой сис" теме помогает выявить проблемы с конфигурацией DLL, например загрузку в процесс не той версии DLL. Защита памяти Как уже говорилось в главе 1, Windows обеспечивает защиту памяти, предот" вращая случайную или преднамеренную порчу пользовательскими процес" сами данных в адресном пространстве системы или других процессов. В Windows предусмотрено четыре основных способа защиты памяти.
410 ГЛ А В А 7 БЕЗОПАСНОСТЬ Во"первых, доступ ко всем общесистемным структурам данных и пулам памяти, используемым системными компонентами режима ядра, возможен лишь из режима ядра — у потоков пользовательского режима нет доступа к соответствующим страницам. Когда поток пользовательского режима пыта" ется обратиться к одной из таких страниц, процессор генерирует исключе" ние, и диспетчер памяти сообщает потоку о нарушении доступа. ПРИМЕЧАНИЕ Некоторые страницы в системном адресном про" странстве Windows 95/98 и Windows Millennium Edition, напротив, до" ступны для записи из пользовательского режима, что позволяет сбой" ным приложениям портить важные системные структуры данных и вызывать крах системы. Во"вторых, у каждого процесса имеется индивидуальное закрытое адрес" ное пространство, защищенное от доступа потоков других процессов. Ис" ключение составляют те случаи, когда процесс разделяет какие"либо стра" ницы с другими процессами или когда у другого процесса есть права на до" ступ к объекту «процесс» для чтения и/или записи, что позволяет ему исполь" зовать функции ReadProcessMemory и WriteProcessMemory. Как только поток ссылается на какой"нибудь адрес, аппаратные средства поддержки виртуаль" ной памяти совместно с диспетчером памяти перехватывают это обращение и транслируют виртуальный адрес в физический. Контролируя трансляцию виртуальных адресов, Windows гарантирует, что потоки одного процесса не получат несанкционированного доступа к страницам другого процесса. В"третьих, кроме косвенной защиты, обеспечиваемой трансляцией вир" туальных адресов в физические, все процессоры, поддерживаемые Windows, предоставляют ту или иную форму аппаратной защиты памяти (например доступ для чтения и записи, только для чтения и т. д.); конкретные механиз" мы такой защиты зависят от архитектуры процессора. Скажем, страницы кода в адресном пространстве процесса помечаются атрибутом «только для чтения», что защищает их от изменения пользовательскими потоками. Атрибуты защиты памяти, определенные в Windows API, перечислены в таблице 7"3 (см. также документацию на функции VirtualProtect, VirtualPro tectEx, VirtualQuery и VirtualQueryEx). Таблица 7-3. Атрибуты защиты памяти, определенные в Windows API Атрибут Описание PAGE_NOACCESS Любая попытка чтения, записи или выполнения кода на этой странице вызывает нарушение доступа PAGE_READONLY Любая попытка записи (или выполнения кода на процессо" рах без поддержки запрета на выполнение) на этой страни" це вызывает нарушение доступа, но чтение разрешено PAGE_READWRITE Страница доступна для чтения и записи — никакие действия не вызывают нарушения доступа PAGE_EXECUTE Любая попытка записи на этой странице вызывает наруше" ние доступа, но выполнение кода (и чтения на всех сущест" вующих процессорах) разрешено
ГЛАВА 9 Управление памятью 411 Таблица 7-3. (окончание) Атрибут Описание PAGE_EXECUTE_READ Любая попытка записи на этой странице вызывает наруше" ние доступа, но чтение и выполнение разрешено PAGE_EXECUTE_ READWRITE Страница доступна для чтения, записи и выполнения — никакие действия не вызывают нарушения доступа PAGE_WRITECOPY Любая попытка записи на этой странице заставляет систему выдать процессу закрытую копию данной страницы; при попытке выполнения кода на этой странице возникает нару" шение доступа PAGE_EXECUTE_ WRITECOPY Любая попытка записи на этой странице заставляет систему выдать процессу закрытую копию данной страницы. Чтение и выполнение кода на этой странице разрешено (в этом слу" чае копия страницы не создается) PAGE_GUARD Любая попытка чтения или записи сторожевой страницы вызывает исключение EXCEPTION_GUARD_PAGE, и она пере" стает быть сторожевой; этот атрибут можно комбинировать с любым другим атрибутом, кроме PAGE_NOACCESS PAGE_NOCACHE Используется некэшируемая физическая память, что, как правило, не рекомендуется делать. Имеет смысл для драйве" ров устройств, например, для проецирования буфера видео" кадра без кэширования PAGE_WRITECOMBINE Разрешает комбинированную запись на страницу памяти. В этом случае процессор может кэшировать запросы на за" пись в память для большей производительности. Например, при наличии нескольких запросов на запись по одному ад" ресу возможна запись лишь по последнему запросу ПРИМЕЧАНИЕ Атрибут защиты «запрет на выполнение» (no execute protection) поддерживается Windows XP Service Pack 2 и Windows Ser" ver 2003 Service Pack 1 на процессорах с соответствующей аппаратной поддержкой (например, на x64", IA64" и будущих x86"процессорах). В более ранних версиях Windows и на процессорах без поддержки ат" рибута защиты «запрет на выполнение», выполнение всегда разреше" но. Более подробные сведения об этом атрибуте защиты см. в следую" щем разделе. Наконец, совместно используемые объекты «раздел» имеют стандартные для Windows списки контроля доступа (access control lists, ACL), проверяемые при попытках процессов открыть эти объекты. Таким образом, доступ к раз" деляемой памяти ограничен кругом процессов с соответствующими права" ми. Когда поток создает раздел для проецирования файла, в этом принима" ет участие и подсистема защиты. Для создания раздела поток должен иметь права хотя бы на чтение нижележащего объекта «файл», иначе операция за" кончится неудачно. После успешного открытия описателя раздела действия потока все рав" но зависят от описанных выше атрибутов защиты, реализуемых диспетче"
412 ГЛ А В А 7 БЕЗОПАСНОСТЬ ром памяти на основе аппаратной поддержки. Поток может менять атрибу" ты защиты виртуальных страниц раздела (на уровне отдельных страниц), если это не противоречит разрешениям, указанным в ACL для данного раз" дела. Так, диспетчер памяти позволит потоку сменить атрибут страниц об" щего раздела «только для чтения» на «копирование при записи», но запре" тит его изменение на атрибут «для чтения и записи». Копирование при за" писи разрешается потому, что не влияет на другие процессы, тоже исполь" зующие эти данные. Все эти механизмы защиты памяти вносят свой вклад в надежность, ста" бильность и устойчивость Windows к ошибкам и сбоям приложений. Запрет на выполнение Хотя в API управления памятью в Windows всегда были определены биты защиты страницы, позволяющие указывать, может ли страница содержать исполняемый код, лишь с появлением Windows XP Service Pack 2 и Windows Server 2003 Service Pack 1 эта функциональность стала поддерживаться на процессорах с аппаратной защитой «запрет на выполнение», в том числе на всех процессорах AMD64 (AMD Athlon64, AMD Opteron), на некоторых чис" то 32"разрядных процессорах AMD (отдельных AMD Sempron), на Intel IA64 и Intel Pentium 4 или Xeon с поддержкой EM64T (Intel Extended Memory 64 Technology). Эта защита, также называемая предотвращением выполнения данных (data execution prevention, DEP), означает, что попытка передачи управления какой"либо инструкции на странице, помеченной атрибутом «запрет на выполнение», приведет к нарушению доступа к памяти. Благодаря этому бло" кируются попытки определенных типов вирусов воспользоваться ошибка" ми в операционной системе, которые иначе позволили бы выполнить код, размещенный на странице данных. Попытка выполнить код на странице, помеченной атрибутом «запрет на выполнение», в режиме ядра вызывает крах системы с кодом ATTEMPTED_EXECUTE_OF_NOEXECUTE_MEMORY. Если такая же попытка предпринимается в пользовательском режиме, то ге" нерируется исключение STATUS_ACCESS_VIOLATION (0xc0000005); оно до" ставляется потоку, в котором была эта недопустимая ссылка. Если процесс выделяет память, которая должна быть исполняемой, то при вызове функ" ций, отвечающих за выделение памяти, он обязан явно указать для соответ" ствующих страниц флаг PAGE_EXECUTE, PAGE_EXECUTE_READ, PAGE_EXE" CUTE_READWRITE или PAGE_EXECUTE_WRITECOPY. В 64"разрядных версиях Windows атрибут защиты «запрет на выполне" ние» всегда применяется ко всем 64"разрядным программам и драйверам устройств, и его нельзя отключить. Поддержка такой защиты для 32"разряд" ных программ зависит от конфигурационных параметров системы. В 64" разрядной Windows защита от выполнения применяется к стекам потоков (как режима ядра, так и пользовательского режима), к страницам пользова" тельского режима, не помеченным явно как исполняемые, к пулу подкачи"
ГЛАВА 9 Управление памятью 413 ваемой памяти ядра и к сеансовому пулу ядра (описание пулов памяти ядра см. в разделе «Системные пулы памяти»). Однако в 32"разрядной Windows защита от выполнения применяется только к стекам потоков и страницам пользовательского режима. Кроме того, когда в 32"разрядной Windows раз" решена защита от выполнения, система автоматически загружается в PAE" режиме (переходя на использование PAE"ядра, \Windows\System32\Ntkrnl" pa.exe). Описание PAE см. в разделе «Physical Address Extension (PAE)». Активизация защиты от выполнения для 32"разрядных программ зависит от ключа /NOEXECUTE= в Boot.ini. Эти настройки можно изменить и на вкладке Data Execution Prevention, которая открывается последовательным выбором My Computer, Properties, Advanced, Performance Settings (см. рис. 7"2.) Когда вы вы" бираете защиту от выполнения в диалоговом окне настройки DEP, файл Boot.ini модифицируется добавлением в него соответствующего ключа /NOEXECUTE. Список аргументов для этого ключа и их описание см. в таблице 7"4. 32"раз" рядные приложения, исключенные из защиты от выполнения, перечисляют" ся в параметрах в разделе реестра HKLM\Software\Microsoft\Windows NT \CurrentVersion\AppCompatFlags\Layers; при этом в качестве имени парамет" ра используется полный путь к исполняемому файлу, а в качестве его значе" ния — «DisableNXShowUI». Рис. 7-2. Параметры Data Execution Protection В Windows XP (в 64" и 32"разрядных версиях) защита от выполнения для 32"разрядных программ по умолчанию применяется только к базовым испол" няемым образам операционной системы Windows (/NOEXECUTE=OPTIN), чтобы не нарушить работу 32"разрядных приложений, которые могут пола" гаться на выполнение кода в страницах, не помеченных как исполняемые. В Windows Server 2003 такая защита по умолчанию распространяется на все 32"разрядные приложения (/NOEXECUTE=OPTOUT).
414 ГЛ А В А 7 БЕЗОПАСНОСТЬ ПРИМЕЧАНИЕ Чтобы получить полный список защищаемых программ, установите Windows Application Compatibility Toolkit (его можно скачать с www.microsoft.com) и запустите Compatibility Administrator Tool. Выбери" те System Database, Applications и Windows Components. В правой секции окна появится список защищенных исполняемых файлов. Таблица 7-4. Ключ /NOEXECUTE в Boot.ini Ключ /NOEXECUTE=OPTIN Параметр в диалоговом окне настройки DEP Описание Turn on DEP for necessary Включает DEP для базовых сис" Windows programs and темных образов Windows services only (включение DEP только для необхо" димых программ и серви" сов Windows) /NOEXECUTE=OPTOUT Turn on DEP for all programs Включает DEP для всех исполня" and services except those емых образов, кроме указанных that I select (включение DEP для всех программ и сервисов, кроме выбран" ных мной) /NOEXECUTE= ALWAYSON (Этот вариант в GUI не представлен) /NOEXECUTE= ALWAYSOFF (Этот вариант в GUI не представлен) Включает DEP для всех компо" нентов без возможности исклю" чения определенных приложений Отключает DEP (не рекомендуется) Программный вариант DEP Поскольку большинство процессоров, на которых сегодня работает Windows, не поддерживает аппаратную защиту от выполнения, Win" dows XP Service Pack 2 и Windows Server 2003 Service Pack 1 (или выше) поддерживают ограниченный программный вариант DEP (data execu" tion prevention). Одна из функций программного DEP — сужать воз" можности злоумышленников в использовании механизма обработки исключений в Windows. (Описание структурной обработки исключе" ний см. в главе 3.) Если файлы образа программы опираются на без" опасную структурную обработку исключений (новая функциональ" ность компилятора Microsoft Visual C++ 2003), то, прежде чем переда" вать исключение, система проверяет, зарегистрирован ли обработчик этого исключения в таблице функций, которая помещается в файл образа. Если в файлах образа программы безопасная структурная об" работка исключений не применяется, программный DEP проверяет, находится ли обработчик исключения в области памяти, помеченной как исполняемая, еще до передачи исключения.
ГЛАВА 9 Управление памятью 415 Копирование при записи Защита страницы типа «копирование при записи» — механизм оптимиза" ции, используемый диспетчером памяти для экономии физической памяти. Когда процесс проецирует копируемое при записи представление объекта «раздел» со страницами, доступными для чтения и записи, диспетчер памя" ти — вместо того чтобы создавать закрытую копию этих страниц в момент проецирования представления (как в операционной системе Hewlett Packard OpenVMS) — откладывает создание копии до тех пор, пока не закончится запись в них. Эта методика используется и всеми современными UNIX"сис" темами. На рис. 7"3 показана ситуация, когда два процесса совместно ис" пользуют три страницы, каждая из которых помечена как копируемая при записи, но ни один из процессов еще не пытался их модифицировать. Рис. 7-3. Состояние страниц до копирования при записи Если поток любого из этих процессов что"то записывает на такую стра" ницу, генерируется исключение, связанное с управлением памятью. Обнару" жив, что запись ведется на страницу с атрибутом «копирование при записи», диспетчер памяти, вместо того чтобы сообщить о нарушении доступа, вы" деляет в физической памяти новую страницу, доступную для чтения и запи" си, копирует в нее содержимое исходной страницы, обновляет соответству" ющую информацию о страницах, проецируемых на данный процесс, и зак" рывает исключение. В результате команда, вызвавшая исключение, выполня" ется повторно, и операция записи проходит успешно. Но, как показано на рис. 7"4, новая страница теперь является личной собственностью процесса, инициировавшего запись, и не видима другим процессам, совместно исполь" зующим страницу с атрибутом «копирование при записи». Каждый процесс, что"либо записывающий на эту разделяемую страницу, получает в свое рас" поряжение ее закрытую копию. Одно из применений копирования при записи — поддержка точек пре" рываний для отладчиков. Например, по умолчанию страницы кода доступ" ны только для выполнения. Если программист при отладке программы ус" танавливает точку прерывания, отладчик должен добавить в код программы соответствующую команду. Для этого он сначала меняет атрибут защиты страницы на PAGE_EXECUTE_READWRITE, а затем модифицирует поток ко" манд. Поскольку страница кода является частью проецируемого раздела,
416 ГЛ А В А 7 БЕЗОПАСНОСТЬ диспетчер памяти создает закрытую копию для процесса с установленной точкой прерывания, тогда как другие процессы по"прежнему используют исходную страницу кода. Рис. 7-4. Состояние страниц после копирования при записи Копирование при записи может служить примером алгоритма отложенной оценки (lazy evaluation), который диспетчер памяти применяет при любой воз" можности. В таких алгоритмах операции, чреватые большими издержками, не выполняются до тех пор, пока не станут абсолютно необходимыми, — если операция так и не понадобится, никаких издержек вообще не будет. Подсистема POSIX использует преимущества копирования при записи в реализации функции fork. Как правило, если UNIX"приложения вызывают fork для создания другого процесса, то первое, что делает новый процесс, — об" ращается к функции exec для повторной инициализации адресного простран" ства исполняемой программы. Вместо копирования всего адресного про" странства при вызове fork новый процесс использует страницы родительского процесса, помечая их как копируемые при записи. Если дочерний процесс что"то записывает на эти страницы, он получает их закрытую копию. В ином случае оба процесса продолжают разделять страницы без копирования. Так или иначе диспетчер памяти копирует лишь те страницы, на которые процесс пытается что"то записать, а не все содержимое адресного пространства. Оценить частоту срабатывания механизма копирования при записи мож" но с помощью счетчика Memory: Write Copies/Sec (Память: Запись копий страниц/сек). Диспетчер куч Многие приложения выделяют память небольшими блоками (менее 64 Кб — минимума, поддерживаемого функциями типа VirtualAlloc). Выделение столь большой области (64 Кб) для сравнительно малого блока весьма неоптималь" но с точки зрения использования памяти и производительности. Для устра" нения этой проблемы в Windows имеется компонент — диспетчер куч (heap manager), который управляет распределением памяти внутри больших обла" стей, зарезервированных с помощью функций, выделяющих память в соответ" ствии с гранулярностью страниц. Гранулярность выделения памяти в диспет" чере куч сравнительно мала: 8 байтов в 32"разрядных системах и 16 байтов в
ГЛАВА 9 Управление памятью 417 64"разрядных. Диспетчер куч обеспечивает оптимальное использование па" мяти и производительность при выделении таких небольших блоков памяти. Функции диспетчера куч локализованы в двух местах: в Ntdll.dll и Ntosk" rnl.exe. API"функции подсистем (вроде API"функций Windows"куч) вызыва" ют функции из Ntdll, а компоненты исполнительной системы и драйверы устройств — из Ntoskrnl. Родные интерфейсы (функции с префиксом Rtl) доступны только внутренним компонентам Windows и драйверам устройств режима ядра. Документированный интерфейс Windows API для куч (функции с префиксом Heap) представляют собой тонкие оболочки, которые вызыва" ют родные функции из Ntdll.dll. Кроме того, для поддержки устаревших Windows"приложений предназначены унаследованные API"функции (с пре" фиксом Local или Global). К наиболее часто используемым Windows"функ" циям куч относятся: 쐽 HeapCreate или HeapDestroy — соответственно создает или удаляет кучу. При создании кучи можно указать начальные размеры зарезервирован" ной и переданной памяти; 쐽 HeapAlloc — выделяет блок памяти из кучи; 쐽 HeapFree — освобождает блок, ранее выделенный через HeapAlloc; 쐽 HeapReAlloc — увеличивает или уменьшает размер уже выделенного блока; 쐽 HeapLock и HeapUnlock — управляют взаимным исключением (mutual exclusion) операций, связанных с обращением к куче; 쐽 HeapWalk — перечисляет записи и области в куче. Типы куч У каждого процесса имеется минимум одна куча — куча, выделяемая процес" су по умолчанию (default process heap). Куча по умолчанию создается в мо" мент запуска процесса и никогда не удаляется в течение срока жизни этого процесса. По умолчанию она имеет размер 1 Мб, но ее начальный размер может быть увеличен, если в файле образа указано иное значение с помо" щью ключа /HEAP компоновщика. Однако этот объем памяти резервирует" ся только для начала и по мере необходимости автоматически увеличивается (в файле образа можно указать и начальный размер переданной памяти). Куча по умолчанию может быть явно использована программой или не" явно некоторыми внутренними Windows"функциями. Приложение запраши" вает память из кучи процесса по умолчанию вызовом Windows"функции GetProcessHeap. Процесс может создавать дополнительные закрытые кучи вызовом HeapCreate. Когда куча больше не нужна, занимаемое ею виртуаль" ное адресное пространство можно освободить, вызвав HeapDestroy. Массив всех куч поддерживается в каждом процессе, и поток может обращаться к ним через Windows"функцию GetProcessHeaps. Куча может быть создана в больших регионах памяти, зарезервирован" ных через диспетчер памяти с помощью VirtualAlloc или через объекты «файл, проецируемый в память», отображенные на адресное пространство
418 ГЛ А В А 7 БЕЗОПАСНОСТЬ процесса. Последний подход редко применяется на практике, но удобен в случаях, когда содержимое блоков нужно разделять между двумя процесса" ми или между частями компонента, работающими в режиме ядра и в пользо" вательском режиме. В последнем случае действует ряд ограничений на вы" зов функций куч. Во"первых, внутренние структуры куч используют указа" тели и поэтому не допускают перемещения на другие адреса. Во"вторых, функции куч не поддерживают синхронизацию между несколькими процес" сами или между компонентом ядра и процессом пользовательского режима. Наконец, в случае кучи, разделяемой между кодом пользовательского режи" ма и режима ядра проекция пользовательского режима должна быть только для чтения, чтобы исключить повреждение внутренних структур кучи кодом пользовательского режима. Структура диспетчера кучи Как показано на рис. 7"5, диспетчер куч состоит из двух уровней: необяза" тельного интерфейсного (front"end layer) и базового (core heap layer). Пос" ледний заключает в себе базовую функциональность, которая обеспечива" ет управление блоками внутри сегментов, управление сегментами, поддер" жку политик расширения кучи, передачу и возврат памяти, а также управле" ние большими блоками. Необязательный интерфейсный уровень (только для куч пользователь" ского режима) размещается поверх базового уровня. Существует два типа интерфейсных уровней: ассоциативные списки (look"aside lists) и куча с ма" лой фрагментацией (Low Fragmentation Heap, LFH). LFH доступна лишь в Windows XP и более поздних версиях Windows. Единовременно для каждой кучи можно использовать только один интерфейсный уровень. Рис. 7-5. Уровни диспетчера куч
ГЛАВА 9 Управление памятью 419 Синхронизация доступа к куче Диспетчер куч по умолчанию поддерживает параллельный доступ из не" скольких потоков. Однако, если процесс является однопоточным или ис" пользует внешний механизм синхронизации, он может отключить синхро" низацию, поддерживаемую диспетчером куч, и тем самым избежать издер" жек, связанных с этим видом синхронизации. Для этого при создании кучи или при каждом запросе на выделение памяти такой процесс может указы" вать флаг HEAP_NO_SERIALIZE. Процесс также может блокировать всю кучу и запретить другим потокам выполнение операций, требующих согласования состояний между несколь" кими обращениями к куче. Например, перечисление блоков в куче с помо" щью Windows"функции HeapWalk требует блокировки кучи, если над ней могут выполняться операции сразу несколькими потоками. Если синхронизация куч разрешена, для каждой кучи выделяется по од" ной блокировке, которая защищает все внутренние структуры кучи. В при" ложениях с большим числом потоков (особенно когда они выполняются в многопроцессорных системах) блокировка кучи может превратиться в точ" ку интенсивной конкуренции. В таком случае производительность можно повысить за счет использования интерфейсного уровня. Ассоциативные списки Это однонаправленные связанные списки (single linked lists), поддерживаю" щие элементарные операции вроде заталкивания в список или выталкива" ния из него по принципу «последним пришел, первым вышел» (Last In, First Out, LIFO) без применения блокирующих алгоритмов. Упрощенная версия этих структур данных также доступна Windows"приложениям через функ" ции InterlockedPopEntrySList и InterlockedPushEntrySList. Для каждой кучи соз" дается 128 ассоциативных списков, которые удовлетворяют запросы на вы" деление блоков памяти размером до 1 Кб на 32"разрядных платформах и до 2 Кб на 64"разрядных. Ассоциативные списки обеспечивают гораздо более высокую производи" тельность, чем при обычных запросах на выделение памяти, так как несколь" ко потоков могут одновременно выполнять операции выделения и возвра" та памяти, не требуя применения глобальной для кучи блокировки. Кроме того, благодаря модели размещения LIFO и обращению к меньшему числу внутренних структур данных при каждой операции над кучей оптимизиру" ется локальность кэша. Диспетчер куч поддерживает ряд блокировок в каждом ассоциативном списке и некоторые счетчики, помогающие независимо регулировать работу с каждым списком. Если поток запрашивает блок такого размера, которого нет в соответствующем ассоциативном списке, диспетчер куч переадресует этот вызов базовому уровню и обновит внутренний счетчик неудачных вы" делений, значение которого впоследствии будет использовано при приня" тии решений по оптимизации.
420 ГЛ А В А 7 БЕЗОПАСНОСТЬ Диспетчер куч создает ассоциативные списки автоматически при созда" нии кучи, если только эта куча расширяемая и не включен отладочный ре" жим. У некоторых приложений могут возникать проблемы совместимости из"за использования диспетчером куч ассоциативных списков. В таких слу" чаях для корректной работы нужно указывать флаг DisableHeapLookaside в параметрах выполнения файлов образов унаследованных приложений. (Эти параметры можно задавать с помощью утилиты Imagecfg.exe из Windows 2000 Server Resource Kit, supplement 1.) Куча с малой фрагментацией Многие приложения, выполняемые в Windows, используют сравнительно не" большие объемы памяти из куч (обычно менее одного мегабайта). Для этого класса приложений диспетчер куч применяет политику наибольшей подгон" ки (best"fit policy), которая помогает сохранять небольшим «отпечаток» каж" дого процесса в памяти. Однако такая стратегия не масштабируется для боль" ших процессов и многопроцессорных машин. В этих случаях доступная па" мять в куче может уменьшиться из"за ее фрагментации. В сценариях, где лишь блоки определенного размера часто используются параллельно разными по" токами, выполняемыми на разных процессорах, производительность ухудша" ется. Дело в том, что нескольким процессорам нужно одновременно модифи" цировать один и тот же участок памяти (например, начало ассоциативного списка для блоков этого размера), а это приводит к объявлению недействи" тельной соответствующей кэш"линии для других процессоров. Эти проблемы решаются применением кучи с малой фрагментацией (LFH), которая использует базовый уровень диспетчера куч и ассоциативные списки. В отличие от ситуации, в которой ассоциативные списки по умол" чанию применяются как интерфейсные, если это разрешено другими пара" метрами куч, поддержка LFH включается, только когда приложение вызыва" ет функцию HeapSetInformation. В случае больших куч значительная доля запросов на выделение обычно раскладывается на относительно небольшое число корзин (buckets) определенных размеров. Стратегия выделения памя" ти, применяемая LFH, заключается в оптимизации использования памяти для таких запросов за счет эффективной обработки блоков одного размера. Для устранения проблем с масштабируемостью LFH раскрывает часто используемые внутренние структуры в набор слотов, в два раза больший те" кущего количества процессоров в компьютере. Закрепление потоков за эти" ми слотами выполняется LFH"компонентом, называемым диспетчером при вязки (affinity manager). Изначально LFH использует для распределения па" мяти первый слот, но, как только возникает конкуренция при доступе к не" которым внутренним данным, переключает текущий поток на другой слот. И чем больше конкуренция, тем большее число слотов задействуется для потоков. Эти слоты создаются для корзины каждого размера, что также уве" личивает локальность и сводит к минимуму общий расход памяти.
ГЛАВА 9 Управление памятью 421 Средства отладки Диспетчер куч предоставляет несколько средств, помогающих обнаруживать ошибки. 쐽 Enable tail checking (включить проверку концевой части блока) В конец каждого блока помещается сигнатура, проверяемая при его ос" вобождении. Если эта сигнатура полностью или частично уничтожается из"за переполнения буфера, куча сообщает о соответствующей ошибке. 쐽 Enable free checking (включить проверку свободных блоков) Свободный блок заполняется определенным шаблоном, который прове" ряется, когда диспетчеру куч нужен доступ к этому блоку. Если процесс продолжает записывать в блок после его освобождения, диспетчер куч об" наружит изменения в шаблоне и сообщит об ошибке. 쐽 Parameter checking (проверка параметров) передаваемых функциям куч. 쐽 Heap validation (проверка кучи) обращении к ней. Проверка параметров, Вся куча проверяется при каждом 쐽 Heap tagging and stack traces support (поддержка меток и трасси! ровки стека) Это средство поддерживает задание меток для выделяе" мой памяти и/или перехват трассировок стека пользовательского режи" ма при обращениях к куче, что помогает локализовать причину той или иной ошибки. Первые три средства включаются по умолчанию, если загрузчик обнару" живает, что процесс запущен под управлением отладчика. (Отладчик может переопределить такое поведение и выключить эти средства.) Средства отлад" ки для куч могут быть заданы установкой различных отладочных флагов в заголовке образа через утилиту gflags (см. раздел «Глобальные флаги Windows» в главе 3) или командой !heap в любом стандартном отладчике Windows. Включение средств отладки влияет на все кучи в процессе. Кроме того, включение любого средства отладки приводит к автоматическому отключе" нию интерфейсного уровня и переходу на использование базового. Интер" фейсный уровень также не применяется для нерасширяемых куч (из"за до" полнительных издержек) или для куч, не допускающих сериализации. Pageheap Так как при проверке концевых частей блоков и шаблона свободных блоков могут обнаруживаться повреждения, произошедшие задолго до проявления собственно проблемы, предоставляется дополнительный инструмент отлад" ки куч, pageheap, который переадресует все обращения к куче (или их часть) другому диспетчеру куч. Pageheap является частью Windows Application Com" patibility Toolkit, и его можно скачать с www.microsoft.com. Pageheap помеща" ет выделенные блоки в конец страниц, поэтому при переполнении буфера возникнет нарушение доступа, что упростит выявление ошибочного кода. Блоки можно помещать и в начало страниц для обнаружения проблем, свя"
422 ГЛ А В А 7 БЕЗОПАСНОСТЬ занных с неполным использованием буферов (buffer underruns). (Такие си" туации — большая редкость.) Pageheap также позволяет защищать освобож" денные страницы от любых видов доступа для выявления ссылок на блоки после их освобождения. Заметьте, что применение pageheap может привести к нехватке адресно" го пространства, так как выделение даже очень малых блоков памяти сопря" жено с существенными издержками. Также может ухудшиться производи" тельность из"за увеличения количества ссылок на обнуленные страницы, потери локальности и частых вызовов для проверки структур кучи. Чтобы уменьшить негативное влияние на производительность, pageheap можно использовать только для блоков определенных размеров, конкретных диа" пазонов адресов и т. д. ПРИМЕЧАНИЕ Подробнее о pageheap см. статью 286470 в Microsoft Knowledge Base (http://support.microsoft.com). Address Windowing Extensions Хотя 32"разрядные версии Windows поддерживают до 128 Гб физической памяти (см. таблицу 2"4 в главе 2), размер виртуального адресного простран" ства любого 32"разрядного пользовательского процесса по умолчанию ра" вен 2 Гб (при указании загрузочных параметров /3GB и /USERVA в Boot.ini этот размер составляет 3 Гб). Чтобы 32"разрядный процесс мог получить доступ к большему объему физической памяти, Windows поддерживает на" бор функций под общим названием Address Windowing Extensions (AWE). Так, в системе под управлением Windows 2000 Advanced Server с 8 Гб физичес" кой памяти серверное приложение базы данных может с помощью AWE ис" пользовать под кэш базы данных до 6 Гб памяти. Выделение и использование памяти через функции AWE осуществляется в три этапа. 1. Выделение физической памяти. 2. Создание региона виртуального адресного пространства — окна, на ко" торое будут проецироваться представления физической памяти. 3. Проецирование на окно представлений физической памяти. Для выделения физической памяти приложение вызывает Windows"функ" цию AllocateUserPhysicalPages. (Эта функция требует, чтобы у пользователя была привилегия Lock Pages In Memory.) Затем приложение обращается к Windows"функции VirtualAlloc с флагом MEM_PHYSICAL, чтобы создать окно в закрытой части адресного пространства процесса, на которое проецирует" ся (частично или полностью) ранее выделенная физическая память. Память, выделенная через AWE, может быть использована почти всеми функциями Windows API. (Например, функции Microsoft DirectX ее не поддерживают.) Если приложение создает в своем адресном пространстве окно размером 256 Мб и выделяет 4 Гб физической памяти (в системе с объемом физичес" кой памяти более 4 Гб), то оно получает доступ к любой части физической
ГЛАВА 9 Управление памятью 423 памяти, проецируя ее на это окно через Windows"функции MapUserPhysical Pages или MapUserPhysicalPagesScatter. Размер физической памяти, единовре" менно доступный приложению при такой схеме выделения, определяется размером окна в виртуальном адресном пространстве. На рис. 7"6 показано AWE"окно в адресном пространстве серверного приложения, на которое проецируется регион физической памяти, предварительно выделенный че" рез AllocateUserPhysicalPages. Рис. 7-6. Использование AWE для проецирования физической памяти AWE"функции имеются во всех выпусках Windows и доступны независи" мо от объема физической памяти в системе. Однако AWE наиболее полезен в системах с объемом физической памяти не менее 2 Гб, поскольку тогда этот механизм — единственное средство для прямого использования более чем 2 Гб памяти 32"разрядным процессом. Еще одно его применение — за" щита. Так как AWE"память никогда не выгружается на диск, данные в этой памяти никогда не имеют копии в страничном файле, а значит, никто не сумеет просмотреть их, загрузив компьютер с помощью альтернативной операционной системы. Теперь несколько слов об ограничениях, налагаемых на память, которая выделяется и проецируется с помощью AWE"функций. 쐽 Страницы такой памяти нельзя разделять между процессами. 쐽 Одну и ту же физическую страницу нельзя проецировать по более чем одному виртуальному адресу в рамках одного процесса. 쐽 В более старых версиях Windows страницы такой памяти могут иметь единственный атрибут защиты — «для чтения и записи». В Windows Server
424 ГЛ А В А 7 БЕЗОПАСНОСТЬ 2003 Service Pack 1 и выше также поддерживаются атрибуты «нет досту" па» и «только для чтения». О структурах данных таблицы страниц, используемой для проецирова" ния памяти в системах с более чем 4 Гб физической памяти, см. раздел «Phy" sical Address Extension (PAE)» далее в этой главе. Системные пулы памяти При инициализации системы диспетчер памяти создает два типа динамичес" ких пулов памяти, используемых компонентами режима ядра для выделения системной памяти. 쐽 Пул неподкачиваемой памяти (nonpaged pool) Состоит из диапа" зонов системных виртуальных адресов, которые всегда присутствуют в физической памяти и доступны в любой момент (при любом IRQL и из контекста любого процесса) без генерации ошибок страниц. Одна из причин существования такого пула — невозможность обработки ошибок страниц при IRQL уровня «DPC/dispatch» и выше (см. главу 2). 쐽 Пул подкачиваемой памяти (paged pool) Регион виртуальной памя" ти в системном пространстве, содержимое которого система может вы" гружать в страничный файл и загружать из него. Драйверы, не требующие доступа к памяти при IRQL уровня «DPC/dispatch» и выше, могут исполь" зовать память из этого пула. Он доступен из контекста любого процесса. Оба пула находятся в системном адресном пространстве и проецируются на виртуальное адресное пространство любого процесса (их начальные адреса в системной памяти перечислены в таблице 7"8). Исполнительная система предо" ставляет функции для выделения и освобождения памяти в этих пулах (см. опи" сание функций, чьи имена начинаются с ExAllocatePool, в Windows DDK). В однопроцессорных системах создается три пула подкачиваемой памя" ти, а в многопроцессорных — пять. Наличие нескольких подкачиваемых пулов уменьшает частоту блокировки системного кода при одновременных обращениях нескольких потоков к процедурам управления пулами. Началь" ный размер подкачиваемого и неподкачиваемого пулов зависит от объема физической памяти и может при необходимости расти до максимального значения, вычисляемого в период загрузки системы. ПРИМЕЧАНИЕ Будущие выпуски Windows, возможно, будут поддер" живать пулы динамических размеров, а значит, лимита на максималь" ный размер больше не будет. Таким образом, в приложениях и драй" верах устройств нельзя исходить из того, что максимальный размер пула является фиксированной величиной в любой системе. Настройка размеров пулов Чтобы установить другие начальные размеры этих пулов, измените значе" ния параметров NonPagedPoolSize и PagedPoolSize в разделе реестра HKLM\ SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management с 0
ГЛАВА 9 Управление памятью 425 (при этом система сама вычисляет размеры) на нужные величины (в байтах). Но вы не сможете превысить предельные значения, перечисленные в табли" це 7"5. Значение 0xFFFFFFFF для PagedPoolSize указывает, что выбран наи" больший из возможных размеров, однако увеличение пула подкачиваемой памяти будет происходить за счет записей системной таблицы страниц (page table entries, PTE). Таблица 7-5. Максимальные размеры пулов Максимальный размер в 32-разрядных системах Максимальный размер в 64-разрядных системах Неподкачиваемый 256 Мб (128 Мб, если был задан загрузочный параметр /3GB) 128 Гб Подкачиваемый 491,875 Мб (в Windows 2000 и Windows XP); 650 Мб (Windows Server 2003) 128 Гб Тип пула Рассчитанные значения размеров хранятся в четырех переменных ядра, три из которых экспортируются как счетчики производительности. Имена переменных, счетчиков и параметров реестра, позволяющих изменять раз" меры пулов, перечислены в таблице 7"6. Таблица 7-6. Переменные и счетчики производительности, отражающие размеры системных пулов Переменная ядра Счетчик производительности Раздел реестра MmSizeOfNonPa Memory: Pool Nonpa" Нет gedPoolInBytes ged Bytes (Память: Байт в невыгружаемом страничном пуле) Описание Текущий размер пула не" подкачиваемой памяти MmMaximum NonPaged PoolInBytes Нет HKLM\SYSTEM\ Максимальный размер CurrentControlSet\ пула неподкачиваемой Control\Session памяти Manager\Memory Management\ NonPagedPoolSize Нет Memory: Pool Paged Bytes (Память: Байт в выгружаемом стра" ничном пуле) Нет Текущий размер вирту" альной части пула под" качиваемой памяти MmPagedPool Memory: Pool Paged Нет Page Resident Bytes (Память: (число страниц) байт в резидентном страничном пуле) Текущий размер физи" ческой (резидентной) части пула подкачивае" мой памяти MmSizeOfPaged Нет PoolInBytes HKLM\SYSTEM\ Максимальный размер CurrentControlSet\ виртуальной части пула Control\Session подкачиваемой памяти Manager\Memory Management\ PagedPoolSize
426 ГЛ А В А 7 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: определяем максимальные размеры пулов Поскольку пулы подкачиваемой и неподкачиваемой памяти являются критическими ресурсами системы, важно знать, когда их размер при" ближается к расчетному для вашей системы пределу, чтобы задать зна" чение, отличное от установленного по умолчанию в соответствующих параметрах реестра. Счетчики выводят лишь текущий, но не макси" мальный размер, поэтому вы не узнаете о приближении к лимиту, пока не достигнете его. (Как уже говорилось, будущие версии Windows, воз" можно, будут поддерживать пулы динамических размеров. И тогда не" обходимость в проверке максимальных размеров пулов отпадет.) Получить максимальные размеры пулов можно с помощью Process Explorer или отладки ядра в работающей системе (см. главу 1). Для просмотра этих данных через Process Explorer, щелкните View, System Information. Максимальные размеры пулов показываются в секции Kernel Memory, как на следующей иллюстрации. Заметьте: чтобы Process Explorer мог получить эту информацию, у него должен быть доступ к символам для ядра данной системы. (Как настроить Process Explorer на использование символов, см. в экспери" менте «Просмотр детальных сведений о процессах с помощью Process Explorer» в главе 1.) Для просмотра той же информации в отладчике ядра используйте команду !vm: lkd> !vm *** Virtual Memory Usage *** Physical Memory: 261980 ( 1047920 Kb) Page File: \??\C:\pagefile.sys Current: 1024000Kb Free Space: 862236Kb Minimum: 1024000Kb Maximum: 1024000Kb Available Pages: 96077 ( 384308 Kb)
ГЛАВА 9 ResAvail Pages: Locked IO Pages: Free System PTEs: Free NP PTEs: Free Special NP: Modified Pages: Modified PF Pages: NonPagedPool Usage: NonPagedPool Max: PagedPool 0 Usage: PagedPool 1 Usage: PagedPool 2 Usage: PagedPool Usage: PagedPool Maximum: 194722 89 175933 31832 0 529 529 5617 52741 6582 3009 3044 12635 40960 ( ( ( ( ( ( ( ( ( ( ( ( ( ( 778888 356 703732 127328 0 2116 2116 22468 210964 26328 12036 12176 50540 163840 Управление памятью 427 Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) Kb) В этой системе размеры пулов подкачиваемой и неподкачиваемой памяти далеки от своих максимумов. Отладчик ядра также позволяет изучить значения переменных ядра, перечисленных в таблице 7"6: kd> dd mmmaximumnonpagedpoolinbytes l1 8047f620 0328c000 kd> ? 328c000 Evaluate expression: 53002240 = 0328c000 kd> dd mmsizeofpagedpoolinbytes l1 80470a98 06800000 kd> ? 6800000 Evaluate expression: 109051904 = 06800000 Из этого примера видно, что максимальный размер неподкачива" емого пула составляет 53 002 240 байтов (примерно 50 Мб), а макси" мальный размер подкачиваемого пула — 109 051 904 байта (104 Мб). В тестовой системе, использованной нами для этого эксперимента, текущий размер использованной памяти неподкачиваемого пула со" ставлял 5,5 Мб, а подкачиваемого пула — 34 Мб, так что оба пула были далеки от заполнения. Мониторинг использования пулов Объект Memory (Память) предоставляет отдельные счетчики размеров пулов неподкачиваемой и подкачиваемой памяти (как для виртуальной, так и для физической частей). Кроме того, утилита Poolmon из Windows Support Tools сообщает детальную информацию об использовании этих пулов. Для про" смотра такой информации нужно включить внутренний параметр Enable Pool Tagging (который всегда включен в проверочных версиях, а также в Windows Server 2003, где его вообще нельзя выключить). Чтобы включить данный па" раметр, запустите утилиту Gflags из Windows Support Tools, Platform SDK или DDK и выберите переключатель Enable Pool Tagging, как показано ниже.
428 ГЛ А В А 7 БЕЗОПАСНОСТЬ Теперь щелкните кнопку Apply и перезагрузите систему. После перезагруз" ки запустите Poolmon. При этом вы должны увидеть примерно следующее. Строки с меняющимися данными выделяются подсветкой. (Ее можно выключить, введя букву l в окне Poolmon. Повторный ввод l вновь включает подсветку.) Нажав клавишу со знаком вопроса в Poolmon, можно просмот" реть справочный экран. Вы можете указать пулы, за которыми хотите наблю" дать (только подкачиваемый, только неподкачиваемый или и то, и другое), а также порядок сортировки. Кроме того, на справочном экране поясняют" ся параметры командной строки, позволяющие наблюдать за конкретными структурами (или за всеми структурами, но одного типа). Так, команда pool mon iCM позволит следить только за структурами типа CM (которые при" надлежат диспетчеру конфигурации, управляющему реестром). Колонки, в которых программа выводит свою информацию, описаны в таблице 7"7.
ГЛАВА 9 Управление памятью 429 Таблица 7-7. Колонки в Poolmon Колонка Описание Tag Четырехбайтовая метка, которая присвоена данной области, выделенной из пула Type Тип пула (подкачиваемый или неподкачиваемый) Allocs Счетчик всех выделений из пула (число в скобках сообщает разни" цу между текущим значением в колонке Allocs и значением на мо" мент последнего обновления) Frees Счетчик всех освобождений (число в скобках сообщает разницу между текущим значением в колонке Frees и значением на момент последнего обновления) Diff Разница между Allocs и Frees Bytes Суммарное число байтов, занятых структурами этого типа (число в скобках сообщает разницу между текущим значением в колонке Bytes и значением на момент последнего обновления) Per Alloc Размер одного экземпляра данной структуры (в байтах) В этом примере структуры CM занимают основную часть пула подкачи" ваемой памяти, а структуры MmSt (структуры, относящиеся к управлению памятью и используемые для проецируемых файлов) — основную часть пула неподкачиваемой памяти. Описание меток пулов см. в файле \Program Files\Debugging Tools for Windows\Triage\Pooltag.txt. (Он устанавливается вместе с Windows Debugging Tools.) Поскольку в этом файле не перечислены метки пулов для сторонних драйверов устройств, используйте ключ –c в версии Poolmon, поставляемой с Windows Server 2003 Device Driver Kit (DDK), для генерации файла меток локальных пулов (Localtag.txt). В этом файле содержатся метки пулов, ис" пользуемых любыми драйверами, которые были обнаружены в вашей сис" теме. (Учтите: если двоичный файл драйвера устройства был удален после загрузки, метки его пулов не распознаются.) В качестве альтернативы можно вести поиск драйверов устройств в сис" теме по метке пула, используя утилиту Strings.exe с сайта www.sysinternals.com. Например, команда: strings \windows\system32\drivers\*.sys > findstr /i "abcd" покажет драйверы, содержащие строку «abcd». Заметьте, что драйверы уст" ройств не обязательно должны находиться в \Windows\System32\Drivers — они могут быть в любом каталоге. Чтобы перечислить полные пути всех за" груженных драйверов, откройте меню Start (Пуск), выберите команду Run (Выполнить) и введите Msinfo32. Потом щелкните Software Environment (Программная среда) и System Drivers (Системные драйверы). Еще один способ для просмотра использования пулов драйвером устрой" ства — включение наблюдения за пулами в Driver Verifier (см. далее в этой главе). Хотя при этом способе сопоставление метки пула с драйвером не нужно, он требует перезагрузки (чтобы включить функциональность наблю"
430 ГЛ А В А 7 БЕЗОПАСНОСТЬ дения за пулами в Driver Verifier для интересующих вас драйверов). После этого вы можете либо запустить Driver Verifier Manager (\Windows\System32\ Verifier.exe), либо использовать команду Verifier /Log для записи информации об использовании пулов в какой"либо файл. Наконец, если вы изучаете аварийный дамп, то можете исследовать ис" пользование пулов и с помощью команды !poolused. Команда !poolused 2 со" общает об использовании пула неподкачиваемой памяти с сортировкой по структурам, занимающим наибольшее количество памяти, а команда !poolu sed 4 — об использовании пула подкачиваемой памяти (с той же сортиров" кой). Ниже приведен фрагмент выходной информации этих двух команд. lkd> !poolused 2 Sorting by NonPaged Pool Consumed Pool Used: NonPaged Paged Tag Allocs Used Allocs Used MmCm 386 2237440 0 0 MmAllocateContiguousMemory, Binary: nt!mm File 12544 2121232 0 0 Devi 385 1487184 0 0 Ntfr 19163 1226888 0 0 Binary: ntfs.sys Calls made to File objects Device objects ERESOURCE, kd> !poolused 4 Sorting by Paged Pool Consumed Pool Used: NonPaged Paged Tag Allocs Used Allocs Used CM 11 704 5146 22311904 Gh 5 0 0 727 2523648 MmSt 0 0 968 1975872 Ntff 10 2240 790 682560 Gla1 1 128 383 600544 Ttfd 0 0 265 545440 ЭКСПЕРИМЕНТ: анализ утечки памяти в пуле В этом эксперименте вы устраните реальную утечку в пуле подкачи" ваемой памяти в своей системе, чтобы научиться на практике приме" нять способы, описанные в предыдущем разделе. Утечка будет созда" ваться утилитой NotMyFault, которую можно скачать по ссылке www.sysinternals.com/windowsinternals.shtml. (Заметьте, что эта утилита отсутствует в списке инструментов на основной странице Sysinternals.) После запуска NotMyFault.exe загружает драйвер устройства Myfault.sys и выводит такое диалоговое окно.
ГЛАВА 9 Управление памятью 431 1. Щелкните кнопку Leak Pool. Это заставит NotMyFault посылать зап" росы драйверу устройства Myfault на выделение памяти из подка" чиваемого пула. (Не нажимайте кнопку Do Bug, иначе вы вызовете крах системы; предназначение этой кнопки описывается в главе 14, где демонстрируются различные типы аварийных ситуаций.) Not" MyFault продолжит посылать запросы, пока вы не щелкнете кноп" ку Stop Leaking. Заметьте, что пул подкачиваемой памяти не осво" бождается даже при закрытии программы; в нем происходит посто" янная утечка памяти до перезагрузки системы. Однако, поскольку утечка пула будет непродолжительной, это не должно вызвать ни" каких проблем в вашей системе. 2. Пока происходит утечка памяти в пуле, сначала откройте диспет" чер задач и перейдите на вкладку Performance (Быстродействие). Вы увидите, как растет показатель Paged Pool (Выгружаемая память). То же самое можно увидеть в окне System Information утилиты Pro" cess Explorer. (Выберите Show и System Information.) 3. Чтобы определить метку пула, где происходит утечка, запустите Poolmon и нажмите клавишу b, чтобы сортировать по числу байтов. Дважды нажмите клавишу p для отображения в Poolmon только пула подкачиваемой памяти. Вы должны заметить, что пул с меткой «Leak» поднимается вверх по списку. (Poolmon выделяет строки, где происходят изменения.) 4. Теперь щелкните кнопку Stop Leaking, чтобы не истощить пул под" качиваемой памяти в своей системе. 5. Используя приемы, описанные в предыдущем разделе, запустите Strings (ее можно скачать с www.sysinternals.com) для поиска двоич" ных файлов драйвера, содержащих метку пула «Leak»: Strings \windows\system32\drivers\*.sys | findstr Leak Эта команда должна указать на файл Myfault.sys.
432 ГЛ А В А 7 БЕЗОПАСНОСТЬ Ассоциативные списки Windows поддерживает механизм быстрого выделения памяти — ассоциа тивные списки (look"aside lists). Главное различие между пулом и ассоциа" тивным списком в том, что из пула можно выделять блоки памяти различ" ного размера, а из ассоциативного списка — только фиксированные. Хотя пулы обеспечивают более высокую гибкость, ассоциативные списки рабо" тают быстрее, так как не используют спин"блокировку и не заставляют сис" тему подбирать подходящую область свободной памяти, в которой мог бы уместиться текущий выделяемый блок. Функции ExInitializeNPagedLookasideList и ExInitializePagedLookasideList (документированные в DDK) позволяют компонентам исполнительной си" стемы и драйверам устройств создавать ассоциативные списки, размеры которых кратны размерам наиболее часто используемых структур данных. Для минимизации издержек, связанных с синхронизацией в многопроцес" сорных системах, некоторые компоненты исполнительной системы, в том числе диспетчер ввода"вывода, диспетчер кэша и диспетчер объектов, созда" ют отдельные для каждого процессора ассоциативные списки, из которых выделяется память под часто используемые структуры данных. Сама испол" нительная система создает для каждого процессора универсальные ассоци" ативные списки подкачиваемой и неподкачиваемой памяти с гранулярнос" тью выделения в 256 байтов или менее. Если ассоциативный список пуст (как это бывает сразу после его созда" ния), система должна выделить память из подкачиваемого или неподкачи" ваемого пула. Но если в списке уже присутствует освобожденная структура, то занимаемая ею память выделяется очень быстро. (Список разрастается по мере возврата в него структур.) Процедуры выделения памяти из пула авто" матически настраивают число освобожденных буферов, хранящихся в ассо" циативном списке, в зависимости от частоты выделения памяти из этого списка драйвером или компонентом исполнительной системы. Чем чаще они выделяют память из списка, тем больше буферов в списке. Размер ассо" циативных списков автоматически уменьшается, если память из них не вы" деляется. (Эта проверка выполняется раз в секунду, когда системный поток диспетчера настройки баланса пробуждается и вызывает функцию KiAdjust LookasideDepth.) ЭКСПЕРИМЕНТ: просмотр системных ассоциативных списков Содержимое и размер различных ассоциативных списков в системе можно просмотреть командой !lookaside отладчика ядра. Вот фрагмент вывода этой команды. kd> !lookaside Lookaside "nt!IopSmallIrpLookasideList" @ 804758a0 "Irps" Type = 0000 NonPagedPool
ГЛАВА 9 Управление памятью 433 Current Depth = 3 Max Depth = 4 Size = 148 Max Alloc = 592 AllocateMisses = 32 FreeMisses = 9 TotalAllocates = 52 TotalFrees = 32 Hit Rate = 38% Hit Rate = 71% Lookaside "nt!IopLargeIrpLookasideList" @ 804756a0 "Irpl" Type = 0000 NonPagedPool Current Depth = 4 Max Depth = 4 Size = 436 Max Alloc = 1744 AllocateMisses = 2623 FreeMisses = 2443 TotalAllocates = 7039 TotalFrees = 6863 Hit Rate = 62% Hit Rate = 64% Lookaside "nt!IopMdlLookasideList" @ 80475740 "Mdl " Type = 0000 NonPagedPool Current Depth = 3 Max Depth = 4 Size = 120 Max Alloc = 480 AllocateMisses = 7017 FreeMisses = 1824 TotalAllocates = 10901 TotalFrees = 5711 Hit Rate = 35% Hit Rate = 68% ... Total NonPaged currently allocated for above lists = 4200 Total NonPaged potential for above lists = 6144 Total Paged currently allocated for above lists = 5136 Total Paged potential for above lists = 12032 Утилита Driver Verifier Driver Verifier представляет собой механизм, который можно использовать для поиска и локализации наиболее распространенных ошибок в драйверах устройств и другом системном коде режима ядра. Microsoft проверяет с по" мощью Driver Verifier свои драйверы и все драйверы, передаваемые произ" водителями оборудования для тестирования на совместимость и включения в список Hardware Compatibility List (HCL). Такое тестирование гарантирует совместимость драйверов, включенных в список HCL, с Windows и отсут" ствие в них распространенных ошибок. (Существует и парная утилита Appli" cation Verifier, позволяющая улучшить качество кода пользовательского ре" жима. Однако в этой книге она не рассматривается.) Driver Verifier поддерживается несколькими системными компонента" ми — диспетчером памяти, диспетчером ввода"вывода и HAL, которые пре" дусматривают параметры, включаемые для верификации драйверов. В этом разделе поясняются параметры верификации драйверов на отсутствие оши" бок, связанных с управлением памятью (см. также главу 9). Настройка и инициализация Driver Verifier Для настройки Driver Verifier и просмотра статистики запустите Driver Verifier Manager (Диспетчер проверки драйверов), файл \Windows\System32\Veri"
434 ГЛ А В А 7 БЕЗОПАСНОСТЬ fier.exe. После запуска появится окно с несколькими вкладками. Версия окна для Windows 2000 приведена на рис. 7"7. Чтобы указать, какие драйверы ус" тройств вы хотите проверить, и задать типы проверок, используйте вкладку Settings (Параметры). Рис. 7-7. Driver Verifier Manager в Windows 2000 В Windows XP и Windows Server 2003 этой утилите придали интерфейс в стиле мастера, как показано на рис. 7"8. Рис. 7-8. Driver Verifier Manager в Windows XP и Windows Server 2003 Включать и отключать Driver Verifier, а также просматривать текущие па" раметры можно из командной строки этой утилиты. Для вывода списка клю" чей наберите verifier /?. Настройки Driver Verifier Manager хранятся в разделе реестра HKLM\SYS" TEM\CurrentControlSet\Control\Session Manager\Memory Management. Пара" метр VerifyDriverLevel содержит битовую маску, представляющую включен" ные типы проверок. Имена проверяемых драйверов содержатся в парамет" ре VerifyDrivers. (Эти параметры создаются в реестре только после выбора проверяемых драйверов в окне Driver Verifier Manager.) Если вы выберете верификацию всех драйверов, VerifyDrivers будет содержать символ звездоч" ки. В зависимости от выбранных параметров может понадобиться переза" грузка системы.
ГЛАВА 9 Управление памятью 435 На ранних этапах загрузки диспетчер памяти считывает из реестра зна" чения этих параметров, определяя, какие драйверы следует верифицировать и какие параметры Driver Verifier включены. (Если загрузка происходит в безопасном режиме, все параметры Driver Verifier игнорируются.) Далее, если для проверки выбран хотя бы один драйвер, ядро сравнивает имя каждого загружаемого драйвера с именами драйверов, подлежащих верификации. Если имена совпадают, ядро вызывает функцию MiApplyDriverVerifier, которая заменяет все ссылки драйвера на функции ядра ссылками на эквивалентные функции Driver Verifier. Так, ExAllocatePool заменяется на VerifierAllocatePool. Драйвер подсистемы управления окнами производит аналогичные замены для использования эквивалентных функций Driver Verifier. Теперь рассмотрим четыре параметра верификации драйверов, относя" щиеся к использованию памяти: Special Pool, Pool Tracking, Force IRQL Che" cking и Low Resources Simulation. Special Pool (Особый пул) Этот параметр заставляет функции, отве" чающие за выделение памяти из пулов, окружать выделяемый блок недей" ствительными страницами, чтобы ссылки за пределы этого блока вызывали нарушение доступа в режиме ядра и последующий крах системы. А это по" зволяет тут же указать пальцем на сбойный драйвер. Параметр Special Pool также заставляет проводить дополнительные проверки, когда драйвер выде" ляет или освобождает память. При включении параметра Special Pool функции пулов выделяют в памя" ти ядра регион для Driver Verifier, и последний перенаправляет запросы про" веряемого драйвера на выделение памяти в особый пул, а не в стандартные пулы. При выделении драйвером памяти из особого пула Driver Verifier ок" ругляет размер выделяемого блока до размера, кратного размеру страницы. Поскольку Driver Verifier окружает выделенный блок недействительными страницами, при попытке записи или чтения за пределами этого блока драй" вер попадает на недействительную страницу, и диспетчер памяти сообщает о нарушении доступа в режиме ядра. На рис. 7"9 приведен пример блока, выделенного Driver Verifier в особом пуле для проверяемого драйвера устройства. Рис. 7-9. Структура области памяти, выделяемой в особом пуле
436 ГЛ А В А 7 БЕЗОПАСНОСТЬ По умолчанию Driver Verifier распознает ошибки, связанные с попытка" ми обращения за верхнюю границу выделенного блока (overrun errors). Он делает это, помещая используемый драйвером буфер в конец выделенной страницы и заполняя ее начало случайными значениями. Хотя Driver Verifier Manager не предусматривает параметр для включения детекции ошибок, свя" занных с попытками обращения за нижнюю границу выделенного блока (underrun errors), вы можете активизировать ее вручную, добавив в раздел реестра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory" Management параметр PoolTagOverruns типа DWORD и присвоив ему значе" ние 0 (или запустив утилиту Gflags и установив флажок Verify Start вместо установленного по умолчанию Verify End). Тогда Driver Verifier будет разме" щать буфер драйвера не в конце, а в начале страницы. Конфигурация, при которой Driver Verifier обнаруживает ошибки типа «overrun», до некоторой степени обеспечивает и распознавание ошибок типа «underrun». Когда драйвер освобождает буфер и возвращает его в Driver Verifier, последний должен убедиться, что содержимое памяти, предшествующее буфе" ру, не изменилось. Иное означает, что драйвер обратился к памяти, располо" женной до начала буфера, и что"то записал за пределами этого буфера. При выделении памяти из особого пула и ее освобождении также прове" ряется корректность IRQL процессора. Эта проверка позволяет выявить ошибку, встречающуюся в некоторых драйверах, из"за которой они пытают" ся выделять память в подкачиваемом пуле при IRQL уровня «DPC/dispatch» или выше. Особый пул можно сконфигурировать и вручную, добавив в раздел ре" естра HKLM\SYSTEMCurrentControlSet\Control\Session Manager\Memory Ma" nagement параметр PoolTag типа DWORD; он представляет тэги выделенной памяти, используемые системой для особого пула. Тогда, даже если Driver Verifier не настроен на верификацию данного драйвера, при совпадении тэга, сопоставленного с выделенной драйвером памятью, и значения PoolTag, память будет выделяться из особого пула. Если вы присвоите PoolTag значе" ние 0x0000002a или символ подстановки (*), то при наличии достаточного количества физической и виртуальной памяти вся память для драйверов бу" дет выделяться из особого пула. (Если памяти не хватит, драйверы вернутся к использованию обычного пула; размер каждого выделяемого блока огра" ничен двумя страницами.) Pool Tracking (Слежение за пулом) Если параметр Pool Tracking ак" тивен, диспетчер памяти проверяет при выгрузке драйвера, освободил ли тот всю выделенную для него память. Если нет, диспетчер памяти вызывает крах системы и сообщает о сбойном драйвере. Driver Verifier тоже показывает об" щую статистику по использованию пула — откройте вкладку Pool Tracking (Слежение за пулом) в Driver Verifier Manager (Диспетчер проверки драйве" ров). Кроме того, пригодится и команда !verifier отладчика ядра; она, кстати, выводит больше информации, чем Driver Verifier. Force IRQL Checking (Обяз. проверка IRQL) Одна из самых распро" страненных ошибок в драйверах устройств — попытка обращения к стра"
ГЛАВА 9 Управление памятью 437 ничному файлу при слишком высоком уровне IRQL процессора. Как уже го" ворилось в главе 3, диспетчер памяти не обрабатывает ошибки страниц при IRQL уровня «DPC/dispatch» или выше. Система часто не распознает экзем" пляры драйвера, обращающиеся к данным из подкачиваемого пула при по" вышенном IRQL процессора, поскольку в этот момент такие данные физи" чески присутствуют в памяти. Но в других случаях, если эти данные выгру" жены в страничный файл, попытка обращения к ним вызывает крах систе" мы со стоп"кодом IRQL_NOT_LESS_OR_EQUAL (т. е. IRQL превышает тот уро" вень, при котором возможно обращение к подкачиваемой памяти). Проверка драйверов устройств на наличие подобной ошибки — дело очень трудное, но Driver Verifier упрощает эту задачу. Если параметр Force IRQL Checking включен, Driver Verifier выводит весь подкачиваемый код и данные режима ядра из системного рабочего набора всякий раз, когда про" веряемый драйвер повышает IRQL. Это делается с помощью внутренней функции MmTrimAllSystemPagableMemory. При любой попытке проверяемо" го драйвера обратиться к подкачиваемой памяти при повышенном IRQL си" стема фиксирует нарушение доступа и происходит крах с сообщением, ука" зывающим на сбойный драйвер. Low Resources Simulation (Нехватка ресурсов) При включении это" го параметра Driver Verifier случайным образом отклоняет некоторые запро" сы драйвера на выделение памяти. Раньше разработчики создавали многие драйверы устройств в расчете на то, что памяти ядра всегда достаточно, так как иное означало бы, что система все равно вот"вот рухнет. Но, поскольку временная нехватка памяти иногда возможна, драйверы устройств должны корректно обрабатывать ошибки выделения памяти при ее нехватке. Через 7 минут после загрузки системы (этого времени достаточно для завершения критического периода инициализации, когда из"за нехватки памяти драйвер мог бы просто не загрузиться) Driver Verifier начинает слу" чайным образом отклонять запросы проверяемых драйверов на выделение памяти. Если драйвер не в состоянии корректно обработать ошибки выде" ления памяти, это скорее всего проявится в виде краха системы. Driver Verifier представляет собой ценное пополнение в арсенале средств верификации и отладки, доступном разработчикам драйверов устройств. Этот инструмент позволил с ходу выявить ошибки во многих драйверах. Так что Driver Verifier тоже внес вклад в повышение качества кода Windows, ра" ботающего в режиме ядра. Структуры виртуального адресного пространства Здесь описываются компоненты в пользовательском и системном адресных пространствах, а также специфика адресных пространств в 32" и 64"разряд" ных системах. Эта информация поможет вам понять ограничения на вирту" альную память для процессов и системы на обеих платформах.
438 ГЛ А В А 7 БЕЗОПАСНОСТЬ На виртуальное адресное пространство в Windows проецируются три основных вида данных: код и данные, принадлежащие процессу, код и дан" ные, принадлежащие сеансу, а также общесистемные код и данные. Как мы поясняли в главе 1, каждому процессу выделяется собственное ад" ресное пространство, недоступное другим процессам (если только у них нет разрешения на открытие процесса с правами доступа для чтения и записи). Потоки внутри процесса никогда не получают доступа к виртуальным адре" сам вне адресного пространства своего процесса, если только не проециру" ют данные на раздел общей памяти и/или не используют специальные функ" ции, позволяющие обращаться к адресному пространству другого процесса. Сведения о виртуальном адресном пространстве процесса хранятся в табли цах страниц (page tables), которые рассматриваются в разделе по трансляции адресов. Таблицы страниц размещаются на страницах памяти, доступных только в режиме ядра, поэтому пользовательские потоки в процессе не могут модифицировать структуру адресного пространства своего процесса. В системах с поддержкой нескольких сеансов (Windows 2000 Server с ус" тановленной службой Terminal Services, Windows XP и Windows Server 2003) пространство сеанса содержит информацию, глобальную для каждого сеан" са. (Подробное описание сеанса см. в главе 2.) Сеанс (session) состоит из процессов и других системных объектов (вроде WindowStation, рабочих сто" лов и окон). Эти объекты представляют сеанс единственного пользователя, который зарегистрировался на рабочей станции. У каждого сеанса есть своя область пула подкачиваемой памяти, используемая подсистемой Windows (Win32k.sys) для выделения памяти под сеансовые GUI"структуры данных. Кроме того, каждый сеанс получает свою копию процесса подсистемы Win" dows (Csrss.exe) и Winlogon.exe. За создание новых сеансов отвечает процесс диспетчера сеансов (Smss.exe). Его задачи включают загрузку сеансовых ко" пий Win32k.sys и создание специфических для сеанса экземпляров процес" сов Csrss и Winlogon, а также пространства имен диспетчера объектов. Для виртуализации сеансов все общие для сеанса структуры данных про" ецируются на область системного пространства, которая называется про странством сеанса (session space). При создании процесса этот диапазон адресов проецируется на страницы, принадлежащие тому сеансу, к которо" му относится данный процесс. Размер области для проецируемых представ" лений в пространстве сеанса можно настраивать, используя параметры в разделе реестра HKLM\System\CurrentControlSet\Control\Session Manager\ Memory Management. (В 32"разрядных системах эти параметры игнорируют" ся при загрузке системы с параметром /3GB.) Наконец, системное пространство содержит глобальные код и структу" ры данных операционной системы, видимые каждому процессу. Системное пространство состоит из следующих компонентов: 쐽 Системный код Содержит образ операционной системы, HAL и драй" веры устройств, используемые для загрузки системы.
ГЛАВА 9 Управление памятью 439 쐽 Представления, проецируемые системой Сюда проецируются Win32k.sys, загружаемая часть подсистемы Windows режима ядра, а так" же используемые ею графические драйверы режима ядра (подробнее о Win32k.sys см. главу 2). 쐽 Гиперпространство Особая область, применяемая для проецирования списка рабочего набора процесса и временного проецирования других физических страниц для таких операций, как обнуление страницы из списка свободных страниц (если список обнуленных страниц пуст и нуж" на обнуленная страница), подготовка адресного пространства при созда" нии нового процесса и объявление недействительными PTE в других таб" лицах страниц (например, при удалении страницы из списка простаива" ющих страниц). 쐽 Список системного рабочего набора Структуры данных списка ра" бочего набора, описывающие системный рабочий набор. 쐽 Системный кэш Виртуальное адресное пространство, применяемое для проецирования файлов, открытых в системном кэше. (О диспетчере кэша см. главу 11.) 쐽 Пул подкачиваемой памяти Системная куча подкачиваемой памяти. 쐽 Элементы системной таблицы страниц (PTE) Пул системных PTE, используемых для проецирования таких системных страниц, как про" странство ввода"вывода, стеки ядра и списки дескрипторов памяти. Вы можете узнать, сколько системных PTE доступно, проверив значение счетчика Memory: Free System Page Table Entries (Память: Свободных эле" ментов таблицы страниц) в оснастке Performance (Производительность). 쐽 Пул неподкачиваемой памяти Системная куча неподкачиваемой па" мяти, обычно состоящая из двух частей, которые располагаются внизу и вверху системного пространства. 쐽 Данные аварийного дампа Область, зарезервированная для записи информации о состоянии системы на момент краха. 쐽 Область, используемая HAL туры, специфичные для HAL. Область, зарезервированная под струк" ПРИМЕЧАНИЕ Внутреннее название системного рабочего набора — рабочий набор системного кэша (system cache working set). Однако этот термин неудачен, так как в системный рабочий набор входит не только кэш, но и пул подкачиваемой памяти, подкачиваемые систем" ные код и данные, а также подкачиваемые код и данные драйверов. Теперь после краткого обзора базовых компонентов виртуального адрес" ного пространства в Windows давайте рассмотрим специфику структур это" го пространства на платформах x86, IA64 и x64.
440 ГЛ А В А 7 БЕЗОПАСНОСТЬ Структуры пользовательского адресного пространства на платформе x86 По умолчанию каждый пользовательский процесс в 32"разрядной версии Windows располагает собственным адресным пространством размером до Гб; остальные 2 Гб забирает себе операционная система. Windows 2000 Advan" ced Server, Windows 2000 Datacenter Server, Windows XP Service Pack 2 и выше, а также Windows Server 2003 (все версии) поддерживают загрузочный пара" метр (ключ /3GB в Boot.ini), позволяющий создавать пользовательские ад" ресные пространства размером по 3 Гб. Windows XP и Windows Server 2003 поддерживают дополнительный ключ (/USERVA), который дает возможность задавать размер пользовательского адресного пространства между 2 и 3 Гб (значение указывается в мегабайтах). Структуры этих двух адресных про" странств показаны на рис. 7"10. Поддержка возможности расширения пользовательского адресного про" странства для 32"разрядного процесса за пределы 2 Гб введена как времен" ное решение для поддержки приложений вроде серверов баз данных, кото" рым для хранения данных требуется больше памяти, чем возможно в 2"ги" габайтном адресном пространстве. Но лучше, конечно, пользоваться уже рассмотренными AWE"функциями. Рис. 7-10. Структуры виртуального адресного пространства в системах типа x86
ГЛАВА 9 Управление памятью 441 Для расширения адресного пространства процесса за пределы 2 Гб в за" головке образа должен быть указан флаг IMAGE_FILE_LARGE_ADDRESS_AWA" RE. Иначе Windows резервирует это дополнительное пространство, и вир" туальные адреса выше 0x7FFFFFFF становятся недоступны приложению. (Так делается, чтобы избежать краха приложения, не способного работать с эти" ми адресами.) Этот флаг можно задать ключом компоновщика /LARGEAD" DRESSAWARE при сборке исполняемого файла. Данный флаг не действует при запуске приложения в системе с 2"гигабайтным адресным простран" ством для пользовательских процессов. (Если вы загрузите любую версию Windows Server с параметром /3GB, размер системного пространства умень" шится до 1 Гб, но пользовательское пространство все равно останется двух" гигабайтным, даже несмотря на поддержку запускаемой программой боль" шого адресного пространства.) Несколько системных образов помечаются как поддерживающие большие адресные пространства, благодаря чему они могут использовать преимуще" ства систем, работающих с такими пространствами. К их числу относятся: 쐽 Lsass.exe — подсистема локальной аутентификации; 쐽 Inetinfo.exe — Internet Information Services (IIS); 쐽 Chkdsk.exe — утилита Check Disk; 쐽 Dllhst3g.exe — специальная версия Dllhost.exe (для COM+"приложений). Наконец, поскольку по умолчанию память, выделяемая через VirtualAlloc, начинается с младших адресов (если только процесс не выделяет очень мно" го виртуальной памяти или не имеет очень сильно фрагментированного виртуального адресного пространства), она никогда не достигает самых старших адресов. Поэтому при тестировании вы можете указать, что выде" ление памяти должно начинаться со старших адресов. Для этого добавьте в реестр DWORD"параметр HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management\AllocationPreference и присвойте ему значение 0x100000. Структура системного адресного пространства на платформе x86 В этом разделе подробно описывается структура и содержимое системного пространства в 32"разрядной Windows. На рис. 7"11 показана общая схема 2"гигабайтного системного пространства на платформе x86. В таблице 7"8 перечислены переменные ядра, содержащие стартовые и конечные адреса различных регионов системного пространства: одни из них фиксированы, а другие вычисляются при загрузке с учетом доступного объема системной памяти и выпуска операционной системы Windows — клиентского или серверного.
442 ГЛ А В А 7 БЕЗОПАСНОСТЬ Рис. 7-11. Структура системного пространства в x86-системах (пропорции не соблюдены) Таблица 7-8. Системные переменные, определяющие адреса регионов в системном пространстве 2-гигабайтное системное пространство в х86системах (без PAE) Системная переменная Описание MmSystem RangeStart Стартовый адрес систем" 0x80000000 ного пространства MmSystemCache Список системного WorkingSetList рабочего набора 0xC0C00000 1-гигабайтное системное пространство в х86системах (без PAE) 0xC0000000 Вычисляется MmSystem CacheStart Начало системного кэша Вычисляется Вычисляется MmSystem CacheEnd Конец системного кэша Вычисляется Вычисляется MiSystemCache StartExtra Начало системного кэша Вычисляется или области расширения системных PTE 0
ГЛАВА 9 Управление памятью 443 Таблица 7-8. (окончание) Системная переменная Описание 2-гигабайтное системное пространство в х86системах (без PAE) 1-гигабайтное системное пространство в х86системах (без PAE) MiSystemCache EndExtra Конец системного кэша 0xC0000000 или области расширения системных PTE 0 MmPagedPool Start Начало подкачиваемого Вычисляется пула Вычисляется MmPagedPool End Конец подкачиваемого пула Вычисляется (максимум 650 Мб) Вычисляется (минимум 160 Мб) MmNonPaged SystemStart Начало системных PTE Вычисляется (минимум — 0xEB000000) Вычисляется MmNonPaged PoolStart Начало неподкачивае" мого пула Вычисляется Вычисляется MmNonPaged PoolExpansion Start Начало области расши" рения неподкачивае" мого пула Вычисляется Вычисляется MmNonPaged PoolEnd Конец неподкачивае" мого пула 0xFFBE0000 0xFFBE0000 Пространство сеанса на платформе x86 В системах с поддержкой нескольких сеансов код и данные, уникальные для каждого сеанса, проецируются в системное адресное пространство, но раз" деляются всеми процессами в данном сеансе. Общая схема сеансового про" странства представлена на рис. 7"12. Рис. 7-12. Структура сеансового пространства в x86-системах (пропорции не соблюдены) Размеры областей в сеансовом пространстве можно настраивать, добавляя параметры в раздел реестра HKLM\System\CurrentControlSet\Control\Session
444 ГЛ А В А 7 БЕЗОПАСНОСТЬ Manager\Memory Management. Эти параметры и соответствующие перемен" ные ядра, которые содержат реальные значения, перечислены в таблице 7"9. Таблица 7-9. Параметры конфигурации сеансового пространства Параметры реестра Переменные ядра SessionImageSize MmSessionImageSize SessionViewSize MmSessionViewSize SessionPoolSize MmSessionPoolSize ЭКСПЕРИМЕНТ: просмотр сеансов Узнать, какие процессы и к каким сеансам относятся, можно по счет" чику производительности Session ID (Код сеанса). Он доступен через диспетчер задач, Process Explorer или оснастку Performance (Произво" дительность). Используя команду !session отладчика ядра, можно пере" числить активные сеансы: lkd> !session Sessions on machine: 3 Valid Sessions: 0 1 2 Current Session 0 Далее вы можете установить активный сеанс командой !session –s и вывести адрес сеансовых структур данных и список процессов в этом сеансе командой !sprocess: lkd> !session s 2 Sessions on machine: 3 Implicit process is now 8144f3a0 Using session 2 lkd> !sprocess Dumping Session 2 _MM_SESSION_SPACE f9d5a000 _MMSESSION f9d5ad80 PROCESS 8144f3a0 SessionId: 2 Cid: 0d18 Peb: 7ffdf000 ParentCid: 0134 DirBase: 07ef7000 ObjectTable: e1855bb0 HandleCount: 71. Image: csrss.exe PROCESS 813f6500 SessionId: 2 Cid: 0d04 Peb: 7ffdf000 ParentCid: 0134 DirBase: 0f3fd000 ObjectTable: e18f3008 HandleCount: 131. Image: winlogon.exe Для просмотра детальных сведений о сеансе выведите дамп струк" туры MM_SESSION_SPACE командой dt: lkd> dt nt!_mm_session_space f9d4a000 nt!_MM_SESSION_SPACE +0x000 GlobalVirtualAddress : 0xf9d4a000 +0x004 ReferenceCount : 0x19 +0x008 u : __unnamed
ГЛАВА 9 Управление памятью 445 +0x00c SessionId : 0 +0x010 ProcessList : _LIST_ENTRY [ 0x817d92cc  0x812de88c ] +0x018 LastProcessSwappedOutTime : _LARGE_INTEGER 0x0 +0x020 SessionPageDirectoryIndex : 0x6a29 +0x024 NonPagablePages : 0xf +0x028 CommittedPages : 0x3f +0x02c PagedPoolStart : 0xbc000000 +0x030 PagedPoolEnd : 0xbc3fffff +0x034 PagedPoolBasePde : 0xc0300bc0 +0x038 Color : 0xd6 +0x03c ProcessOutSwapCount : 5 +0x040 SessionPoolAllocationFailures : [4] 0 +0x050 ImageList : _LIST_ENTRY [ 0x81801fa8  0x816933a0 ] +0x058 LocaleId : 0x409 +0x05c AttachCount : 0 +0x060 AttachEvent : _KEVENT +0x070 LastProcess : (null) +0x074 ProcessReferenceToSession : 25 +0x078 WsListEntry : _LIST_ENTRY [ 0x8056d058  0x8056d058 ] +0x080 Lookaside : [26] _GENERAL_LOOKASIDE +0xd80 Session : _MMSESSION +0xdc0 PagedPoolMutex : _KGUARDED_MUTEX +0xde0 PagedPoolInfo : _MM_PAGED_POOL_INFO +0xe00 Vm : _MMSUPPORT +0xe60 Wsle : 0xbf400038 +0xe64 Win32KDriverUnload : 0xbf9169ab +ffffffffbf9169ab +0xe68 PagedPool : _POOL_DESCRIPTOR +0x1e98 PageTables : 0x816e7008 +0x1e9c ImageLoadingCount : 0 ЭКСПЕРИМЕНТ: просмотр памяти, используемой пространством сеанса Просмотреть, как используется память в пространстве сеанса, позволяет команда !vm 4 отладчика ядра. Вот пример для 32"разрядной системы Windows Server 2003 Enterprise Edition с двумя активными сеансами: lkd> !vm 4 ... Terminal Server Memory Usage By Session: Session Paged Pool Maximum is 4096K Session View Space Maximum is 49152K Session ID 0 @ f9d4a000: Paged Pool Usage: 0K Commit Usage: 252K Session ID 1 @ f9d4c000: Paged Pool Usage: 0K Commit Usage: 172K см. след. стр.
446 ГЛ А В А 7 БЕЗОПАСНОСТЬ Та же команда применительно к 64"разрядной системе Windows Server 2003 Enterprise Edition с двумя активными сеансами дает следу" ющий вывод: Terminal Server Memory Usage By Session: Session Paged Pool Maximum is 65536K Session View Space Maximum is 106496K Session ID 0 @ fffffadfe4bb9000: Paged Pool Usage: 0K Commit Usage: 4608K Session ID 1 @ fffffadfe4c5f000: Paged Pool Usage: 0K Commit Usage: 584K Системные PTE Системные PTE используются для динамического проецирования системных страниц, в частности пространства ввода"вывода, стеков ядра и списков деск" рипторов памяти. Системные PTE не являются неисчерпаемым ресурсом. На" пример, Windows 2000 может описывать всего 660 Мб системного виртуально" го адресного пространства (из которых 440 Мб могут быть непрерывными). В 32"разрядных версиях Windows XP и Windows Server 2003 число доступных системных PTE увеличилось, благодаря чему система может описывать до 1,3 Гб системного виртуального адресного пространства, из которых 960 Мб могут быть непрерывными. В 64"разрядной Windows системные PTE позволяют опи" сывать до 128 Гб непрерывного виртуального адресного пространства. Число системных PTE показывается счетчиком Memory: Free System Page Table Entries (Память: Свободных элементов таблицы страниц) в оснастке Performance. По умолчанию Windows при загрузке подсчитывает, сколько системных PTE нужно создать, исходя из объема доступной памяти. Чтобы изменить это число, присвойте параметру реестра HKLM\SYSTEM\Current" ControlSet\Control\Session Manager\Memory Management\SystemPages значе" ние, равное нужному вам количеству PTE. (Это может понадобиться для под" держки устройств, требующих большого количества системных PTE, напри" мер видеоплат с 512 Мб видеопамяти, которую нужно спроецировать всю сразу.) Если параметр содержит значение 0xFFFFFFFF, резервируется макси" мальное число системных PTE. Структуры 64-разрядных адресных пространств Теоретически 64"разрядное виртуальное адресное пространство может быть до 16 экзабайтов (18 446 744 073 709 551 616 байтов, или примерно 17,2 мил" лиарда гигабайтов). В отличие от 32"разрядного адресного пространства на платформ x86, где по умолчанию оно делится на две равные части (полови" на для процесса и половина для системы), 64"разрядное адресное простран" ство делится на ряд регионов разного размера, компоненты которого концеп"
ГЛАВА 9 Управление памятью 447 туально совпадают с порциями пользовательского, системного и сеансового пространств. Размер этих регионов (таблица 7"10) отражает лимиты текущей реализации, которые могут быть расширены в будущих выпусках. Детальные структуры адресных пространств IA64 и x64 различаются не" значительно. Структуру адресного пространства для IA64 см. на рис. 7"13, а для x64 — на рис. 7"14. Рис. 7-13. Структура адресного пространства на платформе IA64
448 ГЛ А В А 7 Таблица 7-10. БЕЗОПАСНОСТЬ Размеры регионов в 64-разрядном адресном пространстве Регион Адресное пространство процесса Пространство системных PTE Системный кэш Пул подкачиваемой памяти Пул неподкачиваемой памяти Рис. 7-14. IA64 7152 Гб 128 Гб 128 Гб 128 Гб 128 Гб x64 8192 Гб 128 Гб 128 Гб 128 Гб 128 Гб Структура адресного пространства на платформе x64 x86 2–3 Гб 1,2 Гб 960 Мб 470–650 Мб 256 Мб
ГЛАВА 9 Управление памятью 449 Трансляция адресов Теперь, когда вы познакомились со структурами виртуального адресного про" странства в Windows, рассмотрим, как она увязывает эти адресные простран" ства со страницами физической памяти (приложения и системный код ис" пользуют виртуальные адреса). Мы начнем с детального описания трансляции 32"разрядных адресов на платформе x86, потом кратко поясним ее отличия на 64"разрядных платформах IA64 и x64. В следующем разделе вы узнаете, что происходит, когда виртуальный адрес не удается разрешить в физический (из" за выгрузки в страничный файл), и как Windows управляет физической памя" тью через рабочие наборы и базу данных номеров фреймов страниц. Трансляция виртуальных адресов на платформе x86 С помощью структур данных (таблиц страниц), создаваемых и поддержива" емых диспетчером памяти, процессор транслирует виртуальные адреса в физические. Каждый виртуальный адрес сопоставлен со структурой систем" ного пространства, которая называется элементом таблицы страниц (page table entry, PTE) и содержит физический адрес, соответствующий виртуаль" ному. Например, на рис. 7"15 показаны три последовательно расположенные виртуальные страницы, проецируемые на три разрозненные физические страницы (платформа x86). Рис. 7-15. Трансляция виртуальных адресов в физические (x86)
450 ГЛ А В А 7 БЕЗОПАСНОСТЬ Пунктирные линии на рис. 7"15 соединяют виртуальные страницы с PTE, представляя косвенные связи между виртуальными и физическими страницами. ПРИМЕЧАНИЕ Код режима ядра (например, драйверов устройств) может ссылаться на физические адреса, транслируя их в виртуальные. Подробнее об этом см. описание функций поддержки списка дескрип" торов памяти (memory descriptor list, MDL) в DDK. По умолчанию в x86"системе Windows для трансляции виртуальных ад" ресов в физические использует двухуровневую таблицу страниц (x86"систе" мы, работающие с PAE"версией ядра, используют трехуровневую таблицу страниц, но они в этом разделе не рассматриваются). 32"разрядный вирту" альный адрес интерпретируется как совокупность трех элементов: индекса каталога страниц, индекса таблицы страниц и индекса байта. Они применя" ются в качестве указателей в структурах, описывающих проекции страниц (рис. 7"16). Размеры страницы и PTE определяет размеры каталога страниц и полей индекса таблицы страниц. Так, в x86"системах длина индекса байта составляет 12 битов, поскольку размер страницы равен 4096 байтов (т. е. 212). Рис. 7-16. Элементы 32-разрядного виртуального адреса в x86-системах Индекс каталога страниц (page directory index) применяется для поис" ка таблицы страниц, содержащей PTE для данного виртуального адреса. С помощью индекса таблицы страниц (page table index) осуществляется по" иск PTE, который, как уже говорилось, содержит физический адрес, по ко" торому проецируется виртуальная страница. Индекс байта (byte index) по" зволяет найти конкретный адрес на физической странице. Взаимосвязи этих трех величин и их использование для трансляции виртуальных адресов в физические показаны на рис. 7"17. При трансляции виртуального адреса выполняются следующие операции. 1. Аппаратные средства управления памятью находят каталог страниц теку" щего процесса. При каждом переключении контекста процесса эти сред" ства получают адрес каталога страниц нового процесса. Обычно операци" онная система записывает этот адрес в специальный регистр процессора. 2. Индекс каталога страниц используется как указатель для поиска элемен" та каталога страниц (page directory entry, PDE), который определяет мес" тонахождение таблицы страниц, нужной для трансляции виртуального адреса. PDE содержит номер фрейма страницы (page frame number, PFN) таблицы страниц (если она находится в памяти; однако такие таблицы могут выгружаться в страничный файл).
ГЛАВА 9 Рис. 7-17. Управление памятью 451 Трансляция виртуального адреса в x86-системах 3. Индекс таблицы страниц используется как указатель для поиска PTE, ко" торый определяет местонахождение требуемой виртуальной страницы. 4. На основе PTE отыскивается страница. Если она действительна, то содер" жит PFN соответствующей страницы физической памяти. Если PTE сооб" щает, что страница недействительна, обработчик ошибок подсистемы управления памятью пытается найти страницу и сделать ее действитель" ной (см. раздел по обработке ошибок страниц далее в этой главе). Если сделать страницу действительной не удалось (например, из"за ошибки защиты), обработчик ошибок генерирует нарушение доступа или вызы" вает переход в состояние отладки. 5. Если PTE указывает на действительную страницу, для поиска адреса нуж" ных данных на физической странице используется индекс байта. Ознакомившись с общей картиной, перейдем к детальному рассмотре" нию структуры каталогов страниц, таблиц страниц и PTE. Каталоги страниц У каждого процесса есть один каталог страниц (page directory), который представляет собой страницу с адресами всех таблиц страниц для данного процесса. Физический адрес каталога страниц процесса хранится в блоке KPROCESS и проецируется по адресу 0xC0300000 в x86"системах или 0xC0600000 в системах с PAE"ядром. Весь код, выполняемый в режиме ядра, использует не физические, а виртуальные адреса (о KPROCESS см. главу 6). Процессору известно местонахождение страницы каталога страниц, по" скольку в специальный регистр процессора (CR3 в x86"системах) загружен ее физический адрес. При каждом переключении контекста на поток другого процесса процедура ядра, отвечающая за переключение контекста, загружает в этот регистр значение из блока KPROCESS нового процесса. Переключе"
452 ГЛ А В А 7 БЕЗОПАСНОСТЬ ние контекста между потоками одного процесса не влечет перезагрузку фи" зического адреса каталога страниц, поскольку все потоки одного процесса используют одно и то же адресное пространство. Каталог страниц состоит из элементов (PDE), каждый из которых имеет длину 4 байта (в системах с PAE"ядром — 8 байтов) и описывает состояние и адреса всех возможных таблиц страниц для данного процесса. (Как будет сказано далее, таблицы страниц создаются по мере необходимости, так что каталоги страниц большинства процессов ссылаются лишь на небольшой набор таких таблиц.) Мы не будем отдельно рассматривать формат PDE, поскольку он в основном совпадает с форматом аппаратного PTE. В x86"системах без PAE для полного описания 4"гигабайтного виртуаль" ного адресного пространства требуется 1024 таблицы страниц. Каталог страниц процесса, связывающий эти таблицы, содержит 1024 PDE. Соответ" ственно размер индекса каталога равен 10 битам (210 = 1024). В x86"систе" мах, работающих в режиме PAE, в таблице страниц 512 элементов (размер индекса каталога страниц равен 9 битам). Из"за наличия 4 каталогов стра" ниц максимальное число таблиц страниц составляет 2048. ЭКСПЕРИМЕНТ: исследуем каталог страниц и PDE Физический адрес каталога страниц текущего процесса можно уви" деть, изучив поле DirBase в выходной информации команды !process отладчика ядра. Виртуальный адрес каталога страниц можно выяснить из инфор" мации, выводимой отладчиком ядра для PTE конкретного виртуально" го адреса, как показано ниже. Часть выходной информации отладчика ядра, касающаяся PTE, рас" сматривается в разделе «Страницы таблиц и PTE» далее в этой главе.
ГЛАВА 9 Управление памятью 453 Поскольку Windows предоставляет каждому процессу закрытое адресное пространство, у каждого процесса свой набор таблиц страниц для проеци" рования этого пространства. В то же время таблицы страниц, описывающие системное пространство, разделяются всеми процессами (а пространство сеанса разделяется процессами в сеансе). Чтобы не допустить появления нескольких таблиц страниц, описывающих одну и ту же виртуальную память, при создании процесса PDE, описывающие системное пространство, ини" циализируются так, чтобы они указывали на существующие системные таб" лицы страниц. Если процесс является частью сеанса, таблицы страниц, опи" сывающие пространство сеанса, тоже используются совместно. Для этого PDE пространства сеанса инициализируются так, чтобы они указывали на существующие сеансовые таблицы страниц. Однако, как показано на рис. 7"18, не все процессы имеют одинаковое пред" ставление системного пространства. Так, если при расширении пула подкачи" ваемой памяти требуется создать новую системную таблицу страниц, диспет" чер памяти — вместо того чтобы сразу записывать указатели на новую систем" ную таблицу во все каталоги страниц процессов — обновляет эти каталоги только по мере обращения процессов по новому виртуальному адресу. Рис. 7-18. Системные таблицы страниц и таблицы страниц, принадлежащие процессам
454 ГЛ А В А 7 БЕЗОПАСНОСТЬ Таким образом, при обращении к пулу подкачиваемой памяти может возник" нуть ошибка страницы из"за того, что каталог страниц процесса еще не содер" жит указатель на новую системную таблицу страниц, описывающую новую об" ласть пула. Но при доступе к пулу неподкачиваемой памяти таких ошибок не возникает, хотя он тоже может расширяться. Дело в том, что при инициализа" ции системы Windows создает все системные таблицы страниц, которые описы" вают максимально возможный объем пула неподкачиваемой памяти. Страницы таблиц и PTE Элементы каталога страниц (page directory entries, PDE), принадлежащего процессу, указывают на индивидуальные таблицы страниц, которые состо" ят из массива PTE. Поле индекса таблицы страницы в виртуальном адресе (как показано на рис. 7"17) определяет PTE нужной страницы данных. В x86" системах размер этого индекса равен 10 битам (в PAE — 9), что позволяет ссылаться на 1024 4"байтных PTE (в PAE — на 512 8"байтных PTE). Но, по" скольку 32"разрядная Windows предоставляет процессам 4"гигабайтное зак" рытое адресное пространство, для проецирования всего адресного про" странства одной таблицы страниц мало. Чтобы подсчитать количество таб" лиц страниц, нужных для проецирования всех 4 Гб виртуального адресного пространства, поделите 4 Гб на объем виртуальной памяти, описываемой одной таблицей. Помните, что каждая таблица страниц в x86"системах оп" ределяет страницы данных суммарным размером в 4 Мб (в PAE — 2 Мб). Поэтому для проецирования всех 4 Гб адресного пространства требуется 1024 (4 Гб / 4 Мб) таблицы страниц, а в PAE"системах — 2048 (4 Гб / 2 Мб). Для изучения PTE используйте команду !pte отладчика ядра (см. экспери" мент «Трансляция адресов» далее в этой главе). Действительные PTE (здесь мы обсуждаем именно их — о недействительных PTE см. далее) состоят из двух основных полей (рис. 7"19): поля PFN физической страницы с данны" ми (или физического адреса страницы в памяти) и поля флагов, описываю" щих состояние и атрибуты защиты страницы. Рис. 7-19. Действительные аппаратные PTE в x86-системах
ГЛАВА 9 Управление памятью 455 Как вы еще увидите, битовые флаги, помеченные как зарезервированные (рис. 7"19), используются, только если PTE недействителен (флаги интерпре" тируются программно). Аппаратно определяемые битовые флаги действи" тельного PTE перечислены в таблице 7"11. Таблица 7-11. Битовые флаги PTE Битовые флаги Описание Accessed Была операция чтения с данной страницы Cache disabled Кэширование данной страницы отключено Dirty Страница модифицирована Global Трансляция относится ко всем процессам (например, сброс буфера трансляции не повлияет на этот PTE) Large page Указывает, что PDE относится к 4"мегабайтной странице (или к 2"мегабайтной в PAE) Owner Указывает, доступна ли страница из кода пользователь" ского режима Valid Указывает, соответствует ли PTE странице в физической памяти Write through Отключает кэширование записи на данную страницу, в результате чего все измененные данные сразу же сбрасываются на диск Write В однопроцессорных системах указывает тип доступа (для чтения и записи или только для чтения), а в много" процессорных системах определяет, доступна ли эта страница для записи (битовый флаг Write хранится в зарезервированной области PTE) В x86"системах аппаратный PTE содержит биты Dirty и Accessed. Бит Accessed равен 0, если данные физической страницы, представляемой PTE, не были считаны или записаны. Процессор устанавливает этот бит при пер" вой операции чтения или записи страницы. Бит Dirty устанавливается только после первой записи на страницу. Кроме того, бит Write обеспечивает защи" ту страницы: если он сброшен, страница доступна только для чтения, а если он установлен, страница доступна как для чтения, так и для записи. Когда поток пытается что"то записать на страницу со сброшенным битом Write, возникает исключение управления памятью, и обработчик, принадлежащий диспетчеру памяти, решает, может ли поток записывать данные на эту стра" ницу (если она, например, помечена как копируемая при записи) или сле" дует сгенерировать нарушение доступа. Для аппаратных PTE в многопроцессорных x86"системах предусматри" вается дополнительный бит Write, реализуемый программно и предотвраща" ющий остановку системы при сбросе кэша PTE (также называемого ассоци" ативным буфером трансляции). Этот бит указывает, что страница была мо" дифицирована другим процессором.
456 ГЛ А В А 7 БЕЗОПАСНОСТЬ Адрес байта в пределах страницы Как только диспетчер памяти находит искомую страницу, он переходит к поиску нужных данных на этой странице. На этом этапе используется поле индекса байта. Оно сообщает процессору, к какому байту данных на этой странице вы хотите обратиться. В x86"системах этот индекс состоит из 12 битов, что позволяет адресоваться максимум к 4096 байтам данных. Таким образом, добавление смещения байта к PFN, извлеченному из PTE, заверша" ет трансляцию виртуального адреса в физический. ЭКСПЕРИМЕНТ: трансляция адресов Чтобы получше разобраться в том, как транслируются адреса, рассмот" рим реальный пример трансляции виртуального адреса в x86"систе" ме без поддержки PAE и с помощью отладчика ядра исследуем катало" ги страниц, таблицы страниц и PTE. В этом примере мы используем процесс с виртуальным адресом 0x50001, спроецированным на дей" ствительный физический адрес. Как наблюдать за трансляцией недей" ствительных адресов, мы поясним в последующих примерах. Сначала преобразуем 0x50001 в двоичное значение и разобьем его на три поля, используемых при трансляции адреса. В двоичной систе" ме счисления 0x50001 соответствует значению 101.0000.0000.0000.0001, а его поля выглядят так: Чтобы начать трансляцию, процессор должен знать физический адрес каталога страниц, который хранится в регистре CR3, пока вы" полняется поток соответствующего процесса. Этот адрес можно полу" чить как из регистра CR3, так и из дампа блока KPROCESS интересую" щего вас процесса с помощью команды !process отладчика ядра. В данном случае физический адрес каталога страниц — 0x12F0000. Как видно на иллюстрации, поле индекса каталога страниц в этом при" мере равно 0. Поэтому физический адрес PDE — 0x12F0000. Команда !pte отладчика ядра выводит PDE и PTE, описывающие вир" туальный адрес:
ГЛАВА 9 Управление памятью 457 В первой колонке отладчик ядра сообщает PDE, а во второй — PTE. Заметьте, что показывается виртуальный адрес PDE, а не физический. Как уже говорилось, каталог страниц процесса в x86"системах начина" ется с виртуального адреса 0xC0300000. Поскольку мы изучаем первый PDE каталога страниц, его адрес совпадает с адресом самого каталога. Виртуальный адрес PTE равен 0xC0000140. Его можно вычислить, умножив индекс таблицы страниц (в данном случае — 0x50) на размер PTE (4), что дает 0x140. Поскольку диспетчер памяти проецирует таб" лицы страниц с адреса 0xC0000000, после добавления 140 получится виртуальный адрес, показанный на листинге: 0xC0000140. PFN страни" цы в каталоге страниц равен 0x700, а PFN страницы данных — 0xe63. Флаги PTE показываются справа от PFN. Так, PTE, описывающий упомянутую выше страницу, имеет флаги D"""UWV, где D обозначает dirty (данные страницы изменены), U — user"mode page (страница пользовательского режима), а V — valid (действительная страница). Ассоциативный буфер трансляции Как вы уже знаете, трансляция каждого адреса требует двух операций поис" ка: сначала нужно найти подходящую таблицу страниц в каталоге страниц, затем — элемент в этой таблице. Поскольку выполнение этих двух операций при каждом обращении по виртуальному адресу могло бы снизить быстро" действие системы до неприемлемого уровня, большинство процессоров кэ" шируют транслируемые адреса, в результате чего необходимость в повтор" ной трансляции при обращении к тем же адресам отпадает. Процессор под" держивает такой кэш в виде массива ассоциативной памяти, называемого ассоциативным буфером трансляции (translation look"aside buffer, TLB). Ассоциативная память вроде TLB представляет собой вектор, ячейки кото" рого можно считывать и сразу сравнивать с целевым значением. В случае TLB вектор содержит сопоставления физических и виртуальных адресов для недавно использовавшихся страниц, а также атрибуты защиты каждой стра" ницы, как показано на рис. 7"20. Каждый элемент TLB похож на элемент кэша, в метке которого хранятся компоненты виртуального адреса, а в поле
458 ГЛ А В А 7 БЕЗОПАСНОСТЬ данных — номер физической страницы, атрибуты защиты, битовый флаг Valid и, как правило, битовый флаг Dirty. Эти флаги отражают состояние страницы, которой соответствует кэшированный PTE. Если в PTE установлен битовый флаг Global (используется для страниц системного пространства, глобально видимых всем процессам), то при переключениях контекста эле" мент TLB не объявляется недействительным. Рис. 7-20. Применение ассоциативного буфера трансляции Часто используемым виртуальным адресам обычно соответствуют эле" менты в TLB, который обеспечивает чрезвычайно быструю трансляцию вир" туальных адресов в физические, а в результате и быстрый доступ к памяти. Если виртуального адреса в TLB нет, он все еще может быть в памяти, но для его поиска понадобится несколько обращений к памяти, что увеличит вре" мя доступа. Если виртуальный адрес оказался в страничном файле или если диспетчер памяти изменил его PTE, диспетчер памяти должен явно объявить соответствующий элемент TLB недействительным. Если процесс повторно обращается к нему, генерируется ошибка страницы, нужная страница загру" жается обратно в память и для нее вновь создается элемент TLB. Диспетчер памяти по возможности обрабатывает аппаратные и програм" мные PTE одинаково. Так, при объявлении недействительного PTE действи" тельным диспетчер памяти вызывает функцию ядра, которая обеспечивает аппаратно"независимую загрузку в TLB нового PTE. В x86"системах эта функ" ция заменяется командой NOP, поскольку процессоры типа x86 самостоя" тельно загружают данные в TLB. Physical Address Extension (PAE) Режим проецирования памяти Physical Address Extension (PAE) впервые по" явился в x86"процессорах Intel Pentium Pro. При наличии соответствующей поддержки со стороны чипсета в режиме PAE можно адресоваться максимум к 64 Гб физической памяти на текущих x86"процессорах Intel и к 1024 Гб на
ГЛАВА 9 Управление памятью 459 x64"процессорах (хотя в настоящее время Windows ограничивает этот по" казатель 128 Гб из"за размера базы данных PFN, которая понадобилась бы для проецирования такого большого объема памяти). При работе процессо" ра в режиме PAE блок управления памятью (memory management unit, MMU) разделяет виртуальные адреса на 4 поля (рис. 7"21). Рис. 7-21. Проецирование страниц по механизму PAE При этом MMU по"прежнему реализует каталоги и таблицы страниц, но создает над ними третий уровень — таблицу указателей на каталоги страниц. PAE"режим позволяет адресовать больше памяти, чем стандартный, — но не из"за дополнительного уровня трансляции, а из"за большего размера PDE и PTE (по 64 бита вместо 32). Внутренне система представляет физический адрес 25 битами, что позволяет поддерживать максимум 225+12 байтов, или 128 Гб, памяти. Для 32"разрядных приложений один из способов использо" вания конфигураций с такими большими объемами памяти был представлен в разделе «Address Windowing Extensions» ранее в этой главе. Но, даже если приложения не обращаются к таким функциям, диспетчер памяти все рав" но задействует всю доступную физическую память под данные файлового кэша (см. раздел «База данных PFN» далее в этой главе). Как мы поясняли в главе 2, существует специальная версия 32"разрядно" го ядра с поддержкой PAE — Ntkrnlpa.exe. Для загрузки этой версии ядра ука" жите в Boot.ini параметр /PAE. Заметьте, что она устанавливается во всех 32"разрядных системах Windows, даже в системах Windows 2000 Professional или Windows XP с малой памятью. Цель — упростить тестирование драйве" ров устройств. Поскольку в PAE"ядре драйверы устройств и другой систем" ный код используют 64"разрядные адреса, загрузка с параметром /PAE по"
460 ГЛ А В А 7 БЕЗОПАСНОСТЬ зволяет разработчикам тестировать свои драйверы на совместимость с сис" темами, имеющими большие объемы памяти. Кстати, в связи с этим Boot.ini поддерживает еще один параметр — /NOLOWMEM, который запрещает ис" пользовать первые 4 Гб памяти (предполагается, что на компьютере установ" лено минимум 5 Гб физической памяти) и модифицирует адреса драйверов устройств для размещения выше этой границы, что гарантирует выход фи" зических адресов драйверов за пределы 32"разрядных значений. Трансляция виртуальных адресов на платформе IA64 Виртуальное адресное пространство на платформе IA64 аппаратно делится на восемь регионов. У каждого региона свой набор таблиц страниц. Windows использует только пять регионов, закрепляя таблицы страниц за тремя из них. Все регионы перечислены в таблице 7"12. Таблица 7-12. Регионы IA64 Регион Описание 0 Пользовательский код и данные 1 Код и данные пространства сеанса 2 Не используется 3 Не используется 4 Kseg3, который представляет собой кэшируемую проекцию «один к одному» (cached 1"to"1 mapping) физической памяти. Таблицы стра" ниц для этого региона не нужны, так как операции вставки в TLB вы" полняются напрямую диспетчером памяти 5 Kseg4, который представляет собой некэшируемую проекцию «один к одному» (noncached 1"to"1 mapping) для физической памяти. Используется только в некоторых местах для доступа к адресам ввода" вывода, например к диапазонам портов ввода"вывода. Таблицы стра" ниц для этого региона не нужны 6 Не используется 7 Код и данные ядра При трансляции адресов 64"разрядной Windows на платформе IA64 ис" пользуется трехуровневая схема таблиц страниц. Каждый процесс получает специальную структуру, содержащую 1024 указателя на каталоги страниц. Каждый каталог страниц содержит 1024 указателя на таблицы страниц, а те в свою очередь указывают на страницы физической памяти. Формат аппа" ратных PTE на платформе IA64 показан на рис. 7"22.
ГЛАВА 9 Рис. 7-22. Управление памятью 461 Аппаратные PTE в IA64-системах Трансляция виртуальных адресов на платформе x64 64"разрядная Windows на платформе x64 применяет четырехуровневую схе" му таблиц страниц. У каждого процесса имеется расширенный каталог стра" ниц верхнего уровня (называемый картой страниц уровня 4), содержащий 512 указателей на структуру третьего уровня — родительский каталог стра" ниц. Каждый родительский каталог страниц хранит 512 указателей на ката" логи страниц второго уровня, а те содержат по 512 указателей на индиви" дуальные таблицы страниц. Наконец, таблицы страниц (в каждой из кото" рых 512 PTE) указывают на страницы в памяти. В текущих реализациях ар" хитектуры x64 размер виртуальных адресов ограничен 48 битами. Элемен" ты 48"битного виртуального адреса представлены на рис. 7"23. Взаимосвязь между этими элементами показана на рис. 7"24, а формат аппаратного PTE на платформе x64 приведен на рис. 7"25. Рис. 7-23. Виртуальный адрес на платформе x64
462 ГЛ А В А 7 БЕЗОПАСНОСТЬ Рис. 7-24. Структуры трансляции адресов в x64-системах Рис. 7-25. Аппаратные PTE в x64-системах Обработка ошибок страниц Мы уже разобрались, как происходит трансляция адресов при действитель" ных PTE. Если битовый флаг Valid в PTE сброшен, это значит, что нужная страница по какой"либо причине сейчас недоступна процессу. Здесь мы рас" скажем о типах недействительных PTE и о том, как разрешаются ссылки на такие PTE. ПРИМЕЧАНИЕ В этой книге детально рассматриваются только PTE на 32"разрядной платформе x86. PTE для 64"разрядных систем содержат ана" логичную информацию, но их подробную структуру мы не описываем. При ссылке на недействительную страницу возникает ошибка страни цы (page fault), и обработчик ловушки ядра (см. главу 3) перенаправляет ее
ГЛАВА 9 Управление памятью 463 обработчику MmAccessFault диспетчера памяти. Последняя функция, выпол" няемая в контексте вызвавшего ошибку потока, предпринимает попытку ее разрешения (если это возможно) или генерирует соответствующее исклю" чение. Причины таких ошибок перечислены в таблице 7"13. Таблица 7-13. Причины ошибок доступа к страницам Причина Результат Обращение к странице, которая нахо" дится в страничном или проецируе" мом файле, но отсутствует в памяти Выделение физической страницы и считы" вание нужной страницы с диска в рабочий набор Обращение к странице из списка про" стаивающих (standby list) или моди" фицированных страниц (modified list) Перемещение страницы в рабочий набор системы или процесса Обращение к еще не переданной странице (например, к зарезервиро" ванному или еще не выделенному адресному пространству) Нарушение доступа Обращение из пользовательского режима к странице, доступной только из режима ядра Нарушение доступа Попытка записи на страницу, доступ" ную только для чтения Нарушение доступа Обращение к странице, обнуляемой по требованию (demand"zero page) Добавление страницы, заполненной нулями, в рабочий набор процесса Попытка записи на сторожевую стра" ницу (guard page) Нарушение доступа (если ссылка относи" лась к стеку пользовательского режима, он автоматически расширяется) Попытка записи на страницу с атри" бутом «копирование при записи» Создание копии этой страницы для процес" са (или сеанса) и замена ею исходной стра" ницы в рабочем наборе процесса, сеанса или системы Ссылка на действительную страницу Копирование PDE из главного системного в системном пространстве, но отсут" каталога страниц и закрытие исключения ствующую в каталоге страниц процесса (например при расширении подкачи" ваемого пула уже после того, как был создан каталог страниц процесса) Запись на действительную, но пока не изменявшуюся страницу в много" процессорной системе Установка битового флага Dirty в PTE Попытка выполнения кода на странице Нарушение доступа [только на аппаратных с атрибутом защиты «запрет на выпол" платформах с поддержкой защиты «запрет нение» на выполнение» (no execute protection) под управлением Windows XP Service Pack 2 или Windows Server 2003 Service Pack 1 и выше] В следующем разделе описываются четыре базовых типа недействитель" ных PTE. Затем мы рассмотрим особый случай недействительных PTE — прототипные PTE, используемые для поддержки разделяемых страниц.
464 ГЛ А В А 7 БЕЗОПАСНОСТЬ Недействительные PTE Ниже приведен список типов недействительных PTE с описанием их струк" туры. Некоторые их флаги идентичны флагам аппаратных PTE (см. таблицу 7"11). 쐽 PTE для страницы в страничном файле (page file PTE) Нужная страница находится в страничном файле. Инициируется операция заг" рузки страницы. 쐽 PTE для страницы, обнуляемой по требованию (demand zero PTE) Нужная страница должна быть заполнена нулями. Сначала просматрива" ется список обнуленных страниц (zero page list). Если он пуст, просмат" ривается список свободных страниц (free list). Если в нем есть свободная страница, она заполняется нулями. Если этот список тоже пуст, исполь" зуется список простаивающих страниц (stanby list). Формат этого PTE идентичен формату PTE для страницы в страничном файле, но номер страничного файла и смещение в нем равны 0. 쐽 Переходный PTE (transition PTE) Нужная страница находится в па" мяти в списке простаивающих, модифицированных (modified list) или модифицированных, но не записываемых страниц (modified"no"write list). Страница будет удалена из списка и добавлена в рабочий набор, как только на нее будет ссылка. 쐽 Неизвестный PTE (unknown PTE) PTE равен 0, либо таблицы стра" ниц еще нет. В обоих случаях этот флаг означает, что определить, пере" дана ли память по данному адресу, можно только через дескрипторы вир" туальных адресов (VAD). Если передана, то формируются таблицы стра" ниц, представляющие новую область адресного пространства, которому
ГЛАВА 9 Управление памятью 465 передана физическая память. (Описание VAD см. в разделе «Дескрипто" ры виртуальных адресов» далее в этой главе.) Прототипные PTE Если какая"то страница может разделяться двумя процессами, то при про" ецировании таких потенциально разделяемых страниц диспетчер памяти использует структуру, называемую прототипным PTE (prototype page table entry). В случае разделов, поддерживаемых страничными файлами (page file backed sections), массив прототипных PTE формируется при первом созда" нии объекта «раздел», а в случае проецируемых файлов этот массив созда" ется порциями при проецировании каждого представления. Прототипные PTE являются частью структуры сегмента, описываемой в конце этой главы. ПРИМЕЧАНИЕ В Windows 2000 и Windows 2000 Service Pack 1 диспет" чер памяти создает все прототипные PTE, нужные для проецирования всего файла, даже если приложение единовременно проецирует пред" ставления лишь на небольшие части файла. Поскольку эти структуры создаются в конечном ресурсе (в пуле подкачиваемой памяти), попыт" ка спроецировать большие файлы может привести к истощению это" го ресурса. В итоге предельный общий объем единовременно исполь" зуемых проецируемых файлов составляет около 200 Гб. Этот лимит снят в Windows 2000 Service Pack 2 и более поздних вер" сиях за счет того, что диспетчер памяти теперь создает такие струк" туры только при создании проецируемых на файл представлений. Благодаря этому стало возможным резервное копирование огромных файлов даже на компьютерах с малым объемом памяти. Когда процесс впервые ссылается на страницу, проецируемую на пред" ставление объекта «раздел» (вспомните, что VAD создаются только при про" ецировании представления), диспетчер памяти — на основе информации из прототипного PTE — заполняет реальный PTE, используемый для трансля" ции адресов в таблице страниц процесса. Когда разделяемая страница ста" новится действительной, PTE процесса и прототипный PTE указывают на физическую страницу с данными. Для учета числа PTE, ссылающихся на дей" ствительные разделяемые страницы, в базе данных PFN увеличивается зна" чение соответствующего счетчика (см. раздел «База данных PFN» далее в этой главе). Благодаря этому диспетчер памяти сможет определить тот мо" мент, когда на разделяемую страницу больше не будет ссылок ни в одной таблице страниц, а затем объявить ее недействительной и поместить в спи" сок переходных страниц или выгрузить на диск. Как только разделяемая страница объявлена недействительной, PTE в таб" лице страниц процесса заменяется особым PTE, указывающим на прототип" ный PTE, который описывает данную страницу (рис. 7"26).
466 ГЛ А В А 7 Рис. 7-26. БЕЗОПАСНОСТЬ Структура недействительного PTE, указывающего на прототипный PTE Таким образом, при последующем обращении к странице диспетчер памя" ти, используя информацию из особого PTE, может найти прототипный PTE, который в свою очередь описывает нужную страницу. Разделяемая страница может находиться в одном из шести состояний, указанных в прототипном PTE. 쐽 Активная/действительная (active/valid) Страница находится в фи" зической памяти в результате обращения к ней другого процесса. 쐽 Переходная (transition) Страница находится в памяти в списке про" стаивающих или модифицированных страниц. 쐽 Модифицированная, но не записываемая (modified!no!write) Страница находится в памяти в списке модифицированных, но не запи" сываемых страниц (см. таблицу 7"20). 쐽 Обнуляемая по требованию (demand zero) нулить (заполнить нулями). Страницу требуется об" 쐽 Выгруженная в страничный файл (page file) в страничном файле. Страница находится 쐽 Содержащаяся в проецируемом файле (mapped file) Страница на" ходится в проецируемом файле. Хотя формат прототипных PTE идентичен формату реальных PTE, они используются не для трансляции адресов, а как уровень между таблицей страниц и базой данных PFN и никогда не записываются непосредственно в таблицы страниц. Заставляя всех пользователей потенциально разделяемой страницы ссы" латься на прототипный PTE, диспетчер памяти может управлять разделяемы" ми страницами, не обновляя таблицы страниц в каждом процессе. Допустим, в какой"то момент разделяемая страница выгружается в страничный файл на диске. При ее загрузке обратно в память диспетчеру памяти понадобится изменить только прототипный PTE, записав в него указатель на новый фи" зический адрес страницы, а PTE в таблицах страниц всех процессов, совме" стно использующих эту страницу, останутся прежними (в этих PTE битовый флаг Valid сброшен, они ссылаются на прототипный PTE). Реальные PTE обновляются позднее, по мере обращения процессов к этой странице. На рис. 7"27 показаны две виртуальные страницы в проецируемом пред" ставлении. Одна из них действительна, другая — нет. Как видите, на действи" тельную страницу ссылаются PTE процесса и прототипный PTE. Недействи" тельная страница находится в страничном файле, ее точный адрес определя" ется прототипным PTE. PTE данного процесса (как и любого другого процес" са, проецирующего эту страницу) содержит указатель на прототипный PTE.
ГЛАВА 9 Управление памятью 467 Рис. 7-27. Прототипные PTE Операции ввода-вывода, связанные с подкачкой страниц Такие операции ввода"вывода происходят в результате запроса на чтение страничного или проецируемого файла из"за ошибки страницы. Кроме того, поскольку в страничный файл могут помещаться и таблицы страниц, обра" ботка ошибки страницы в случае таблицы страниц может повлечь за собой новые ошибки страниц. Операции ввода"вывода, связанные с подкачкой, являются синхронными, т. е. поток ждет завершения подобной операции на каком"либо событии и она не может быть прервана вызовом асинхронной процедуры (APC). Для идентификации ввода"вывода как связанного с подкачкой подсистема под" качки страниц (pager) вызывает функцию запроса ввода"вывода, указывая специальный модификатор. По завершении операции подсистема ввода" вывода освобождает событие. Это пробуждает подсистему подкачки страниц, и она продолжает свою работу. В ходе операции ввода"вывода, связанной с подкачкой, поток, который вызвал ошибку страницы, не владеет критичными синхронизирующими объектами, используемыми при управлении памятью. Другие потоки того же процесса могут вызывать функции управления виртуальной памятью и об" рабатывать ошибки страниц в ходе операции ввода"вывода, связанной с подкачкой. Однако подсистема подкачки страниц должна уметь выходить из некоторых ситуаций, которые могут возникать на момент завершения такой операции: 쐽 другой поток в том же или другом процессе вызывает ошибку той же страницы, из"за чего происходит конфликт ошибок страницы (см. сле" дующий раздел); 쐽 страница удалена из виртуального адресного пространства и перепрое" цирована;
468 ГЛ А В А 7 БЕЗОПАСНОСТЬ 쐽 сменился атрибут защиты страницы; 쐽 ошибка относится к прототипному PTE, а страница, которая проецирует этот PTE, отсутствует в рабочем наборе. Подсистема подкачки страниц выходит из таких ситуаций следующим образом. Перед запросом на операцию ввода"вывода, связанную с подкач" кой, она сохраняет в стеке ядра потока статусную информацию, что позво" ляет после выполнения запроса распознать возникновение одной из пере" численных выше ситуаций и при необходимости отбросить ошибку страни" цы, не делая эту страницу действительной. Если команда, вызвавшая ошиб" ку страницы, выдается повторно, вновь активизируется подсистема подкач" ки страниц, и PTE вычисляется заново. Конфликты ошибок страницы Конфликт ошибок страницы (collided page fault) возникает, когда другой поток или процесс вызывает ошибку страницы, уже обрабатываемой в дан" ный момент из"за предыдущей ошибки того же типа. Подсистема подкачки страниц распознает и оптимальным образом разрешает такие конфликты, поскольку они нередки в системах с поддержкой многопоточности. Если другой поток или процесс вызывает ошибку той же страницы, подсистема подкачки страниц обнаруживает конфликт ошибок страницы, отмечая при этом, что страница находится в переходном состоянии и что она сейчас считывается. (Эта информация извлекается из элемента базы данных PFN.) Далее подсистема подкачки страниц переходит в ожидание на событии, ука" занном в элементе базы данных PFN. Это событие было инициализировано потоком, вызвавшим первую ошибку страницы. По завершении операции ввода"вывода событие переходит в свободное со" стояние. Первый поток, захвативший блокировку базы данных PFN, отвечает за заключительные операции, связанные с подкачкой. К ним относятся проверка статуса операции ввода"вывода (чтобы убедиться в ее успешном завершении), сброс бита «в процессе чтения» в базе данных PFN и обновление PTE. Когда следующие потоки захватывают блокировку базы данных PFN для завершения обработки конфликтующих ошибок страницы, сброшенный бит «в процессе чтения» сообщает подсистеме подкачки страниц, что начальное обновление закончено, и она проверяет флаг ошибок в элементе базы дан" ных PFN. Если этот флаг установлен, PTE не обновляется, и в потоке, вызвав" шем ошибку страницы, генерируется исключение «in"page error» (ошибка в процессе загрузки страницы). Страничные файлы Страничные файлы (page files) предназначены для хранения модифициро" ванных страниц, которые используются каким"то процессом, но должны быть выгружены из памяти на диск. Пространство в страничном файле ре" зервируется, когда происходит начальная передача страниц, но реальные участки страничного файла не выбираются до тех пор, пока страницы не
ГЛАВА 9 Управление памятью 469 выгружаются на диск. Важно отметить, что система накладывает ограниче" ние на число передаваемых закрытых страниц. Поэтому значение счетчика производительности Process: Page File Bytes на самом деле отражает суммар" ный объем закрытой памяти, переданной процессам. Соответствующие страницы могут находиться в страничном файле (частично или целиком) или, напротив, в физической памяти. (В сущности этот счетчик идентичен счетчику Process: Private Bytes.) Диспетчер памяти отслеживает использование закрытой переданной па" мяти на глобальном уровне и по каждому процессу отдельно (в виде квоты страничного файла). И вновь эти данные отражают не размер использован" ного пространства в страничном файле, а объем переданной закрытой па" мяти. Соответствующие счетчики увеличиваются при передаче виртуальных адресов, требующих новых закрытых физических страниц. Как только сис" тема достигнет глобального лимита на переданную память (т. е. физическая память и страничные файлы заполнены), попытки выделения виртуальной памяти будут заканчиваться неудачно — пока какой"либо процесс не осво" бодит переданную ему память (например, после завершения). При загрузке системы процесс диспетчера сеансов (см. главу 4) считывает список страничных файлов, которые он должен открыть. Этот список хра" нится в параметре реестра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\PagingFiles. Этот многострочный параметр со" держит имя, минимальный и максимальный размеры каждого страничного файла. Windows поддерживает до 16 страничных файлов. В x86"системах с обычным ядром каждый страничный файл может быть размером до 4095 Мб, в x64" и x86"системах с PAE"ядром — до 16 Тб, а в IA64"системах — до 32 Тб. Страничные файлы нельзя удалить во время работы системы, так как про" цесс System (см. главу 2) открывает описатель каждого страничного файла. Тот факт, что страничные файлы открываются системой, объясняет, почему встроенное средство дефрагментации не в состоянии дефрагментировать страничный файл в процессе работы системы. Для дефрагментации стра" ничного файла используйте бесплатную утилиту Pagedefrag с сайта www.sy sinternals.com. В ней применяется тот же подход, что и в других сторонних утилитах дефрагментации: она запускает свой процесс дефрагментации на самом раннем этапе загрузки системы, еще до открытия страничных фай" лов диспетчером сеансов. Поскольку страничный файл содержит части виртуальной памяти процес" сов и ядра, для большей безопасности его можно настроить на очистку при выключении системы. Для этого установите параметр реестра HKLM\SYSTEM \CurrentControlSet\Control\Session Manager\Memory Management\ClearPageFile" AtShutdown в 1. Иначе в страничном файле останутся те данные, которые были выгружены в него к моменту выключения системы. И к этим данным сможет обратиться любой, кто получит физический доступ к компьютеру. Если не указано ни одного страничного файла, Windows 2000 создает в загрузочном разделе 20"мегабайтный страничный файл. Windows XP и Win" dows Server 2003 не создают этот временный страничный файл, и поэтому
470 ГЛ А В А 7 БЕЗОПАСНОСТЬ в такой ситуации объем системной виртуальной памяти будет ограничен доступной физической памятью. Windows XP и Windows Server 2003, если минимальный и максимальный размеры страничного файла заданы нулевы" ми, считают, что этот файл управляется системой, и его размер выбирается в соответствии с данными, показанными в таблице 7"14. Таблица 7-14. Размеры страничного файла по умолчанию Объем оперативной памяти (RAM) Минимальный размер страничного файла Максимальный размер страничного файла Менее 1 Гб 1,5 * RAM 3 * RAM 1 Гб и более 1 * RAM 3 * RAM ЭКСПЕРИМЕНТ: просмотр страничных файлов Как уже говорилось, список страничных файлов хранится в парамет" ре реестра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\ Memory Management\PagingFiles. Он содержит конфигурационные параметры страничных файлов, которые модифицируются через ап" плет System (Система) в Control Panel (Панель управления). В Windows 2000 щелкните кнопку Performance Options (Параметры быстродей" ствия) на вкладке Advanced (Дополнительно) и нажмите кнопку Chan" ge (Изменить). В Windows XP и Windows Server 2003 откройте вкладку Advanced (Дополнительно), щелкните кнопку Settings (Параметры) в разделе Performance (Быстродействие), откройте еще одну вкладку Advanced (Дополнительно) и, наконец, нажмите кнопку Change (Изме" нить) в разделе Virtual Memory (Виртуальная память). Создать новый страничный файл можно через Control Panel. При этом вызывается системный сервис NtCreatePagingFile, определенный в Ntdll.dll и предназначенный только для внутреннего использования. Страничные фай" лы всегда создаются несжатыми, даже если находятся в сжатом каталоге. Для защиты новых страничных файлов от удаления их описатели дублируются в процесс System. В таблице 7"15 перечислены счетчики производительности, с помощью которых можно исследовать использование переданной закрытой памяти в рамках как всей системы, так и каждого страничного файла. К сожалению, определить соотношение резидентной и нерезидентной (находящейся в страничном файле) частей закрытой памяти, которая передана какому"либо процессу, нельзя. Заметьте, что эти счетчики могут помочь в подборе размера странично" го файла. Исходить из объема оперативной памяти (RAM) нет смысла: чем больше у вас памяти, тем меньше вероятность того, что вам понадобится вы" грузка данных на диск. Чтобы определить, какой размер страничного фай" ла действительно нужен в вашей системе с учетом используемых вами при" ложений, проверьте пиковое значение переданной памяти, которое отобра" жается в разделе Commit Charge (Выделение памяти) на вкладке Performance
ГЛАВА 9 Управление памятью 471 (Быстродействие) диспетчера задач, а также в окне System Information ути" литы Process Explorer. Этот показатель отражает пиковый объем странично" го файла с момента загрузки системы, который понадобился бы в том слу" чае, если бы системе пришлось выгрузить всю закрытую переданную вирту" альную память (что происходит крайне редко). Таблица 7-15. Счетчики, относящиеся к переданной памяти и страничному файлу Счетчик Описание Memory: Committed Bytes (Память: Число байтов переданной виртуальной Байт выделенной виртуальной памяти) (не зарезервированной) памяти. Это значе" ние не обязательно отражает использова" ние страничного файла, поскольку включа" ет закрытые переданные страницы в физи" ческой памяти, никогда не выгружавшиеся в страничный файл. Так что оно скорее ука" зывает, сколько места в страничном файле понадобилось бы в том случае, если бы про" цесс был полностью выгружен из памяти Memory: Commit Limit (Память: Предел выделенной виртуальной памяти) Число байтов виртуальной памяти, которое может быть передано без расширения стра" ничных файлов. Если страничные файлы можно расширять, этот лимит не является жестким Paging File: % Usage (Файл подкачки: % использования) Процентная доля памяти, переданной из страничного файла Paging File: % Usage Peak [Файл подкач" ки: % использования (пик)] Пиковое значение процентной доли памя" ти, переданной из страничного файла Если страничный файл в вашей системе слишком велик, Windows не бу" дет использовать лишнее пространство; иначе говоря, увеличение размера страничного файла не изменит производительность системы — просто у нее будет больше неразделяемой (non"shareable) переданной виртуальной памя" ти. Но если страничный файл слишком мал для запускаемого вами набора приложений, может появиться сообщение об ошибке «system running low on virtual memory» (в системе не хватает виртуальной памяти). В таком случае сначала проверьте, не дает ли какой"нибудь процесс утечки памяти. Для это" го посмотрите на счетчики байтов закрытой памяти для процессов в столб" це VM Size (Объем виртуальной памяти) на вкладке Processes (Процессы) диспетчера задач. Если ни один из процессов вроде бы не дает утечки памя" ти, проделайте операции, описанные в эксперименте «Анализ утечки памя" ти в пуле» ранее в этой главе. ЭКСПЕРИМЕНТ: наблюдаем за использованием страничного файла через диспетчер задач Вы можете узнать, как используется переданная память, и с помощью Task Manager (Диспетчер задач), открыв в нем вкладку Performance (Быстродействие). При этом вы увидите следующие счетчики, связан" ные со страничными файлами. см. след. стр.
472 ГЛ А В А 7 БЕЗОПАСНОСТЬ Заметьте, что график Mem Usage, который в Windows XP и Windows Server 2003 называется PF Usage (Файл подкачки), на самом деле соот" ветствует общему объему переданной системной памяти (system com" mit total). Это значение отражает потенциально возможное, а не ре" альное использование страничного файла. Как мы уже говорили, столько места в страничном файле понадобилось бы в том случае, если бы системе вдруг пришлось выгрузить сразу всю закрытую передан" ную виртуальную память. Дополнительную информацию вы найдете в окне System Informa" tion утилиты Process Explorer.
ГЛАВА 9 Управление памятью 473 Дескрипторы виртуальных адресов Момент загрузки страниц в память диспетчер памяти определяет, используя алгоритм подкачки по требованию (demand"paging algorithm). Страница заг" ружается с диска, если поток, обращаясь к ней, вызывает ошибку страницы. Подобно копированию при записи подкачка по требованию является одной из форм отложенной оценки (lazy evaluation) — выполнения операции толь" ко при ее абсолютной необходимости. Диспетчер памяти использует отложенную оценку не только при загруз" ке страниц в память, но и при формировании таблиц, описывающих новые страницы. Например, когда поток передает память большой области вирту" альной памяти с помощью VirtualAlloc, диспетчер памяти мог бы немедлен" но создать таблицы страниц, необходимые для доступа ко всему диапазону выделенной памяти. А что если часть этого диапазона останется невостре" бованной? Зачем впустую расходовать процессорное время? Вместо этого диспетчер памяти откладывает формирование таблицы страниц до тех пор, пока поток не вызовет ошибку страницы. Такой подход существенно увели" чивает быстродействие процессов, резервирующих и/или передающих большие объемы памяти, но обращающихся к ней не очень часто. При использовании алгоритма отложенной оценки выделение даже боль" ших блоков памяти происходит очень быстро. Когда поток выделяет память, диспетчер памяти должен соответственно отреагировать. Для этого диспет" чер памяти поддерживает набор структур данных, которые позволяют вес" ти учет зарезервированных и свободных виртуальных адресов в адресном пространстве процесса. Эти структуры данных называются дескрипторами виртуальных адресов (virtual address descriptors, VAD). Для каждого процес" са диспетчер памяти поддерживает свой набор VAD, описывающий состоя" ние адресного пространства этого процесса. Для большей эффективности поиска VAD организованы в виде двоичного дерева с автоматической балан" сировкой. В Windows Server 2003 реализован алгоритм дерева AVL (это пер" вые буквы фамилий его разработчиков — Adelson"Velskii и Landis), который обеспечивает более эффективную балансировку VAD"дерева, а это уменьша" ет среднее число операций сравнения при поиске VAD, соответствующего некоему виртуальному адресу. Схема дерева VAD показана на рис. 7"28. Когда процесс резервирует адресное пространство или проецирует пред" ставление раздела, диспетчер памяти создает VAD для хранения информа" ции из запроса на выделение — диапазона резервируемых адресов, его типа (разделяемый или закрытый), возможности наследования содержимого ди" апазона дочерними процессами, атрибутов защиты, установленных для стра" ниц этого диапазона. При первом обращении потока по какому"либо адресу диспетчер памя" ти должен создать PTE страницы, содержащей данный адрес. Для этого он находит VAD, чей диапазон включает нужный адрес, и использует его инфор" мацию для заполнения PTE. Если адрес выпадает из диапазонов VAD или на" ходится в зарезервированном, но не переданном диапазоне адресов, диспет"
474 ГЛ А В А 7 БЕЗОПАСНОСТЬ чер памяти узнает, что поток не выделил память до попытки ее использова" ния, и генерирует нарушение доступа. Рис. 7-28. Дескрипторы виртуальных адресов ЭКСПЕРИМЕНТ: просмотр дескрипторов виртуальных адресов Чтобы просмотреть VAD для какого"либо процесса, используйте коман" ду !vad отладчика ядра. Сначала найдите адрес корня VAD"дерева с по" мощью команды !process. Затем введите полученный адрес в команде !vad, как показано в примере для процесса, выполняющего Notepad.exe. kd> !process 2a0 1 Searching for Process with Cid == 2a0 PROCESS 8614d030 SessionId: 0 Cid: 02a0 Peb: 7ffdf000 ParentCid: 0554 DirBase: 00d93000 ObjectTable: 81bc47c8 TableSize: 41. Image: notepad.exe VadRoot 8118d868 Clone 0 Private 252. Modified 0. Locked 0. ... kd> !vad 8118d868 VAD level start 84df4148 ( 2) 10 850cdbe8 ( 3) 20 810b0ee8 ( 1) 30 8109d308 ( 3) 70 810e9a28 ( 2) 170 84aedfc8 ( 3) 180 8118d868 ( 0) 1a0 81190a08 ( 4) 1d0 85c7b928 ( 3) 220 86253a08 ( 4) 230 810aab48 ( 2) 300 end 10 20 6f 16f 17f 195 1ce 210 223 2f7 342 commit 1 1 7 32 0 0 0 0 0 0 0 Private Private Private Private Mapped Mapped Mapped Mapped Mapped Mapped Mapped READWRITE READWRITE READWRITE READWRITE READWRITE READONLY READONLY READONLY READONLY EXECUTE_READ READONLY
ГЛАВА 9 80db5448 ( 5) ... Total VADs: 350 64f 49 average level: Управление памятью 0 Mapped 475 EXECUTE_READ 6 maximum depth: 13 Объекты-разделы Вероятно, вы помните, что объект «раздел» (section object), в подсистеме Windows называемый объектом «проекция файла» (file mapping object), пред" ставляет блок памяти, доступный двум и более процессам для совместного использования. Объект"раздел можно проецировать на страничный файл или другой файл на диске. Исполнительная система использует разделы для загрузки исполняемых образов в память, а диспетчер кэша — для доступа к данным в кэшированном файле (подробнее на эту тему см. главу 11). Объекты «раздел» также позволя" ют проецировать файлы на адресные пространства процессов. При этом мож" но обращаться к файлу как к большому массиву, проецируя разные представ" ления объекта"раздела и выполняя операции чтения"записи в памяти, а не в самом файле, — такие операции называются вводомвыводом в проецируемые файлы (mapped file I/O). Если программа обратится к недействительной стра" нице (отсутствующей в физической памяти), возникнет ошибка страницы, и диспетчер памяти автоматически загрузит эту страницу в память из проеци" руемого файла. Если программа модифицирует страницу, диспетчер памяти сохранит изменения в файле в процессе обычных операций, связанных с подкачкой. (Приложение может самостоятельно сбросить представление файла на диск вызовом Windows"функции FlushViewOfFile.) Как и другие объекты, разделы создаются и уничтожаются диспетчером объектов. Он создает и инициализирует заголовок объекта «раздел», а дис" петчер памяти определяет тело этого объекта. Диспетчер памяти также ре" ализует сервисы, через которые потоки пользовательского режима могут получать и изменять атрибуты, хранящиеся в теле объекта «раздел». Струк" тура объекта «раздел» показана на рис. 7"29. Рис. 7-29. Объект «раздел»
476 ГЛ А В А 7 БЕЗОПАСНОСТЬ Уникальные атрибуты, хранящиеся в объектах «раздел» перечислены в таблице 7"16. Таблица 7-16. Атрибуты, хранящиеся в теле объекта-раздела Атрибут Описание Максимальный размер Предельный размер, до которого может увеличиваться раздел (в байтах). При проецировании файла максималь" ный размер не может быть больше длины файла Атрибуты защиты страниц Атрибуты защиты, назначенные всем страницам раздела при его создании Страничный/проеци" руемый файл Указывает, создан ли раздел пустым (как поддерживае" мый страничным файлом) или в него загружен файл (как поддерживаемый проецируемым файлом) Базовый/не базовый Указывает, является ли раздел базовым (загружаемым по одному и тому же виртуальному адресу для всех исполь" зующих его процессов) или нет (при необходимости за" гружаемым по разным виртуальным адресам для разных процессов) ЭКСПЕРИМЕНТ: просмотр объектов «раздел» Утилита Object Viewer (Winobj.exe с сайта www.sysinternals.com или Winobj.exe из Platform SDK) позволяет просмотреть список разделов с глобальными именами. Вы можете перечислить открытые описате" ли объектов «раздел» с помощью любых утилит, описанных в разделе «Диспетчер объектов» главы 3 и способных перечислять содержимое таблицы открытых описателей. (Как уже говорилось в главе 3, эти име" на хранятся в каталоге диспетчера объектов \BaseNamedObjects.) Используя Process Explorer или Handles.exe (www.sysinternals.com), либо утилиту Oh.exe (Open Handles) из ресурсов Windows, можно вы" вести список открытых описателей объектов «раздел». Например, сле" дующая команда показывает все открытые описатели каждого объек" та «раздел» независимо от того, есть ли у него имя. (Разделу должно быть присвоено имя, если другой процесс открывает его по имени.) c:\> oh t section a 00000008 System 0000008C smss.exe 000000A4 csrss.exe 000000A4 csrss.exe 000000A4 csrss.exe 000000A4 csrss.exe 000000A4 csrss.exe 000000A4 csrss.exe 000000A4 csrss.exe 000000A4 csrss.exe 000000A0 winlogon.exe 000000A0 winlogon.exe Section Section Section Section Section Section Section Section Section Section Section Section 0070 0004 0004 0024 0038 0040 0044 0048 004c 0050 0004 0034 \NLS\NlsSectionUnicode \NLS\NlsSectionLocale \NLS\NlsSectionCType \NLS\NlsSectionSortkey \NLS\NlsSectionSortTbls
ГЛАВА 9 Управление памятью 477 000000A0 winlogon.exe Section 0168 \BaseNamedObjects\mmGlobalPnpInfo ... Для просмотра проецируемых файлов можно воспользоваться и утилитой Process Explorer. Выберите из меню View команду Lower Pane View, а затем DLLs. Файлы в колонке ММ, помеченные звездочкой, яв" ляются проецируемыми (в отличие от DLL и других файлов, загружа" емых загрузчиком образов в виде модулей). Вот пример: Рис. 7-30. Внутренние структуры раздела
478 ГЛ А В А 7 БЕЗОПАСНОСТЬ Структуры данных, поддерживаемые диспетчером памяти и описываю" щие проецируемые разделы, показаны на рис. 7"30. Эти структуры гаранти" руют согласованность данных, считанных из проецируемого файла, незави" симо от типа доступа. Каждому открытому файлу, представленному объектом «файл», соответ" ствует структура указателей объекта «раздел» (section object pointers struc" ture). Эта структура является ключевой для поддержания согласованности данных при всех типах доступа к файлу; она же используется и при кэши" ровании файлов. Структура указателей объекта «раздел» ссылается на одну или две области управления (control areas). Одна из них используется для проецирования файла при обращении к нему как к файлу данных, а дру" гая — для проецирования файла при запуске его как исполняемого образа. Область управления в свою очередь указывает на структуры подразде ла (subsection structures), содержащие информацию о проецировании каж" дого раздела файла (только для чтения, для чтения и записи, копирование при записи и т. д.). Область управления также ссылается на структуру сег мента (segment structure), которая создается в пуле подкачиваемой памяти и указывает на прототипные PTE, указывающие на реальные страницы, про" ецируемые объектом «раздел». Как уже говорилось, таблицы страниц процес" са ссылаются на эти прототипные PTE, а те указывают на страницы, к кото" рым происходит обращение. Хотя Windows гарантирует, что любой процесс, обращающийся к файлу (для чтения или записи), всегда имеет дело с согласованными данными, воз" можна одна ситуация, при которой в физической памяти могут находиться две копии страниц файла (но и в этом случае предоставляется только самая последняя копия и поддерживается согласованность данных). Такое дубли" рование происходит из"за обращения к файлу образа как к файлу данных (для чтения или записи) с его последующим запуском как исполняемого файла. Например, при сборке и последующем запуске файла образа компо" новщик открывает его для доступа к данным, а при запуске программы заг" рузчик образов проецирует этот файл как исполняемый. При этом выпол" няются следующие операции. 1. Если исполняемый образ был создан через API"функции проецирования файлов (или с помощью диспетчера кэша), создается и область управле" ния для представления считываемых или записываемых страниц данных в этом файле. 2. Когда запускается образ и создается объект «раздел» для проецирования образа как исполняемого, диспетчер памяти обнаруживает, что указате" ли объекта «раздел» для файла образа ссылаются на область управления данными, и сбрасывает этот раздел на диск. Эта операция нужна для того, чтобы гарантировать сохранение любых модифицированных страниц на диске до обращения к образу через область управления кодом. 3. Диспетчер памяти создает область управления кодом.
ГЛАВА 9 Управление памятью 479 4. Как только начинается выполнение образа, обращение к страницам его файла (доступным только для чтения) вызывает ошибки страниц, и они загружаются в память. Поскольку страницы, проецируемые областью управления данными, все еще могут быть резидентными (в списке простаивающих страниц), эта си" туация является одним из примеров существования двух копий одних и тех же данных на разных страницах памяти. Но такое дублирование не нарушает согласованность данных, поскольку область управления данными уже сбро" шена на диск, а значит, страницы, считанные из файла, содержат последние данные (причем эти страницы никогда не записываются обратно на диск). ЭКСПЕРИМЕНТ: просмотр областей управления Чтобы найти адрес структур областей управления, вы должны снача" ла найти адрес нужного объекта «файл». Его можно получить с помо" щью отладчика ядра, создав командой !handle дамп таблицы описате" лей, принадлежащей процессу. Хотя команда !file отладчика ядра сооб" щает основные сведения об объекте «файл», она не дает указатель на структуру указателей объекта «раздел». Затем, используя команду dt, отформатируйте объект «файл», чтобы получить адрес структуры ука" зателей объекта «раздел». Эта структура состоит из трех указателей: на область управления данными, на разделяемую проекцию кэша (см. гла" ву 11) и на область управления кодом. Получив адрес нужной области управления (если она есть) из структуры указателей объекта «раздел», укажите его как аргумент в команде !ca. Скажем, если вы откроете файл PowerPoint и выведете таблицу опи" сателей для этого процесса командой !handle, то найдете открытый описатель файла PowerPoint, как показано ниже. (Об использовании команды !handle см. раздел «Диспетчер объектов» главы 3.) lkd> !handle 1 f 5c4 file ... 0284: Object: 8645c038 GrantedAccess: 00120089 Object: 8645c038 Type: (867ddca0) File ObjectHeader: 8645c020 HandleCount: 1 PointerCount: 1 Directory Object: 00000000 Name: \slides\ntint\new\ 3systemarchitecture.ppt {HarddiskVolume1} Взяв адрес объекта «файл» (8645c038) и отформатировав его ко" мандой dt, вы получите: lkd> dt nt!_file_object 8645c038 nt!_FILE_OBJECT +0x000 Type : 5 +0x002 Size : 112 +0x004 DeviceObject : 0x86742e30 +0x008 Vpb : 0x867a3090 см. след. стр.
480 ГЛ А В А 7 БЕЗОПАСНОСТЬ +0x00c FsContext : 0xe2786530 +0x010 FsContext2 : 0xe309a378 +0x014 SectionObjectPointer : 0x85512fec Затем, сделав то же самое, но применительно к адресу структуры указателей объекта «раздел» (0x85512fec), вы получите: lkd> dt nt!_section_object_pointers 0x85512fec nt!_SECTION_OBJECT_POINTERS +0x000 DataSectionObject : 0x8564f8a0 +0x004 SharedCacheMap : (null) +0x008 ImageSectionObject : (null) Наконец, команда !ca покажет вам область управления по этому адресу: lkd> !ca 0x8564f8a0 ControlArea @8564f8a0 Segment: e3817528 Flink 0 Blink Section Ref 1 Pfn Ref 25c Mapped Views User Ref 2 WaitForDel 0 Flush Count File Object 85774580 ModWriteCount 0 System Views Flags (9008080) File WasPurged HadUserReference Accessed File: \slides\ntint\new\3systemarchitecture.ppt 0 1 0 0 Другой метод — применение команды !memusage. Ниже приведен фрагмент вывода этой команды. kd> !memusage loading PFN database loading (99% complete) Zeroed: 9 ( 36 kb) Free: 0 ( 0 kb) Standby: 2103 ( 8412 kb) Modified: 300 ( 1200 kb) ModifiedNoWrite: 1 ( 4 kb) Active/Valid: 30318 (121272 kb) Transition: 3 ( 12 kb) Unknown: 0 ( 0 kb) TOTAL: 32734 (130936 kb) Building kernel map Finished building kernel map Usage Summary (in Kb): Control Valid Standby Dirty Shared Locked 8119b608 3000 528 0 0 0 849e7c68 96 0 0 0 0 8109c388 24 0 0 0 0 81402488 236 0 0 0 0 80fba0a8 268 0 0 0 0 810ab168 1504 380 0 0 0 81126a08 0 276 0 0 0 PageTables name 0 mapped_file( WINWORD.EXE ) 0 No Name for File 0 mapped_file( DEVDTG.PKG ) 0 No Name for File 0 mapped_file( kernel32.pdb ) 0 mapped_file( OUTLLIB.DLL ) 0 mapped_file( H )
ГЛАВА 9 81112d28 ... 656 0 0 0 0 0 481 Управление памятью No Name for File Значения в колонке Control указывают на структуру области управ" ления, описывающую проецируемый файл. Вы можете просмотреть области управления, сегменты и подразделы с помощью команды !ca отладчика ядра. Например, чтобы получить дамп области управления для проецируемого файла Winword.exe, введите команду !ca и укажи" те в ней число из колонки Control, как показано ниже. kd> !ca 8119b608 ControlArea @8119b608 Segment: e2c28000 Section Ref 1 User Ref 2 File Object 8213fb98 WaitForDel 0 Flags (90000a0) Image Flink 0 Blink: 0 Pfn Ref 372 Mapped Views: 1 Subsections 6 Flush Count: 0 ModWriteCount 0 System Views: 0 Paged Usage 3000 NonPaged Usage 100 File HadUserReference Accessed File: \Program Files\Microsoft Office\Office\WINWORD.EXE Segment @ e2c28000: Base address 0 Image commit d7 Image Base 0 Based Addr 30000000 Total Ptes 86a NonExtendPtes: 86a ControlArea 8119b608 SizeOfSegment: 86a000 Committed 0 PTE Template: 919b6c38 ProtoPtes e2c28038 Image Info: e2c2a1e4 Subsection 1. @ 8119b640 ControlArea: 8119b608 Starting Sector 0 Number Of Sectors 8 Base Pte e2c28038 Ptes In subsect 1 Unused Ptes Flags 15 Sector Offset 0 Protection ReadOnly CopyOnWrite 0 1 Subsection 2. @ 8119b660 ControlArea: 8119b608 Starting Sector 10 Number Of Sectors 3c00 Base Pte e2c2803c Ptes In subsect 780 Unused Ptes Flags 35 Sector Offset 0 Protection ReadOnly CopyOnWrite Subsection 3. @ 8119b680 ControlArea: 8119b608 Starting Sector 3C10 Number Of Sectors 5d8 Base Pte e2c29e3c Ptes In subsect c1 Unused Ptes Flags 55 Sector Offset 0 Protection ReadOnly CopyOnWrite 0 3 0 5 Subsection 4. @ 8119b6a0 ControlArea: 8119b608 Starting Sector 41E8 Number Of Sectors a8 см. след. стр.
482 ГЛ А В А 7 БЕЗОПАСНОСТЬ Base Pte e2c2a140 Ptes In subsect Flags 55 Sector Offset ReadOnly CopyOnWrite 15 Unused Ptes 0 Protection Subsection 5. @ 8119b6c0 ControlArea: 8119b608 Starting Sector 0 Number Of Sectors 0 Base Pte e2c2a194 Ptes In subsect 1 Unused Ptes Flags 55 Sector Offset 0 Protection ReadOnly CopyOnWrite Subsection 6. @ 8119b6e0 ControlArea: 8119b608 Starting Sector 4290 Number Of Sectors 90 Base Pte e2c2a198 Ptes In subsect 12 Unused Ptes Flags 15 Sector Offset 0 Protection ReadOnly CopyOnWrite 0 5 0 5 0 1 Рабочие наборы Здесь мы сосредоточимся на виртуальной части Windows"процесса — таб" лицах страниц, PTE и VAD. В оставшейся части главы мы расскажем, как Windows хранит в физической памяти подмножество виртуальных адресов. Как вы помните, подмножество виртуальных страниц, резидентных в физической памяти, называется рабочим набором (working set). Существу" ет три вида рабочих наборов: 쐽 процесса — содержит страницы, на которые ссылаются его потоки; 쐽 системы — содержит резидентное подмножество подкачиваемого сис" темного кода (например, Ntoskrnl.exe и драйверов), пула подкачиваемой памяти и системного кэша; 쐽 сеанса — в системах с включенной службой Terminal Services каждый сеанс получает свой рабочий набор. Он содержит резидентное подмножество специфичных для сеанса структур данных режима ядра, создаваемых час" тью подсистемы Windows, которая работает в режиме ядра (Win32k.sys), пула подкачиваемой памяти сеанса, представлений, проецируемых в сеан" се, и других драйверов устройств, проецируемых на пространство сеанса. Прежде чем детально рассматривать каждый тип рабочего набора, обсу" дим общие правила выбора страниц, загружаемых в память, и определения срока их пребывания в физической памяти. Подкачка по требованию Диспетчер памяти Windows использует алгоритм подкачки по требованию с кластеризацией. Когда поток вызывает ошибку страницы, диспетчер памя" ти загружает не только страницу, при обращении к которой возникла ошиб" ка, но и несколько предшествующих и/или последующих страниц. Эта стра" тегия обеспечивает минимизацию числа операций ввода"вывода, связанных с подкачкой. Поскольку программы (особенно большие) в любой момент
ГЛАВА 9 Управление памятью 483 времени обычно выполняются в небольших областях своего адресного про" странства, загрузка виртуальных страниц кластерами уменьшает число опе" раций чтения с диска. При ошибках, связанных со ссылками на страницы данных в образах, размер кластера равен 3, в остальных случаях — 7. Однако политика подкачки по требованию может привести к тому, что какой"то процесс будет вызывать очень много ошибок страниц в момент начала выполнения его потоков или позднее при возобновлении их выпол" нения. Для оптимизации запуска процесса (и системы) в Windows XP и Win" dows Server 2003 введен механизм интеллектуальной предвыборки (intelli" gent prefetch engine), также называемый средством логической предвыбор" ки (logical prefetcher); о нем мы рассказываем в следующем разделе. Средство логической предвыборки В ходе типичной загрузки системы или приложения порядок ошибок стра" ниц таков, что некоторые страницы запрашиваются из одной части файла, затем из совсем другой его части, потом из другого файла и т. д. Такие скач" кообразные переходы значительно замедляют каждую операцию доступа, и, как показывает анализ, время поиска на диске становится доминирующим фактором, который негативно сказывается на скорости загрузки системы и приложений. Предварительная выборка целого пакета страниц позволяет упорядочить операции доступа без лишнего «рыскания» по диску и тем са" мым ускорить запуск системы и приложений. Нужные страницы могут быть известны заранее благодаря высокой степени корреляции операций досту" па при загрузках системы или запусках приложений. Средство предвыборки, впервые появившееся в Windows XP, пытается ускорить загрузку системы и запуск приложений, отслеживая данные и код, к которым происходит обращение при этих процессах, и используя полу" ченную информацию при последующих загрузке системы и запуске прило" жений для заблаговременного считывания необходимых кода и данных. Когда средство предвыборки активно, диспетчер памяти уведомляет код средства предвыборки в ядре об ошибках страниц — как аппаратных (тре" бующих чтения данных с диска), так и программных (требующих простого добавления данных, которые уже находятся в памяти, в рабочий набор про" цесса). Средство предвыборки ведет мониторинг первых 10 секунд процес" са запуска приложения. В случае загрузки системы это средство по умолча" нию ведет мониторинг в течение 30 секунд после запуска пользовательской оболочки (обычно Explorer), или 60 секунд по окончании инициализации всех Windows"сервисов, или просто в течение 120 секунд — в зависимости от того, какое из этих трех событий произойдет первым. Собрав трассировочную информацию об ошибках страниц, организо" ванную в виде списка обращений к файлу метаданных NTFS MFT (Master File Table) (если приложение пыталось получить доступ к файлам или каталогам на NTFS"томах), а также списка ссылок на файлы и каталоги, код средства предвыборки, работающий в режиме ядра, уведомляет компонент предвы" борки в службе Task Scheduler (Планировщик заданий) (\Windows\System32\
484 ГЛ А В А 7 БЕЗОПАСНОСТЬ Schedsvc.dll) и с этой целью переводит в свободное состояние объект"собы" тие с именем PrefetchTracesReady. ПРИМЕЧАНИЕ Включить или отключить предвыборку при загрузке системы и/или запуске приложений позволяет DWORD"параметр ре" естра HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management\PrefetchParameters\EnablePrefetcher: 0 — полное отключе" ние предвыборки, 1 — предвыборка разрешена только при запуске приложений, 2 — предвыборка разрешена только при загрузке систе" мы и 3 — предвыборка разрешена как при загрузке системы, так и при запуске приложений. Когда событие PrefetchTracesReady переводится в свободное состояние, Task Scheduler вызывает внутрисистемную функцию NtQuerySystemInforma tion, запрашивая через нее трассировочные данные. После дополнительной обработки этих данных Task Scheduler записывает их в файл, помещаемый в каталог \Windows\Prefetch (рис. 7"31). Файлу присваивается имя, форми" руемое из имени приложения, к которому относятся трассировочные дан" ные, дефиса и шестнадцатеричного представления хэша, полученного из строки пути к файлу. Затем к имени добавляется расширение .pf. Например, для Notepad создается файл NOTEPAD.EXE"AF43252301.PF. В этом правиле есть два исключения. Первое относится к образам, кото" рые служат хостами других компонентов, в том числе к Microsoft Manage" ment Console (\Windows\System32\Mmc.exe) и Dllhost (\Windows\System32\ Dllhost.exe). Поскольку в командной строке запуска этих приложений ука" зываются дополнительные компоненты, средство предвыборки включает командную строку в генерируемый хэш. Таким образом, запуск таких при" ложений с другими компонентами в командной строке даст другой набор трассировочных данных. Средство предвыборки считывает список испол" няемых образов, которые оно должно обрабатывать таким способом, из па" раметра HostingAppList в разделе реестра HKLM\System\CurrentControlSet\ Control\Session Manager\Memory Management\PrefetchParameters. Рис. 7-31. Каталог Prefetch
ГЛАВА 9 Управление памятью 485 Второе исключение составляет файл, в котором хранится трассировоч" ная информация, полученная в процессе загрузки системы, — ему всегда присваивается имя NTOSBOOT"B00DFAAD.PF. Средство предвыборки соби" рает информацию об ошибках страниц для конкретных приложений толь" ко после того, как закончит мониторинг процесса загрузки системы. ЭКСПЕРИМЕНТ: просмотр содержимого файла предвыборки Содержимое этого файла содержит записи о файлах и каталогах, к которым было обращение при загрузке системы или запуске прило" жения, и для их просмотра можно использовать утилиту Strings с сай" та www.sysinternals.com. Следующая команда перечисляет все файлы и каталоги, на которые были ссылки при последней загрузке системы: C:\Windows\Prefetch>Strings ntosbootboodfaad.pf Strings v2.1 Copyright (C) 19992003 Mark Russinovich Systems Internals  www.sysinternals.com NTOSBOOT SCCA \DEVICE\HARDDISKVOLUME2\$MFT \DEVICE\HARDDISKVOLUME2\WINDOWS\PREFETCH\NTOSBOOTB00DFAAD.PF \DEVICE\HARDDISKVOLUME2\SYSTEM VOLUME INFORMATION\_RESTORE{ 987E03310F01427CA58A7A2E4AABF84D}\RP24\CHANGE.LOG \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\PROCESSR.SYS \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\FGLRYM.SYS \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\VIDEOPRT.SYS \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\E1000325.SYS \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\USBUHCI.SYS \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\USBPORT.SYS \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\USBEHCI.SYS \DEVICE\HARDDISKVOLUME2\WINDOWS\SYSTEM32\DRIVERS\NIC1394.SYS ... Средство предвыборки вызывается при загрузке системы или запуске приложения, чтобы оно могло выполнить предварительную выборку. Сред" ство предвыборки просматривает каталог Prefetch и проверяет, есть ли в нем какой"нибудь файл с трассировочной информацией, необходимый для те" кущего варианта предварительной выборки. Если такой файл имеется, оно обращается к NTFS для предварительной выборки любых ссылок файла ме" таданных MFT, считывает содержимое каждого каталога, на который есть ссылка, а затем открывает все файлы в соответствии со списком ссылок. Да" лее вызывается функция MmPrefetchPages диспетчера памяти, чтобы загру" зить в память любые данные и код, указанные в трассировочной информа" ции, но пока отсутствующие в памяти. Диспетчер памяти инициирует все необходимые операции как асинхронные и ждет их завершения, прежде чем разрешить продолжение процесса запуска приложения.
486 ГЛ А В А 7 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: наблюдение за чтением и записью файла предвыборки Если вы запишете трассировку запуска приложения с помощью File" mon (www.sysinternals.com) в Windows XP, то заметите, что средство предвыборки проверяет наличие файла предвыборки и, если он есть, считывает его содержимое, а примерно через десять секунд от начала запуска приложения средство предвыборки записывает новую копию этого файла. Ниже показан пример для процесса запуска Notepad (фильтр Include был установлен как «prefetch», чтобы Filemon сообщал об обращениях только к каталогу \Windows\Prefetch). Строки 1–3 показывают, что файл предвыборки Notepad считывал" ся в контексте процесса Notepad в ходе его запуска. Строки 4–10 (с временными метками на 10 секунд позже, чем в первых трех строках) демонстрируют, что Task Scheduler, который выполняется в контексте процесса Svchost, записал обновленный файл предвыборки. Чтобы еще больше уменьшить вероятность скачкообразного поиска, че" рез каждые три дня (или около того) Task Scheduler в периоды простоя фор" мирует список файлов и каталогов в том порядке, в каком на них были ссыл" ки при загрузке системы или запуске приложения, и сохраняет его в файле \Windows\Prefetch\Layout.ini (рис. 7"32). Рис. 7-32. Содержимое файла Layout.ini
ГЛАВА 9 Управление памятью 487 Далее он запускает системный дефрагментатор, указывая ему через ко" мандную строку выполнить дефрагментацию на основе содержимого фай" ла Layout.ini. Дефрагментатор находит на каждом томе непрерывную об" ласть, достаточно большую, чтобы в ней уместились все файлы и каталоги, перечисленные для данного тома, а затем целиком перемещает их в эту об" ласть в указанном порядке. Благодаря этому будущие операции предвари" тельной выборки окажутся еще эффективнее, поскольку все считываемые данные теперь физически хранятся на диске в нужной последовательности. Такая дефрагментация обычно затрагивает всего несколько сотен файлов и поэтому выполняется гораздо быстрее, чем полная дефрагментация диска. (Подробнее о дефрагментации см. в главе 12.) Правила размещения Когда поток вызывает ошибку страницы, диспетчер памяти должен также определить, в каком участке физической памяти следует разместить вирту" альную страницу. При этом он руководствуется правилами размещения (placement policy). Выбирая фреймы страниц, Windows учитывает размер кэшей процессора и стремится свести нагрузку на них к минимуму. Если на момент появления ошибки страницы физическая память запол" нена, выбирается страница, подлежащая выгрузке на диск для освобождения памяти под новую страницу. Этот выбор осуществляется по правилам заме ны (replacement policy). При этом действуют два общих правила замены: LRU (least recently used) и FIFO (first in, first out). Алгоритм LRU (также известный как алгоритм часов и реализованный в большинстве версий UNIX) требует от подсистемы виртуальной памяти следить за тем, когда используется стра" ница в памяти. Страница, не использовавшаяся в течение самого длительно" го времени, удаляется из рабочего набора. Алгоритм FIFO работает проще: он выгружает из физической памяти страницу, которая находилась там доль" ше всего независимо от частоты ее использования. Правила замены страниц могут быть глобальными или локальными. Гло" бальные правила позволяют использовать для обработки ошибки страницы любой фрейм страниц независимо от того, принадлежит ли он другому про" цессу. Например, в результате применения глобальных правил замены с при" менением алгоритма FIFO будет найдена и выгружена на диск страница, на" ходившаяся в памяти наибольшее время, а локальные правила замены огра" ничат сферу поиска самой старой страницей из набора, который принад" лежит процессу, вызвавшему ошибку страницы. Таким образом, глобальные правила замены делают процессы уязвимыми от поведения других процес" сов, и одно сбойное приложение может негативно отразиться на всей опе" рационной системе. В Windows реализована комбинация локальных и глобальных правил за" мены. Когда размер рабочего набора достигает своего лимита и/или появ" ляется необходимость его усечения из"за нехватки физической памяти, дис" петчер памяти удаляет из рабочих наборов ровно столько страниц, сколь" ко ему нужно освободить.
488 ГЛ А В А 7 БЕЗОПАСНОСТЬ Управление рабочими наборами Все процессы начинают свой жизненный цикл с максимальным и минималь" ным размерами рабочего набора по умолчанию — 50 и 345 страниц соответ" ственно. Хотя это мало что дает, эти значения по умолчанию можно изменить для конкретного процесса через Windows"функцию SetProcessWorkingSetSize, но для этого нужна привилегия Increase Scheduling Priority. Однако, если толь" ко вы не укажете процессу использовать жесткие лимиты на рабочий набор (новшество Windows Server 2003), эти лимиты игнорируются в том смысле, что диспетчер памяти разрешит процессу расширение за установленный мак" симум при наличии интенсивной подкачки страниц и достаточного объема свободной памяти (либо, напротив, уменьшит его рабочий набор ниже ми" нимума при отсутствии подкачки страниц и при высокой потребности сис" темы в физической памяти). Хотя в Windows 2000 степень расширения про" цесса за максимальную границу рабочего набора увязывалась с вероятностью его усечения, в Windows XP это решение принимается исключительно на ос" нове того, к скольким страницам обращался процесс. В Windows Server 2003 жесткие лимиты на размеры рабочего набора мо" гут быть заданы вызовом функции SetProcessWorkingSetSizeEx с флагом QUOTA_LIMITS_HARDWS_ENABLE. Этой функцией пользуется, например, Windows System Resource Manager (WSRM), описанный в главе 6. Максимальный размер рабочего набора не может превышать общесис" темный максимум, вычисленный при инициализации системы и хранящий" ся в переменной ядра MmMaximumWorkingSetSize. Это значение представля" ет собой число страниц, доступных на момент вычислений (суммарный раз" мер списков обнуленных, свободных и простаивающих страниц), за выче" том 512 страниц. Однако существуют жесткие верхние лимиты на размеры рабочих наборов — они перечислены в таблице 7"17. Таблица 7-17. Верхний лимит на максимальные размеры рабочих наборов Версия Windows Максимальный размер рабочего набора x86"версии Windows 2000, Windows XP, Windows XP SP1, Windows Server 2003 1984 Мб x86"версии Windows XP SP2, Windows Server 2003 SP1 2047,9 Мб x86"версии Windows, загружаемые с ключом /3GB 3008 Мб IA64 7152 Гб x64 8192 Гб Когда возникает ошибка страницы, система проверяет лимиты рабочего набора процесса и объем свободной памяти. Если условия позволяют, дис" петчер памяти разрешает процессу увеличить размер своего рабочего набо" ра до максимума (и даже превысить его, если свободных страниц достаточ" но и если для этого процесса не задан жесткий лимит на размер рабочего набора). Но если памяти мало, Windows предпочитает заменять страницы в рабочем наборе, а не добавлять в него новые.
ГЛАВА 9 Управление памятью 489 Хотя Windows пытается поддерживать достаточный объем доступной памяти, записывая измененные страницы на диск, при слишком быстрой генерации модифицированных страниц понадобится больше свободной памяти. Поэтому, когда свободной физической памяти становится мало, вы" зывается диспетчер рабочих наборов (working set manager), который выпол" няется в контексте системного потока диспетчера настройки баланса (см. следующий раздел) и инициирует автоматическое усечение рабочего набо" ра для увеличения объема доступной в системе свободной памяти. (Исполь" зуя Windows"функцию SetProcessWorkingSetSize, вы можете вызвать усечение рабочего набора своего процесса, например после его инициализации.) Диспетчер рабочих наборов принимает решения об усечении каких"либо рабочих наборов, исходя из объема доступной памяти. Если памяти доста" точно, он подсчитывает, сколько страниц можно при необходимости изъять из рабочего набора. Как только такая необходимость появится, он уменьшит рабочие наборы, размер которых превышает минимальный. Диспетчер ра" бочих наборов динамически регулирует частоту проверки рабочих наборов и оптимальным образом упорядочивает список процессов — кандидатов на усечение рабочего набора. Например, первыми проверяются процессы со множеством страниц, к которым не было недавних обращений; часто про" стаивающие процессы большего размера являются более вероятными кан" дидатами, чем реже простаивающие процессы меньшего размера; процес" сы активного приложения рассматриваются в последнюю очередь и т. д. Определив, что размеры рабочих наборов процессов превышают мини" мальные значения, диспетчер ищет страницы, которые можно удалить из их рабочих наборов и сделать доступными для использования в других целях. Если свободной памяти по"прежнему не хватает, диспетчер продолжает уда" лять страницы из рабочих наборов процессов, пока в системе не появится минимальное количество свободных страниц. В однопроцессорных системах Windows 2000 и всех системах Windows XP или Windows Server 2003 диспетчер рабочих наборов старается удалять страницы, к которым не было обращений в последнее время. Такие страни" цы обнаруживаются проверкой битового флага Accessed в аппаратном PTE. Если этот флаг сброшен, страница считается устаревшей, и соответствую" щий счетчик увеличивается на 1, показывая, что с момента последнего ска" нирования данного рабочего набора к этой странице не было обращений. Впоследствии возраст страниц учитывается при поиске кандидатов на уда" ление из рабочего набора. ПРИМЕЧАНИЕ В многопроцессорной системе Windows 2000 диспет" чер рабочего набора ошибочно не проверял битовый флаг Accessed, что приводило к удалению страниц из рабочего набора без учета со" стояния этого флага. Если битовый флаг Accessed в аппаратном PTE установлен, диспетчер ра" бочих наборов сбрасывает его и проверяет следующую страницу рабочего набора. Таким образом, если при следующем сканировании битовый флаг
490 ГЛ А В А 7 БЕЗОПАСНОСТЬ Accessed окажется сброшенным, диспетчер будет знать, что со времени пос" леднего сканирования к этой странице не было обращений. Сканирование списка рабочего набора продолжается до удаления нужного числа страниц или до возврата к начальной точке. (В следующий раз сканирование начнет" ся там, где оно остановилось в прошлый раз.) ЭКСПЕРИМЕНТ: просмотр размеров рабочих наборов процессов С этой целью можно использовать счетчики в оснастке Performance (Производительность), перечисленные в следующей таблице. Счетчик Описание Process: Working Set (Процесс: Рабочее множество) Текущий размер рабочего набора выбранного процесса (в байтах) Process: Working Set Peak [Процесс: Рабочее множество (пик)] Пиковый размер рабочего набора выбранного процесса (в байтах) Process: Page Faults/Sec (Процесс: Ошибок страницы/сек) Число ошибок страниц, генерируемых процессом каждую секунду Несколько других утилит для просмотра сведений о процессах (Task Manager, Pview и Pviewer) тоже показывают размеры рабочих наборов. Суммарный размер рабочих наборов всех процессов можно полу" чить, выбрав процесс _Total в оснастке Performance. Этот несуществу" ющий процесс просто представляет суммарные значения счетчиков всех процессов, выполняемых в системе в данный момент. Однако сум" марный размер не соответствует истине, так как при подсчете разме" ра рабочего набора процесса учитываются его разделяемые страницы. В итоге страница, разделяемая двумя или более процессами, засчиты" вается в размер рабочего набора каждого из таких процессов. ЭКСПЕРИМЕНТ: просмотр списка рабочего набора Элементы рабочего набора можно увидеть с помощью команды !wsle отладчика ядра. Ниже показан фрагмент выходной информации о списке рабочего набора, полученной с помощью LiveKd (эта команда была выполнена применительно к процессу LiveKd). kd> !wsle 7 Working Set @ c0502000 Quota: 9f FirstFree: 40 FirstDynamic: 3 LastEntry 1fe NextSlot: 3 LastInitialized 257 NonDirect 5c HashTable: 0 HashTableSize: 0 Virtual Address Age Locked ReferenceCount c0300203 0 1 1 c0301203 0 1 1 c0502203 0 1 1
ГЛАВА 9 c01df201 c01ff201 c0005201 c0001201 c0002201 c0000201 c0006201 77e87119 00402319 77e01201 7ffdf201 00130201 77e9e119 78033201 00230221 00131201 77d50119 00132201 c01e0201 00411309 0040d201 77edf201 77ee0201 77fcd201 0040e201 7ffc1009 00401319 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Управление памятью 491 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 Заметьте, что одни элементы списка рабочего набора представля" ют собой страницы, содержащие таблицы страниц (элементы с адре" сами выше 0xC0000000), другие — страницы системных DLL (в диапа" зоне 0x7nnnnnnn), третьи — страницы кода самой LiveKd.exe (в диа" пазоне 0x004nnnnn). Диспетчер настройки баланса и подсистема загрузки-выгрузки Расширение и усечение рабочего набора выполняется в контексте систем" ного потока диспетчера настройки баланса (balance set manager) (процеду" ра KeBalanceSetManager). Его поток создается при инициализации системы. Хотя с технической точки зрения диспетчер настройки баланса входит в состав ядра, для анализа и регулировки рабочих наборов он обращается к диспетчеру рабочих наборов. Диспетчер настройки баланса ждет на двух объектах «событие»: один из них освобождается по сигналу таймера, срабатывающего раз в секунду, а дру" гой представляет собой внутреннее событие диспетчера рабочих наборов, освобождаемое диспетчером памяти, когда возникает необходимость в изме"
492 ГЛ А В А 7 БЕЗОПАСНОСТЬ нении рабочих наборов. Например, если в системе слишком часто генериру" ются ошибки страниц или список свободных страниц слишком мал, диспет" чер памяти пробуждает диспетчер настройки баланса, а тот вызывает диспет" чер рабочих наборов для усечения таких наборов. Если свободной памяти много, диспетчер рабочих наборов разрешает процессам, часто вызывающим ошибки страниц, постепенно увеличивать размеры своих рабочих наборов, подкачивая в память страницы, при обращении к которым возникали ошиб" ки. Однако рабочие наборы расширяются лишь по мере необходимости. Диспетчер настройки баланса, пробуждаемый в результате срабатывания таймера, выполняет следующие операции. 1. При каждом четвертом пробуждении из"за срабатывания таймера освобож" дает событие, которое активизирует системный поток, выполняющий про" цедуру KeSwapProcessOrStack — подсистему загрузки"выгрузки (swapper). 2. Проверяет ассоциативные списки и регулирует глубину их вложения, если это необходимо (для ускорения доступа, снижения нагрузки на пул и уменьшения его фрагментации). 3. Ищет потоки, чей приоритет может быть повышен из"за нехватки про" цессорного времени (см. раздел «Динамическое повышение приоритета при нехватке процессорного времени» главы 6). 4. Вызывает диспетчер рабочих наборов (имеющий собственные внутрен" ние счетчики, которые определяют, когда и насколько агрессивно следу" ет проводить усечение рабочих наборов). Подсистема загрузки"выгрузки пробуждается и планировщиком, если стек ядра потока, подлежащего выполнению, или весь процесс выгружен в страничный файл. Подсистема загрузки"выгрузки ищет потоки, которые находились в состоянии ожидания в течение 7 секунд (Windows 2000) или 15 секунд (Windows XP и Windows Server 2003). Если такой поток есть, под" система загрузки"выгрузки переводит его стек ядра в переходное состояние (перемещая соответствующие страницы в список модифицированных или простаивающих страниц). Здесь действует принцип «если поток столько времени ждал, подождет и еще». Когда из памяти удаляется стек ядра послед" него потока процесса, этот процесс помечается как полностью выгружен" ный. Вот почему у долго простаивавших процессов (например, у Winlogon после вашего входа в систему) может быть нулевой размер рабочих наборов. Системный рабочий набор Подкачиваемый код и данные операционной системы тоже управляются как единый системный рабочий набор (system working set). В системный рабо" чий набор могут входить страницы пяти видов: 쐽 системного кэша; 쐽 пула подкачиваемой памяти; 쐽 подкачиваемого кода и данных Ntoskrnl.exe; 쐽 подкачиваемого кода и данных драйверов устройств;
ГЛАВА 9 Управление памятью 493 쐽 проецируемых системой представлений. Выяснить размер системного рабочего набора и пяти его элементов мож" но с помощью счетчиков производительности или системных переменных, перечисленных в таблице 7"18. Учтите, что значения счетчиков выражают" ся в байтах, а значения системных переменных — в страницах. Узнать интенсивность подкачки страниц в системном рабочем наборе позволяет счетчик Memory: Cache Faults/Sec (Память: Ошибок кэш"памяти/ сек), который сообщает число ошибок страниц, генерируемых в системном рабочем наборе (как аппаратных, так и программных). Таблица 7-18. Счетчики, относящиеся к системному рабочему набору Счетчик Системная переменная Описание Memory: Cache Bytes (Память: Байт кэш"памяти)1 MmSystemCacheWs.Work ingSetSize Суммарный размер системно" го рабочего набора (включая кэш, пул подкачиваемой памя" ти, подкачиваемый код Ntoskrnl и драйверов, а также представ" ления, проецируемые систе" мой); это не размер только системного кэша, как можно было бы подумать по назва" нию счетчика Memory: Cache Bytes Peak MmSystemCacheWs.Peak [Память: Байт кэш"памяти (пик)] Пиковый размер системного рабочего набора Memory: System Cache Resident Bytes (Память: Резидентных байт сис" темного кэша) MmSystemCachePage Физическая память, занятая системным кэшем Memory: System Code Resident Bytes (Память: Резидентных байт сис" темного кода) MmSystemCodePage Физическая память, занятая подкачиваемым кодом Ntoskrnl.exe Memory: System Driver Resident Bytes (Память: Резидентных байт сис" темных драйверов) MmSystemDriverPage Физическая память, занятая подкачиваемым кодом драй" веров устройств Memory: Pool Paged Resident Bytes (Память: Байт в резидентном страничном пуле) MmPagedPoolPage Физическая память, занятая пулом подкачиваемой памяти 1 Внутреннее название этого рабочего набора — рабочий набор сиcтемного кэша, хотя системный кэш является лишь одним из пяти элементов системного рабоче" го набора. Из"за этой путаницы некоторые утилиты, сообщая размер файлового кэша, на самом деле показывают суммарный размер системного рабочего набора. Минимальный и максимальный размеры системного рабочего набора вычисляются при инициализации системы, исходя из объема физической памяти компьютера и выпуска Windows — клиентского или серверного.
494 ГЛ А В А 7 БЕЗОПАСНОСТЬ Вычисленные значения максимального и минимального размеров хра" нятся в системных переменных, показанных в таблице 7"19 (их значения недоступны через счетчики производительности, но вы можете просмотреть их в отладчике ядра). Таблица 7-19. Системные переменные, хранящие максимальный и минимальный размеры системного рабочего набора Переменная Тип Описание MmSystemCacheWs.Minimum WorkingSetSize ULONG Минимальный размер системного рабочего набора MmSystemCacheWs.Maximum WorkingSetSize ULONG Максимальный размер системного рабочего набора Вы можете отдать приоритет системному рабочему набору (в противопо" ложность рабочим наборам процессов), изменив параметр реестра HKLM\ SYSTEM\CurrentControlSet\Control\Session Manager\Memory Management\ LargeSystemCache. В системах Windows 2000 Server это значение можно было косвенно модифицировать заданием свойств для службы файлового серве" ра; Windows XP и Windows Server 2003 позволяют сделать это явно: щелкни" те My Computer (Мой компьютер) правой кнопкой мыши, выберите Pro" perties (Свойства), откройте вкладку Advanced (Дополнительно), нажмите кнопку Settings (Параметры) в разделе Performance (Быстродействие) и пе" рейдите на очередную вкладку Advanced (детали см. в главе 11). База данных PFN Если рабочие наборы описывают резидентные страницы, принадлежащие процессу или системе, то база данных PFN (номеров фреймов страниц) оп" ределяет состояние каждой страницы в физической памяти. Состояния стра" ниц перечислены в таблице 7"20. Таблица 7-20. Возможные состояния страниц Состояние Описание Активная, или дейст" вительная (active/valid) Данная страница либо является частью рабочего набора (процесса или системы), либо не входит ни в один рабо" чий набор (находясь, например, в пуле неподкачиваемой памяти ядра), но при этом на нее ссылается действитель" ный PTE Переходная (transition) Временное состояние страницы, не принадлежащей ни одному рабочему набору или списку. Страница пребыва" ет в этом состоянии в ходе операции ввода"вывода. PTE программируются так, чтобы можно было обнаруживать и корректно обрабатывать конфликты ошибок страни" цы. (Заметьте, что здесь термин «переходная» имеет дру" гой смысл в отличие от того же термина, употреблявше" гося в разделе по недействительным PTE; недействитель" ный переходный PTE ссылается на страницу в списке простаивающих или модифицированных страниц.)
ГЛАВА 9 Управление памятью 495 Таблица 7-20. (окончание) Состояние Описание Простаивающая (standby) Данная страница раньше входила в рабочий набор, но теперь удалена из него. Страница осталась неизменной с момента последней записи на диск. PTE все еще ссыла" ется на физическую страницу, но уже помечен как не" действительный и находящийся в переходном состоянии Модифицированная (modified) Данная страница раньше входила в рабочий набор, но теперь удалена из него. Однако она была изменена, и ее содержимое еще не записано на диск. PTE все еще ссыла" ется на физическую страницу, но уже помечен как не" действительный и находящийся в переходном состоя" нии. Перед повторным использованием страницы ее содержимое должно быть записано на диск Модифицированная, но не записываемая (modified no"write) То же, что и предыдущее состояние, но страница помече" на так, что подсистема записи модифицированных стра" ниц (принадлежащая диспетчеру памяти) не будет запи" сывать ее на диск. Диспетчер кэша помечает страницы как модифицированные, но не записываемые по запросу драйверов файловой системы. Так, NTFS использует это состояние для страниц, содержащих метаданные файло" вой системы, чтобы записи журнала транзакций сбрасы" вались на диск до содержимого защищаемых ими стра" ниц (о протоколировании транзакций NTFS см. главу 12) Свободная (free) Эта страница свободна, но содержит какие"то данные. Ее нельзя передать пользовательскому процессу до за" полнения нулями (из соображений безопасности) Обнуленная (zeroed) Данная страница свободна и инициализирована нулевы" ми значениями (потоком обнуления страниц) Только для чтения (ROM) Ошибка страницы была вызвана из памяти только для чтения (новшество Windows XP) Аварийная (bad) Данная страница вызвала ошибку четности или другую аппаратную ошибку. Ее больше нельзя использовать База данных PFN состоит из массива структур, представляющих каждую страницу физической памяти в системе. Как показано на рис. 7"33, действи" тельные PTE ссылаются на записи базы данных PFN, а эти записи (если они не относятся к прототипным PFN) — на таблицу страниц, которая их ис" пользует. Прототипные PFN ссылаются на прототипные PTE.
496 ГЛ А В А 7 Рис. 7-33. БЕЗОПАСНОСТЬ Таблицы страниц и база данных номеров фреймов страниц Страницы, находящиеся в некоторых из перечисленных в таблице 7"20 состояний, организуются в связанные списки, что помогает диспетчеру памя" ти быстро находить страницы определенного типа. (Активные и переходные страницы не включаются ни в один общесистемный список.) Пример взаи" мосвязей элементов таких списков в базе данных PFN показан на рис. 7"34.
ГЛАВА 9 Рис. 7-34. Управление памятью 497 Списки страниц в базе данных PFN В следующем разделе вы узнаете, как эти связанные списки используют" ся при обработке ошибок страниц и как страницы перемещаются между различными списками. ЭКСПЕРИМЕНТ: просмотр базы данных PFN Команда !memusage отладчика ядра позволяет получить информацию о размерах различных списков страниц. Вот пример вывода этой команды. lkd> !memusage loading PFN database loading (100% complete) Compiling memory usage data Zeroed: 8474 Free: 256 Standby: 50790 Modified: 496 ModifiedNoWrite: 0 Active/Valid: 201980 Transition: 1 Unknown: 0 TOTAL: 261997 (99% Complete). (33896 kb) ( 1024 kb) (203160 kb) ( 1984 kb) ( 0 kb) (807920 kb) ( 4 kb) ( 0 kb) (1047988 kb)
498 ГЛ А В А 7 БЕЗОПАСНОСТЬ Динамика списков страниц На рис. 7"35 показана схема состояний фрейма страниц. Для упрощения на ней отсутствует список модифицированных, но не записываемых страниц. Фреймы страниц перемещаются между различными списками следую" щим образом. 쐽 Когда диспетчеру памяти нужна обнуленная страница для обслуживания ошибки страницы, обнуляемой по требованию (demand"zero page fault) (ссылки на страницу, которая должна быть заполнена нулями, или на зак" рытую переданную страницу пользовательского режима, к которой еще не было обращений), он прежде всего пытается получить ее из списка обну" ленных страниц. Если этот список пуст, он берет ее из списка свободных страниц и заполняет нулями. Если и этот список пуст, диспетчер памяти извлекает страницу из списка простаивающих страниц и обнуляет ее. Рис. 7-35. Схема состояний фреймов страниц Одна из причин необходимости обнуления страниц — соответствие требованиям защиты уровня C2: процессам пользовательского режима должны передаваться фреймы обнуленных страниц, чтобы не допустить чтения содержимого памяти предыдущих процессов. Поэтому диспетчер памяти передает процессам пользовательского режима фреймы обнулен"
ГЛАВА 9 Управление памятью 499 ных страниц, если только страница не считывается из проецируемого файла. В последнем случае диспетчер памяти использует фреймы необ" нуленных страниц, инициализируя их данными с диска. Список обнуленных страниц заполняется страницами из списка сво" бодных страниц системным потоком обнуления страниц (zero page thre" ad) — это поток 0 процесса System. Он ждет на объекте"событии, кото" рый переходит в свободное состояние при наличии в списке свободных страниц восьми и более страниц. Однако этот поток выполняется, толь" ко если не работают другие потоки, поскольку он имеет нулевой приори" тет, а наименьший приоритет пользовательского потока — 1. ПРИМЕЧАНИЕ В Windows Server 2003 и более новых версиях, когда возникает необходимость в обнулении памяти из"за выделения физи" ческой страницы драйвером, вызвавшим MmAllocatePagesForMdl, или Windows"приложением, вызвавшим AllocateUserPhysicalPages, либо ког" да приложение выделяет большие страницы, диспетчер памяти обну" ляет память через более эффективную функцию MiZeroInParallel. Она проецирует регионы большего размера, чем поток обнуления страниц, который выполняет свою операцию только над одной страницей еди" новременно. Кроме того, в многопроцессорных системах эта функция создает дополнительные системные потоки для параллельного выпол" нения операций обнуления (с поддержкой специфических оптимиза" ций на NUMA"платформах). 쐽 Если диспетчеру памяти не нужны обнуленные станицы, он сначала об" ращается к списку свободных страниц и, если тот пуст, переходит к спис" ку простаивающих страниц. Прежде чем диспетчер сможет воспользо" ваться фреймом страниц из списка простаивающих страниц, он должен проследить ссылку из недействительного PTE (или прототипного PTE), который еще ссылается на этот фрейм, и удалить ее. Поскольку элемен" ты (записи) базы данных PFN содержат обратные указатели на таблицу страниц предыдущего пользователя (или на прототипный PTE, если стра" ницы разделяемые), диспетчер памяти может быстро найти PTE и внести требуемые изменения. 쐽 Когда процессу приходится отдать страницу из своего рабочего набора (из"за ссылки на новую страницу при заполненном рабочем наборе или из"за усечения рабочего набора, инициированного диспетчером памяти), она переходит в список простаивающих страниц (если ее данные не из" менялись) или в список модифицированных (если ее данные изменялись, пока она находилась в памяти). По завершении процесса все его закры" тые страницы переходят в список свободных страниц. И еще: как только закрывается последняя ссылка на раздел, поддерживаемый страничным файлом, все его страницы тоже переходят в список свободных страниц.
500 ГЛ А В А 7 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: наблюдаем за ошибками страниц Утилита Pfmon из ресурсов Windows 2000 и 2003, а также из Windows XP Support Tools позволяет наблюдать за ошибками страниц по мере их возникновения. Ниже показан фрагмент вывода Pfmon при запус" ке Notepad и его последующем закрытии. Слово SOFT означает, что ошибка страницы была устранена с помощью одного из переходных списков, а слово HARD — что ошибка страницы потребовала чтения с диска. Обратите внимание на итоговые сведения о подкачке страниц в конце листинга. C:\> pfmon notepad SOFT: KiUserApcDispatcher : KiUserApcDispatcher SOFT: LdrInitializeThunk : LdrInitializeThunk SOFT: 0x77f61016 : : 0x77f61016 SOFT: 0x77f6105b : : fltused+0xe00 HARD: 0x77f6105b : : fltused+0xe00 SOFT: LdrQueryImageFileExecutionOptions : LdrQueryImageFileExecutionOptions SOFT: RtlAppendUnicodeToString : RtlAppendUnicodeToString SOFT: RtlInitUnicodeString : RtlInitUnicodeString ... notepad Caused 8 faults had 9 Soft 5 Hard faulted VA's ntdll Caused 94 faults had 42 Soft 8 Hard faulted VA's comdlg32 Caused 3 faults had 0 Soft 3 Hard faulted VA's shlwapi Caused 2 faults had 2 Soft 2 Hard faulted VA's gdi32 Caused 18 faults had 10 Soft 2 Hard faulted VA's kernel32 Caused 48 faults had 36 Soft 3 Hard faulted VA's user32 Caused 38 faults had 26 Soft 6 Hard faulted VA's advapi32 Caused 7 faults had 6 Soft 3 Hard faulted VA's rpcrt4 Caused 6 faults had 4 Soft 2 Hard faulted VA's comctl32 Caused 6 faults had 5 Soft 2 Hard faulted VA's shell32 Caused 6 faults had 5 Soft 2 Hard faulted VA's Caused 10 faults had 9 Soft 5 Hard faulted VA's winspool Caused 4 faults had 2 Soft 2 Hard faulted VA's PFMON: Total Faults 250 (KM 74 UM 250 Soft 204, Hard 46, Code 121, Data 129) Подсистема записи модифицированных страниц При чрезмерном увеличении списка модифицированных страниц либо при уменьшении размера списков обнуленных или простаивающих страниц ниже определенного порогового значения, вычисляемого в ходе загрузки системы и хранящегося в переменной ядра MmMinimumFreePages, пробуж" дается один из двух системных потоков, который записывает страницы на диск и переводит их в список простаивающих. Один из системных потоков (MiModifiedPageWriter) записывает модифицированные страницы в странич"
ГЛАВА 9 Управление памятью 501 ный файл, а другой (MiMappedPageWriter) — в проецируемые файлы. Два потока нужны для того, чтобы избежать тупиковой ситуации, возможной при ошибке страницы в момент записи страниц проецируемых файлов. Эта ошибка потребовала бы свободной страницы в отсутствие таковых, что в свою очередь потребовало бы от подсистемы записи модифицированных страниц создания новых свободных страниц. Поскольку операции ввода" вывода с проецируемыми файлами выполняет второй поток этой подсисте" мы, он может переходить в состояние ожидания, не блокируя обычные опе" рации ввода"вывода со страничным файлом. Оба потока выполняются с приоритетом 17, и после инициализации каж" дый из них ждет на своем объекте"событии. Этот объект переходит в свобод" ное состояние по одной из двух причин. 쐽 Число модифицированных страниц превышает максимум, рассчитанный при инициализации системы (MmModifiedPageMaximum) (в настоящее время — 800 страниц для всех систем). 쐽 Число доступных страниц (MmAvailablePages) меньше значения MmMini mumFreePages. Подсистема записи модифицированных страниц ждет еще на одном со" бытии (MiMappedPagesTooOldEvent), которое устанавливается по истечении предопределенного числа секунд (MmModifiedPageLifeInSeconds), указывая, что проецируемые (а не просто измененные) страницы должны быть запи" саны на диск. (По умолчанию этот интервал равен 300 секундам. Вы можете изменить его, добавив в раздел реестра HKLM\SYSTEM\CurrentControlSet\ Control\Session Manager\Memory Management параметр ModifiedPageLife типа DWORD.) Дополнительное событие используется для того, чтобы снизить риск потери данных при крахе системы или отказе электропитания путем сохранения модифицированных проецируемых страниц, даже если размер списка модифицированных страниц не достиг порогового значения в 800 страниц. При активизации подсистема записи модифицированных страниц пыта" ется записать на диск как можно больше страниц одним пакетом. Для этого она анализирует поле исходного содержимого PTE в элементах базы данных PFN, которые относятся к страницам, входящим в список модифицирован" ных страниц, и ищет страницы, хранящиеся в непрерывных областях на диске. Подобрав пакет страниц для записи, она выдает запрос на ввод"вывод и после успешного завершения операции ввода"вывода перемещает их в конец списка простаивающих страниц. При записи страницы к ней может обратиться другой поток. В этом слу" чае счетчики ссылок и числа пользователей в элементе PFN, который пред" ставляет физическую страницу, увеличиваются на 1. По окончании операции ввода"вывода подсистема записи модифицированных страниц обнаружит, что счетчик числа пользователей больше не равен 0, и не станет перемещать эту страницу в список простаивающих страниц.
502 ГЛ А В А 7 БЕЗОПАСНОСТЬ Структуры данных PFN Хотя записи базы данных PFN имеют фиксированную длину, они могут на" ходиться в нескольких состояниях в зависимости от состояния страницы. Таким образом, отдельные поля могут иметь разный смысл. Состояния запи" си базы данных PFN иллюстрирует рис. 7"36. Рис. 7-36. Состояния записи базы данных PFN Некоторые поля одинаковы для нескольких типов PFN, другие специфич" ны для конкретного типа PFN. Следующие поля встречаются в PFN несколь" ких типов. 쐽 Адрес PTE Виртуальный адрес PTE, указывающего на данную страницу. 쐽 Счетчик ссылок Число ссылок на данную страницу. Этот счетчик уве" личивается на 1, когда страница впервые добавляется в рабочий набор и/ или когда она блокируется в памяти для операции ввода"вывода (напри" мер драйвером устройства). Счетчик ссылок уменьшается на 1, когда об" нуляется счетчик числа пользователей страницы или когда снимается бло" кировка страницы в памяти. Когда счетчик числа пользователей становит" ся равным 0, страница больше не принадлежит рабочему набору. Далее, если счетчик ссылок тоже равен 0, страница перемещается в список сво" бодных, простаивающих или модифицированных страниц, и запись базы данных PFN, описывающая эту страницу, соответственно обновляется. 쐽 Тип Тип страницы, представленной этим PFN (активная/действитель" ная, переходная, простаивающая, модифицированная, модифицирован"
ГЛАВА 9 Управление памятью 503 ная, но не записываемая, свободная, обнуленная, только для чтения или аварийная). 쐽 Флаги Информация, содержащаяся в поле флагов, поясняется в табли" це 7"21. 쐽 Исходное содержимое PTE Все записи базы данных PFN включают ис" ходное содержимое PTE, указывающего на страницу (который может быть прототипным PTE). Сохранение исходного содержимого PTE позволяет восстанавливать его, когда физическая страница больше не резидентна. 쐽 PFN элемента PTE Номер физической страницы для виртуальной стра" ницы с таблицей страниц, включающей PTE страницы, к которой отно" сится данный PFN. Таблица 7-21. Флаги в записях базы данных PFN Флаг Описание Состояние модификации Указывает, модифицирована ли страница (если да, то перед удалением из памяти ее содержимое должно быть сохранено на диске) Прототипный PTE Указывает, что PTE, на который ссылается запись PFN, является прототипным. (Например, эта страница доступ" на для совместного использования.) Ошибка четности Указывает, что на физической странице обнаружена ошибка четности или ECC В процессе чтения Указывает, что страница загружается в память. Первое поле типа DWORD содержит адрес объекта «событие», который освободится по окончании операции ввода" вывода; также указывает первый PFN при выделении памяти из неподкачиваемого пула В процессе записи Указывает, что страница записывается. Первое поле типа DWORD содержит адрес объекта «событие», который ос" вободится по окончании операции ввода"вывода; также указывает последний PFN при выделении памяти из неподкачиваемого пула Начало пула неподкачи" ваемой памяти Для страниц пула неподкачиваемой памяти указывает, что данный PFN является первым для данной области, выделенной в пуле неподкачиваемой памяти Конец пула неподкачи" ваемой памяти Для страниц пула неподкачиваемой памяти указывает, что данный PFN является последним для данной области, выделенной в пуле неподкачиваемой памяти Ошибка загрузки страницы Указывает, что при загрузке данной страницы произошла ошибка (в этом случае первое поле PFN содержит код ошибки) Остальные поля специфичны для PFN конкретных типов. Так, первый PFN на рис. 7"36 представляет активную страницу, входящую в рабочий набор. Поле счетчика числа пользователей (share count) сообщает количество PTE, ссылающихся на данную страницу. (Страницы с атрибутом «только для чте" ния», «копирование при записи» или «разделяемая, для чтения и записи» могут использоваться сразу несколькими процессами.) В случае страниц с
504 ГЛ А В А 7 БЕЗОПАСНОСТЬ таблицами страниц это поле содержит количество действительных PTE в таблице страниц. Пока счетчик числа пользователей страницы больше 0, она не удаляется из памяти. Поле индекса рабочего набора — это индекс в списке рабочего набора (процесса, системы или сеанса), включающем виртуальный адрес, по кото" рому проецируется данная физическая страница. Если страница не входит ни в один рабочий набор, это поле равно 0. Если страница является закры" той, индекс рабочего набора ссылается непосредственно на элемент спис" ка рабочего набора, поскольку страница проецируется только по одному виртуальному адресу. В случае разделяемой страницы индекс рабочего на" бора представляет собой ссылку, корректность которой гарантируется лишь для первого процесса, объявившего эту страницу действительной. (Осталь" ные процессы будут пытаться по возможности использовать тот же индекс.) Процесс, первым настроивший это поле, обязательно получит корректную ссылку, и ему не надо добавлять в дерево хэшей своего рабочего набора эле" мент хэша списка рабочего набора, на который указывает виртуальный ад" рес. Это позволяет уменьшить размер дерева хэшей рабочего набора и ус" корить поиск его элементов. Второй PFN на рис. 7"36 соответствует странице из списка простаиваю" щих или модифицированных страниц. В этом случае элементы списка свя" заны полями прямых и обратных связей. Эти связи позволяют легко мани" пулировать страницами при обработке ошибок страниц. Когда страница находится в одном из списков, ее счетчик числа пользователей по опреде" лению равен 0 (поскольку она не используется ни в одном рабочем наборе) и поэтому может быть перекрыта обратной связью. Счетчик ссылок также равен 0, если страница находится в одном из списков. Если же он отличен от 0 (из"за выполнения над данной страницей операции ввода"вывода, на" пример записи на диск), страница сначала удаляется из списка. Третий PFN на рис. 7"36 соответствует странице из списка свободных или обнуленных страниц. Эти записи базы данных PFN связывают не только стра" ницы внутри двух списков, но и — с помощью дополнительного поля — фи" зические страницы «по цвету», т. е. по их местонахождению в кэш"памяти процессора. Windows пытается свести к минимуму лишнюю нагрузку на кэш" память процессора из"за наличия в ней разных физических страниц. Эта оп" тимизация реализуется за счет того, что Windows по возможности избегает использования одного и того же элемента кэша для двух разных страниц. Для систем с прямым проецированием кэшей оптимальное использование аппа" ратных возможностей дает существенный выигрыш в производительности. Четвертый PFN на рис. 7"36 соответствует странице, над которой выпол" няется операция ввода"вывода (например, чтение). Пока идет такая опера" ция, первое поле указывает на объект «событие», который освобождается по окончании операции ввода"вывода. Если при этом произойдет ошибка, в данное поле будет записан код статуса ошибки Windows, представляющий ошибку ввода"вывода. PFN этого типа используются в разрешении конфлик" тов ошибок страницы.
ГЛАВА 9 Управление памятью 505 ЭКСПЕРИМЕНТ: просмотр записей PFN Отдельные записи PFN можно исследовать с помощью команды !pfn отладчика ядра, указывая PFN как аргумент. (Так, !pfn 0 сообщает ин" формацию о первой записи, !pfn 1 — о второй и т. д.) В следующем примере показывается PTE для виртуального адреса 0x50000, PFN страницы с каталогом страниц и сама страница. kd> !pte 50000 00050000  PDE at C0300000 PTE at C0000140 contains 00700067 contains 00DAA047 pfn 00700 DAUWV pfn 00DAA DUWV kd> !pfn 700 PFN 00000700 at address 827CD800 flink 00000004 blink / share count 00000010 pteaddress C0300000 reference count 0001 color 0 restore pte 00000080 containing page 00030 Active ... Modified kd> !pfn daa PFN 00000DAA at address 827D77F0 flink 00000077 blink / share count 00000001 pteaddress C0000140 reference count 0001 color 0 restore pte 00000080 containing page 00700 Active ... Modified Общее состояние физической памяти описывается не только базой дан" ных PFN, но и системными переменными, перечисленными в таблице 7"22. Таблица 7-22. Системные переменные, описывающие состояние физической памяти Переменная Описание MmNumberOfPhysicalPages Общее количество физических страниц, доступное в системе MmAvailablePages Общее количество страниц, доступное в системе: суммарное число страниц в списках обнуленных, свободных и простаивающих страниц MmResidentAvailablePages Общее количество физических страниц, которое могло бы быть доступно при минимальном размере всех рабочих наборов процессов Уведомление о малом или большом объеме памяти Windows XP и Windows Server 2003 позволяют процессам пользовательско" го режима получать уведомления, когда памяти мало и/или много. На осно" ве этой информации можно определять характер использования памяти. Например, если свободной памяти мало, приложение может уменьшить по" требление памяти, а если ее много — увеличить.
506 ГЛ А В А 7 БЕЗОПАСНОСТЬ Для уведомления о малом или большом объеме памяти вызовите функцию CreateMemoryResourceNotification, указав, какое именно уведомление вас инте" ресует. Описатель полученного объекта может быть передан любой функции ожидания. Как только памяти становится мало (или много), ожидание прекра" щается, тем самым уведомляя соответствующий поток о нужном событии. В качестве альтернативы можно использовать QueryMemoryResourceNotification для запроса о состоянии системной памяти в любой момент. Уведомление реализуется диспетчером памяти, который переводит в сво" бодное состояние глобально именованный объект «событие» LowMemory Condition или HighMemoryCondition. Эти именованные объекты находятся не в обычном каталоге \BaseNamedObjects диспетчера объектов, а в специаль" ном каталоге \KernelObjects. Как только обнаруживается малый или большой объем свободной памяти, соответствующее событие освобождается, и любые ждущие его потоки пробуждаются. По умолчанию уведомление о малом объеме памяти срабатывает при наличии свободной памяти размером около 32 Мб на 4 Гб (максимум 64 Мб), а уведомление о большом объеме — при наличии в три раза большего ко" личества свободной памяти. Эти значения (в мегабайтах) можно переопре" делить, добавив DWORD"параметр LowMemoryThreshold или HighMemory" Threshold в раздел реестра HKEY_LOCAL_MACHINE\System\CurrentControl" Set\Session Manager\Memory Management. ЭКСПЕРИМЕНТ: просмотр событий уведомления ресурса памяти Для просмотра событий уведомления ресурса памяти (memory resource notification events) запустите Winobj (www.sysinternals.com) и щелкни" те каталог KernelObjects. В правой секции окна вы увидите события LowMemoryCondition и HighMemoryCondition. Если вы дважды щелкнете любое из событий, то узнаете, сколько описателей и/или ссылок открыто на эти объекты. Чтобы выяснить, есть ли в системе процессы, запросившие уведом" ления о ресурсе памяти, ищите в таблице описателей ссылки на «Low" MemoryCondition» или «HighMemoryCondition». Это можно сделать в Process Explorer (команда Handle в меню Find) или в утилите Oh.exe из ресурсов Windows. (О том, что такое таблица описателей, см. раздел «Диспетчер объектов» главы 3.)
ГЛАВА 9 Управление памятью 507 Оптимизаторы памяти — миф или реальность? При серфинге по Web вы наверняка нередко видели всплывающие окна в браузере с рекламой наподобие «Дефрагментируйте память и повысьте производительность» или «Избавьтесь от сбоев приложений и системы и освободите неиспользуемую память». Такие ссылки обыч" но ведут к утилитам, авторы которых обещают сделать все и даже боль" ше. А работают ли они на самом деле? Оптимизаторы памяти обычно предоставляют UI, где выводятся график под названием «доступная память» и линия, отражающая ниж" нее пороговое значение, начиная с которого утилита вступает в дей" ствие. Еще одна линия, как правило, показывает объем памяти, кото" рый оптимизатор попытается освободить. Вы можете настроить один или оба уровня, а также запускать оптимизацию вручную или по рас" писанию. Некоторые утилиты также показывают список процессов, выполняемых в системе. Когда начинается оптимизация, счетчик до" ступной памяти в утилите увеличивается, иногда весьма резко, сооб" щая тем самым, что утилита действительно освобождает память для ваших приложений. Но на самом деле подобные утилиты просто вы" зывают обнуление полезной памяти, искусственно увеличивая объем свободной памяти. Оптимизаторы памяти выделяют, а потом освобождают большие объемы виртуальной памяти. На иллюстрации ниже показано, какое влияние оказывают оптимизаторы памяти на систему. Полоска «до оптимизации» отражает рабочие наборы и свободную память до оптимизации. На полоске «при оптимизации» видно, что оптимизатор создает высокую потребность в памяти, вызывая массу ошибок страниц в течение короткого времени. В ответ диспетчер па" мяти увеличивает рабочий набор оптимизатора памяти. Это расшире" ние рабочего набора происходит за счет свободной памяти, а когда свободная память заканчивается, то и за счет рабочих наборов других процессов. Полоска «после оптимизации» демонстрирует, что после см. след. стр.
508 ГЛ А В А 7 БЕЗОПАСНОСТЬ освобождения своей памяти оптимизатором диспетчер памяти пере" водит все страницы, которые были закреплены за оптимизатором, в список свободных страниц. Там они в конечном счете заполняются нулями потоком обнуления страниц, а затем перемещаются в список обнуленных страниц, что и дает вклад в увеличение счетчика доступ" ной памяти. Большинство оптимизаторов скрывают резкое уменьше" ние свободной памяти на первом этапе, но, запустив диспетчер задач при оптимизации, вы легко заметите, что такое падение объема сво" бодной памяти действительно имеет место. Хотя получение большего объема свободной памяти может пока" заться полезным, это не так. Когда оптимизаторы вызывают подъем значений счетчика доступной памяти, они заставляют систему выгру" жать из памяти код и данные других процессов. Если, например, вы работаете с Word, то текст открытых документов и код этой програм" мы до оптимизации являются частью рабочего набора Word (и, следо" вательно, находятся в физической памяти), а после оптимизации при" дется вновь считывать их с диска, как только вы захотите продолжить работу с документами. На серверах падение производительности бы" вает просто колоссальным, так как на них после оптимизации могут быть отброшены файловые данные, которые кэшировались в списке простаивающих страниц и системном рабочем наборе (то же самое относится к коду и данным, используемым любыми выполняемыми серверными приложениями). Некоторые разработчики оптимизаторов памяти заявляют, будто их утилиты освобождают память, бессмысленно занимаемую неис" пользуемыми процессами, например теми, значки которых помеща" ются в секцию индикаторов панели задач. Это могло бы быть правдой только в том случае, если бы к моменту оптимизации у этих процес" сов были рабочие наборы существенного размера. Но Windows авто" матически усекает рабочие наборы простаивающих процессов, и по" этому подобные заявления не соответствуют истине. Все, что нужно для реальной оптимизации, делает диспетчер памяти. Авторы оптимизаторов памяти также утверждают, что их утилиты дефрагментируют память. Действительно, выделение и последующее освобождение большого объема виртуальной памяти может в качестве побочного эффекта привести к появлению больших блоков непрерыв" ной свободной памяти. Однако, так как виртуальная память скрывает реальную структуру физической памяти от процессов, они не могут получить прямой выигрыш от виртуальной памяти, спроецированной на непрерывную область физической памяти. По мере выполнения процессов и периодического расширения"усечения их рабочих набо" ров физическая память, сопоставленная с занимаемой ими виртуаль" ной памятью, может стать фрагментированной несмотря на наличие больших непрерывных областей. К тому же, любой незначительный выигрыш от дефрагментации свободной физической памяти с лихвой
ГЛАВА 9 Управление памятью 509 перекрывается негативным эффектом от выгрузки из памяти исполь" зуемого кода и данных. Наконец, можно услышать, что оптимизаторы возвращают память, потерянную в результате утечек. Это, наверное, самое ложное утверж" дение. Диспетчеру памяти всегда известно, какая физическая и вирту" альная память принадлежит тому или иному процессу. Однако, если процесс выделяет память, а потом не освобождает ее из"за какой"то ошибки (это событие и называется утечкой), диспетчер памяти не в состоянии распознать, что выделенная память больше не будет ис" пользоваться, и поэтому вынужден ждать завершения процесса, что" бы отобрать эту память. Даже у процессов, которые вызывают утечку памяти и не завершаются, диспетчер памяти в конечном счете, в ре" зультате усечения рабочего набора отберет все физические страницы, связанные с утекающей виртуальной памятью. Страницы последней будут отправлены в страничный файл, а физическая память будет ос" вобождена для использования в других целях. Таким образом, утечка памяти лишь ограниченно влияет на доступную физическую память. По"настоящему она влияет на потребление виртуальной памяти, кото" рое хорошо заметно по счетчикам PF Usage и Commit Charge в диспет" чере задач. Никакая утилита ничего не сможет сделать с пустым рас" ходом виртуальной памяти, если только не «убьет» процессы, погло" щающие эту память. Короче говоря, если бы от оптимизаторов памяти был хоть какой" нибудь толк, разработчики Microsoft давно интегрировали бы такую технологию в ядро Windows. Резюме В этой главе мы изучили, как диспетчер памяти управляет виртуальной памя" тью. Как и в большинстве других современных операционных систем, в Win" dows у каждого процесса имеется закрытое адресное пространство, защищен" ное от доступа других процессов, но обеспечивающее эффективное и безопас" ное разделение памяти несколькими процессами. Поддерживаются и такие дополнительные возможности, как включение (inclusion) проецируемых фай" лов и разреженная память. Подсистема окружения Windows предоставляет при" ложениям большинство функций диспетчера памяти через Windows API. Диспетчер памяти везде, где это возможно, использует алгоритмы отложен" ной оценки, что помогает избежать выполнения лишних операций, отнимаю" щих много времени. Такие операции выполняются только по необходимости. Диспетчер памяти также является самонастраивающейся подсистемой, которая автоматически адаптируется для работы как на мощных многопроцессорных серверах, так и на однопроцессорных персональных компьютерах. В этой главе мы не затронули такой аспект, как тесная интеграция диспетче" ра памяти с диспетчером кэша, — об этом будет рассказано в главе 11. А теперь давайте перейдем к детальному рассмотрению механизмов защиты Windows .
Г Л А В А 8 Защита Защита конфиденциальных данных от несанкционированного доступа очень важна в любой среде, где множество пользователей обращается к од! ним и тем же физическим или сетевым ресурсам. У операционной системы, как и у отдельных пользователей, должна быть возможность защиты файлов, памяти и конфигурационных параметров от нежелательного просмотра и внесения изменений. Безопасность операционной системы обеспечивается такими очевидными механизмами, как учетные записи, пароли и защита файлов. Но она требует и менее очевидных механизмов — защиты операци! онной системы от повреждения, запрета непривилегированным пользова! телям определенных действий (например, перезагрузки компьютера), пред! отвращения неблагоприятного воздействия программ одних пользователей на программы других пользователей или на операционную систему. В этой главе мы поясним, как жесткие требования к защите повлияли на внутреннее устройство и реализацию Microsoft Windows. Классы безопасности Четкие стандарты безопасности программного обеспечения, в том числе операционных систем, помогают правительству, корпорациям и индивиду! альным пользователям защищать хранящиеся в компьютерных системах данные, составляющие личную и коммерческую тайну. Текущий стандарт на рейтинги безопасности, применяемый в США и многих других странах, — Common Criteria (CC). Однако, чтобы понять средства защиты, существую! щие в Windows, нужно знать историю системы рейтингов безопасности, повлиявшей на архитектуру системы защиты Windows, — Trusted Computer System Evaluation Criteria (TCSEC). Trusted Computer System Evaluation Criteria Национальный центр компьютерной безопасности (National Computer Secu! rity Center, NCSC, www.radium.ncsc.mil/tpep) был создан в 1981 году в Агент! стве национальной безопасности (NSA) Министерства обороны США. Одна из задач NCSC заключалась в определении рейтингов безопасности (см. таб! лицу 8!1), отражающих степень защищенности коммерческих операцион! ных систем, сетевых компонентов и приложений. Эти рейтинги, детальное описание которых вы найдете по ссылке www.radium.ncsc.mil/tpep/library/
ГЛАВА 9 Защита 511 rainbow/5200.28STD.html, были определены в 1983 году и часто называют! ся «Оранжевой книгой» («Orange Book»). Таблица 8-1. Рейтинги безопасности TCSEC Рейтинг Название A1 Verified Design B3 Security Domains B2 Structured Protection B1 Labeled Security Protection C2 Controlled Access Protection C1 Discretionary Access Protection (устарел) D Minimal Protection Стандарт TCSEC состоит из рейтингов «уровней доверия» («levels of trust» ratings), где более высокие уровни строятся на более низких за счет после! довательного ужесточения требований к безопасности и проверке. Ни одна операционная система не соответствует уровню А1 (Verified Design). Хотя некоторым операционным системам присвоен один из уровней В, уровень С2 считается достаточным и является высшим для операционных систем общего назначения. В июле 1995 года Windows NT 3.5 (Workstation и Server) с Service Pack 3 пер! вой из всех версий Windows NT получила подтверждение об уровне безопас! ности С2. В марте 1999 года организация ITSEC (Information Technology Security) правительства Великобритании присвоила Windows NT 4 с Service Pack 3 уро! вень Е3, эквивалентный американскому уровню С2. Windows NT 4 с Service Pack 6a получила уровень С2 для сетевой и автономной конфигураций. Какие требования предъявляются к уровню безопасности С2? Основные требования (они остались прежними) перечислены ниже. 쐽 Механизм безопасной регистрации, требующий уникальной идентифи! кации пользователей. Доступ к компьютеру предоставляется лишь после аутентификации. 쐽 Управление избирательным доступом, позволяющее владельцу ресурса определять круг лиц, имеющих доступ к ресурсу, а также их права на опе! рации с этим ресурсом. Владелец предоставляет пользователям и их груп! пам различные права доступа. 쐽 Аудит безопасности, обеспечивающий возможность регистрации собы! тий, связанных с защитой, а также любых попыток создания, удаления и обращения к системным ресурсам. При входе регистрируются идентифи! кационные данные всех пользователей, что позволяет легко выявить лю! бого, кто попытался выполнить несанкционированную операцию. 쐽 Защита при повторном использовании объектов, которая предотвраща! ет просмотр одним из пользователей данных, удаленных из памяти дру! гим, а также доступ к памяти, освобожденной предыдущим пользовате! лем. Например, в некоторых операционных системах можно создать но!
512 ГЛ А В А 8 БЕЗОПАСНОСТЬ вый файл определенной длины, а затем просмотреть те данные, которые остались на диске и попали в область, отведенную под новый файл. Сре! ди этих данных может оказаться конфиденциальная информация, хра! нившаяся в недавно удаленном файле другого пользователя. Так что за! щита при повторном использовании объектов устраняет потенциальную дыру в системе безопасности, заново инициализируя перед выделением новому пользователю все объекты, включая файлы и память. Windows также отвечает двум требованиям защиты уровня В. 쐽 Функциональность пути доверительных отношений (trusted path func! tionality), которая предотвращает перехват имен и паролей пользовате! лей программами — троянскими конями. Эта функциональность реали! зована в Windows в виде входной сигнальной комбинации клавиш Ctrl+Alt+Del и не может быть перехвачена непривилегированными при! ложениями. Такая комбинация клавиш, известная как SAS (secure attention sequence), вызывает диалоговое окно входа в систему, обходя вызов его фальшивого эквивалента из троянского коня. 쐽 Управление доверительными отношениями (trusted facility management), которое требует поддержки набора ролей (различных типов учетных за! писей) для разных уровней работы в системе. Например, функции адми! нистрирования доступны только по одной группе учетных записей — Administrators (Администраторы). Windows соответствует всем перечисленным требованиям. Common Criteria В январе 1996 года США, Великобритания, Германия, Франция, Канада и Нидерланды опубликовали совместно разработанную спецификацию оцен! ки безопасности Common Criteria for Information Technology Security Evalua! tion (CCITSE). Эта спецификация, чаще называемая Common Criteria (СС) (csrc.nist.gov/cc), является международным стандартом оценки степени защи! щенности продуктов. СС гибче уровней доверия TCSEC и по структуре ближе ITSEC, чем TCSEC. СС включает две концепции: 쐽 профиля защиты (Protection Profile, PP) — требования к безопасности разбиваются на группы, которые легко определять и сравнивать; 쐽 объекта защиты (Security Target, ST) — предоставляет набор требований к защите, которые могут быть подготовлены с помощью PP. Windows 2000 оценивалась на соответствие требованиям Controlled Ac! cess PP, эквивалентным TCSEC C2, и на соответствие дополнительным требо! ваниям Common Criteria в октябре 2002 года. Подробности можно найти по ссылкам niap.nist.gov/ccscheme.html и niap.nist.gov/ccscheme/CCEVSVID402 ST.pdf. К значимым требованиям, не включенным в Controlled Access PP, но предъявляемым по условиям Windows 2000 Security Target, относятся: 쐽 функции управления избирательным доступом (Discretionary Access Control Functions), основанные на применении криптографии. Они реа!
ГЛАВА 9 Защита 513 лизуются файловой системой Encrypting File System и Data Protection API в Windows 2000; 쐽 политика управления избирательным доступом (Discretionary Access Control Policy) для дополнительных пользовательских объектов данных (User Data Objects), например объекты Desktop и WindowStation (реали! зуются подсистемой поддержки окон Windows 2000), а также объекты Active Directory (реализуются службой каталогов в Windows 2000); 쐽 внутренняя репликация (Internal Replication) для гарантированной син! хронизации элементов данных, связанных с защитой, между физически раздельными частями системы Windows 2000 как распределенной опера! ционной системы. Это требование реализуется службой каталогов Win! dows 2000 с применением модели репликации каталогов с несколькими хозяевами; 쐽 утилизация ресурсов (Resource Utilization) для физических пространств дисков. Это требование реализуется файловой системой NTFS в Windows 2000; 쐽 блокировка интерактивного сеанса (Interactive Session Locking) и путь доверительных отношений (Trusted Path) для первоначального входа пользователя (initial user logging on). Это требование реализуется компо! нентом Winlogon в Windows 2000; 쐽 защита внутренней передачи данных (Internal Data Transfer Protection), чтобы обезопасить данные от раскрытия и несанкционированной моди! фикации при передаче между физически раздельными частями системы Windows 2000 как распределенной операционной системы. Это требова! ние реализуется службой IPSEC в Windows 2000; 쐽 систематическое устранение обнаруживаемых недостатков в систе ме защиты (Systematic Flaw Remediation). Это требование реализуется Microsoft Security Response Center и Windows Sustained Engineering Team. На момент написания этой книги Windows XP Embedded, Windows XP Professional и Windows Server 2003 все еще проходили оценку на соответ! ствие Common Criteria. Набор критериев расширен по сравнению с тем, который применялся к Windows 2000. Комитет Common Criteria в насто! ящее время рассматривает Windows XP и Windows Server 2003 (Standard, Enterprise и Datacenter Edition) для оценки технологий следующих типов (см. niap.nist .gov/ccscheme/in_evaluation.html): 쐽 распределенной операционной системы; 쐽 защиты конфиденциальных данных; 쐽 управления сетью; 쐽 службы каталогов; 쐽 брандмауэра; 쐽 VPN (Virtual Private Network); 쐽 управления рабочим столом;
514 ГЛ А В А 8 БЕЗОПАСНОСТЬ 쐽 инфраструктуры открытого ключа (Public Key Infrastructure, PKI); 쐽 выдачи и управления сертификатами открытого ключа; 쐽 встраиваемой операционной системы. Компоненты системы защиты Ниже перечислены главные компоненты и базы данных, на основе которых реализуется защита в Windows. 쐽 Монитор состояния защиты (Security Reference Monitor, SRM) Компонент исполнительной системы (\Windows\System32\ Ntoskrnl.exe), отвечающий за определение структуры данных маркера доступа для пред! ставления контекста защиты, за проверку прав доступа к объектам, мани! пулирование привилегиями (правами пользователей) и генерацию сооб! щений аудита безопасности. 쐽 Подсистема локальной аутентификации (local security authen tication subsystem, LSASS) Процесс пользовательского режима, вы! полняющий образ \Windows\System32\Lsass.exe, который отвечает за по! литику безопасности в локальной системе (например, круг пользовате! лей, имеющих право на вход в систему, правила, связанные с паролями, привилегии, выдаваемые пользователям и их группам, параметры аудита безопасности системы), а также за аутентификацию пользователей и пе! редачу сообщений аудита безопасности в Event Log. Основную часть этой функциональности реализует сервис локальной аутентификации Lsasrv (\Windows\System32\Lsasrv.dll) — DLL!модуль, загружаемый Lsass. 쐽 База данных политики LSASS База данных, содержащая параметры политики безопасности локальной системы. Она хранится в разделе ре! естра HKLM\SECURITY и включает следующую информацию: каким доме! нам доверена аутентификация попыток входа в систему, кто имеет права на доступ к системе и каким образом, кому предоставлены те или иные привилегии и какие виды аудита следует выполнять. База данных поли! тики LSASS также хранит «секреты», которые включают в себя регистра! ционные данные, применяемые для входа в домены и при вызове Win! dows!сервисов (о Windows!сервисах см. главу 5). 쐽 Диспетчер учетных записей безопасности (Security Accounts Ma nager, SAM) Набор подпрограмм, отвечающих за поддержку базы дан! ных, которая содержит имена пользователей и группы, определенные на локальной машине. Служба SAM, реализованная как \Windows\System32\ Samsrv.dll, выполняется в процессе Lsass. 쐽 База данных SAM База данных, которая в системах, отличных от кон! троллеров домена, содержит информацию о локальных пользователях и группах вместе с их паролями и другими атрибутами. На контроллерах домена SAM содержит определение и пароль учетной записи админист! ратора, имеющего права на восстановление системы. Эта база данных хранится в разделе реестра HKLM\SAM.
ГЛАВА 9 Защита 515 쐽 Active Directory Служба каталогов, содержащая базу данных со сведе! ниями об объектах в домене. Домен — это совокупность компьютеров и сопоставленных с ними групп безопасности, которые управляются как единое целое. Active Directory хранит информацию об объектах домена, в том числе о пользователях, группах и компьютерах. Сведения о паро! лях и привилегиях пользователей домена и их групп содержатся в Active Directory и реплицируются на компьютеры, выполняющие роль контрол! леров домена. Сервер Active Directory, реализованный как \Windows\Sys! tem32\Ntdsa.dll, выполняется в процессе Lsass. Подробнее об Active Direc! tory см. главу 13. 쐽 Пакеты аутентификации DLL!модули, выполняемые в контексте про! цесса Lsass и клиентских процессов и реализующие политику аутентифи! кации в Windows. DLL аутентификации отвечает за проверку пароля и имени пользователя, а также за возврат LSASS (в случае успешной провер! ки) детальной информации о правах пользователя, на основе которой LSASS генерирует маркер (token). 쐽 Процесс входа (Winlogon) Процесс пользовательского режима (\Win! dows\System32\Winlogon.exe), отвечающий за поддержку SAS и управление сеансами интерактивного входа в систему. Например, при регистрации пользователя Winlogon создает оболочку — пользовательский интерфейс. 쐽 GINA (Graphical Identification and Authentication) DLL пользова! тельского режима, выполняемая в процессе Winlogon и применяемая для получения пароля и имени пользователя или PIN!кода смарт!карты. Стан! дартная GINA хранится в \Windows\System32\Msgina.dll. 쐽 Служба сетевого входа (Netlogon) Windows!сервис (\Windows\Sys! tem32 \Netlogon.dll), устанавливающий защищенный канал с контролле! ром домена, по которому посылаются запросы, связанные с защитой, на! пример для интерактивного входа (если контроллер домена работает под управлением Windows NT), или запросы на аутентификацию от LAN Ma! nager либо NT LAN Manager (v1 и v2). 쐽 Kernel Security Device Driver (KSecDD) Библиотека функций режи! ма ядра, реализующая интерфейсы LPC (local procedure call), которые ис! пользуются другими компонентами защиты режима ядра — в том числе шифрующей файловой системой (Encrypting File System, EFS) — для вза! имодействия с LSASS в пользовательском режиме. KsecDD содержится в \Windows\System32\Drivers\Ksecdd.sys. На рис. 8!1 показаны взаимосвязи между некоторыми из этих компонен! тов и базами данных, которыми они управляют.
516 Рис. 8-1. ГЛ А В А 8 БЕЗОПАСНОСТЬ Компоненты защиты Windows ЭКСПЕРИМЕНТ: просмотр содержимого HKLM\SAM и HKLM\Security Дескрипторы защиты, сопоставленные с разделами реестра SAM и Security, блокируют доступ по любой учетной записи, кроме Local Sys! tem. Один из способов получить доступ к этим разделам — сбросить их защиту, но это может ослабить безопасность системы. Другой спо! соб — запустить Regedit.exe под учетной записью Local System; такой способ поддерживается утилитой PsExec (www.sysinternals.com), кото! рая позволяет запускать процессы под этой учетной записью: C:>psexec s i d c:\windows\regedit.exe
ГЛАВА 9 Защита 517 SRM, выполняемый в режиме ядра, и LSASS, работающий в пользователь! ском режиме, взаимодействуют по механизму LPC (см. главу 3). При иници! ализации системы SRM создает порт SeRmCommandPort, к которому подклю! чается LSASS. Процесс Lsass при запуске создает LPC!порт SeLsaCommandPort. К этому порту подключается SRM. В результате формируются закрытые ком! муникационные порты. SRM создает раздел общей памяти для передачи со! общений длиннее 256 байтов и передает его описатель при запросе на со! единение. После соединения SRM и LSASS на этапе инициализации системы они больше не прослушивают свои порты. Поэтому никакой пользователь! ский процесс не сможет подключиться к одному из этих портов. Рис. 8!2 иллюстрирует коммуникационные пути после инициализации системы. Рис. 8-2. Взаимодействие между SRM и LSASS
518 ГЛ А В А 8 БЕЗОПАСНОСТЬ Защита объектов Защита объектов и протоколирование обращений к ним — вот сущность управления избирательным доступом и аудита. Защищаемые объекты Win! dows включают файлы, устройства, почтовые ящики, каналы (именованные и анонимные), задания, процессы, потоки, события, пары событий, мьютек! сы, семафоры, порты завершения ввода!вывода, разделы общей памяти, LPC! порты, ожидаемые таймеры, маркеры доступа, тома, объекты WindowStation, рабочие столы, сетевые ресурсы, сервисы, разделы реестра, принтеры и объекты Active Directory. Поскольку системные ресурсы, экспортируемые в пользовательский ре! жим (и поэтому требующие проверки защиты), реализуются как объекты режима ядра, диспетчер объектов играет ключевую роль в их защите (о дис! петчере объектов см. главу 3). Для контроля за операциями над объектом система защиты должна быть уверена в правильности идентификации каж! дого пользователя. Именно по этой причине Windows требует от пользова! теля входа с аутентификацией, прежде чем ему будет разрешено обращать! ся к системным ресурсам. Когда какой!либо процесс запрашивает описатель объекта, диспетчер объектов и система защиты на основе идентификацион! ных данных вызывающего процесса определяют, можно ли предоставить ему описатель, разрешающий доступ к нужному объекту. Контекст защиты потока может отличаться от контекста защиты его про! цесса. Этот механизм называется олицетворением (impersonation), или под! меной. При олицетворении механизмы проверки защиты используют вме! сто контекста защиты процесса контекст защиты потока, а без олицетворе! ния — контекст защиты процесса, которому принадлежит поток. Важно не забывать, что все потоки процесса используют одну и ту же таблицу описа! телей, поэтому, когда поток открывает какой!нибудь объект (даже при оли! цетворении), все потоки процесса получают доступ к этому объекту. Проверка прав доступа Модель защиты Windows требует, чтобы поток заранее — еще до открытия объекта — указывал, какие операции он собирается выполнять над этим объектом. Система проверяет тип доступа, запрошенный потоком, и, если такой доступ ему разрешен, он получает описатель, позволяющий ему (и другим потокам того же процесса) выполнять операции над объектом. Как уже говорилось в главе 3, диспетчер объектов регистрирует права доступа, предоставленные для данного описателя, в таблице описателей, принадле! жащей процессу. Одно из событий, заставляющее диспетчер объектов проверять права доступа, — открытие процессом существующего объекта по имени. При от! крытии объекта по имени диспетчер объектов ищет его в своем простран! стве имен. Если этого объекта нет во вторичном пространстве имен (напри! мер, в пространстве имен реестра, принадлежащем диспетчеру конфигура!
ГЛАВА 9 Защита 519 ции, или в пространстве имен файловой системы, принадлежащем драйве! ру файловой системы), диспетчер объектов вызывает внутреннюю функцию ObpCreateHandle. Как и подсказывает ее имя, она создает элемент в таблице описателей, который сопоставляется с объектом. Однако ObpCreateHandle вызывает функцию исполнительной системы ExCreateHandle и создает опи! сатель, только если другая функция диспетчера объектов, ObpIncrement HandleCount, сообщает, что поток имеет право на доступ к данному объек! ту. Правда, реальную проверку прав доступа осуществляет другая функция диспетчера объектов, ObCheckObjectAccess, которая возвращает результаты проверки функции ObpIncrementHandleCount. ObpIncrementHandleCount передает ObCheckObjectAccess удостоверения защиты потока, открывающего объект, типы запрошенного им доступа (чте! ние, запись, удаление и т. д.), а также указатель на объект. ObCheckObjectAccess сначала блокирует защиту объекта и контекст защиты потока. Блокировка защиты объекта предотвращает ее изменение другим потоком в процессе проверки прав доступа, а блокировка контекста защиты потока не дает дру! гому потоку того же или другого процесса изменить идентификационные данные защиты первого потока при проверке его прав доступа. Далее Ob CheckObjectAccess вызывает метод защиты объекта, чтобы получить парамет! ры защиты объекта (описание методов объектов см. в главе 3). Вызов мето! да защиты может привести к вызову функции из другого компонента испол! нительной системы, но многие объекты исполнительной системы полагают! ся на стандартную поддержку управления защитой, предлагаемую системой. Если компонент исполнительной системы, определяя объект, не собира! ется заменять стандартную политику безопасности, он помечает тип этих объектов как использующий стандартную защиту. Всякий раз, когда SRM вы! зывает метод защиты объекта, он сначала проверяет, использует ли объект стандартную защиту. Объект со стандартной защитой хранит информацию о защите в своем заголовке и предоставляет метод защиты с именем SeDefault ObjectMethod. Объект, не использующий стандартную защиту, должен сам под! держивать информацию о защите и предоставлять собственный метод защи! ты. Стандартную защиту используют такие объекты, как мьютексы, события и семафоры. Пример объекта с нестандартной защитой — файл. У диспетче! ра ввода!вывода, определяющего объекты типа «файл», имеется драйвер фай! ловой системы, который управляет защитой своих файлов (или решает не реализовать ее). Таким образом, когда система запрашивает информацию о защите объекта «файл», представляющего файл на томе NTFS, она получает эту информацию от драйвера файловой системы NTFS, который в свою очередь получает ее от метода защиты объекта «файл», принадлежащего диспетчеру ввода!вывода. Заметьте, что при открытии файла ObCheckObjectAccess не вы! полняется, так как объекты «файл» находятся во вторичных пространствах имен; система вызывает метод защиты объекта «файл», только если поток явно запрашивает или устанавливает параметры защиты файла (например, через Windows!функции SetFileSecurity или GetFileSecurity).
520 ГЛ А В А 8 БЕЗОПАСНОСТЬ Получив информацию о защите объекта, ObCheckObjectAccess вызывает SRM!функцию SeAccessCheck, на которую опирается вся модель защиты Win! dows. Она принимает параметры защиты объекта, идентификационные дан! ные защиты потока (в том виде, в каком они получены ObCheckObjectAccess) и тип доступа, запрашиваемый потоком. SeAccessCheck возвращает True или False в зависимости от того, предоставляет ли она потоку запрошенный тип доступа к объекту. Другое событие, заставляющее диспетчер объектов выполнять проверку прав доступа, — ссылка процесса на объект по существующему описателю. Подобные ссылки часто делаются косвенно, например при манипуляциях с объектом через Windows API с передачей его описателя. Допустим, поток, открывающий файл, запрашивает доступ для чтения из файла. Если у пото! ка есть соответствующие права, определяемые его контекстом защиты и па! раметрами защиты файла, диспетчер объектов создает описатель данного файла в таблице описателей, которая принадлежит процессу — владельцу этого потока. Информация о предоставленном процессу типе доступа сопо! ставляется с описателем и сохраняется диспетчером объектов. Впоследствии поток может попытаться что!то записать в этот файл через Windows!функцию WriteFile, передав в качестве параметра описатель файла. Системный сервис NtWriteFile, который WriteFile вызовет через Ntdll.dll, обра! тится к функции диспетчера объектов ObReferenceObjectByHandle, чтобы получить указатель на объект «файл» по его описателю. ObReferenceObjectBy Handle принимает запрошенный тип доступа как параметр. Найдя в табли! це описателей элемент, соответствующий нужному описателю, ObReference ObjectByHandle сравнит запрошенный тип доступа с тем, который был пре! доставлен при открытии файла. В данном случае ObReferenceObjectByHandle укажет, что операция записи должна завершиться неудачно, так как вызыва! ющий поток, открывая файл, не получил право на его запись. Функции защиты Windows также позволяют Windows!приложениям оп! ределять собственные закрытые объекты и вызывать SRM!сервисы для при! менения к этим объектам средств защиты Windows. Многие функции режи! ма ядра, используемые диспетчером объектов и другими компонентами ис! полнительной системы для защиты своих объектов, экспортируются в виде Windows!функций пользовательского режима. Например, эквивалентом Se AccessCheck для пользовательского режима является AccessCheck. Таким обра! зом, Windows!приложения могут применять модель защиты Windows и ин! тегрироваться с интерфейсами аутентификации и администрирования этой операционной системы. Сущность модели защиты SRM отражает математическое выражение с тремя входными параметрами: идентификационными данными защиты по! тока, запрошенным типом доступа и информацией о защите объекта. Его результат — значения «да» или «нет», которые определяют, предоставит ли модель защиты запрошенный тип доступа. В следующих разделах мы пого!
ГЛАВА 9 Защита 521 ворим об этих входных параметрах и алгоритме проверки прав доступа в модели защиты. Идентификаторы защиты Для идентификации объектов, выполняющих в системе различные действия, Windows использует не имена (которые могут быть не уникальными), а иден тификаторы защиты (security identifiers, SID). SID имеются у пользовате! лей, локальных и доменных групп, локальных компьютеров, доменов и чле! нов доменов. SID представляет собой числовое значение переменной дли! ны, формируемое из номера версии структуры SID, 48!битного кода агента идентификатора и переменного количества 32!битных кодов субагентов и/ или относительных идентификаторов (relative identifiers, RID). Код аген! та идентификатора (identifier authority value) определяет агент, выдавший SID. Таким агентом обычно является локальная система или домен под уп! равлением Windows. Коды субагентов идентифицируют попечителей, упол! номоченных агентом, который выдал SID, а RID — не более чем средство создания уникальных SID на основе общего базового SID (common!based SID). Поскольку длина SID довольно велика и Windows старается генериро! вать истинно случайные значения для каждого SID, вероятность появления двух одинаковых SID практически равна нулю. В текстовой форме каждый SID начинается с префикса S, за которым сле! дуют группы чисел, разделяемые дефисами, например: S1521146343724512248128008638421981128 В этом SID номер версии равен 1, код агента идентификатора — 5 (центр безопасности Windows ), далее идут коды четырех субагентов и один RID в конце (1128). Этот SID относится к домену, так что локальный компьютер этого домена получит SID с тем же номером версии и кодом агента иденти! фикатора; кроме того, в нем будет столько же кодов субагентов. SID назначается компьютеру при установке Windows (программой Win! dows Setup). Далее Windows назначает SID локальным учетным записям на этом компьютере. SID каждой локальной учетной записи формируется на ос! нове SID компьютера с добавлением RID. RID пользовательской учетной за! писи начинается с 1000 и увеличивается на 1 для каждого нового пользова! теля или группы. Аналогичным образом Dcpromo.exe — утилита, применяе! мая при создании нового домена Windows, — выдает SID только что создан! ному домену. Новые учетные записи домена получают SID, формируемые на основе SID домена с добавлением RID (который также начинается с 1000 и увеличивается на 1 для каждого нового пользователя или группы). RID с но! мером 1028 указывает на то, что его SID является 29!м, выданным доменом. Многим предопределенным учетным записям и группам Windows выда! ет SID, состоящие из SID компьютера или домена и предопределенного RID. Так, RID учетной записи администратора равен 500, а RID гостевой учетной записи — 501. Например, в основе SID учетной записи локального админи! стратора лежит SID компьютера, к которому добавлен RID, равный 500:
522 ГЛ А В А 8 БЕЗОПАСНОСТЬ S1521131244551254125561235125500 Для групп Windows также определяет ряд встроенных локальных и до! менных SID. Например, SID, представляющий любую учетную запись, назы! вается Everyone или World и имеет вид S!1!1!0. Еще один пример — сетевая группа, т. е. группа, пользователи которой зарегистрировались на данном компьютере из сети. SID сетевой группы имеет вид S!1!5!2. Список некото! рых общеизвестных SID приведен в таблице 8!2 (полный список см. в доку! ментации Platform SDK). Наконец, Winlogon создает уникальный SID для каждого интерактивного сеанса входа. SID входа, как правило, используется в элементе списка управ! ления доступом (access!control entry, ACE), который разрешает доступ на вре! мя сеанса входа клиента. Например, Windows!сервис может вызвать функцию LogonUser для запуска нового сеанса входа. Эта функция возвращает маркер доступа, из которого сервис может извлечь SID входа. Потом этот SID сер! вис может использовать в ACE, разрешающем обращение к интерактивным объектам WindowStation и Desktop из сеанса входа клиента. SID для сеанса входа выглядит как S!1!5!5!0, а RID генерируется случайным образом. Таблица 8-2. Некоторые общеизвестные SID SID Группа Описание S!1!1!0 Everyone Группа, включающая всех пользователей S!1!2!0 Local Пользователи, которые регистрируются на терми! налах, локально (физически) подключенных к системе S!1!3!0 Creator Owner ID Идентификатор защиты, подлежащий замене идентификатором защиты пользователя, создав! шего новый объект; этот SID применяется в насле! дуемых ACE S!1!3!1 Creator Group ID Идентификатор защиты, подлежащий замене SID основной группы, в которую входит пользователь, создавший новый объект; этот SID применяется в наследуемых ACE ЭКСПЕРИМЕНТ: просмотр SID учетных записей с помощью PsGetSid Представление SID для любой учетной записи легко увидеть, запустив утилиту PsGetSid (www.sysinternals.com). У нее следующий интерфейс: C:\>psgetsid ? PsGetSid displays the machine SID for the local or remote Windows system. Usage: psgetsid [\\RemoteComputer [u Username [p Password]]] [account | SID] u Specifies optional user name for login to remote computer.
ГЛАВА 9 Защита 523 p Specifies optional password for user name. If you omit this you will be prompted to enter a hidden password. account PsGetSid will report the SID for the specified user account rather than the computer. SID PsGetSid will report the account for the specified SID. Параметры PsGetSid позволяют транслировать имена учетных за! писей пользователей и компьютеров в соответствующие SID и наобо! рот. Если PsGetSid запускается без параметров, она выводит SID, назна! ченный локальному компьютеру. Используя тот факт, что учетной за! писи Administrator всегда присваивается RID, равный 500, вы можете определить имя этой учетной записи (в тех случаях, когда системный администратор переименовал ее по соображениям безопасности), просто передав SID компьютера, дополненный «–500», как аргумент командной строки PsGetSid. Чтобы получить SID доменной учетной записи, введите имя пользо! вателя с указанием домена: c:\>psgetsid redmond\daryl Вы можете выяснить SID домена, передав в PsGetSid его имя как ар! гумент: c:\>psgetsid Redmond Наконец, изучив RID своей учетной записи, вы по крайней мере узнаете, сколько учетных записей защиты (security accounts), равное значению, полученному вычитанием 999 из вашего RID, было созда! но в вашем домене или на вашем локальном компьютере (в зависимо! сти от используемой вами учетной записи — доменной или локаль! ной). Чтобы определить, каким учетным записям были присвоены RID, передайте SID с интересующим вас RID. Если PsGetSid сообщит, что сопоставить SID с каким!либо именем учетной записи не удалось, и значение RID окажется меньше, чем у вашей учетной записи, значит, учетная запись, по которой был присвоен RID, уже удалена. Например, чтобы выяснить имя учетной записи, по которой был назначен двадцать восьмой RID, передайте SID домена с добавлением «–1027»: c:\>psgetsid S15211787744166391067528027272641931027 Account for S15211787744166391067528027272641931027: User: redmond\daryl
524 ГЛ А В А 8 БЕЗОПАСНОСТЬ Маркеры Для идентификации контекста защиты процесса или потока SRM использу! ет объект, называемый маркером (token), или маркером доступа (access token). В контекст защиты входит информация, описывающая привилегии, учетные записи и группы, сопоставленные с процессом или потоком. В про! цессе входа в систему (этот процесс рассматривается в конце главы) Winlo! gon создает начальный маркер, представляющий пользователя, который вхо! дит в систему, и сопоставляет его с начальным процессом (или процесса! ми) — по умолчанию запускается Userinit.exe. Так как дочерние процессы по умолчанию наследуют копию маркера своего создателя, все процессы в се! ансе данного пользователя выполняются с одним и тем же маркером. Вы можете сгенерировать маркер вызовом Windows!функции LogonUser и при! менить его для создания процесса, который будет выполняться в контексте защиты пользователя, зарегистрированного с помощью функции LogonUser; с этой целью вы должны передать полученный маркер Windows!функции CreateProcessAsUser. Функция CreateProcessWithLogon тоже создает маркер, создавая новый сеанс входа с начальным процессом. Именно так команда runas запускает процессы с альтернативными маркерами. Рис. 8-3. Маркеры доступа
ГЛАВА 9 Защита 525 Длина маркеров варьируется из!за того, что учетные записи разных поль! зователей имеют неодинаковые наборы привилегий и сопоставлены с раз! ными учетными записями групп. Но все маркеры содержат одну и ту же ин! формацию, показанную на рис. 8!3. Механизмы защиты в Windows используют два элемента маркера, опре! деляя, какие объекты доступны и какие операции можно выполнять. Первый элемент состоит из SID учетной записи пользователя и полей SID групп. Ис! пользуя SID!идентификаторы, SRM определяет, можно ли предоставить зап! рошенный тип доступа к защищаемому объекту, например к файлу в NTFS. SID групп в маркере указывают, в какие группы входит учетная запись пользователя. При обработке клиентских запросов серверные приложения могут блокировать определенные группы для ограничения удостоверений защиты, сопоставленных с маркером. Блокирование группы дает почти тот же эффект, что и ее исключение из маркера. (Блокированные SID все же ис! пользуются при проверке прав доступа, но об этом мы расскажем потом.) Вторым элементом маркера, определяющим, что может делать поток или процесс, которому назначен данный маркер, является список привилегий — прав, сопоставленных с маркером. Примером привилегии может служить право процесса или потока, сопоставленного с маркером, на выключение компьютера. (Подробнее привилегии будут рассмотрены позже.) Поля ос! новной группы маркера по умолчанию и списка управления избирательным доступом (discretionary access!control list, DACL) представляют собой атрибу! ты защиты, применяемые Windows к объектам, которые создаются процес! сом или потоком с использованием маркера. Включая в маркеры информа! цию о защите, Windows упрощает процессам и потокам создание объектов со стандартными атрибутами защиты, так как в этом случае им не требует! ся запрашивать информацию о защите при создании каждого объекта. Маркер может быть основным (primary token) (идентифицирует контекст защиты процесса) и олицетворяющим (impersonation token) (применяется для временного заимствования потоком другого контекста защиты — обыч! но другого пользователя). Маркеры олицетворения сообщают уровень оли! цетворения, определяющий, какой тип олицетворения активен в маркере. Остальные поля маркера служат для информационных нужд. Поле источ! ника маркера содержит сведения (в текстовой форме) о создателе маркера. Оно позволяет различать такие источники, как диспетчер сеансов Windows, сетевой файл!сервер или RPC!сервер. Идентификатор маркера представляет собой локально уникальный идентификатор (locally unique identifier, LUID), который SRM присваивает маркеру при его создании. Исполнительная сис! тема поддерживает свой LUID — счетчик, с помощью которого она назна! чает каждому маркеру уникальный числовой идентификатор. Еще одна разновидность LUID — идентификатор аутентификации (authentication ID). Он назначается маркеру создателем при вызове функции LsaLogonUser. Если создатель не указывает LUID, то LSASS формирует LUID из LUID исполнительной системы. LSASS копирует идентификатор аутентифи! кации для всех маркеров — потомков начального маркера. Используя этот
526 ГЛ А В А 8 БЕЗОПАСНОСТЬ идентификатор, программа может определить, принадлежит ли какой!то маркер тому же сеансу, что и остальные маркеры, анализируемые данной программой. LUID исполнительной системы обновляет идентификатор модификации при каждом изменении характеристик маркера. Проверяя этот идентифи! катор, программа может обнаруживать изменения в контексте защиты с момента его последнего использования. Маркеры содержат поле времени окончания действия, которое присут! ствует в них, начиная с Windows NT 3.1, но до сих пор не используется. Бу! дущая версия Windows, возможно, будет поддерживать маркеры, действи! тельные только в течение определенного срока. Представьте, что админис! тратор выдал пользователю учетную запись, срок действия которой ограни! чен. Сейчас, если срок действия учетной записи истекает в тот момент, ког! да пользователь все еще находится в системе, он может по!прежнему обра! щаться к системным ресурсам, доступ к которым был разрешен по просро! ченной учетной записи. Единственное, что можно сделать в такой ситуа! ции, — принудительно завершить сеанс работы этого пользователя. Если бы Windows поддерживала маркеры с ограниченным сроком действия, систе! ма могла бы запретить пользователю доступ к ресурсу сразу по окончании срока действия маркера. ЭКСПЕРИМЕНТ: просмотр маркеров доступа Команда dt _TOKEN отладчика ядра показывает формат внутреннего объекта «маркер». Хотя его структура отличается от структуры марке! ра пользовательского режима, возвращаемой Windows!функциями защиты, их поля аналогичны. Детальное описание маркеров см. в до! кументации Platform SDK. Ниже приведен пример вывода команды dt _TOKEN отладчика ядра. kd> dt _TOKEN +0x000 TokenSource : _TOKEN_SOURCE +0x010 TokenId : _LUID +0x018 AuthenticationId : _LUID +0x020 ParentTokenId : _LUID +0x028 ExpirationTime : _LARGE_INTEGER +0x030 TokenLock : Ptr32 _ERESOURCE +0x034 ModifiedId : _LUID +0x03c SessionId : Uint4B +0x040 UserAndGroupCount : Uint4B +0x044 RestrictedSidCount : Uint4B +0x048 PrivilegeCount : Uint4B +0x04c VariableLength : Uint4B +0x050 DynamicCharged : Uint4B +0x054 DynamicAvailable : Uint4B +0x058 DefaultOwnerIndex : Uint4B +0x05c UserAndGroups : Ptr32 _SID_AND_ATTRIBUTES +0x060 RestrictedSids : Ptr32 _SID_AND_ATTRIBUTES
ГЛАВА 9 Защита +0x064 +0x068 +0x06c +0x070 +0x074 +0x078 +0x07c +0x07d +0x080 +0x084 +0x088 PrimaryGroup : Privileges : DynamicPart : DefaultDacl : TokenType : ImpersonationLevel TokenFlags : TokenInUse : ProxyData : AuditData : VariablePart : 527 Ptr32 Void Ptr32 _LUID_AND_ATTRIBUTES Ptr32 Uint4B Ptr32 _ACL _TOKEN_TYPE : _SECURITY_IMPERSONATION_LEVEL UChar UChar Ptr32 _SECURITY_TOKEN_PROXY_DATA Ptr32 _SECURITY_TOKEN_AUDIT_DATA Uint4B Маркер для процесса можно увидеть с помощью команды !token. Адрес маркера вы найдете в информации, сообщаемой командой !pro cess, как показано в следующем примере. kd> !process 380 1 !process 380 1 Searching for Process with Cid == 380 PROCESS ff8027a0 SessionId: 0 Cid: 0380 Peb: 7ffdf000 ParentCid: 0124 DirBase: 06433000 ObjectTable: ff7e0b68 TableSize: 23. Image: cmd.exe VadRoot 84c30568 Clone 0 Private 77. Modified 0. Locked 0. DeviceMap 818a3368 Token e22bc730 ElapsedTime 14:22:56.0536 UserTime 0:00:00.0040 KernelTime 0:00:00.0100 QuotaPoolUsage[PagedPool] 13628 QuotaPoolUsage[NonPagedPool] 1616 Working Set Sizes (now,min,max) (261, 50, 345)(1044KB, 200KB, 1380KB) PeakWorkingSetSize 262 VirtualSize 11 Mb PeakVirtualSize 11 Mb PageFaultCount 313 MemoryPriority FOREGROUND BasePriority 8 CommitCharge 86 kd> !token e22bc730 _TOKEN e22bc730 TS Session ID: 0 User: S1521178774416639106752802727264193500 Groups: 00 S1521178774416639106752802727264193513 Attributes  Mandatory Default Enabled 01 S110 Attributes  Mandatory Default Enabled см. след. стр.
528 ГЛ А В А 8 БЕЗОПАСНОСТЬ 02 S1532544 Attributes  Mandatory Default Enabled Owner 03 S1532545 Attributes  Mandatory Default Enabled 04 S155092587 Attributes  Mandatory Default Enabled LogonId 05 S120 Attributes  Mandatory Default Enabled 06 S1514 Attributes  Mandatory Default Enabled 07 S154 Attributes  Mandatory Default Enabled 08 S1511 Attributes  Mandatory Default Enabled Primary Group: S1521178774416639106752802727264193513 Privs: 00 0x000000017 SeChangeNotifyPrivilege Attributes Enabled Default 01 0x000000008 SeSecurityPrivilege Attributes 02 0x000000011 SeBackupPrivilege Attributes 03 0x000000012 SeRestorePrivilege Attributes 04 0x00000000c SeSystemtimePrivilege Attributes 05 0x000000013 SeShutdownPrivilege Attributes 06 0x000000018 SeRemoteShutdownPrivilege Attributes 07 0x000000009 SeTakeOwnershipPrivilege Attributes 08 0x000000014 SeDebugPrivilege Attributes 09 0x000000016 SeSystemEnvironmentPrivilege Attributes 10 0x00000000b SeSystemProfilePrivilege Attributes 11 0x00000000d SeProfileSingleProcessPrivilege Attributes 12 0x00000000e SeIncreaseBasePriorityPrivilege Attributes 13 0x00000000a SeLoadDriverPrivilege Attributes Enabled 14 0x00000000f SeCreatePagefilePrivilege Attributes 15 0x000000005 SeIncreaseQuotaPrivilege Attributes 16 0x000000019 SeUndockPrivilege Attributes Enabled 17 0x00000001c SeManageVolumePrivilege Attributes Authentication ID: (0,169e4) Impersonation Level: Anonymous TokenType: Primary Source: User32 TokenFlags: 0x9 ( Token in use ) Token ID: 3a86d0d ParentToken ID: 0 Modified ID: (0, 3a86d0f) RestrictedSidCount: 0 RestrictedSids: 00000000                   Содержимое маркера можно косвенно увидеть с помощью Process Explorer (www.sysinternals.com) на вкладке Security в диалоговом окне свойств процесса. В этом окне показываются группы и привилегии, включенные в маркер исследуемого вами процесса.
ГЛАВА 9 Защита 529 Олицетворение Олицетворение (impersonation) — мощное средство, часто используемое в модели защиты Windows. Олицетворение также применяется в модели про! граммирования «клиент!сервер». Например, серверное приложение может экспортировать ресурсы (файлы, принтеры или базы данных). Клиенты, ко! торые хотят обратиться к этим ресурсам, посылают серверу запрос. Получив запрос, сервер должен убедиться, что у клиента есть разрешение на выпол! нение над ресурсом запрошенных операций. Так, если пользователь на уда! ленной машине пытается удалить файл с сетевого диска NTFS, сервер, экс! портирующий этот сетевой ресурс, должен проверить, имеет ли пользова! тель право удалить данный файл. Казалось бы, в таком случае сервер должен запросить учетную запись пользователя и SID!идентификаторы группы, а также просканировать атрибуты защиты файла. Но этот процесс труден для программирования, подвержен ошибкам и не позволяет обеспечить поддер! жку новых функций защиты. Поэтому Windows в таких ситуациях предос! тавляет серверу сервисы олицетворения. Олицетворение позволяет серверу уведомить SRM о временном заимство! вании профиля защиты клиента, запрашивающего ресурс. После этого сер! вер может обращаться к ресурсам от имени клиента, а SRM — проводить проверку его прав доступа. Обычно серверу доступен более широкий круг ресурсов, чем клиенту, и при олицетворении сервер может терять часть ис! ходных прав доступа. Также вероятно и обратное: при олицетворении сер! вер может получить дополнительные права. Сервер олицетворяет клиент лишь в пределах потока, выдавшего запрос на олицетворение. Управляющие структуры данных потока содержат необя! зательный элемент для маркера доступа. Однако основной маркер потока, отражающий его реальные права, всегда доступен через управляющие струк! туры процесса. За поддержку олицетворения в Windows отвечает несколько механизмов. Если сервер взаимодействует с клиентом через именованный канал, он мо! жет вызвать Windows!функцию ImpersonateNamedPipeClient и тем самым сообщить SRM о том, что ему нужно подменить собой пользователя на дру! гом конце канала. Если сервер взаимодействует с клиентом через DDE (Dyna! mic Data Exchange) или RPC, то выдает аналогичный запрос на олицетворе! ние через DdeImpersonateClient или RpcImpersonateClient. Поток может соз! дать маркер олицетворения просто как копию маркера своего процесса, вызвав функцию ImpersonateSelf. Для блокировки каких!то SID или привиле! гий поток может потом изменить полученный маркер олицетворения. На! конец, пакет SSPI (Security Support Provider Interface) может олицетворять своих клиентов через ImpersonateSecurityContext. SSPI реализует модель се! тевой защиты вроде LAN Manager версии 2 или Kerberos. После того как серверный поток завершает выполнение своей задачи, он возвращает себе прежний профиль защиты. Эти формы олицетворения удоб! ны для выполнения определенных операций по запросу клиента и для кор! ректного аудита обращений к объектам. (Например, генерируемые данные
530 ГЛ А В А 8 БЕЗОПАСНОСТЬ аудита сообщают идентификацию подменяемого клиента, а не серверного процесса.) Их недостаток в том, что нельзя выполнять всю программу в кон! тексте клиента. Кроме того, маркер олицетворения не дает доступа к сетевым файлам или принтерам, если только они не поддерживают null!сеансы или не используется олицетворение уровня делегирования (delegation!level imperso! nation), причем удостоверения защиты достаточны для аутентификации на удаленном компьютере. (Null!сеанс создается при анонимном входе.) Если все приложение должно выполняться в контексте защиты клиента или получать доступ к сетевым ресурсам, клиент должен быть зарегистри! рован в системе. Для этого предназначена Windows!функция LogonUser, ко! торая принимает в качестве параметров имя учетной записи, пароль, имя домена или компьютера, тип входа (интерактивный, пакетный или сервис! ный) и провайдер входа (logon provider), а возвращает основной маркер. Серверный поток принимает маркер в виде маркера олицетворения, либо сервер запускает программу, основной маркер которой включает удостове! рения клиента. С точки зрения защиты, процесс, создаваемый с применени! ем маркера, который возвращается при интерактивном входе через Logon User, например API!функцией CreateProcessAsUser, выглядит как программа, запущенная пользователем при интерактивном входе в систему. Недостаток этого подхода в том, что серверу приходится получать имя и пароль по учет! ной записи пользователя. Если сервер передает эту информацию по сети, он должен надежно шифровать ее, чтобы избежать получения имени и пароля злоумышленником, перехватывающим сетевой трафик. Windows не позволяет серверам подменять клиенты без их ведома. Кли! ентский процесс может ограничить уровень олицетворения серверным про! цессом, сообщив при соединении с ним требуемый SQOS (Security Quality of Service). Процесс может указывать флаги SECURITY_ANONYMOUS, SECU! RITY_IDENTIFICATION, SECURITY_IMPERSONATION и SECURITY_DELEGA! TION при вызове Windows!функции CreateFile. Каждый уровень позволяет серверу выполнять различный набор операций относительно контекста за! щиты клиента: 쐽 SecurityAnonymous — самый ограниченный уровень; сервер не может олицетворять или идентифицировать клиент; 쐽 SecurityIdentification — сервер может получать SID и привилегии клиен! та, но не получает право на олицетворение клиента; 쐽 SecurityImpersonation — сервер может идентифицировать и олицетворять клиент в локальной системе; 쐽 SecurityDelegation — наименее ограниченный уровень. Позволяет серве! ру олицетворять клиент в локальных и удаленных системах. Windows NT 4 и более ранние версии лишь частично поддерживают этот уровень оли! цетворения. Если клиент не устанавливает уровень олицетворения, Windows по умолча! нию выбирает SecurityImpersonation. Функция CreateFile также принимает мо! дификаторы SECURITY_EFFECTIVE_ONLY и SECURITY_CONTEXT_TRACKING.
ГЛАВА 9 Защита 531 Первый из них не дает серверу включать/выключать какие!то привилегии или группы клиента на время олицетворения. А второй указывает, что все измене! ния, вносимые клиентом в свой контекст защиты, отражаются и на сервере, который олицетворяет этот клиент. Данный модификатор действует, только если клиентский и серверный процессы находятся в одной системе. Ограниченные маркеры Ограниченный маркер (restricted token) создается на базе основного или олицетворяющего с помощью функции CreateRestrictedToken и является его копией, в которую можно внести следующие изменения: 쐽 удалить некоторые элементы из таблицы привилегий маркера; 쐽 пометить SID!идентификаторы маркера атрибутом проверки только на запрет (deny!only); 쐽 пометить SID!идентификаторы маркера как ограниченные. Поведение SID с атрибутом проверки только на запрет (deny!only SID) и ограниченных SID (restricted SID) кратко поясняется в следующих разделах. Ограниченные маркеры удобны, когда приложение подменяет клиент при выполнении небезопасного кода. В ограниченном маркере может, напри! мер, отсутствовать привилегия на перезагрузку системы, что не позволит коду, выполняемому в контексте защиты ограниченного маркера, перезагру! зить систему. ЭКСПЕРИМЕНТ: просмотр ограниченных маркеров В Windows XP или Windows Server 2003 можно заставить Explorer соз! дать процесс с ограниченным маркером по следующей процедуре. 1. Создайте на рабочем столе ярлык для \Windows\Notepad.exe. 2. Отредактируйте свойства ярлыка и установите флажок Run With Different Credentials (Запускать с другими учетными данными). За! метьте: в описании под этим флажком говорится о том, что вы мо! жете запускать программу от своего имени, в то же время защищая компьютер от несанкционированных действий данной программы* . 3. Закройте окно свойств и запустите программу двойным щелчком ее ярлыка. 4. Согласитесь с параметрами по умолчанию для выполнения под те! кущей учетной записью и защиты компьютера от несанкциониро! ванных действий этой программы. 5. Запустите Process Explorer и просмотрите содержимое вкладки Se! curity для свойств запущенного вами процесса Notepad. Заметьте, что маркер содержит ограниченные SID и SID с атрибутом провер! ки только на запрет, а также что у него лишь одна привилегия. Свойства в левой части окна, показанного на следующей иллюст! см. след. стр. * В русской версии Windows XP ошибочно говорится о защите от несанкциониро! ванных действий других программ. — Прим. перев.
532 ГЛ А В А 8 БЕЗОПАСНОСТЬ рации, относятся к Notepad, выполняемому с неограниченным мар! кером, а свойства в правой части окна — к его экземпляру, запущен! ному по описанной процедуре. 쐽 쐽 쐽 쐽 Ограниченный маркер дает несколько побочных эффектов. Удаляются все привилегии, кроме SeChangeNotifyPrivilege. Любые SID администраторов или пользователей с правами админи! страторов помечаются как Deny!Only (проверка только на запрет). Такой SID удаляет права доступа к любым ресурсам, доступ к кото! рым для администраторов запрещен соответствующим ACE, но в ином случае был бы замещен ACE, ранее выданным группе админи! страторов через дескриптор защиты. RESTRICTED SID добавляется в список ограниченных SID, как и все остальные SID маркера, кроме SID пользователя и любых SID адми! нистраторов или пользователей с правами администраторов. SID учетной записи, под которой вы запустили процесс, не включа! ется в список как ограниченный. То есть процесс не сможет обра! щаться к объектам, доступ к которым разрешен по вашей учетной за! писи, но не по учетным записям любых групп, в которые вы входи! те. Например, у каталога вашего профиля в \Documents and Settings имеется дескриптор защиты по умолчанию, разрешающий доступ по вашей учетной записи, по учетной записи группы администраторов и по учетной записи System. Попытавшись открыть этот каталог из Notepad, запущенного так, как было показано ранее, вы не получите к нему доступа, потому что вторая, внутренняя проверка прав дос! тупа, выполняемая с применением ограниченных SID, закончится неудачей — SID пользователя нет в списке ограниченных SID.
ГЛАВА 9 Защита 533 Дескрипторы защиты и управление доступом Маркеры, которые идентифицируют удостоверения пользователя, являются лишь частью выражения, описывающего защиту объектов. Другая его часть — информация о защите, сопоставленная с объектом и указывающая, кому и какие действия разрешено выполнять над объектом. Структура данных, хра! нящая эту информацию, называется дескриптором защиты (security de! scriptor). Дескриптор защиты включает следующие атрибуты. 쐽 Номер версии Версия модели защиты SRM, использованной для созда! ния дескриптора. 쐽 Флаги Необязательные модификаторы, определяющие поведение или характеристики дескриптора. Пример — флаг SE_DACL_PROTECTED, ко! торый запрещает наследование дескриптором параметров защиты от другого объекта. 쐽 SID владельца Идентификатор защиты владельца. 쐽 SID группы Идентификатор защиты основной группы для данного объекта (используется только POSIX). 쐽 Список управления избирательным доступом (discretionary ac cesscontrol list, DACL) Указывает, кто может получать доступ к объек! ту и какие виды доступа. 쐽 Системный список управления доступом (system accesscontrol list, SACL) Указывает, какие операции и каких пользователей должны регистрироваться в журнале аудита безопасности. Список управления доступом (access!control list, ACL) состоит из заголов! ка и может содержать элементы (access!control entries, ACE). Существует два типа ACL: DACL и SACL. В DACL каждый ACE содержит SID и маску доступа (а также набор флагов), причем ACE могут быть четырех типов: «доступ разре! шен» (access allowed), «доступ отклонен» (access denied), «разрешенный объект» (allowed!object) и «запрещенный объект» (denied!object). Как вы, на! верное, и подумали, первый тип ACE разрешает пользователю доступ к объек! ту, а второй — отказывает в предоставлении прав, указанных в маске доступа. Разница между ACE типа «разрешенный объект» и «доступ разрешен», а также между ACE типа «запрещенный объект» и «доступ отклонен» заключа! ется в том, что эти типы используются только в Active Directory. ACE этих типов имеют поле глобально уникального идентификатора (globally unique identifier, GUID), которое сообщает, что данный ACE применим только к оп! ределенным объектам или подобъектам (с GUID!идентификаторами). Кро! ме того, необязательный GUID указывает, что тип дочернего объекта насле! дует ACE при его (объекта) создании в контейнере Active Directory, к кото! рому применен ACE. (GUID — это гарантированно уникальный 128!битный идентификатор.) За счет аккумуляции прав доступа, сопоставленных с индивидуальными ACE, формируется набор прав, предоставляемых ACL!списком. Если в деск! рипторе защиты нет DACL (DACL = null), любой пользователь получает пол!
534 ГЛ А В А 8 БЕЗОПАСНОСТЬ ный доступ к объекту. Если DACL пуст (т. е. в нем нет ACE), доступа к объекту не получает никто. ACE, используемые в DACL, также имеют набор флагов, контролирующих и определяющих характеристики ACE, связанные с наследованием. Некоторые пространства имен объектов содержат объекты!контейнеры и объекты!лис! ты (leaf objects). Контейнер может включать другие контейнеры и листы, ко! торые являются его дочерними объектами. Примеры контейнеров — катало! ги в пространстве имен файловой системы и разделы в пространстве имен реестра. Отдельные флаги контролируют, как ACE применяется к дочерним объектам контейнера, сопоставленного с этим ACE. Часть правил наследова! ния ACE представлена в таблице 8!3 (полный список см. в Platform SDK). Таблица 8-3. Битовые флаги, определяющие правила наследования ACE Флаг Правило наследования CONTAINER_INHERIT_ACE Дочерние объекты!контейнеры, например каталоги, на! следуют ACE как эффективный (effective ACE). Унаследо! ванный ACE является наследуемым, если не установлен и флаг NO_PROPAGATE_INHERIT_ACE INHERIT_ONLY_ACE Указывает, что это только наследуемый ACE (inherit!only ACE); он не контролирует доступ к объекту, сопоставлен! ному с ним INHERITED_ACE Указывает, что данный ACE унаследован. Система уста! навливает этот флаг при передаче дочернему объекту наследуемого ACE NO_PROPAGATE_ INHERIT_ACE Если ACE наследуется дочерним объектом, система сбра! сывает флаги OBJECT_INHERIT_ACE и CONTAINER_INHE! RIT_ACE в унаследованном ACE. Это предотвращает на! следование данного ACE последующими поколениями объектов OBJECT_INHERIT_ACE Дочерние объекты, не являющиеся контейнерами, насле! дуют ACE как эффективный. Но дочерние объекты!кон! тейнеры наследуют ACE как «только наследуемый», если не установлен и флаг NO_PROPAGATE_INHERIT_ACE SACL состоит из ACE двух типов: системного аудита (system audit ACE) и объекта системного аудита (system audit!object ACE). Эти ACE определяют, какие операции, выполняемые над объектами конкретными пользователя! ми или группами, подлежат аудиту. Информация аудита хранится в систем! ном журнале аудита. Аудиту могут подлежать как успешные, так и неудачные операции. Как и специфические для объектов ACE из DACL, ACE объектов системного аудита содержат GUID, указывающий типы объектов или под! объектов, к которым применим данный ACE, и необязательный GUID, кон! тролирующий передачу ACE дочерним объектам конкретных типов. При SACL, равном null, аудит объекта не ведется. (Об аудите безопасности мы расскажем позже.) Флаги наследования, применимые к DACL ACE, примени! мы к ACE системного аудита и объектов системного аудита. Упрощенная схема объекта «файл» и его DACL представлена на рис. 8!4.
ГЛАВА 9 Защита Рис. 8-4. 535 Список управления избирательным доступом Как показано на рис. 8!4, первый ACE позволяет USER1 читать файл. Вто! рой ACE разрешает членам группы TEAM1 читать и записывать файл. Третий ACE предоставляет доступ к файлу для выполнения всем пользователям. ЭКСПЕРИМЕНТ: просмотр дескриптора защиты Управляя дескрипторами защиты своих объектов, большинство под! систем исполнительной системы полагаются на функции защиты по умолчанию, предоставляемые диспетчером объектов. Эти функции сохраняют дескрипторы защиты для таких объектов, используя указа! тель дескриптора защиты (security descriptor pointer). Например, защи! той по умолчанию пользуется диспетчер процессов, поэтому диспет! чер объектов хранит дескрипторы защиты процессов и потоков в за! головках объектов «процесс» и «поток» соответственно. Указатель дес! криптора защиты также применяется для хранения дескрипторов за! щиты событий, мьютексов и семафоров. Для просмотра дескрипторов защиты этих объектов можно использовать отладчик ядра, но снача! ла вы должны найти заголовок нужного объекта. Вся эта процедура поясняется ниже. 1. Запустите отладчик ядра. 2. Введите !process 0 0, чтобы увидеть адрес Winlogon. (Если в систе! ме активно более одного сеанса Terminal Server, выполняется не! сколько экземпляров Winlogon.) Затем вновь введите !process, но укажите адрес одного из процессов Winlogon: kd> !process 88d0c020 PROCESS 88d0c020 SessionId: 0 Cid: 0bdc Peb: 7ffdf000 ParentCid: 00a8 DirBase: 59a58000 ObjectTable: e21df920 HandleCount: 62. Image: winlogon.exe 3. Введите !object и адрес, следующий за словом PROCESS в выводе предыдущей команды. Это позволит увидеть структуру данных объекта: kd> !object 88d0c020 Object: 88d0c020 Type: (8a0ed388) Process ObjectHeader: 88d0c008 HandleCount: 1 PointerCount: 32 см. след. стр.
536 ГЛ А В А 8 БЕЗОПАСНОСТЬ 4. Введите dt _OBJECT_HEADER и адрес поля заголовка объекта из вывода предыдущей команды для просмотра структуры данных за! головка объекта, включая значение указателя дескриптора защиты: lkd> dt _OBJECT_HEADER 88d0c008 +0x000 PointerCount : 36 +0x004 HandleCount : 1 +0x004 NextToFree : 0x00000001 +0x008 Type : 0x8a0ed388 +0x00c NameInfoOffset : 0 '' +0x00d HandleInfoOffset : 0 '' +0x00e QuotaInfoOffset : 0 '' +0x00f Flags : 0x20 '' +0x010 ObjectCreateInfo : 0x89e596a0 +0x010 QuotaBlockCharged : 0x89e596a0 +0x014 SecurityDescriptor : 0xe242b864 +0x018 Body : _QUAD 5. Указатели дескрипторов защиты в заголовке объекта используют младшие три бита как флаги, поэтому следующая команда позволяет создать дамп дескриптора защиты. Вы указываете адрес, полученный из структуры заголовка объекта, но удаляете его младшие три бита: lkd> !sd 0xe242b864 & 8 >Revision: 0x1 >Sbz1 : 0x0 >Control : 0x8004 SE_DACL_PRESENT SE_SELF_RELATIVE >Owner : S1521178774416639106752802727264193500 >Group : S1521178774416639106752802727264193513 >Dacl : >Dacl : >AclRevision: 0x2 >Dacl : >Sbz1 : 0x0 >Dacl : >AclSize : 0x40 >Dacl : >AceCount : 0x2 >Dacl : >Sbz2 : 0x0 >Dacl : >Ace[0]: >AceType: ACCESS_ALLOWED_ACE_TYPE >Dacl : >Ace[0]: >AceFlags: 0x0 >Dacl : >Ace[0]: >AceSize: 0x24 >Dacl : >Ace[0]: >Mask : 0x001f0fff >Dacl : >Ace[0]: >SID: S15211787744166 39106752802727264193500 >Dacl >Dacl >Dacl >Dacl >Dacl : : : : : >Ace[1]: >Ace[1]: >Ace[1]: >Ace[1]: >Ace[1]: >Sacl : is NULL >AceType: ACCESS_ALLOWED_ACE_TYPE >AceFlags: 0x0 >AceSize: 0x14 >Mask : 0x001f0fff >SID: S1518
ГЛАВА 9 Защита 537 Дескриптор защиты содержит два ACE типа «доступ разрешен», причем один из них указывает учетную запись администратора (ее можно распознать по RID, равному 500), а другой — учетную запись System (которая всегда выглядит как S!1!5!18). Без декодирования би! тов, установленных в масках доступа в ACE и определения того, каким типам доступа к процессам они соответствуют, очень трудно сказать, какими правами доступа к объекту «процесс» для Winlogon обладает каждая из этих учетных записей. Однако, если вы сделаете это, исполь! зуя заголовочные файлы из SDK, то обнаружите, что обе учетные за! писи имеют полные права доступа. Присвоение ACL Чтобы определить, какой DACL следует назначить новому объекту, система защиты использует первое применимое правило из следующего списка. 1. Если вызывающий поток явно предоставляет дескриптор защиты при создании объекта, то система защиты применяет его к объекту. Если у объекта есть имя и он находится в объекте!контейнере (например, име! нованное событие в каталоге \BaseNamedObjects пространства имен дис! петчера объектов), система объединяет в DACL все наследуемые ACE (ACE, которые могут быть переданы от контейнера объекта), но только в том случае, если в дескрипторе защиты не установлен флаг SE_DACL_PRO! TECTED, запрещающий наследование. 2. Если вызывающий поток не предоставляет дескриптор защиты и объек! ту присваивается имя, система защиты ищет этот дескриптор в контей! нере, в котором хранится имя нового объекта. Некоторые ACE каталога объектов могут быть помечены как наследуемые. Это означает, что они должны применяться к новым объектам, создаваемым в данном катало! ге. При наличии наследуемых ACE система защиты формирует из них ACL, назначаемый новому объекту. (В ACE, наследуемых только объектами! контейнерами, устанавливаются отдельные флаги.) 3. Если дескриптор защиты не определен и объект не наследует какие!либо ACE, система защиты извлекает DACL по умолчанию из маркера доступа вызывающего потока и применяет его к новому объекту. В некоторые подсистемы Windows (например, службы, LSA и SAM!объекты) «зашиты» свои DACL, назначаемые ими объектам при создании. 4. Если дескриптор защиты не определен и нет ни наследуемых ACE, ни DACL по умолчанию, система создает объект без DACL, что открывает полный доступ к нему любым пользователям и группам. Это правило идентично третьему, если маркер содержит нулевой DACL по умолчанию. Правила, используемые системой при назначении SACL новому объекту, аналогичны правилам присвоения DACL за двумя исключениями. Первое заключается в том, что наследуемые ACE системного аудита не передаются
538 ГЛ А В А 8 БЕЗОПАСНОСТЬ объектам с дескрипторами защиты, помеченными флагом SE_SACL_PROTEC! TED (DACL точно так же защищается флагом SE_DACL_PROTECTED). Второе исключение: если ACE системного аудита не определены и наследуемого SACL нет, то SACL вообще не присваивается объекту (в маркерах нет SACL по умолчанию). Когда к контейнеру применяется новый дескриптор защиты, содержащий наследуемые ACE, система автоматически передает их в дескрипторы защи! ты дочерних объектов. (Заметьте, что DACL дескриптора защиты не прини! мает наследуемые DACL ACE, если установлен флаг SE_DACL_PROTECTED, а его SACL не наследует SACL ACE, если установлен флаг SE_SACL_PROTECTED.) В соответствии с порядком слияния наследуемых ACE с дескриптором защи! ты дочернего объекта любые ACE, явно примененные к ACL, размещаются до ACE, унаследованных объектом. Система использует следующие правила пе! редачи наследуемых ACE. 쐽 Если дочерний объект без DACL наследует ACE, он получает DACL, содер! жащий лишь унаследованные ACE. 쐽 Если дочерний объект с пустым DACL наследует ACE, он также получает DACL, содержащий лишь унаследованные ACE. 쐽 Только для объектов в Active Directory: если наследуемый ACE удаляется из родительского объекта, все копии этого ACE автоматически удаляются из всех дочерних объектов. 쐽 Только для объектов в Active Directory: если из DACL дочернего объекта автоматически удалены все ACE, у дочернего объекта остается пустой DACL. Как вы вскоре убедитесь, порядок ACE в ACL является важным аспектом модели защиты Windows. ПРИМЕЧАНИЕ Как правило, наследование не поддерживается напря! мую такими хранилищами объектов, как файловые системы, реестр или Active Directory. Функции Windows API, поддерживающие наследо! вание, в том числе SetSecurityInfo и SetNamedSecurityInfo, реализуют на! следование вызовом соответствующих функций из DLL поддержки наследования атрибутов защиты (\Windows\System32\Ntmarta.Dll), которым известно, как устроены эти хранилища объектов. Определение прав доступа Для определения прав доступа к объекту используются два алгоритма: 쐽 сравнивающий запрошенные права с максимально возможными для дан! ного объекта и экспортируемый в пользовательский режим в виде Win! dows!функции GetEffectiveRightsFromAcl; 쐽 проверяющий наличие конкретных прав доступа и активизируемый че! рез Windows!функцию AccessCheck или AccessCheckByType. Первый алгоритм проверяет элементы DACL следующим образом.
ГЛАВА 9 Защита 539 1. В отсутствие DACL (DACL = null) объект является незащищенным, и сис! тема защиты предоставляет к нему полный доступ. 2. Если у вызывающего потока имеется привилегия на захват объекта во владение (take!ownership privilege), система защиты предоставляет вла! дельцу право на доступ для записи (write!owner access) до анализа DACL (что такое привилегия захвата объекта во владение и право владельца на доступ для записи, мы поясним чуть позже). 3. Если вызывающий поток является владельцем объекта, ему предоставля! ются права управления чтением (read!control access) и доступа к DACL для записи (write!DACL access). 4. Из маски предоставленных прав доступа удаляется маска доступа каждо! го ACE типа «доступ отклонен», SID которого совпадает с SID маркера до! ступа вызывающего потока. 5. К маске предоставленных прав доступа добавляется маска доступа каж! дого ACE типа «доступ разрешен», SID которого совпадает с SID маркера доступа вызывающего потока (исключение составляют права доступа, в предоставлении которых уже отказано). После анализа всех элементов DACL рассчитанная маска предоставлен! ных прав доступа возвращается вызывающему потоку как максимальные права доступа. Эта маска отражает полный набор типов доступа, которые этот поток сможет успешно запрашивать при открытии данного объекта. Все сказанное применимо лишь к той разновидности алгоритма, которая работает в режиме ядра. Его Windows!версия, реализованная функцией Get EffectiveRightsFromAcl, отличается отсутствием шага 2, а также тем, что вмес! то маркера доступа она рассматривает SID единственного пользователя или группы. Второй алгоритм проверяет, можно ли удовлетворить конкретный запрос на доступ, исходя из маркера доступа вызывающего потока. У каждой Win! dows!функции открытия защищенных объектов есть параметр, указывающий желательную маску доступа — последний элемент выражения, описывающе! го защиту объектов. Чтобы определить, имеет ли вызывающий поток право на доступ к защищенному объекту, выполняются следующие операции. 1. В отсутствие DACL (DACL = null) объект является незащищенным, и сис! тема защиты предоставляет к нему запрошенный тип доступа. 2. Если у вызывающего потока имеется привилегия на захват объекта во владение, система защиты предоставляет владельцу право на доступ для записи, а затем анализирует DACL. Однако, если такой поток запросил только доступ владельца для записи, система защиты предоставляет этот тип доступа и не просматривает DACL. 3. Если вызывающий поток является владельцем объекта, ему предоставля! ются права управления чтением и доступа к DACL для записи. Если вызы! вающий поток запросил только эти права, система защиты предоставля! ет их без просмотра DACL.
540 ГЛ А В А 8 БЕЗОПАСНОСТЬ 4. Просматриваются все ACE в DACL — от первого к последнему. Обработка ACE выполняется при одном из следующих условий: a. SID в ACE типа «доступ отклонен» совпадает с незаблокированным SID (SID могут быть незаблокированными и заблокированными) или SID с атрибутом проверки только на запрет в маркере доступа вызываю! щего потока; b. SID в ACE типа «доступ разрешен» совпадает с незаблокированным SID в маркере доступа вызывающего потока, и этот SID не имеет атрибута проверки только на запрет; c. Идет уже второй проход поиска в дескрипторе ограниченных SID, и SID в ACE совпадает с ограниченным SID в маркере доступа вызываю! щего потока. 5. В случае ACE типа «доступ разрешен» предоставляются запрошенные пра! ва из маски доступа ACE; проверка считается успешной, если предостав! ляются все запрошенные права. Доступ к объекту не предоставляется в случае ACE типа «доступ отклонен» и отказа в предоставлении какого! либо из запрошенных прав. 6. Если достигнут конец DACL и некоторые из запрошенных прав доступа еще не предоставлены, доступ к объекту запрещается. 7. Если все права доступа предоставлены, но в маркере доступа вызывающе! го потока имеется хотя бы один ограниченный SID, то система повтор! но сканирует DACL в поисках ACE, маски доступа которых соответству! ют набору запрошенных прав доступа. При этом также идет поиск ACE, SID которых совпадает с любым из ограниченных SID вызывающего по! тока. Поток получает доступ к объекту, если запрошенные права доступа предоставлялись после каждого прохода по DACL. Поведение обоих алгоритмов проверки прав доступа зависит от относи! тельного расположения разрешающих и запрещающих ACE. Возьмем для примера объект с двумя ACE, первый из которых указывает, что определен! ному пользователю разрешен полный доступ к объекту, а второй отказыва! ет в доступе. Если разрешающий ACE предшествует запрещающему, пользо! ватель получит полный доступ к объекту. При другом порядке этих ACE пользователь вообще не получит доступа к объекту. Более старые Windows!функции вроде AddAccessAllowedAce добавляли ACE в конец DACL, что нежелательно. Таким образом, до появления Windows 2000 большинство Windows!приложений были вынуждены создавать DACL вруч! ную, помещая запрещающие ACE в начало списка. Несколько функций Win! dows, например SetSecurityInfo и SetNamedSecurityInfo, используют предпоч! тительный порядок ACE: запрещающие ACE предшествуют разрешающим. Заметьте, что эти функции вызываются при редактировании, например, прав доступа к NTFS!файлам и разделам реестра. SetSecurityInfo и SetNamedSecurity Info также применяют правила наследования ACE к дескриптору защиты, для операций над которым они вызываются.
ГЛАВА 9 Защита 541 На рис. 8!5 показан пример проверки прав доступа, демонстрирующий, насколько важен порядок ACE. В этом примере пользователю отказано в до! ступе к файлу, хотя ACE в DACL объекта предоставляет такое право (в силу принадлежности пользователя к группе Writers). Это вызвано тем, что зап! рещающий ACE предшествует разрешающему. Рис. 8-5. Пример проверки прав доступа Как уже говорилось, обработка DACL системой защиты при каждом ис! пользовании описателя процессом была бы неэффективной, поэтому SRM проверяет права доступа только при открытии описателя, а не при каждом его использовании. Так что, если процесс один раз успешно открыл описа! тель, система защиты не может аннулировать предоставленные при этом права доступа — даже когда DACL объекта изменяется. Учтите и вот еще что: поскольку код режима ядра обращается к объектам по указателям, а не по описателям, при использовании объектов операционной системой права доступа не проверяются. Иначе говоря, исполнительная система полностью доверяет себе в смысле защиты.
542 ГЛ А В А 8 БЕЗОПАСНОСТЬ Тот факт, что владелец объекта всегда получает право на запись DACL при доступе к объекту, означает, что пользователям нельзя запретить доступ к при! надлежащим им объектам. Если в силу каких!то причин DACL объекта пуст (доступ запрещен), владелец все равно может открыть объект с правом запи! си DACL и применить новый DACL, определяющий нужные права доступа. Будьте осторожны при использовании GUI-средств изменения параметров защиты Модифицируя с помощью GUI!средств параметры защиты объектов «файл», «реестр», Active Directory или других защищаемых объектов, имейте в виду, что основное диалоговое окно безопасности создает потенциально неверное представление о защите, применяемой для объекта. В верхней части этого окна в алфавитном порядке показыва! ются группы и пользователи, чьи ACE имеются в ACL данного объекта. Если вы выдадите Full Control группе Administrators и запретите его группе Everyone, то, судя по алфавитному списку, можете подумать, будто ACE типа «доступ разрешен» для группы Administrators предше! ствует ACE типа «доступ отклонен» для группы Everyone. Однако, как мы уже говорили, средства редактирования, применяя ACL к объекту, помещают запрещающие ACE перед разрешающими. На вкладке Permissions (Разрешения) диалогового окна Advanced Security Settings (Дополнительные параметры безопасности) показы! вается порядок ACE в DACL. Однако даже это диалоговое окно может ввести в заблуждение, так как в сложном DACL за запрещающими ACE для различных видов доступа могут быть расположены разрешающие ACE для других типов доступа.
ГЛАВА 9 Защита 543 Единственный способ точно узнать, какие виды доступа к объекту будут разрешены конкретному пользователю или группе (помимо ме! тода проб и ошибок), — открыть вкладку Effective Permissions. Введите здесь имя пользователя или группы, и диалоговое окно покажет, какие разрешения на доступ к объекту будут действовать на самом деле. AuthZ API AuthZ API, впервые введенный в Windows XP, реализует ту же модель защиты, что и Security Reference Monitor (монитор состояния защиты), но исключительно для пользовательского режима; все функции AuthZ API находятся в библиотеке \Windows\System32\Authz.Dll. Это позво! ляет приложениям, нуждающимся в защите своих закрытых объектов (вроде таблиц базы данных), задействовать Windows!модель защиты без издержек, связанных с переходами из пользовательского режима см. след. стр.
544 ГЛ А В А 8 БЕЗОПАСНОСТЬ в режим ядра, которые были бы неизбежны при использовании Secu! rity Reference Monitor. AuthZ API оперирует стандартными структурами дескриптора за! щиты, SID и привилегиями. Вместо применения маркеров для пред! ставления клиентов, AuthZ использует AUTHZ_CLIENT_CONTEXT. AuthZ включает эквиваленты всех функций проверки прав доступа и защиты Windows; например, AuthzAccessCheck — это AuthZ!версия Win! dows!функции AccessCheck, которая вызывает функцию SeAccessCheck, принадлежащую Security Reference Monitor. Еще одно преимущество AuthZ заключается в том, что приложения могут указывать AuthZ кэшировать результаты проверок прав доступа для ускорения последующих проверок, где используются те же кон! текст клиента и дескриптор защиты. AuthZ полностью документирован в Platform SDK. Права и привилегии учетных записей Многие операции, выполняемые процессами, нельзя авторизовать через подсистему защиты доступа к объектам, так как при этом не происходит вза! имодействия с конкретным объектом. Например, возможность обходить проверки прав доступа при открытии файлов для резервного копирования является атрибутом учетной записи, а не конкретного объекта. Windows ис! пользует как привилегии, так и права учетных записей, чтобы системный администратор мог управлять тем, каким учетным записям разрешено вы! полнять операции, затрагивающие безопасность. Привилегия (privilege) — это право (right) учетной записи на выполнение определенной операции, затрагивающей безопасность, например на выклю! чение компьютера или изменение системного времени. Право учетной за! писи разрешает или запрещает конкретный тип входа в систему, скажем, локальный или интерактивный. Системный администратор назначает привилегии группам и учетным записям с помощью таких инструментов, как MMC!оснастка Active Directory Users and Groups (Active Directory — пользователи и группы) или редактора локальной политики безопасности (Local Security Policy Editor)* . Запустить этот редактор можно из папки Administrative Tools (Администрирование). На рис. 8!6 показана конфигурация User Rights Assignment (Назначение прав пользователя) редактора локальной политики безопасности, при которой в правой части окна выводится полный список привилегий и прав (учетных записей), доступных в Windows Server 2003. Заметьте, что этот редактор не различает привилегии и права учетных записей. Но вы можете сделать это сами, поскольку любое право, в названии которого встречается слово «logon» («вход»), на самом деле является привилегией. * В русской версии Windows XP окно этого редактора называется «Локальные па! раметры безопасности». — Прим. перев.
ГЛАВА 9 Защита 545 Рис. 8-6. Конфигурация User Rights Assignment редактора локальной политики безопасности Права учетной записи Права учетной записи не вводятся в действие монитором состояния защиты (Security Reference Monitor, SRM) и не хранятся в маркерах. За вход отвечает функция LsaLogonUser. В частности, WinLogon вызывает API!функцию Logon User, когда пользователь интерактивно входит в систему, а LogonUser обраща! ется к LsaLogonUser. Эта функция принимает параметр, указывающий тип вы! полняемого входа, который может быть интерактивным, сетевым, пакетным, сервисным, через службу терминала или для разблокировки (unlock). В ответ на запросы входа служба локальной безопасности (Local Security Authority, LSA) извлекает назначенные пользователю права учетной записи из своей базы данных; эта операция выполняется при попытке пользовате! ля войти в систему. LSA сверяет тип входа с правами учетной записи и по результатам этой проверки отклоняет попытку входа, если у учетной запи! си нет права, разрешающего данный тип входа, или, напротив, есть право, которое запрещает данный тип входа. Права пользователей, определенные в Windows, перечислены в таблице 8!4. Windows!приложения могут добавлять или удалять права из учетной за! писи пользователя через функции LsaAddAccountRights и LsaRemoveAccount Rights соответственно, а также определять, какие права назначены учетной записи, вызывая функцию LsaEnumerateAccountRights.
546 ГЛ А В А 8 Таблица 8-4. БЕЗОПАСНОСТЬ Права учетной записи Право Описание Deny logon interactively (Отклонить интерактивный вход), Allow logon interactively (Интерактивный вход) Используется для интерактивного входа, запрос на который исходит с локального компьютера Deny logon over the network Используется для входа, запрос на который (Отказ в доступе к компьютеру из сети), исходит с удаленного компьютера Allow logon over the network (Доступ к компьютеру из сети) Deny logon through Terminal Services1 (Запретить вход в систему через службу терминалов), Allow logon through Terminal Services1 (Разрешать вход в систему через службу терминалов) Используется для входа через клиент службы терминалов Deny logon as a service (Отказать во входе в качестве службы), Allow logon as a service (Вход в качестве службы) Применяется SCM при запуске сервиса под учетной записью определенного пользователя Deny logon as a batch job (Отказ Используется при пакетном входе во входе в качестве пакетного задания), Allow logon as a batch job (Вход в качестве пакетного задания) 1 Впервые введено в Windows XP. Привилегии Число привилегий, определяемых в операционной системе, со временем выросло. В отличие от прав пользователей, которые вводятся в действие в одном месте службой LSA, разные привилегии определяются разными ком! понентами и ими же применяются. Скажем, привилегия отладки, позволяю! щая процессу обходить проверки прав доступа при открытии описателя другого процесса через API!функцию OpenProcess, проверяется диспетчером процессов. Полный список привилегий приведен в таблице 8!5. Компонент, которому нужно проверить маркер на наличие некоей при! вилегии, обращается к API!функции PrivilegeCheck или LsaEnumerateAccount Rights, если он выполняется в пользовательском режиме, либо к SeSingle PrivilegeCheck или SePrivilegeCheck, если он работает в режиме ядра. API!функ! ции, работающие с привилегиями, ничего не знают о правах учетных запи! сей, но API!функциям, оперирующим с правами, привилегии известны. В отличие от прав учетной записи привилегии можно включать и отклю! чать. Чтобы проверка привилегии прошла успешно, эта привилегия должна находиться в указанном маркере и должна быть включена. Смысл такой схе! мы в том, что привилегии должны включаться только при реальном их ис! пользовании, и в том, чтобы процесс не мог случайно выполнить привиле! гированную операцию.
ГЛАВА 9 Защита 547 ЭКСПЕРИМЕНТ: наблюдение за включением привилегии Следующая процедура позволит увидеть, как апплет Date and Time (Дата и время) из Control Panel включает привилегию SeSystemTime! Privilege, исходя из того, что его интерфейс будет использован для из! менения даты или времени на компьютере. 1. Войдите в систему под учетной записью, имеющей право «Change the system time» (Изменение системного времени); такая учетная запись обычно входит в группу администраторов или пользовате! лей с правами администраторов. 2. Запустите Process Explorer и выберите для частоты обновления зна! чение Paused. 3. Откройте вкладку Security в окне свойств какого!либо процесса, например Explorer. Вы должны увидеть, что привилегия SeChange! SystemTimePrivilege отключена. 4. Запустите апплет Date and Time из Control Panel и обновите окно Process Explorer. В списке появится новый процесс Rundll, выделен! ный зеленым цветом. 5. Откройте окно свойств для процесса Rundll (дважды щелкнув имя этого процесса) и убедитесь, что командная строка содержит текст «Timedate.Cpl». Наличие этого аргумента сообщает Rundll (хост! процессу Control Panel DLL) загрузить DLL, реализующую UI, кото! рый позволяет изменять дату и время. 6. Перейдите на вкладку Security в окне свойств процесса Rundll и вы увидите, что привилегия SeSystemTimePrivilege включена. см. след. стр.
548 ГЛ А В А 8 Таблица 8-5. БЕЗОПАСНОСТЬ Привилегии Внутреннее название привилегии Название привилегии в UI* SeAssignPrimary! TokenPrivilege Замена маркера уровня процесса Проверяется различными компонента! ми, например функцией NtSetInforma tionJob, которая задает маркер процесса SeAuditPrivilege Аудит безопасности Нужна для генерации событий в журна! ле событий безопасности с помощью API!функции ReportEvent SeBackupPrivilege Резервное копирование Заставляет NTFS разрешать следующие файлов и каталогов виды доступа к любому файлу или ката! логу независимо от дескриптора защи! ты: READ_CONTROL, ACCESS_SYSTEM_ SECURITY, FILE_GENERIC_READ, FILE_ TRAVERSE. Заметьте: при открытии фай! ла для резервного копирования вызвав! ший код должен указывать флаг FILE_ FLAG_BACKUP_SEMANTICS SeChangeNotify! Privilege Обход промежуточных проверок Используется NTFS во избежание про! верки разрешений для промежуточных каталогов при проходе многоуровне! вых каталогов. Также используется фай! ловыми системами, когда приложения регистрируются на уведомление об из! менениях в структуре файловой системы SeCreateGlobal! Privilege1 Создание глобальных объектов Требуется процессу, чтобы создать объекты «раздел» и «символьная ссыл! ка» в каталогах пространства имен дис! петчера объектов, которые закреплены за другим сеансом * Описание В этом столбце дается перевод английских названий привилегий, а не названия привилегий в русской версии Windows. — Прим. перев.
ГЛАВА 9 Защита 549 Таблица 8-5. (продолжение) Внутреннее название привилегии Название привилегии в UI SeCreatePagefile! Privilege Создание страничного файла Проверяется функцией NtCreatePaging File, применяемой для создания нового страничного файла SeCreatePerma! nentPrivilege Создание постоянных разделяемых объектов Проверяется диспетчером объектов при создании постоянного объекта (не удаляемого в отсутствие ссылок на него) SeCreateToken! Privilege Создание объекта «маркер» Проверяется функцией NtCreateToken, создающей объект «маркер» SeDebug Отладка программ При наличии такой привилегии дис! петчер процессов разрешает доступ к любому процессу через NtOpenProcess независимо от его дескриптора защиты SeEnableDelega! tionPrivilege2 Сделать учетные записи Используется сервисами Active Direc! компьютера и пользова! tory для делегирования аутентифици! теля доверяемыми для рованных удостоверений делегирования SeImpersonate! Privilege1 Подмена клиента после Проверяется диспетчером процессов, аутентификации когда какому!то потоку нужно исполь! зовать маркер для олицетворения, представляющий другого пользователя SeIncreaseBase! PriorityPrivilege Повышение приоритета Проверяется диспетчером процессов и в планировании необходима для повышения приорите! та процесса SeIncreaseQuota! Privilege Увеличение квот (в Win! dows 2000) или измене! ние квот на память для процесса (в Windows XP и Windows Server 2003) Включается при изменении квоты реес! тра (только в Windows 2000), порого! вых размеров рабочего набора процес! са и квот на пулы подкачиваемой и не подкачиваемой памяти для процесса SeLoadDriver! Privilege Загрузка и выгрузка драйверов устройств Проверяется функциями NtLoadDriver и NtUnloadDriver SeLockMemory! Privilege Блокирование страниц в памяти Проверяется NtLockVirtualMemory — реализацией VirtualLock в ядре SeMachineAcco! untPrivilege Добавление рабочих станций в домен Проверяется диспетчером учетных за! писей безопасности (Security Accounts Manager, SAM) на контроллере домена при создании учетной записи компью! тера в домене SeManageVolume! Privilege2 Выполнение сервисных Включается драйверами файловой сис! операций для тома темы при операции открытия тома, не! обходимой для проверки диска и де! фрагментации SeProfileSingle! ProcessPrivilege Профилирование одного процесса Описание Проверяется функцией средства пред! выборки (prefetcher), которая возвра! щает информацию для индивидуально! го процесса см. след. стр.
550 ГЛ А В А 8 Таблица 8-5. БЕЗОПАСНОСТЬ (продолжение) Внутреннее название привилегии SeRemoteShut! downPrivilege SeRestorePrivilege Название привилегии в UI Принудительное выклю! чение с удаленного компьютера Восстановление файлов и каталогов SeSecurityPrivilege Управление аудитом и журналом событий безопасности SeShutdown! Выключение системы Privilege SeSyncAgent! Privilege Синхронизация данных службы каталогов SeSystemEnviron! mentPrivilege Модификация перемен! ных окружения микрокода SeSystemProfile! Privilege Профилирование произ! водительности системы SeSystemtime! Privilege SeTakeOwnership Изменение системного времени Смена владельца файлов и других объектов SeTcbPrivilege Работа в режиме опера! ционной системы Описание Проверяется Winlogon для удаленного кода, вызывающего функцию Initiate SystemShutdown Заставляет NTFS разрешать следующие виды доступа к любому файлу или ката! логу независимо от дескриптора защи! ты: WRITE_DAC, WRITE_OWNER, ACCESS_SYSTEM_SECURITY, FILE_GENE! RIC_WRITE, FILE_ADD_FILE, FILE_ADD_ SUBDIRECTORY, DELETE. Заметьте: при открытии файла для восстановления вызвавший код должен указывать флаг FILE_FLAG_BACKUP_SEMANTICS Требуется для доступа к SACL дескрип! тора защиты, для чтения и очистки журнала событий безопасности Проверяется функциями NtShutdown System и NtRaiseHardError, которые вы! водят в интерактивной консоли диало! говое окно о возникновении систем! ной ошибки Требуется для использования сервисов синхронизации каталогов LDAP и по! зволяет владельцу этой привилегии чи! тать все объекты и свойства в каталоге независимо от атрибутов защиты этих объектов и свойств Требуется NtSetSystemEnvironmentValue и NtQuerySystemEnvironmentValue для модификации и чтения переменных окружения микрокода (firmware envi! ronment variables) через HAL Проверяется функцией NtCreateProfile при профилировании системы. Исполь! зуется, например, утилитой Kernprof Требуется для изменения времени или даты Требуется для смены владельца объекта без получения разрешения на избира! тельный доступ Проверяется SRM, если в маркере задан идентификатор сеанса, диспетчером Plug and Play при событиях, связанных с созданием и управлением, версией Lo gonUser, реализованной в Windows 2000, BroadcastSystemMessageEx при вызове с флагом BSM_ALLDESKTOPS и функцией LsaRegisterLogonProcess
ГЛАВА 9 Защита 551 Таблица 8-5. (окончание) Внутреннее название привилегии Название привилегии в UI Описание SeUndockPrivilege Извлечение компьютера Проверяется диспетчером Plug and Play из стыковочного узла пользовательского режима, когда ини! циируется извлечение компьютера из стыковочного узла (docking station) или выдается запрос на извлечение устройства 1 Введено в Windows Server 2003. 2 Введено в Windows XP. ЭКСПЕРИМЕНТ: привилегия Bypass Traverse Checking Если вы являетесь системным администратором, то должны знать о привилегии Bypass Traverse Checking (Обход перекрестной проверки)* (ее внутреннее название — SeNotifyPrivilege) и о том, какие послед! ствия влечет за собой ее включение. Этот эксперимент демонстриру! ет, что непонимание ее поведения может привести к серьезному на! рушению безопасности. 1. Создайте папку, а в ней — новый текстовый файл с каким!нибудь текстом. 2. Перейдите в Explorer к новому файлу и откройте вкладку Security (Безопасность) в его окне свойств. Щелкните кнопку Advanced (До! полнительно) и сбросьте флажок, управляющий наследованием. Выберите Copy (Копировать), когда появится запрос с предложени! ем удалить или скопировать унаследованные разрешения. 3. Далее сделайте так, чтобы по вашей учетной записи нельзя было получить доступ к этой новой папке. Для этого выберите свою учет! ную запись и в списке разрешений выберите все флажки типа Deny (отклонить или запретить). 4. Запустите Notepad и попробуйте через его UI перейти в новую пап! ку. Вы не сможете этого сделать. 5. В поле File Name (Имя файла) диалогового окна Open (Открыть) введите полный путь к новому файлу. Файл должен открыться. Если в вашей учетной записи нет привилегии Bypass Traverse Che! cking, NTFS будет проверять права доступа к каждому каталогу в пути к файлу, когда вы попытаетесь открыть этот файл. И только в таком случае вам будет отказано в доступе к данному файлу. * Так эта привилегия называется в русской версии Windows XP, но на самом деле никакой перекрестной проверки нет — проверяются промежуточные каталоги в пути к файлу. Поэтому такую привилегию следовало бы назвать «Обход промежу! точных проверок». — Прим. перев.
552 ГЛ А В А 8 БЕЗОПАСНОСТЬ Суперпривилегии Несколько привилегий дают настолько широкие права, что пользователя, которому они назначаются, называют «суперпользователем» — он получает полный контроль над компьютером. Эти привилегии позволяют получать неавторизованный доступ к закрытым ресурсам и выполнять любые опера! ции. Но мы уделим основное внимание применению привилегии на запуск кода, который выдает привилегии, изначально не назначавшиеся пользова! телю, и при этом не будем забывать, что это может быть использовано для выполнения любой операции на локальном компьютере. В этом разделе пе! речисляются такие привилегии и рассматриваются способы их применения. Прочие привилегии вроде Lock Pages In Physical Memory (Закрепление стра! ниц в памяти) можно использовать для атак типа «отказ в обслуживании», но мы не станем их обсуждать. 쐽 Debug programs (Отладка программ) Пользователь с этой привиле! гией может открыть любой процесс в системе независимо от его дескрип! тора защиты. Например, располагая такой привилегией, можно запустить свою программу, которая открывает процесс LSASS, копирует в ее адресное пространство исполняемый код, а затем внедряет поток с помощью API! функции CreateRemoteThread для выполнения внедренного кода в более привилегированном контексте защиты. Этот код мог бы выдавать пользо! вателю дополнительные привилегии и расширять его членство в группах. 쐽 Take ownership (Смена владельца)* Эта привилегия позволяет ее об! ладателю сменить владельца любого защищаемого объекта, просто вписав свой SID в поле владельца в дескрипторе защиты объекта. Вспомните, что владелец всегда получает разрешение на чтение и модификацию DACL дес! криптора защиты, поэтому процесс с такой привилегией мог бы изменить DACL, чтобы разрешить себе полный доступ к объекту, а затем закрыть объект и вновь открыть его с правами полного доступа. Это позволило бы увидеть любые конфиденциальные данные и даже подменить системные фай! лы, выполняемые при обычных системных операциях, например LSASS, сво! ими программами, которые расширяют привилегии некоего пользователя. 쐽 Restore files and directories (Восстановление файлов и каталогов) Пользователь с такой привилегией может заменить любой файл в систе! ме на свой — так же, как было описано в предыдущем абзаце. 쐽 Load and unload device drivers (Загрузка и выгрузка драйверов устройств) Злоумышленник мог бы воспользоваться этой привилеги! ей для загрузки драйвера устройства в систему. Такие драйверы считают! ся доверяемыми частями операционной системы, которые выполняются под системной учетной записью, поэтому драйвер мог бы запускать при! вилегированные программы, назначающие пользователю!злоумышлен! нику другие права. * В русской версии Windows XP эта привилегия называется «Овладение файлами или иными объектами». — Прим. перев.
ГЛАВА 9 Защита 553 쐽 Create a token object (Создание маркерного объекта) Эта приви! легия позволяет создавать объекты «маркеры», представляющие произ! вольные учетные записи с членством в любых группах и любыми разре! шениями. 쐽 Act as part of operating system (Работа в режиме операционной системы) Эта привилегия проверяется функцией LsaRegisterLogonPro cess, вызываемой процессом для установления доверяемого соединения с LSASS. Злоумышленник с такой привилегией может установить доверя! емое соединение с LSASS, а затем вызвать LsaLogonUser — функцию, ис! пользуемую для создания новых сеансов входа. LsaLogonUser требует ука! зания действительных имени и пароля пользователя и принимает необя! зательный список SID, добавляемый к начальному маркеру, который соз! дается для нового сеанса входа. В итоге можно было бы использовать свои имя и пароль для создания нового сеанса входа, в маркер которого включены SID более привилегированных групп или пользователей. Заметьте, что расширенные привилегии не распространяются за грани! цы локальной системы в сети, потому что любое взаимодействие с другим компьютером требует аутентификации контроллером домена и применения доменных паролей. А доменные пароли не хранятся на компьютерах (даже в зашифрованном виде) и поэтому недоступны злонамеренному коду. Аудит безопасности События аудита может генерировать диспетчер объектов в результате про! верки прав доступа. Их могут генерировать и непосредственно Windows! функции, доступные пользовательским приложениям. Это же право, разуме! ется, есть и у кода режима ядра. С аудитом связаны две привилегии: SeSecu! rityPrivilege и SeAuditPrivilege. Для управления журналом событий безопасно! сти, а также для просмотра и изменения SACL объектов процесс должен об! ладать привилегией SeSecurityPrivilege. Однако процесс, вызывающий сис! темные сервисы аудита, должен обладать привилегией SeAuditPrivilege, что! бы успешно сгенерировать запись аудита в этом журнале. Решения об аудите конкретного типа событий безопасности принимают! ся в соответствии с политикой аудита локальной системы. Политика ауди! та, также называемая локальной политикой безопасности (local security po! licy), является частью политики безопасности, поддерживаемой LSASS в ло! кальной системе, и настраивается с помощью редактора локальной полити! ки безопасности (рис. 8!7). При инициализации системы и изменении политики LSASS посылает SRM сообщения, информирующие его о текущей политике аудита. LSASS отвеча! ет за прием записей аудита, генерируемых на основе событий аудита от SRM, их редактирование и передачу Event Logger (регистратору событий). Эти записи посылает именно LSASS (а не SRM), так как он добавляет в них сопут! ствующие подробности, например информацию, нужную для более полной идентификации процесса, по отношению к которому проводится аудит.
554 Рис. 8-7. ГЛ А В А 8 БЕЗОПАСНОСТЬ Конфигурация Audit Policy редактора локальной политики безопасности SRM посылает записи аудита LSASS через свое LPC!соединение. После это! го Event Logger заносит записи в журнал безопасности. В дополнение к за! писям аудита, передаваемым SRM, LSASS и SAM тоже генерируют записи ауди! та, которые LSASS пересылает непосредственно Event Logger; кроме того, AuthZ API позволяет приложениям генерировать записи аудита, определен! ные этими приложениями. Вся эта схема представлена на рис. 8!8. Рис. 8-8. Схема передачи записей аудита безопасности Записи аудита, подлежащие пересылке LSA, помещаются в очередь по мере получения — они не передаются пакетами. Пересылка этих записей осуществляется одним из двух способов. Если запись аудита невелика (мень! ше максимального размера LPC!сообщения), она посылается как LPC!сооб! щение. Записи аудита копируются из адресного пространства SRM в адрес! ное пространство процесса Lsass. Если запись аудита велика, SRM делает ее доступной Lsass через разделяемую память и передает Lsass указатель на нее, используя для этого LPC!сообщение.
ГЛАВА 9 Защита 555 Рис. 8!9 обобщает изложенные в этой главе концепции, иллюстрируя ба! зовые структуры защиты процессов и потоков. Обратите внимание на то, что у объектов «процесс» и «поток» имеются ACL, равно как и у самих объектов «маркер доступа». Кроме того, на этой иллюстрации показано, что у пото! ков 2 и 3 есть маркер олицетворения, тогда как поток 1 по умолчанию ис! пользует маркер доступа своего процесса. Рис. 8-9. Структуры защиты процессов и потоков Вход в систему При интерактивном входе в систему (в отличие от входа через сеть) проис! ходит взаимодействие с процессами Winlogon, Lsass, одним или нескольки! ми пакетами аутентификации, а также SAM или Active Directory. Пакеты аутентификации (authentication packages) — это DLL!модули, выполняю! щие проверки, связанные с аутентификацией. Пакетом аутентификации Windows для интерактивного входа в домен является Kerberos, а MSV1_0 — аналогичным пакетом для интерактивного входа на локальные компьютеры, доменного входа в доверяемые домены под управлением версий Windows, предшествовавших Windows 2000, а также для входа в отсутствие контрол! лера домена.
556 ГЛ А В А 8 БЕЗОПАСНОСТЬ Winlogon — доверяемый процесс, отвечающий за управление взаимодей! ствием с пользователем в связи с защитой. Он координирует вход, запуска! ет первый процесс при входе в систему данного пользователя, обрабатыва! ет выход из системы и управляет множеством других операций, имеющих отношение к защите, — вводом паролей при регистрации, сменой паролей, блокированием и разблокированием рабочих станций и т. д. Процесс Win! logon должен обеспечить невидимость операций, связанных с защитой, дру! гим активным процессам. Так, Winlogon гарантирует, что в ходе этих опера! ций недоверяемый процесс не сможет перехватить управление рабочим сто! лом и таким образом получить доступ к паролю. Winlogon получает имя и пароль пользователя через Graphical Identifica! tion and Authentication (GINA) DLL. Стандартная GINA — \Windows\System32\ Msgina.dll. Msgina выводит диалоговое окно для входа в систему. Позволяя заменять Msgina другими GINA!библиотеками, Windows дает возможность менять механизмы идентификации пользователей. Например, сторонний разработчик может создать GINA для поддержки устройства распознавания отпечатков пальцев и для выборки паролей пользователей из зашифрован! ной базы данных. Winlogon — единственный процесс, который перехватывает запросы на регистрацию с клавиатуры. Получив имя и пароль пользователя от GINA, Winlogon вызывает LSASS для аутентификации этого пользователя. Если аутентификация прошла успешно, процесс Winlogon активизирует оболоч! ку. Схема взаимодействия между компонентами, участвующими в процессе регистрации, показана на рис. 8!10. Рис. 8-10. Компоненты, участвующие в процессе входа
ГЛАВА 9 Защита 557 Winlogon не только поддерживает альтернативные GINA, но и может заг! ружать дополнительные DLL провайдеров доступа к сетям, необходимые для вторичной аутентификации. Это позволяет сразу нескольким сетевым про! вайдерам получать идентификационные и регистрационные данные в про! цессе обычного входа пользователя в систему. Входя в систему под управле! нием Windows, пользователь может одновременно аутентифицироваться и на UNIX!сервере. После этого он получит доступ к ресурсам UNIX!сервера с компьютера под управлением Windows без дополнительной аутентифика! ции. Эта функциональность является одной из форм унифицированной ре гистрации (single sign!on). Инициализация Winlogon При инициализации системы, когда ни одно пользовательское приложение еще не активно, Winlogon выполняет ряд операций, обеспечивающих ему контроль над рабочей станцией с момента готовности системы к взаимодей! ствию с пользователем. 1. Создает и открывает интерактивный объект WindowStation (например, \Windows\WindowStations\WinSta0 в пространстве имен диспетчера объектов), представляющий клавиатуру, мышь и монитор. Далее создает дескриптор защиты станции с одним ACE, содержащим только систем! ный SID. Этот уникальный дескриптор безопасности гарантирует, что другой процесс получит доступ к рабочей станции, только если Winlogon явно разрешит это. 2. Создает и открывает два объекта «рабочий стол»: для приложений (\Win! dows\WinSta0\Default, также известный как интерактивный рабочий стол) и Winlogon (\Windows\WinSta0\Winlogon, также известный как за! щищенный рабочий стол). Защита объекта «рабочий стол» Winlogon организуется так, чтобы к нему мог обращаться только Winlogon. Другой объект «рабочий стол» доступен как Winlogon, так и пользователям. Сле! довательно, пока активен объект «рабочий стол» Winlogon, никакой дру! гой процесс не получает доступа к коду и данным, сопоставленным с этим рабочим столом. Эта функциональность используется Windows для защи! ты операций, требующих передачи паролей, а также для блокировки и разблокировки рабочего стола. 3. До входа какого!либо пользователя в систему видимым рабочим столом является объект «рабочий стол» Winlogon. После входа нажатие клавиш Ctrl+Alt+Del вызывает переключение объектов «рабочий стол» — с Default на Winlogon. (Это объясняет, почему после нажатия Ctrl+Alt+Del с рабо! чего стола исчезают все окна и почему они возвращаются, как только зак! рывается диалоговое окно Windows Security.) Таким образом, SAS всегда активизирует защищенный рабочий стол, контролируемый Winlogon. 4. Устанавливает LPC!соединение с LSASS через LsaAuthenticationPort (вызо! вом LsaRegisterLogonProcess). Это соединение понадобится для обмена
558 ГЛ А В А 8 БЕЗОПАСНОСТЬ информацией при входе и выходе пользователя из системы и при опе! рациях с паролем. Далее Winlogon настраивает оконную среду. 5. Инициализирует и регистрирует структуру данных оконного класса, ко! торая сопоставляет процедуру Winlogon с создаваемым ею окном. 6. Регистрирует SAS, сопоставляя ее с только что созданным окном. Это га! рантирует, что ввод пользователем SAS будет вызывать именно оконную процедуру Winlogon и что программы типа троянских коней не смогут перехватывать управление при вводе SAS. 7. Регистрирует окно, чтобы при выходе пользователя вызывалась процеду! ра, сопоставленная с этим окном. Подсистема Windows проверяет, что запросивший уведомление процесс является именно Winlogon. Как реализована SAS SAS безопасна потому, что никакое приложение не может перехватить комбинацию клавиш Ctrl+Alt+Del или воспрепятствовать его получе! ние Winlogon. Winlogon использует документированную API!функцию RegisterHotKey для резервирования комбинации клавиш Ctrl+Alt+Del, поэтому подсистема ввода Windows, обнаружив эту комбинацию, по! сылает специальное сообщение окну, создаваемому Winlogon для при! ема таких уведомлений. Любая зарезервированная комбинация кла! виш посылается только тому процессу, который зарезервировал ее, и лишь поток, зарезервировавший данную комбинацию клавиш, может отменить ее регистрацию (через API!функцию UnregisterHotKey), так что троянская программа не в состоянии забрать на себя SAS. Windows!функция SetWindowsHook позволяет приложению устано! вить процедуру!ловушку, вызываемую при каждом нажатии клавиш еще до обработки какой!либо комбинации, и модифицировать эти клавиши. Однако в коде обработки комбинаций клавиш содержится специальный блок case для Ctrl+Alt+Del, который отключает ловушки, исключая возможность перехвата этой последовательности. Кроме того, если интерактивный рабочий стол блокирован, обрабатывают! ся только комбинации клавиш, принадлежащие Winlogon. Как только при инициализации системы создается рабочий стол Winlo! gon, он становится активным рабочим столом. Причем активный рабочий стол Winlogon всегда заблокирован. Winlogon разблокирует свой рабочий стол лишь для переключения на рабочий стол приложений или экранной за! ставки. (Блокировать или разблокировать рабочий стол может только про! цесс Winlogon.) Этапы входа пользователя Регистрация начинается, когда пользователь нажимает комбинацию клавиш SAS (по умолчанию — Ctrl+Alt+Del). После этого Winlogon вызывает GINA,
ГЛАВА 9 Защита 559 чтобы получить имя и пароль пользователя. Winlogon также создает уникаль! ный локальный SID для этого пользователя и назначает его данному экзем! пляру объекта «рабочий стол» (который представляет клавиатуру, экран и мышь). Winlogon передает этот SID в LSASS при вызове LsaLogonUser. Если вход пользователя прошел успешно, этот SID будет включен в маркер про! цесса входа (logon process token) — такой шаг предпринимается для защи! ты доступа к объекту «рабочий стол». Например, второй вход по той же учет! ной записи, но в другой системе, не предоставит доступа для записи к объек! ту «рабочий стол» первого компьютера, так как в его маркере не будет SID, полученного при втором входе. После ввода имени и пароля пользователя Winlogon получает описатель пакета аутентификации вызовом Lsass!функции LsaLookupAuthentication Package. Эти пакеты перечисляются в разделе реестра HKLM\SYSTEM\Cur! rentControlSet\Control\Lsa. Winlogon передает пакету данные входа через LsaLogonUser. После того как пакет аутентифицирует пользователя, Winlogon продолжает процесс входа этого пользователя. Если ни один из пакетов не сообщает об успешной аутентификации, процесс входа прекращается. Windows использует два стандартных пакета аутентификации при интер! активном входе: Kerberos и MSV1_0. Пакет аутентификации по умолчанию в автономной системе Windows — MSV1_0 (\Windows\System32\Msv1_0.dll); он реализует протокол LAN Manager 2. LSASS также использует MSV1_0 на компьютерах, входящих в домен, чтобы аутентифицировать домены и ком! пьютеры под управлением версий Windows до Windows 2000, не способные найти контроллер домена для аутентификации. (Отключенные от сети пор! тативные компьютеры относятся к той же категории.) Пакет аутентифика! ции Kerberos (\Windows\System32\Kerberos.dll) используется на компьюте! рах, входящих в домены Windows. Этот пакет во взаимодействии со служба! ми Kerberos, выполняемыми на контроллере домена, поддерживает прото! кол Kerberos версии 5 (ревизии 6). Данный протокол определен в RFC 1510. (Подробнее о стандарте Kerberos см. на сайте Internet Engineering Task Force по ссылке www.ietf.org.) Пакет аутентификации MSV1_0 принимает имя пользователя и хэширо! ванную версию пароля и посылает локальному SAM запрос на получение информации из учетной записи, включая пароль, группы, в которые входит пользователь, и список ограничений по данной учетной записи. Сначала MSV1_0 проверяет ограничения, например разрешенное время или типы доступа. Если ограничения из базы данных SAM запрещают регистрацию пользователя в это время суток, MSV1_0 возвращает LSA статус отказа. Далее MSV1_0 сравнивает хэшированный пароль и имя пользователя с теми, которые хранятся в SAM. В случае кэшированного доменного входа MSV1_0 обращается к кэшированной информации через функции LSASS, отвечающие за сохранение и получение «секретов» из базы данных LSA (куст реестра SECURITY). Если эти данные совпадают, MSV1_0 генерирует LUID сеанса входа и создает собственно сеанс входа вызовом LSASS. При этом MSV1_0 сопоставляет данный уникальный идентификатор с сеансом и пе!
560 ГЛ А В А 8 БЕЗОПАСНОСТЬ редает данные, необходимые для того, чтобы в конечном счете создать мар! кер доступа для пользователя. (Вспомните, что маркер доступа включает SID пользователя, SID групп и назначенные привилегии.) ПРИМЕЧАНИЕ MSV1_0 не кэширует весь хэш пароля пользователя в реестре, так как это позволило бы любому лицу, имеющему физичес! кий доступ к системе, легко скомпрометировать доменную учетную за! пись пользователя и получить доступ к зашифрованным файлам и к сетевым ресурсам, к которым данный пользователь имеет право обра! щаться. Поэтому MSV1_0 кэширует лишь половину хэша. Этой поло! вины достаточно для проверки правильности пароля пользователя, но недостаточно для получения доступа к ключам EFS и для аутентифи! кации в домене вместо этого пользователя, так как эти операции тре! буют полного хэша. Если MSV1_0 нужно аутентифицировать пользователя с удаленной сис! темы, например при его регистрации в доверяемом домене под управлени! ем версий Windows до Windows 2000, то MSV1_0 взаимодействует с экземп! ляром Netlogon в удаленной системе через службу Netlogon (сетевого входа в систему). Netlogon в удаленной системе взаимодействует с пакетом аутен! тификации MSV1_0 этой системы, передавая результаты аутентификации системе, в которой выполняется вход. Базовая последовательность действий при аутентификации Kerberos в основном та же, что и в случае MSV1_0. Однако в большинстве случаев до! менный вход проходит на рабочих станциях или серверах, включенных в домен (а не на контроллере домена), поэтому пакет в процессе аутентифи! кации должен взаимодействовать с ними через сеть. Взаимодействие этого пакета со службой Kerberos на контроллере домена осуществляется через TCP/IP!порт Kerberos (88). Служба Kerberos Key Distribution Center (\Windows\ System32\Kdcsvc.dll), реализующая протокол аутентификации Kerberos, вы! полняется в процессе Lsass на контроллерах домена. После проверки хэшированной информации об имени и пароле пользо! вателя с помощью объектов учетных записей пользователей (user account objects) Active Directory (через сервер Active Directory, \Windows\System32\ Ntdsa.dll) Kdcsvc возвращает доменные удостоверения LSASS, который при успешном входе передает через сеть результат аутентификации и удостове! рения пользователя той системе, где выполняется вход. ПРИМЕЧАНИЕ Приведенное здесь описание аутентификации паке! том Kerberos сильно упрощено, и тем не менее оно иллюстрирует роль различных компонентов в этом процессе. Хотя протокол аутентифи! кации Kerberos играет ключевую роль в обеспечении распределенной защиты доменов в Windows, его детальное рассмотрение выходит за рамки нашей книги. Как только учетные данные аутентифицированы, LSASS ищет в базе дан! ных локальной политики разрешенный пользователю тип доступа — интер!
ГЛАВА 9 Защита 561 активный, сетевой, пакетный или сервисный. Если тип запрошенного вхо! да в систему не соответствует разрешенному, вход прекращается. LSASS уда! ляет только что созданный сеанс входа, освобождая его структуры данных, и сообщает Winlogon о неудаче. Winlogon в свою очередь сообщает об этом пользователю. Если же запрошенный тип входа в систему разрешается, LSASS добавляет любые дополнительные идентификаторы защиты (например, Eve! ryone, Interactive и т. п.). Затем он проверяет в своей базе данных привиле! гии, назначенные всем идентификаторам данного пользователя, и включа! ет эти привилегии в маркер доступа пользователя. Собрав всю необходимую информацию, LSASS вызывает исполнительную систему для создания маркера доступа. Исполнительная система создает ос! новной маркер доступа для интерактивного или сервисного сеанса и мар! кер олицетворения для сетевого сеанса. После успешного создания марке! ра доступа LSASS дублирует его, создавая описатель, который может быть передан Winlogon, а свой описатель закрывает. Если нужно, проводится аудит операции входа. На этом этапе LSASS сообщает Winlogon об успешном входе и возвращает описатель маркера доступа, LUID сеанса входа и инфор! мацию из профиля, полученную от пакета аутентификации (если она есть). ЭКСПЕРИМЕНТ: перечисление активных сеансов входа Пока существует хотя бы один маркер с данным LUID сеанса входа, Windows считает этот сеанс активным. С помощью утилиты Logon! Sessions (www.sysinternals.com), которая использует функцию LsaEnu merateLogonSessions (документированную в Platform SDK), можно пе! речислить активные сеансы входа: C:\>logonsessions LogonSessions 1.0 Copyright (C) 2004 Bryce Cogswell Sysinternals  www.sysinternals.com [0] Logon session User name: Auth package: Logon type: Session: Sid: Logon time: Logon server: DNS Domain: UPN: [1] Logon session User name: Auth package: Logon type: Session: Sid: 00000000:000003e7: AUSTIN\MARKLAP$ NTLM (none) 0 S1518 5/13/2004 9:05:43 AM 00000000:0000d37d: NTLM (none) 0 (none) см. след. стр.
562 ГЛ А В А 8 БЕЗОПАСНОСТЬ Logon time: Logon server: DNS Domain: UPN: [2] Logon session User name: Auth package: Logon type: Session: Sid: Logon time: Logon server: DNS Domain: UPN: ... 8/17/2004 5:08:10 PM [8] Logon session User name: Auth package: Logon type: Session: Sid: Logon time: Logon server: DNS Domain: UPN: 00000000:0079da73: MARKLAP\Administrator MICROSOFT_AUTHENTICATION_PACKAGE_V1_0 NetworkCleartext 0 S1521178774416639106752802727264193500 5/13/2004 12:14:20 PM MARKLAP 00000000:000003e4: NT AUTHORITY\NETWORK SERVICE Negotiate Service 0 S1520 8/17/2004 5:08:18 PM В информацию, сообщаемую по каждому сеансу, включаются SID и имя пользователя, сопоставленные с данным сеансом, а также пакет аутентификации и время входа. Заметьте, что пакет аутентификации Negotiate, отмеченный в сеансе входа 2, выполняет аутентификацию через Kerberos или NTLM в зависимости от того, какой из них больше подходит для данного запроса на аутентификацию. LUID для сеанса показывается в строке «Logon Session» блока ин! формации по каждому сеансу, и с помощью утилиты Handle (также доступной с www.sysinternals.com) можно найти маркеры, представля! ющие конкретный сеанс входа. Например, чтобы найти маркеры для сеанса входа 8 в предыдущем примере вывода, вы могли бы ввести та! кую команду: C:\>handle a 79da73 43c: Token MARKLAP\Administrator:79da73 Далее Winlogon просматривает параметр реестра HKLM\SOFTWARE\Mic! rosoft\Windows NT\Current Version\Winlogon\Userinit и создает процесс для запуска программ, указанных в строковом значении этого параметра (там могут присутствовать имена нескольких EXE!файлов, разделенные запяты! ми). Значение этого параметра по умолчанию приводит к запуску Useri!
ГЛАВА 9 Защита 563 nit.exe, который загружает профиль пользователя, а затем создает процесс для запуска программ, перечисленных в HKCU\SOFTWARE\Microsoft\Win! dows NT\Current Version\Winlogon\Shell, если такой параметр есть. Если же этого параметра нет, Userinit.exe обращается к параметру HKLM\SOFTWARE\ Microsoft\Windows NT\Current Version\Winlogon\Shell, который по умолча! нию задает Explorer.exe. После этого Userinit завершается — вот почему Process Explorer показывает Explorer.exe как процесс, не имеющий предка. Подробнее о том, что происходит в процессе входа, см. в главе 5. Политики ограниченного использования программ Злонамеренный код вроде вирусов и червей создает все больше проблем. В Windows XP введен механизм Software Restriction Policies (Политики ограни! ченного использования программ), который позволяет администраторам контролировать образы и сценарии, выполняемые в их системах. Узел Soft! ware Restriction Policies в редакторе локальной политики безопасности (рис. 8!11) служит интерфейсом управления для политик выполнения кода на компьютере, хотя возможны и политики, индивидуальные для пользова! телей; в последнем случае применяются доменные политики групп. Рис. 8-11. Конфигурация Software Restriction Policy редактора локальной политики безопасности Узел Software Restriction Policies (Политики ограниченного использова! ния программ) содержит несколько глобальных параметров. 쐽 Параметр Enforcement (Принудительный) определяет, как применяются политики ограничения — к библиотекам вроде DLL, только к пользова! телям или к пользователям и администраторам. 쐽 Параметр Designated File Types (Назначенные типы файлов) регистриру! ет расширения файлов, которые считаются исполняемыми. 쐽 Параметр Trusted Publishers (Доверенные издатели) контролирует, кто имеет право решать, каким издателям сертификатов можно доверять.
564 ГЛ А В А 8 БЕЗОПАСНОСТЬ При настройке параметра для конкретного сценария или образа админи! стратор может указать системе распознавать этот сценарий или образ по его пути, хэшу, зоне Интернета (как определено в Internet Explorer) или по крип! тографическому сертификату, а также сопоставить его с уровнем безопас! ности Disallowed (Не разрешено) либо Unrestricted (Неограниченный). Политики ограниченного использования программ применяются внут! ри различных компонентов, где файлы рассматриваются как содержащие исполняемый код. Некоторые из таких компонентов перечислены ниже. 쐽 Windows!функция CreateProcess (\Windows\System32\Kernel32.dll) поль! зовательского режима применяет эти политики к исполняемым образам. 쐽 Код загрузки DLL в Ntdll (\Windows\System32\Ntdll.dll) применяет эти политики к DLL. 쐽 Командная оболочка Windows (\Windows\System32\Cmd.exe) применяет эти политики к командным файлам. 쐽 Компоненты Windows Scripting Host, запускающие сценарии, — \Win! dows\System32\Cscript.exe (для сценариев командной строки), \Windows\ System32\Wscript.exe (для UI!сценариев) и \Windows\System32\Scrobj.dll (для объектов!сценариев) — применяют эти политики к сценариям. Каждый из этих компонентов определяет, действуют ли политики огра! ничения, по значению параметра реестра HKLM\SOFTWARE\Policies\Micro! soft\Windows\Safer\CodeIdentifiers\TransparentEnabled. Если он равен 1, то политики действуют. Далее каждый из компонентов проверяет, подпадает ли код, который он собирается выполнить, под действие одного из правил, ука! занных в подразделе раздела CodeIdentifiers, и, если да, следует ли разрешить выполнение. Если ни одно из правил к данному коду не относится, его вы! полнение зависит от политики по умолчанию, определяемой параметром DefaultLevel в разделе CodeIdentifiers. Software Restriction Policies — мощное средство для предотвращения запус! ка неавторизованного кода и сценариев, но только при правильном приме! нении. Если политика по умолчанию не запрещает выполнение, то в образ, который не разрешено запускать в данной системе, можно внести минималь! ные изменения, и это позволит обойти правило и запустить данный образ. ЭКСПЕРИМЕНТ: наблюдение за применением политики ограниченного использования программ Вы можете косвенно убедиться в применении политик ограниченно! го использования программ, наблюдая за обращениями к реестру при попытке выполнения образа, запуск которого запрещен. 1. Запустите secpol.msc, чтобы открыть редактор локальной полити! ки безопасности, и перейдите в узел Software Restriction Policies (Политики ограниченного использования программ). 2. Выберите Create New Policies (Создать новые политики) из контек! стного меню, если такие политики не определены.
ГЛАВА 9 Защита 565 3. Создайте правило, запрещающее путь \Windows\System32\Note! pad.exe. 4. Запустите Regmon и установите включающий фильтр для «Safer» (описание Regmon см. в главе 4). 5. Откройте окно командной строки и попробуйте запустить Notepad. Ваша попытка запуска Notepad должна закончиться появлением сообщения о том, что вам запрещен запуск указанной программы, и Regmon должна показать, как командная оболочка (cmd.exe) запраши! вает политики ограничения на локальном компьютере. Резюме Windows поддерживает большой набор функций защиты, соответствующий ключевым требованиям как правительственных организаций, так и коммер! ческих структур. В этой главе мы кратко рассмотрели внутренние компонен! ты, лежащие в основе функций защиты. В следующей главе мы обсудим последний из основных компонентов исполнительной системы, описываемых в этой книге, — подсистему ввода! вывода.
Г Л А В А 9 Подсистема ввода-вывода Подсистема ввода вывода в Microsoft Windows состоит из нескольких ком понентов исполнительной системы, которые совместно управляют аппарат ными устройствами и предоставляют интерфейсы для обращения к ним сис теме и приложениям. В этой главе мы сначала перечислим цели разработ ки подсистемы ввода вывода, повлиявшие на ее реализацию. Затем мы рас смотрим ее компоненты, в том числе диспетчер ввода вывода, диспетчер Plug and Play (PnP) и диспетчер электропитания. Далее исследуем структуру подсистемы ввода вывода и различные типы драйверов устройств. Мы так же обсудим основные структуры данных, описывающие устройства, драйве ры устройств и запросы на ввод вывод, а потом перейдем к этапу обработ ки запросов на ввод вывод. В завершение будет рассказано о том, как рас познаются устройства, как устанавливаются их драйверы и как осуществля ется управление электропитанием. Компоненты подсистемы ввода-вывода Согласно целям, поставленным при разработке, подсистема ввода вывода в Windows должна обеспечивать приложениям абстракцию устройств — как аппаратных (физических), так и программных (виртуальных или логичес ких) — и при этом предоставлять следующую функциональность: 쐽 стандартные средства безопасности и именования устройств для защи ты разделяемых ресурсов (описание модели защиты см. в главе 8); 쐽 высокопроизводительный асинхронный пакетный ввод вывод для под держки масштабируемых приложений; 쐽 сервисы для написания драйверов устройств на высокоуровневом языке и упрощения их переноса между разными аппаратными платформами; 쐽 поддержку многоуровневой модели и расширяемости для добавления драйверов, модифицирующих поведение других драйверов или уст ройств без внесения изменений в них; 쐽 динамическую загрузку и выгрузку драйверов устройств, чтобы драйве ры можно было загружать по требованию и не расходовать системные ресурсы без необходимости; 쐽 поддержку Plug and Play, благодаря которой система находит и устанав ливает драйверы для нового оборудования, а затем выделяет им нужные аппаратные ресурсы;
ГЛАВА 9 Подсистема ввода-вывода 567 쐽 управление электропитанием, чтобы система и отдельные устройства могли переходить в состояния с низким энергопотреблением; 쐽 поддержку множества устанавливаемых файловых систем, в том числе FAT, CDFS (файловую систему CD ROM), UDF (Universal Disk Format) и NTFS (подробнее о типах и архитектуре файловых систем см. в главе 12). 쐽 поддержку Windows Management Instrumentation (WMI) и средств диаг ностики, позволяющую управлять драйверами и вести мониторинг за ними через WMI приложения и сценарии. (Описание WMI см. в главе 4.) Для реализации этой функциональности подсистема ввода вывода в Win dows состоит из нескольких компонентов исполнительной системы и драй веров устройств (рис. 9 1). 쐽 Центральное место в этой подсистеме занимает диспетчер ввода выво да; он подключает приложения и системные компоненты к виртуальным, логическим и физическим устройствам, а также определяет инфраструк туру, поддерживающую драйверы устройств. 쐽 Драйвер устройства, как правило, предоставляет интерфейс ввода выво да для устройств конкретного типа. Такие драйверы принимают от дис петчера ввода вывода команды, предназначенные управляемым ими ус тройствам, и уведомляют диспетчер ввода вывода о выполнении этих команд. Драйверы часто используют этот диспетчер для пересылки ко манд ввода вывода другим драйверам, задействованным в реализации интерфейса того же устройства и участвующим в управлении им. 쐽 Диспетчер PnP работает в тесном взаимодействии с диспетчером ввода вывода и драйвером шины (bus driver) — одной из разновидностей драйверов устройств. Он управляет выделением аппаратных ресурсов, а также распознает устройства и реагирует на их подключение или отклю чение. Диспетчер PnP и драйверы шины отвечают за загрузку соответству ющего драйвера при обнаружении нового устройства. Если устройство добавляется в систему, в которой нет нужного драйвера устройства, ком поненты исполнительной системы, отвечающие за поддержку PnP, вызы вают сервисы установки устройств, поддерживаемые диспетчером PnP пользовательского режима. 쐽 Диспетчер электропитания, также в тесном взаимодействии с диспетче ром ввода вывода, управляет системой и драйверами устройств при их переходе в различные состояния энергопотребления. 쐽 Процедуры поддержки Windows Management Instrumentation (WMI) (Ин струментарий управления Windows), образующие провайдер WDM (Win dows Driver Model) WMI, позволяют драйверам устройств выступать в роли провайдеров, взаимодействуя со службой WMI пользовательского режима через провайдер WDM WMI. (Подробнее о WMI см. раздел «Win dows Management Instrumentation» главы 4.) 쐽 Реестр служит в качестве базы данных, в которой хранится описание ос новных устройств, подключенных к системе, а также параметры иници ализации драйверов и конфигурационные настройки (см. главу 4).
568 ГЛ А В А 9 Рис. 9-1. БЕЗОПАСНОСТЬ Компоненты подсистемы ввода-вывода 쐽 Для установки драйверов используются INF файлы; они связывают кон кретное аппаратное устройство с драйвером, который берет на себя ве дущую роль в управлении этим устройством. Содержимое INF файла со стоит из инструкций, описывающих соответствующее устройство, исход ное и целевое местонахождение файлов драйвера, изменения, которые нужно внести в реестр при установке драйвера, и информацию о зави симостях драйвера. В CAT файлах хранятся цифровые подписи, которые удостоверяют файлы драйверов, прошедших испытания в лаборатории Microsoft Windows Hardware Quality Lab (WHQL). 쐽 Уровень абстрагирования от оборудования (HAL) изолирует драйверы от специфических особенностей конкретных процессоров и контроллеров прерываний, поддерживая API, скрывающие межплатформенные различия. В сущности HAL является драйвером шины для тех устройств на материн ской плате компьютера, которые не контролируются другими драйверами. Диспетчер ввода-вывода Диспетчер вводавывода (I/O manager) определяет модель доставки запро сов на ввод вывод драйверам устройств. Подсистема ввода вывода управля ется пакетами. Большинство запросов ввода вывода представляется пакета ми запросов вводавывода (I/O request packets, IRP), передаваемых от одно го компонента подсистемы ввода вывода другому. (Как вы еще убедитесь, исключением является быстрый ввод вывод, при котором IRP не использу
ГЛАВА 9 Подсистема ввода-вывода 569 ются.) Подсистема ввода вывода позволяет индивидуальному потоку прило жения управлять сразу несколькими запросами на ввод вывод. IRP — это структура данных, которая содержит информацию, полностью описываю щую запрос ввода вывода (подробнее об IRP см. раздел «Пакеты запросов ввода вывода» далее в этой главе). Диспетчер ввода вывода создает IRP (представляющий операцию ввода вывода), передает указатель на IRP соответствующему драйверу и удаляет пакет по завершении операции ввода вывода. Драйвер, получивший IRP, вы полняет указанную в пакете операцию и возвращает IRP диспетчеру ввода вывода, чтобы тот либо завершил эту операцию, либо передал пакет друго му драйверу для дальнейшей обработки. Диспетчер ввода вывода не только создает и уничтожает IRP, но и содер жит общий для различных драйверов код, который они используют при об работке ввода вывода. Благодаря этому драйверы стали проще и компактнее. Так, одна из функций диспетчера ввода вывода позволяет драйверу вызывать другие драйверы. Этот диспетчер также управляет буферами запросов вво да вывода, таймаутами драйверов и регистрирует, какие устанавливаемые файловые системы загружаются в операционную систему. Драйверы уст ройств могут вызывать около сотни функций, предоставляемых диспетче ром ввода вывода. Диспетчер ввода вывода также предоставляет гибкие сервисы ввода выво да, на основе которых подсистемы окружения (например, Windows и POSIX) реализуют свои функции. В их число входят весьма изощренные сервисы асинхронного ввода вывода, которые дают возможность разработчикам соз давать высокопроизводительные масштабируемые серверные приложения. Унифицированный модульный интерфейс драйверов позволяет диспет черу ввода вывода вызывать любой драйвер, ничего не зная о его структуре и внутреннем устройстве. Операционная система обрабатывает запросы на ввод вывод так, будто они адресованы файлам; драйвер преобразует запро сы к виртуальному файлу в запросы, специфичные для устройства. Драйве ры также могут вызывать друг друга (через диспетчер ввода вывода), обес печивая многоуровневую независимую обработку запросов на ввод вывод. Кроме обычных функций для открытия, закрытия, чтения и записи под система ввода вывода Windows предоставляет ряд дополнительных функ ций, например для асинхронного, прямого и буферизованного ввода выво да, а также для ввода вывода по механизму «scatter/gather»* (см. раздел «Типы ввода вывода» далее в этой главе). Типичная обработка ввода-вывода Большинство операций ввода вывода не требует участия всех компонентов подсистемы ввода вывода. Как правило, запрос на ввод вывод выдается при * Механизм, позволяющий интерпретировать, записывать и считывать физически нелинейную область памяти как единое целое. — Прим. перев.
570 ГЛ А В А 9 БЕЗОПАСНОСТЬ ложением, выполняющим соответствующую операцию (например, чтение данных с устройства); такие операции обрабатываются диспетчером ввода вывода, одним или несколькими драйверами устройств и HAL. Как уже упоминалось, в Windows потоки выполняют операции ввода вы вода над виртуальными файлами. Операционная система абстрагирует все запросы на ввод вывод, скрывая тот факт, что конечное устройство ввода вывода может и не быть устройством с файловой структурой. Это позволяет обобщить интерфейс между приложениями и устройствами. Таким образом, виртуальный файл относится к любому источнику или приемнику ввода вы вода (файлу, каталогу, именованному каналу и почтовому ящику), который рассматривается как файл. Все считываемые или записываемые данные пред ставляются простыми потоками байтов, направляемыми в виртуальные фай лы. Приложения пользовательского режима (к какой бы подсистеме они ни относились — Windows или POSIX) вызывают документированные функции, которые в свою очередь обращаются к внутренним функциям подсистемы ввода вывода для чтения/записи файла и для выполнения других операций. Запросы, адресованные виртуальным файлам, диспетчер ввода вывода дина мически направляет соответствующим драйверам устройств. Базовая схема обработки запроса на ввод вывод показана на рис. 9 2. Рис. 9-2. Схема обработки типичного запроса на ввод-вывод Далее мы детальнее рассмотрим эти компоненты, исследуем различные типы драйверов устройств, рассмотрим их структуру, загрузку, инициализа цию и обработку запросов на ввод вывод. Кроме того, мы обсудим роль и функциональность диспетчеров PnP и электропитания.
ГЛАВА 9 Подсистема ввода-вывода 571 Драйверы устройств Для интеграции с диспетчером ввода вывода и другими компонентами под системы ввода вывода драйвер устройства должен быть написан в соответ ствии с правилами, специфичными для управляемого им типа устройств и для его роли в управлении такими устройствами. Здесь мы познакомимся с типами драйверов устройств, поддерживаемых Windows, и исследуем внут реннюю структуру драйвера устройства. Типы драйверов устройств Windows поддерживает множество типов драйверов устройств и сред их программирования. Среды программирования могут различаться даже для драйверов одного типа — в зависимости от типа устройства, для которого предназначен драйвер. Драйверы могут работать в двух режимах: в пользо вательском или в режиме ядра. Windows поддерживает несколько типов драйверов пользовательского режима: 쐽 Драйверы виртуальных устройств (virtual device drivers, VDD) Используются для эмуляции 16 разрядных программ MS DOS. Они пере хватывают обращения таких программ к портам ввода вывода и транс лируют их в вызовы Windows функций ввода вывода, передаваемые ре альным драйверам устройств. Поскольку Windows является полностью защищенной операционной системой, программы MS DOS пользователь ского режима не могут напрямую обращаться к аппаратным средствам — они должны делать это через драйверы устройств режима ядра. 쐽 Драйверы принтеров Драйверы подсистемы Windows, которые транс лируют аппаратно независимые запросы на графические операции в ко манды, специфичные для принтера. Далее эти команды обычно направля ются драйверу режима ядра, например драйверу параллельного порта (Parport.sys) или драйверу порта принтера на USB шине (Usb print.sys). В этой главе основное внимание уделяется драйверам устройств, работа ющим в режиме ядра. Эти драйверы можно разбить на несколько основ ных категорий. 쐽 Драйверы файловой системы Принимают запросы на ввод вывод и выполняют их, выдавая более специфические запросы драйверам уст ройств массовой памяти или сетевым драйверам. 쐽 PnPдрайверы Драйверы, работающие с оборудованием и интегриру емые с диспетчерами электропитания и PnP. В их число входят драйве ры для устройств массовой памяти, видеоадаптеров, устройств ввода и се тевых адаптеров. 쐽 Драйверы, не отвечающие спецификации Plug and Play Также на зываются расширениями ядра. Расширяют функциональность системы, предоставляя доступ из пользовательского режима к сервисам и драйве рам режима ядра. Они не интегрируются с диспетчерами PnP и электро
572 ГЛ А В А 9 БЕЗОПАСНОСТЬ питания. К ним, в частности, относятся драйверы протоколов и сетевого API. Драйвер Regmon, описанный в главе 4, тоже входит в эту категорию. Категория драйверов режима ядра подразделяется на группы в зависимо сти от модели, на которой они основаны, и их роли в обслуживании запро сов к устройствам. WDM-драйверы Это драйверы устройств, отвечающие спецификации Windows Driver Model (WDM). WDM требует от драйверов поддержки управления электропитани ем, Plug and Play и WMI. Большинство драйверов Plug and Play построены как раз на модели WDM. Эта модель реализована в Windows, Windows 98 и Win dows Millennium Edition, поэтому WDM драйверы этих операционных сис тем совместимы на уровне исходного кода, а во многих случаях и на уровне двоичного кода. Существует три типа WDM драйверов. 쐽 Драйверы шин Управляют логическими или физическими шинами. Примеры шин — PCMCIA, PCI, USB, IEEE 1394, ISA. Драйвер шины отвеча ет за распознавание устройств, подключенных к управляемой им шине, оповещение о них диспетчера PnP и управление параметрами электро питания шины. 쐽 Функциональные драйверы Управляют конкретным типом уст ройств. Драйверы шин представляют устройства функциональным драй верам через диспетчер PnP. Функциональным считается драйвер, экспор тирующий рабочий интерфейс устройства операционной системе. Как правило, это драйвер, больше других знающий о функционировании оп ределенного устройства. 쐽 Драйверы фильтров Занимающие более высокий логический уро вень, чем функциональные драйверы, они дополняют функциональность или изменяют поведение устройства либо другого драйвера. Так, утили ту для перехвата ввода с клавиатуры можно реализовать в виде драйвера фильтра клавиатуры, расположенного на более высоком уровне, чем функ циональный драйвер клавиатуры. В WDM ни один драйвер не отвечает за все аспекты управления конкрет ным устройством. Драйвер шины определяет изменения в составе устройств на шине (при подключении и отключении устройств), помогает диспетче ру PnP в перечислении устройств на шине, обращается к специфичным для шины регистрам и в некоторых случаях управляет электропитанием под ключенных к шине устройств. К аппаратной части устройства обычно об ращается только функциональный драйвер.
ГЛАВА 9 Подсистема ввода-вывода 573 ПРИМЕЧАНИЕ В Windows 2000, Windows XP и Windows Server 2003 уровень HAL играет несколько иную роль, чем в Windows NT. До Win dows 2000 сторонним поставщикам оборудования, которым нужно было добавить поддержку аппаратных шин, не поддерживаемых самой операционной системой, приходилось разрабатывать собственный HAL. Windows 2000, Windows XP и Windows Server 2003 позволяют сто ронним разработчикам реализовать поддержку таких шин в виде драй веров шин. Многоуровневые драйверы Поддержка индивидуального устройства часто распределяется между не сколькими драйверами, каждый из которых обеспечивает часть функцио нальности, необходимой для нормальной работы устройства. Кроме WDM драйверов шин, функциональных драйверов и драйверов фильтров, обору дование могут поддерживать и следующие компоненты. 쐽 Драйверы классов устройств (class drivers) Реализуют обработку ввода вывода для конкретного класса устройств, например дисковых ус тройств, ленточных накопителей или приводов CD ROM, где аппаратные интерфейсы стандартизированы и один драйвер может обслуживать ана логичные устройства от множества производителей. 쐽 Портдрайверы (port drivers) Обрабатывают запросы на ввод вывод, специфичные для определенного типа порта ввода вывода, например SCSI. Порт драйверы реализуются как библиотеки функций режима ядра, а не как драйверы устройств. 쐽 Минипортдрайверы (miniport drivers) Преобразуют универсаль ные запросы ввода вывода к порту конкретного типа в запросы, специ фичные для адаптера конкретного типа, например для SCSI адаптера. Минипорт драйверы являются истинными драйверами устройств, кото рые импортируют функции, предоставляемые порт драйвером. Вот пример, который демонстрирует, как работают драйверы устройств. Драйвер файловой системы принимает запрос на запись данных в опреде ленное место конкретного файла. Он преобразует его в запрос на запись определенного числа байтов по определенному «логическому» адресу на диске. После этого он передает этот запрос (через диспетчер ввода вывода) простому драйверу диска. Последний в свою очередь преобразует запрос в физический адрес на диске (цилиндр/дорожка/сектор) и позиционирует головки дискового устройства для записи данных. Эта схема действий пока зана на рис. 9 3. Эта схема иллюстрирует разделение труда между двумя драйверами. Дис петчер ввода вывода получает запрос на запись, в котором адрес записи от носителен началу конкретного файла. Далее диспетчер ввода вывода пере дает запрос драйверу файловой системы, который преобразует информа цию запроса в адрес начала записи на диске и число байтов, которые нуж
574 ГЛ А В А 9 БЕЗОПАСНОСТЬ но записать на диск. Драйвер файловой системы передает через диспетчер ввода вывода запрос драйверу диска, который транслирует его в физичес кий адрес на диске и переносит нужные данные. Рис. 9-3. Взаимодействие драйвера файловой системы и драйвера диска Поскольку все драйверы — и устройств, и файловой системы — предо ставляют операционной системе одинаковую инфраструктуру, в их иерар хию легко добавить еще один драйвер, не изменяя существующие драйверы или подсистему ввода вывода. Например, введя соответствующий драйвер, можно логически представить несколько дисков как один большой диск. Такой драйвер, кстати, имеется в Windows — он обеспечивает поддержку от казоустойчивых дисков. (Хотя этот драйвер присутствует во всех версиях Windows, поддержка отказоустойчивых дисков доступна лишь в серверных версиях Windows.) Драйвер диспетчера томов вполне логично размещается между драйверами файловой системы и дисков, как показано на рис. 9 4. Подробнее о драйверах диспетчера томов см. в главе 10.
ГЛАВА 9 Рис. 9-4. Подсистема ввода-вывода Добавление промежуточного драйвера 575
576 ГЛ А В А 9 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: просмотр списка загруженных драйверов Вы можете увидеть список зарегистрированных драйверов в системе Windows 2000, перейдя в раздел Drivers (Драйверы) оснастки Computer Management (Управление компьютером) в Microsoft Management Con sole (MMC) (Консоль управления Microsoft) или щелкнув правой кноп кой мыши значок My Computer (Мой компьютер) на рабочем столе и выбрав из контекстного меню команду Manage (Управление). Оснаст ка Computer Management также доступна в подменю Administrative Tools (Администрирование). Чтобы добраться до раздела Drivers в Computer Management, последовательно раскройте узлы System Tools (Служеб ные программы), System Information (Сведения о системе) и Software Environment (Программная среда), как показано ниже. В Windows XP и Windows Server 2003 можно получить ту же инфор мацию, запустив утилиту Msinfo32.exe из диалогового окна Run (Запуск программы). Выберите System Drivers (Системные драйверы) в Soft ware Environment (Программная среда) для вывода списка драйверов, сконфигурированных в системе. Те из них, которые загружены на дан ный момент, помечены словом «Yes» (Да) в столбце Started (Работает). Список загруженных драйверов режима ядра можно просмотреть и с помощью Process Explorer (www.sysinternals.com). Запустите Process Explorer, укажите процесс System и выберите DLLs из подменю Lower Pane в меню View. Process Explorer перечисляет загруженные драйве ры, их имена, информацию о версиях, включая название компании и описание, а также адрес загрузки (предполагается, что вы настроили отображение соответствующих столбцов в окне Process Explorer).
ГЛАВА 9 Подсистема ввода-вывода 577 Наконец, если вы изучаете аварийный дамп (или «снимок» работа ющей системы) с помощью отладчика ядра, то можете получить ана логичные сведения командой lm kv: kd> lm kv start end module name 804d4000 806aa280 nt (pdb symbols) c:\Symbols\ntoskrnl.pdb\ FB1EDACE71FB4812A5D5132819D72E523\ntoskrnl.pdb Loaded symbol image file: ntoskrnl.exe Image path: ntoskrnl.exe Timestamp: Thu Apr 24 10:57:43 2003 (3EA80977) Checksum: 001E311B ImageSize : 001D6280 File version: 5.1.2600.1151 Product version: 5.1.2600.1151 File flags: 0 (Mask 3F) File OS: 40004 NT Windows File type: 1.0 App File date: 00000000.00000000 Translations: 0409.04b0 CompanyName: Microsoft Corporation ProductName: Microsoft" Windows" Operating System InternalName: ntoskrnl.exe OriginalFilename: ntoskrnl.exe см. след. стр.
578 ГЛ А В А 9 БЕЗОПАСНОСТЬ ProductVersion: 5.1.2600.1151 FileVersion: 5.1.2600.1151 (xpsp2.0304221633) FileDescription: NT Kernel & System LegalCopyright: Microsoft Corporation. All rights reserved. 806ab000 806bde80 hal (deferred) Image path: halacpi.dll Timestamp: Thu Aug 29 03:05:02 2002 (3D6DD5AE) Checksum: 000203BD ImageSize : 00012E80 Translations: 0000.04b0 0000.04e0 0409.04b0 0409.04e0 a8b8e000 a8bb4e80 kmixer (deferred) Image path: \SystemRoot\system32\drivers\kmixer.sys Timestamp: Thu Aug 29 03:32:28 2002 (3D6DDC1C) Checksum: 00032574 ImageSize : 00026E80 Translations: 0000.04b0 0000.04e0 0409.04b0 0409.04e0 Структура драйвера Выполнением драйверов устройств управляет подсистема ввода вывода. Драйвер устройства состоит из набора процедур, вызываемых на различных этапах обработки запроса ввода вывода. Основные процедуры драйвера показаны на рис. 9 5. Рис. 9-5. Основные процедуры драйвера устройства 쐽 Инициализирующая процедура Диспетчер ввода вывода выполня ет инициализирующую процедуру драйвера (которая обычно называет ся DriverEntry) при загрузке этого драйвера в операционную систему. Дан ная процедура регистрирует остальные процедуры драйвера в диспетче ре ввода вывода, заполняя соответствующей информацией системные
ГЛАВА 9 Подсистема ввода-вывода 579 структуры данных, и выполняет необходимую глобальную инициализа цию драйвера. 쐽 Процедура добавления устройства Такие процедуры реализуются в драйверах, поддерживающих Plug and Play. Через эту процедуру диспетчер PnP посылает драйверу уведомление при обнаружении устройства, за ко торое отвечает данный драйвер. Выполняя эту процедуру, драйвер обыч но создает объект «устройство», представляющий аппаратное устройство. 쐽 Процедуры диспетчеризации Это основные функции, предоставля емые драйвером устройства, например для открытия, закрытия, чтения, записи и реализации других возможностей устройства, файловой систе мы или сети. Диспетчер ввода вывода, вызванный для выполнения опера ции ввода вывода, генерирует IRP и обращается к драйверу через одну из его процедур диспетчеризации. 쐽 Процедура инициации вводавывода С помощью этой процедуры драйвер может инициировать передачу данных как на устройство, так и с него. Эта процедура определяется лишь в драйверах, использующих под держку диспетчера ввода вывода для помещения входящих запросов в оче редь. Диспетчер ввода вывода ставит в очередь IRP для драйвера, гаранти руя одновременную обработку им только одного IRP. Большинство драй веров обрабатывают сразу несколько IRP, но создание очереди имеет смысл для некоторых драйверов, в частности для драйвера клавиатуры. 쐽 Процедура обслуживания прерываний (ISR) Когда устройство ге нерирует прерывание, диспетчер прерываний ядра передает управление этой процедуре. В модели ввода вывода Windows процедуры ISR работа ют на уровне DIRQL (Device IRQL), поэтому они выполняют минимум дей ствий во избежание слишком продолжительной блокировки прерываний более низкого уровня (подробнее об IRQL см. главу 3). Для выполнения остальной части обработки прерывания ISR ставит в очередь DPC (de ferred procedure call), выполняемый при более низком IRQL (уровня «DPC/ dispatch»). ISR имеются лишь в драйверах устройств, управляемых преры ваниями, — например в драйвере файловой системы ISR нет. 쐽 DPCпроцедура обработки прерываний DPC процедура выполняет основную часть обработки прерывания, оставшуюся после выполнения ISR. Она работает при более низком IRQL (уровня «DPC/dispatch»), чем ISR, чтобы не блокировать без необходимости другие прерывания. DPC проце дура инициирует завершение текущей операции ввода вывода и выполне ние следующей операции ввода вывода из очереди на данном устройстве. У многих драйверов устройств имеются процедуры, не показанные на рис. 9 5. 쐽 Одна или несколько процедур завершения вводавывода У драй вера могут быть процедуры завершения ввода вывода, уведомляющие его об окончании обработки IRP драйвером более низкого уровня. Например, дис петчер ввода вывода вызывает процедуру завершения ввода вывода драйве
580 ГЛ А В А 9 БЕЗОПАСНОСТЬ ра файловой системы, когда драйвер устройства заканчивает передачу дан ных в файл или из него. Эта процедура уведомляет драйвер файловой сис темы об удачном или неудачном завершении операции или о ее отмене, а также позволяет драйверу файловой системы освободить ресурсы. 쐽 Процедура отмены вводавывода Если операция ввода вывода может быть отменена, драйвер определяет одну или более процедур отмены вво да вывода. Получив IRP для запроса ввода вывода, который может быть от менен, драйвер связывает с IRP процедуру отмены. Если поток, выдавший запрос на ввод вывод, завершается до окончания обработки запроса или отменяет операцию (например, вызовом Windows функции CancelIo), дис петчер ввода вывода выполняет процедуру отмены, связанную с IRP (если таковая есть). Процедура отмены отвечает за выполнение любых действий, необходимых для освобождения всех ресурсов, выделенных при обработке IRP, а также за завершение IRP со статусом отмены. 쐽 Процедура выгрузки Эта процедура освобождает все системные ре сурсы, задействованные драйвером, после чего диспетчер ввода вывода может удалить их из памяти. При выполнении процедуры выгрузки обыч но освобождаются ресурсы, выделенные процедурой инициализации. Драйвер может загружаться и выгружаться во время работы системы. 쐽 Процедура уведомления о завершении работы системы Эта про цедура позволяет драйверу проводить очистку при завершении работы системы. 쐽 Процедуры регистрации ошибок При возникновении неожидан ных ошибок (например, когда на диске появляется поврежденный блок), процедуры регистрации ошибок, принадлежащие драйверу, уведомляют о них диспетчер ввода вывода. Последний записывает эту информацию в файл журнала ошибок. ПРИМЕЧАНИЕ Большинство драйверов устройств написано на C. Применение языка ассемблера крайне не рекомендуется из за его сложности и из за того, что он затрудняет перенос драйвера между ап паратными архитектурами вроде x86, x64 и IA64. Объекты «драйвер» и «устройство» Когда поток открывает описатель объекта «файл» (этот процесс описывается в разделе «Обработка ввода вывода» далее в этой главе), диспетчер ввода вывода, исходя из имени этого объекта, должен определить, к какому драй веру (или драйверам) нужно обратиться для обработки запроса. Более того, диспетчер ввода вывода должен знать, где найти эту информацию, когда в следующий раз поток вновь воспользуется тем же описателем файла. Для этого предназначены следующие объекты.
ГЛАВА 9 Подсистема ввода-вывода 581 쐽 Объект «драйвер», представляющий отдельный драйвер в системе. Имен но от этого объекта диспетчер ввода вывода получает адрес процедуры диспетчеризации (точки входа) драйвера. 쐽 Объект «устройство», представляющий физическое или логическое уст ройство в системе и описывающий его характеристики, например грани цы выравнивания буферов и адреса очередей для приема IRP, поступаю щих на это устройство. Диспетчер ввода вывода создает объект «драйвер» при загрузке в систе му соответствующего драйвера и вызывает его инициализирующую проце дуру (например, DriverEntry), которая записывает в атрибуты объекта точки входа этого драйвера. После загрузки драйвер может создавать объекты «устройство» для пред ставления устройств или даже для формирования интерфейса драйвера (вы зовом IoCreateDevice или IoCreateDeviceSecure). Однако большинство PnP драйверов создают объекты «устройство» с помощью своих процедур добав ления устройств, когда диспетчер PnP информирует их о присутствии управ ляемого ими устройства. С другой стороны, драйверы, не отвечающие спе цификации Plug and Play, создают объекты «устройство» при вызове диспет чером ввода вывода их инициализирующих процедур. Диспетчер ввода вы вода выгружает драйвер после удаления его последнего объекта «устрой ство», когда ссылок на устройство больше нет. Создавая объект «устройство», драйвер может присвоить ему имя. Тогда этот объект помещается в пространство имен диспетчера объектов. Драйвер может определить имя этого объекта явно или позволить диспетчеру ввода вывода сгенерировать его автоматически (о пространстве имен диспетчера объектов см. главу 3). По соглашению объекты «устройство» помещаются в каталог \Device пространства имен, недоступный приложениям через Win dows API. ПРИМЕЧАНИЕ Некоторые драйверы размещают объекты «устрой ство» в каталогах, отличных от \Device. Так, диспетчер томов Logical Disk Manager создает объекты «устройство», представляющие разделы жесткого диска, в каталоге \Device\HarddiskDmVolumes (подробнее на эту тему см. главу 10). Чтобы сделать объект «устройство» доступным для приложений, драйвер должен создать в каталоге \Global?? (или в каталоге \?? в Windows 2000) сим вольную ссылку на имя этого объекта в каталоге \Device. Драйверы, не под держивающие Plug and Play, и драйверы файловой системы обычно создают символьную ссылку с общеизвестным именем (скажем, \Device\Hardware2). Поскольку общеизвестные имена не срабатывают в средах с динамически меняющимся составом оборудования, PnP драйверы предоставляют один или несколько интерфейсов через функцию IoRegisterDeviceInterface, переда вая ей GUID, определяющий тип предоставляемой функциональности. GUID являются 128 битными числами, которые можно генерировать с помощью утилиты Guidgen, входящей в состав DDK и Platform SDK. Диапазон чисел,
582 ГЛ А В А 9 БЕЗОПАСНОСТЬ который может быть представлен 128 битами, гарантирует, что каждый GUID, созданный этой утилитой, всегда будет глобально уникальным. IoRegisterDeviceInterface определяет символьную ссылку, сопоставляемую с экземпляром объекта «устройство». Однако, прежде чем диспетчер ввода вывода действительно создаст ссылку, драйвер должен вызвать функцию IoSetDeviceInterfaceState, чтобы разрешить использование интерфейса этого устройства. Обычно драйвер делает это, когда диспетчер PnP посылает ему команду startdevice для запуска устройства. Приложение, которому нужно открыть объект «устройство», представлен ный GUID идентификатором, может вызывать PnP функции настройки, на пример SetupDiEnumDeviceInterfaces для перечисления интерфейсов, доступ ных по конкретному GUID, и получения имен символьных ссылок, с помо щью которых может быть открыт объект «устройство». Чтобы получить до полнительную информацию (например, автоматически сгенерированное имя устройства), приложение вызывает функцию SetupDiGetDeviceInterface Detail для всех устройств, перечисленных SetupDiEnumDeviceInterfaces. Полу чив от SetupDiGetDeviceInterfaceDetail имя устройства, приложение обраща ется к Windows функции CreateFile, чтобы открыть устройство и получить его описатель. ЭКСПЕРИМЕНТ: просмотр каталога \Device Для просмотра имен устройств в каталоге \Device пространства имен диспетчера объектов можно использовать утилиту Winobj (www.sysin ternals.com) или команду !object отладчика ядра. Ниже показан пример символьной ссылки, созданной диспетчером ввода вывода и указываю щей на объект «устройство» с автоматически сгенерированным именем. Команда !object отладчика ядра для каталога \Device выводит следу ющую информацию.
ГЛАВА 9 Подсистема ввода-вывода 583 kd> !object \device Object: e100c4a0 Type: (8a4f3178) Directory ObjectHeader: e100c488 HandleCount: 0 PointerCount: 301 Directory Object: e10011e8 Name: Device 65535 symbolic links snapped through this directory Hash Address Type —— ——— —— 00 8a437398 Device 8a4a56f0 Device 8a0ed5c0 Device 8a1ddb40 Device 8a336d38 Device 8a4ed730 Device 8a4ee4f0 Device 8a4b5030 Device 01 8a2303e8 Device 8a258030 Device 8a4ed4f0 Device 8a4ee2b0 Device 02 8a1756d8 Device 8a4ec730 Device 8a20fd58 Device 8a2ef660 Device 8a4ed2b0 Device 8a4b4030 Device 03 8a4ec4f0 Device 8a15bf18 Device 8a2947d8 Device 8a1b38e0 Device 8a0b6038 Device 8a288b48 Device 8a2501f8 Device 8a4b3030 Device 8a4b4df0 Device 04 8a181030 Device 8a4ec2b0 Device 8a00b038 Device 8a189030 Device ... Name —— KsecDD Ndis ProcExp Beep 0000008e 00000032 00000025 00000019 Netbios 0000008f 00000033 00000026 KSENUM#00000001 00000040 Ip RDP_CONSOLE0 00000034 00000027 00000041 0000009e {EFF45047C9484D3286B5736480DDBB9C} Fips Video0 RDP_CONSOLE1 KeyboardClass0 00000035 00000028 NDProxy 00000042 Video1 KeyboardClass1 При выполнении команды !object с указанием объекта каталога дис петчера объектов отладчик ядра записывает дамп содержимого ката лога в соответствии с его внутренней организацией в диспетчере объектов. Для ускорения поиска каталог хранит объекты в хэш табли це, основанной на хэше имен объектов, поэтому команда !object пере числяет объекты так, как они хранятся в каждой корзине (bucket) хэш таблицы каталога.
584 ГЛ А В А 9 БЕЗОПАСНОСТЬ Как видно на рис. 9 6, объект «устройство» ссылается на свой объект «драй вер», благодаря чему диспетчер ввода вывода знает, из какого драйвера нуж но вызвать процедуру при получении запроса ввода вывода. С помощью объекта «устройство» он находит объект «драйвер», который представляет драйвер, обслуживающий устройство. После этого он обращается к объекту «драйвер», используя номер функции из исходного запроса; каждый номер функции соответствует точке входа драйвера (номера функций на рис. 9 6 подробнее описываются в разделе «Блок стека IRP» далее в этой главе). С объектом «драйвер» нередко сопоставляется несколько объектов «уст ройство». Список объектов «устройство» представляет физические и логи ческие устройства, управляемые драйвером. Так, для каждого раздела жест кого диска имеется отдельный объект «устройство» с информацией, специ фичной для данного раздела. Но для обращения ко всем разделам исполь зуется один и тот же драйвер жесткого диска. При выгрузке драйвера из сис темы диспетчер ввода вывода с помощью очереди объектов «устройство» определяет устройства, на которые повлияет удаление драйвера. Рис. 9-6. Объект «драйвер» ЭКСПЕРИМЕНТ: исследуем объекты «драйвер» и «устройство» Эти объекты можно исследовать с помощью команд !drvobj и !devobj отладчика ядра. Следующий пример относится к объекту «драйвер» для драйверов класса «клавиатура». У этого объекта имеется единственный объект «устройство». kd> !drvobj kbdclass Driver object (81869cb0) is for: \Driver\Kbdclass
ГЛАВА 9 Подсистема ввода-вывода 585 Driver Extension List: (id , addr) Device Object list: 81869310 kd> !devobj 81869310 Device object (81869310) is for: KeyboardClass0 \Driver\Kbdclass DriverObject 81869cb0 Current Irp a57a0e90 RefCount 0 Type 0000000b Flags 00002044 DevExt 818693c8 DevObjExt 818694b8 ExtensionFlags (0000000000) AttachedDevice (Upper) 818691e0 \Driver\Ctrl2cap AttachedTo (Lower) 81869500 \Driver\i8042prt Device queue is busy — Queue empty. Заметьте, что команда !devobj заодно сообщает адреса и имена лю бых объектов «устройство», поверх которых размещен просматрива емый вами объект (строка AttachedTo), а также объектов «устройство», размещенных над указанным объектом (строка AttachedDevice). Использование объектов для регистрации информации о драйверах озна чает, что диспетчеру ввода вывода не нужно знать никаких деталей реализа ции драйверов. Он просто находит драйвер по указателю, тем самым позво ляя легко загружать новые драйверы и обеспечивая их переносимость. Кро ме того, представление устройств и драйверов разными объектами упроща ет подсистеме ввода вывода закрепление драйверов за дополнительными ус тройствами, которые появляются при изменении конфигурации системы. Открытие устройств Объекты «файл» являются структурами режима ядра, которые точно соответ ствуют определению объектов в Windows: это системные ресурсы, доступ ные для совместного использования двум или нескольким процессам, у них могут быть имена, их безопасность обеспечивается моделью защиты объек тов, и они поддерживают синхронизацию. Хотя большинство разделяемых ресурсов в Windows базируется в памяти, основная часть ресурсов, с кото рыми имеет дело подсистема ввода вывода, размещается на физических ус тройствах или представляет их. Несмотря на эту разницу, операции над со вместно используемыми ресурсами подсистемы ввода вывода осуществля ются как над объектами. Объекты «файл» — представление ресурсов в памяти, которое обеспечи вает чтение и запись данных в эти ресурсы. В таблице 9 1 перечислены не которые атрибуты объектов «файл». Описание и размеры полей см. в опре делении структуры FILE_OBJECT в Ntddk.h.
586 ГЛ А В А 9 Таблица 9-1. БЕЗОПАСНОСТЬ Атрибуты объектов «файл» Атрибут Описание Имя файла Идентифицирует физический файл, на который ссылает ся объект «файл» Текущее смещение в байтах Идентифицирует текущий адрес в файле (действителен только для синхронного ввода вывода) Режимы разделения Указывает, могут ли другие потоки открывать файл для чтения, записи или удаления, пока им пользуется теку щий поток Флаги режима открытия Указывают тип ввода вывода — синхронный или асинх ронный, кэшируемый или некэшируемый, с последова тельным или прямым доступом Указатель на объект «устройство» Указывает тип устройства, на котором находится файл Указатель на блок пара метров тома (VPB) Указывает том, или раздел, на котором находится файл Указатель на указатели объекта «раздел» Указывает корневую структуру, описывающую проециру емый файл Указатель на закрытую карту кэша Идентифицирует части файла, кэшируемые диспетчером кэша, и их местонахождение в кэше ЭКСПЕРИМЕНТ: просмотр структуры данных объекта «файл» Вы можете просмотреть содержимое этой структуры с помощью ко манды dt отладчика ядра: kd> dt nt!_file_object nt!_FILE_OBJECT +0x000 Type : Int2B +0x002 Size : Int2B +0x004 DeviceObject : Ptr32 _DEVICE_OBJECT +0x008 Vpb : Ptr32 _VPB +0x00c FsContext : Ptr32 Void +0x010 FsContext2 : Ptr32 Void +0x014 SectionObjectPointer : Ptr32 _SECTION_OBJECT_POINTERS +0x018 PrivateCacheMap : Ptr32 Void +0x01c FinalStatus : Int4B +0x020 RelatedFileObject : Ptr32 _FILE_OBJECT +0x024 LockOperation : UChar +0x025 DeletePending : UChar +0x026 ReadAccess : UChar +0x027 WriteAccess : UChar +0x028 DeleteAccess : UChar +0x029 SharedRead : UChar +0x02a SharedWrite : UChar +0x02b SharedDelete : UChar +0x02c Flags : Uint4B +0x030 FileName : _UNICODE_STRING
ГЛАВА 9 +0x038 +0x040 +0x044 +0x048 +0x04c +0x05c +0x06c Подсистема ввода-вывода 587 CurrentByteOffset : _LARGE_INTEGER Waiters : Uint4B Busy : Uint4B LastLock : Ptr32 Void Lock : _KEVENT Event : _KEVENT CompletionContext : Ptr32 _IO_COMPLETION_CONTEXT Когда поток открывает файл или простое устройство, диспетчер ввода вывода возвращает описатель объекта «файл». Рис. 9 7 иллюстрирует, что происходит при открытии файла. В этом примере С программа (1) вызывает из стандартной библиотеки функцию fopen, которая в свою очередь вызывает Windows функцию Create File (2). Далее DLL подсистемы Windows (в данном случае — Kernel32.dll) вы зывает функцию NtCreateFile из Ntdll.dll (3). Эта функция в Ntdll.dll содержит соответствующие команды, вызывающие переход в режим ядра в диспетчер системных сервисов, который и обращается к настоящей функции NtCreate File (4) из Ntoskrnl.exe (о диспетчеризации системных сервисов см. главу 3). Рис. 9-7. Открытие объекта «файл»
588 ГЛ А В А 9 БЕЗОПАСНОСТЬ ПРИМЕЧАНИЕ Объекты «файл» представляют открытые экземпляры файлов, а не сами файлы. В отличие от UNIX систем, где используют ся vnode, в Windows представление файла не определено — системные драйверы Windows определяют свои представления. Как и другие объекты исполнительной системы, файлы защищаются дес крипторами защиты, которые содержат список управления доступом (ACL). Чтобы выяснить, позволяет ли ACL файла получить процессу доступ того типа, который был запрошен его потоком, диспетчер ввода вывода обраща ется к системе защиты. Если да, диспетчер объектов (5, 6) разрешает доступ и сопоставляет предоставленные права доступа с описателем файла, возвра щаемым потоку. Если этому или другому потоку того же процесса понадо бятся дополнительные операции с файлом, не указанные в исходном запро се, ему придется открыть новый описатель, по которому тоже будет прове дена проверка прав доступа (подробнее о защите объектов см. главу 8). ЭКСПЕРИМЕНТ: просмотр описателей устройств У любого процесса, открывшего описатель какого либо устройства, в таблице описателей появляется объект «файл», соответствующий от крытому экземпляру. Для просмотра таких описателей вполне годит ся Process Explorer: выберите процесс и пометьте Show Lower Pane в меню View и Handles в подменю Lower Pane View меню View. Отсор тируйте по столбцу Type и прокрутите содержимое до того места, где показываются описатели, представляющие объекты «файл»; они поме чаются как «File». В данном примере у процесса Csrss имеются открытые описатели объектов «файл», которые представляют открытые экземпляры уст ройств и получают автоматически генерируемые имена, а также опи сатели объектов «файл», принадлежащих драйверу службы термина лов. Чтобы просмотреть конкретный объект «файл» в отладчике ядра,
ГЛАВА 9 Подсистема ввода-вывода 589 сначала определите адрес этого объекта. Следующая команда выводит сведения о выделенном на иллюстрации описателе (0xB8), который принадлежит процессу Csrss.exe с идентификатором 2332 (0x91c): 0: kd> !handle b8 f 91c processor number 0 Searching for Process with Cid == 91c PROCESS 86a6c020 SessionId: 0 Cid: 091c Peb: 7ffde000 ParentCid: 028c DirBase: 1158a000 ObjectTable: e1b5d080 HandleCount: 643. Image: csrss.exe New version of handle table at e2b44000 with 643 Entries in use 00B8: Object: 866ae9e8 GrantedAccess: 0012019f Object: 866ae9e8 Type: (86fe8ad0) File ObjectHeader: 866ae9d0 HandleCount: 1 PointerCount: 3 Поскольку это объект «файл», вы можете получить информацию о нем командой !fileobj: 0: kd> !fileobj 866ae9e8 File object name: Device Object: 0x86d0c8b8 Vpb is NULL \Driver\TermDD Flags: 0x40000 Handle Created FsContext: 0x866a31d8 CurrentByteOffset: 0 FsContext2: 0x00000001 Поскольку объект «файл» — представление разделяемого ресурса в памя ти, а не сам ресурс, он отличается от остальных объектов исполнительной системы. Объект «файл» содержит лишь данные, уникальные для описателя объекта, тогда как собственно файл — совместно используемые данные или текст. Всякий раз, когда поток открывает описатель файла, создается новый объект «файл» с новым набором атрибутов, специфичным для этого описа теля. Например, атрибут «текущее смещение в байтах» определяет место в файле, где будут записаны или считаны следующие данные по текущему опи сателю. У каждого описателя одного и того же файла свое значение атрибу та «текущее смещение в байтах». Кроме того, объект «файл» уникален для процесса; исключение составляют случаи, когда процесс дублирует описа тель файла для передачи другому процессу (через Windows функцию Dupli cateHandle) или когда дочерний процесс наследует описатель файла от ро дительского. Только в этих двух случаях процессы располагают отдельными описателями, которые ссылаются на один и тот же объект «файл».
590 ГЛ А В А 9 БЕЗОПАСНОСТЬ Описатель файла уникален для процесса, но определяемый им физичес кий ресурс — нет. Поэтому, как и при доступе к любому другому общему ре сурсу, потоки должны синхронизировать свое обращение к совместно ис пользуемым файлам, каталогам и устройствам. Если, например, поток что то записывает в файл, то при открытии описателя файла он должен указать монопольный доступ для записи, чтобы другие потоки не могли записывать в этот файл одновременно с первым потоком. В качестве альтернативы по ток может заблокировать на время записи часть файла с помощью Windows функции LockFile. Имя открываемого файла включает имя объекта «устройство», который представляет устройство, содержащее файл. Например, \Device\Floppy0\My file.dat ссылается на файл Myfile.dat на дискете в дисководе А. Подстрока «\Device\Floppy0» является внутренним именем объекта «устройство», пред ставляющего данный дисковод. При открытии файла Myfile.dat диспетчер ввода вывода создает объект «файл», сохраняет в нем указатель на объект «устройство» Floppy0 и возвращает описатель файла вызывающему потоку. Впоследствии, когда вызывающий поток воспользуется описателем файла, диспетчер ввода вывода сможет обращаться непосредственно к объекту Floppy0. Учтите, что внутренние имена устройств неприменимы в Windows приложениях. Для них имена устройств должны находиться в специальном каталоге пространства имен диспетчера объектов — \?? (в Windows 2000) или \Global?? (в Windows XP и Windows Server 2003). В этом каталоге содер жатся символьные ссылки на внутренние имена устройств. За создание ссы лок в этом каталоге отвечают драйверы устройств. Вы можете просмотреть и даже изменить эти ссылки программным способом, через Windows функ ции QueryDosDevice и DefineDosDevice. ЭКСПЕРИМЕНТ: просмотр сопоставлений Windows-имен устройств внутренним именам устройств Утилита Winobj (www.sysinternals.com) позволяет исследовать символь ные ссылки, определяющие пространство Windows имен устройств. Запустите Winobj и выберите каталог \?? в Windows 2000 или \Global?? в Windows XP либо Windows Server 2003.
ГЛАВА 9 Подсистема ввода-вывода 591 Обратите внимание на символьные ссылки справа. Попробуйте дважды щелкнуть устройство C: — вы должны увидеть нечто вроде того, что показано ниже. C: представляет собой символьную ссылку на внутреннее устрой ство с именем \Device\HarddiskVolume1, или на первый том первого жесткого диска в системе. Элемент COM1, показанный Winobj, — сим вольная ссылка на \Device\Serial0 и т. д. Попробуйте создать собствен ные ссылки командой subst в командной строке. Обработка ввода-вывода Теперь, когда мы рассмотрели структуру и типы драйверов, а также поддер живающие их структуры данных, давайте обсудим то, как запросы ввода вывода проходят по системе. Обработка запросов ввода вывода включает несколько предсказуемых этапов. Наборы операций, выполняемых на этих этапах, варьируются в зависимости от того, какой драйвер управляет устрой ством, которому адресован запрос, — одно или многоуровневый. Но обра ботка зависит и от того, какой ввод вывод запрошен — синхронный или асинхронный. Так что для начала мы рассмотрим эти два типа ввода выво да и уже после этого перейдем к другим темам. Типы ввода-вывода Приложения могут выдавать запросы ввода вывода различных типов, напри мер синхронного, асинхронного, проецируемого (данные с устройства про ецируются на адресное пространство приложения для доступа через вирту альную память приложения, а не API функции ввода вывода), а также ввода вывода, при котором данные передаются между устройством и непрерывны
592 ГЛ А В А 9 БЕЗОПАСНОСТЬ ми буферами приложения за один запрос. Более того, диспетчер ввода выво да позволяет драйверам реализовать специфический интерфейс ввода выво да, что нередко обеспечивает сокращение числа IRP, необходимых для обра ботки ввода вывода. В этом разделе мы рассмотрим все типы ввода вывода. Синхронный и асинхронный ввод-вывод Большинство операций ввода вывода приложений являются синхронными, т. е. приложение ждет, когда устройство выполнит передачу данных и вер нет код статуса по завершении операции ввода вывода. После этого про грамма продолжает работу и немедленно использует полученные данные. В таком простейшем варианте Windows функции ReadFile и WriteFile выполня ются синхронно. Перед возвратом управления они должны завершить опе рацию ввода вывода. Асинхронный вводвывод позволяет приложению выдать запрос на ввод вывод и продолжить выполнение, не дожидаясь передачи данных устрой ством. Этот тип ввода вывода увеличивает эффективность работы приложе ния, позволяя заниматься другими задачами, пока выполняется операция ввода вывода. Для использования асинхронного ввода вывода вы должны указать при вызове CreateFile флаг FILE_FLAG_OVERLAPPED. Конечно, ини циировав операцию асинхронного ввода вывода, поток должен соблюдать осторожность и не обращаться к запрошенным данным до их получения от устройства. Следовательно, поток должен синхронизировать свое выполне ние с завершением обработки запроса на ввод вывод, отслеживая описатель синхронизирующего объекта (которым может быть событие, порт заверше ния ввода вывода или сам объект «файл»), который по окончании ввода вы вода перейдет в свободное состояние. Независимо от типа запроса операции ввода вывода, инициированные драйвером в интересах приложения, выполняются асинхронно, т. е. после выдачи запроса драйвер устройства возвращает управление подсистеме вво да вывода. А когда она вернет управление приложению, зависит от типа зап роса. Схема управления при инициации операции чтения показана на рис. 9 8. Заметьте, что ожидание зависит от состояния флага перекрытия в объекте «файл» и реализуется функцией NtReadFile в режиме ядра. Вы можете проверить статус незавершенной операции асинхронного ввода вывода вызовом Windows функции HasOverlappedIoCompleted. При использовании портов завершения ввода вывода с той же целью можно вы зывать GetQueuedCompletionStatus.
ГЛАВА 9 Рис. 9-8. Подсистема ввода-вывода 593 Схема управления при операции ввода-вывода Быстрый ввод-вывод Быстрый ввод вывод (fast I/O) — специальный механизм, который позволяет подсистеме ввода вывода напрямую, не генерируя IRP, обращаться к драйве ру файловой системы или диспетчеру кэша (быстрый ввод вывод описыва ется в главах 11 и 12). Драйвер регистрирует свои точки входа для быстро го ввода вывода, записывая их адреса в структуру, на которую ссылается ука затель PFAST_IO_DISPATCH его объекта «драйвер». ЭКСПЕРИМЕНТ: просмотр процедур быстрого ввода-вывода, зарегистрированных драйвером Список процедур быстрого ввода вывода, зарегистрированных драй вером в своем объекте «драйвер», выводит команда !drvobj отладчика ядра. Но такие процедуры обычно имеют смысл только для драйверов файловой системы. Ниже показан список процедур быстрого ввода вывода для объекта драйвера файловой системы NTFS. kd> !drvobj \filesystem\ntfs 2 Driver object (8a4372a0) is for: \FileSystem\Ntfs DriverEntry: f7bd7398 Ntfs!DriverEntry см. след. стр.
594 ГЛ А В А 9 БЕЗОПАСНОСТЬ DriverStartIo: 00000000 DriverUnload: 00000000 Dispatch routines: [00] IRP_MJ_CREATE Fast I/O routines: FastIoCheckIfPossible Ntfs!NtfsFastIoCheckIfPossible FastIoRead FastIoWrite FastIoQueryBasicInfo Ntfs!NtfsFastQueryBasicInfo FastIoQueryStandardInfo Ntfs!NtfsFastQueryStdInfo FastIoLock FastIoUnlockSingle Ntfs!NtfsFastUnlockSingle FastIoUnlockAll Ntfs!NtfsFastUnlockAll FastIoUnlockAllByKey Ntfs!NtfsFastUnlockAllByKey AcquireFileForNtCreateSection Ntfs!NtfsAcquireForCreateSection ReleaseFileForNtCreateSection Ntfs!NtfsReleaseForCreateSection FastIoQueryNetworkOpenInfo Ntfs!NtfsFastQueryNetworkOpenInfo AcquireForModWrite Ntfs!NtfsAcquireFileForModWrite MdlRead f7b76390 Ntfs!NtfsFsdCreate f7b74a0b f7b77bbc f7b8a9cc f7b7cd5e Ntfs!NtfsCopyReadA Ntfs!NtfsCopyWriteA f7b7779e f7b8b738 f7b8b66c Ntfs!NtfsFastLock f7ba5cd6 f7bcdab2 f7b77771 f7b77758 f7bbec06 f7b8663d f7bbed20 Ntfs!NtfsMdlReadA Как показывает вывод, NTFS зарегистрировала свою процедуру Ntfs FastIoCheckIfPossible как элемент FastIoCheckIfPossible списка процедур быстрого ввода вывода. По имени этого элемента можно догадаться, что диспетчер ввода вывода вызывает эту функцию перед выдачей зап роса на быстрый ввод вывод и в ответ драйвер сообщает, возможны ли операции быстрого ввода вывода применительно к данному файлу. Ввод-вывод в проецируемые файлы и кэширование файлов Вводвывод в проецируемые файлы (mapped file I/O) — важная функция под системы ввода вывода, поддерживаемая ею совместно с диспетчером памя ти (о проецируемых файлах см. главу 7). Термин «ввод вывод в проецируе мые файлы» относится к возможности интерпретировать файл на диске как часть виртуальной памяти процесса. Программа может обращаться к тако му файлу как к большому массиву, не прибегая к буферизации или дисково му вводу выводу. При доступе программы к памяти диспетчер памяти ис
ГЛАВА 9 Подсистема ввода-вывода 595 пользует свой механизм подкачки для загрузки нужной страницы из диско вого файла. Если программа изменяет какие то данные в своем виртуальном адресном пространстве, диспетчер памяти записывает эти данные обратно в дисковый файл в ходе обычной операции подкачки страниц. Ввод вывод в проецируемые файлы доступен в пользовательском режиме через Windows функции CreateFileMapping и MapViewOfFile. В самой операци онной системе такой ввод вывод используется при выполнении важных опе раций — при кэшировании файлов и активизации образов (загрузке и запуске исполняемых программ). Другим потребителем этого типа ввода вывода явля ется диспетчер кэша. Файловые системы обращаются к диспетчеру кэша для проецирования файлов данных на виртуальную память, что ускоряет работу программ, интенсивно использующих ввод вывод. По мере использования файла диспетчер памяти подгружает в память страницы, к которым произво дится обращение. Если большинство систем кэширования выделяет для кэши рования фиксированную область памяти, то кэш Windows расширяется или сокращается в зависимости от объема свободной памяти. Такое изменение раз мера кэша возможно благодаря тому, что диспетчер кэша опирается на соот ветствующую поддержку со стороны диспетчера памяти (см. главу 7). Исполь зуя преимущества подсистемы подкачки страниц диспетчера памяти, диспет чер кэша избегает дублирования работы, уже проделанной диспетчером памя ти. (Внутреннее устройство диспетчера кэша рассматривается в главе 11.) Ввод-вывод по механизму «scatter/gather» Windows также поддерживает особый вид высокопроизводительного ввода вывода с использованием механизма «scatter/gather»; он доступен через Win dows функции ReadFileScatter и WriteFileGather. Эти функции позволяют при ложению в рамках одной операции считывать или записывать данные из не скольких буферов в виртуальной памяти в непрерывную область дискового файла, а не выдавать отдельный запрос ввода вывода для каждого буфера. Чтобы задействовать такой ввод вывод, вы должны открыть файл для некэ шируемого асинхронного (перекрывающегося) ввода вывода и выровнять пользовательские буферы по границам страниц. Более того, если ввод вы вод направлен на устройство массовой памяти, то передаваемые данные нужно выровнять по границам секторов устройства, а их объем должен быть кратен размеру сектора. Пакеты запроса ввода-вывода Пакет запроса вводавывода (I/O request packet, IRP) хранит информацию, нужную для обработки запроса на ввод вывод. Когда поток вызывает сервис ввода вывода, диспетчер ввода вывода создает IRP для представления опера ции в процессе ее выполнения подсистемой ввода вывода. По возможнос ти диспетчер ввода вывода выделяет память под IRP в одном из двух ассоци ативных списков IRP, индивидуальных для каждого процессора и хранящих ся в пуле неподкачиваемой памяти. Ассоциативный список малых IRP (small
596 ГЛ А В А 9 БЕЗОПАСНОСТЬ IRP look aside list) хранит IRP с одним блоком стека (об этих блоках — чуть позже), а ассоциативный список больших IRP (large IRP look aside list) — IRP с несколькими блоками стека. По умолчанию в IRP второго списка содержит ся 8 блоков стека, но раз в минуту система варьирует это число на основа нии того, сколько блоков было запрошено. Если для IRP требуется больше блоков стека, чем имеется в ассоциативном списке больших IRP, диспетчер ввода вывода выделяет память под IRP из пула неподкачиваемой памяти. После создания и инициализации IRP диспетчер ввода вывода сохраняет в IRP указатель на объект «файл» вызывающего потока. ПРИМЕЧАНИЕ DWORD параметр реестра HKLM\System\CurrentCont rolSet\Session Manager\I/O System\LargIrpStackLocations (если он опре делен) указывает, сколько блоков стека содержится в IRP, которые хра нятся в ассоциативном списке больших IRP. На рис. 9 9 показан пример запроса ввода вывода, демонстрирующий взаимосвязи между IRP и объектами «файл», «устройство» и «драйвер». Дан ный пример относится к запросу ввода вывода, который адресован одно уровневому драйверу, но большинство операций ввода вывода гораздо слож нее, так как в их выполнении участвует не один, а несколько многоуровне вых драйверов. (Этот случай мы рассмотрим позже.) Рис. 9-9. Структуры данных, участвующие в обработке запроса на ввод-вывод, адресованного одноуровневому драйверу
ГЛАВА 9 Подсистема ввода-вывода 597 Блок стека IRP IRP состоит из двух частей: фиксированного заголовка (часто называемого телом IRP) и одного или нескольких блоков стека. Фиксированная часть со держит такую информацию, как тип и размер запроса, указатель на буфер в случае буферизованного ввода вывода, данные о состоянии, изменяющие ся по мере обработки запроса, а также сведения о том, является запрос син хронным или асинхронным. Блок стека IRP (IRP stack location) содержит номер функции (состоящий из основного и дополнительного номеров), параметры, специфичные для функции, и указатель на объект «файл» вызы вающего потока. Основной номер функции (major function code) идентифи цирует принадлежащую драйверу процедуру диспетчеризации, которую дис петчер ввода вывода вызывает при передаче IRP драйверу. Необязательный дополнительный номер функции (minor function code) иногда использует ся как модификатор основного номера. В командах управления электропи танием и Plug and Play всегда указывается дополнительный номер функции. В большинстве драйверов процедуры диспетчеризации определены толь ко для подмножества основных функций, т. е. функций, предназначенных для создания/открытия, записи, чтения, управления вводом выводом на ус тройстве, управления электропитанием, операций Plug and Play, System (для WMI команд) и закрытия. Драйверы файловой системы определяют функ ции для всех (или почти всех) точек входа. Диспетчер ввода вывода записы вает в точки входа, не заполненные драйверами, указатели на свою функцию IopInvalidDeviceRequest. Эта функция возвращает вызывающему потоку код ошибки, который уведомляет о попытке обращения к функции, не поддер живаемой данным устройством. ЭКСПЕРИМЕНТ: исследуем процедуры диспетчеризации, принадлежащие драйверу Вы можете получить список всех функций, определенных драйвером для своих процедур диспетчеризации. Для этого введите команду !drv obj отладчика ядра и после имени (или адреса) объекта «драйвер» ука жите значение 7. Следующий вывод показывает, что драйверы поддер живают 28 типов IRP. kd> !drvobj kbdclass 7 Driver object (8a238900) is for: \Driver\Kbdclass Driver Extension List: (id , addr) Device Object list: 8a189030 8a2501f8 DriverEntry: f7822d22 kbdclass!DriverEntry DriverStartIo: 00000000 DriverUnload: 00000000 см. след. стр.
598 ГЛ А В А 9 БЕЗОПАСНОСТЬ Dispatch routines: [00] IRP_MJ_CREATE kbdclass!KeyboardClassCreate [01] IRP_MJ_CREATE_NAMED_PIPE nt!IopInvalidDeviceRequest [02] IRP_MJ_CLOSE kbdclass!KeyboardClassClose [03] IRP_MJ_READ kbdclass!KeyboardClassRead [04] IRP_MJ_WRITE nt!IopInvalidDeviceRequest [05] IRP_MJ_QUERY_INFORMATION nt!IopInvalidDeviceRequest [06] IRP_MJ_SET_INFORMATION nt!IopInvalidDeviceRequest [07] IRP_MJ_QUERY_EA nt!IopInvalidDeviceRequest [08] IRP_MJ_SET_EA nt!IopInvalidDeviceRequest [09] IRP_MJ_FLUSH_BUFFERS kbdclass!KeyboardClassFlush [0a] IRP_MJ_QUERY_VOLUME_INFORMATION nt!IopInvalidDeviceRequest [0b] IRP_MJ_SET_VOLUME_INFORMATION nt!IopInvalidDeviceRequest [0c] IRP_MJ_DIRECTORY_CONTROL nt!IopInvalidDeviceRequest [0d] IRP_MJ_FILE_SYSTEM_CONTROL nt!IopInvalidDeviceRequest [0e] IRP_MJ_DEVICE_CONTROL kbdclass!KeyboardClassDeviceControl [0f] IRP_MJ_INTERNAL_DEVICE_CONTROL kbdclass!KeyboardClassPassThrough [10] IRP_MJ_SHUTDOWN nt!IopInvalidDeviceRequest [11] IRP_MJ_LOCK_CONTROL nt!IopInvalidDeviceRequest [12] IRP_MJ_CLEANUP kbdclass!KeyboardClassCleanup [13] IRP_MJ_CREATE_MAILSLOT nt!IopInvalidDeviceRequest [14] IRP_MJ_QUERY_SECURITY nt!IopInvalidDeviceRequest [15] IRP_MJ_SET_SECURITY nt!IopInvalidDeviceRequest [16] IRP_MJ_POWER kbdclass!KeyboardClassPower [17] IRP_MJ_SYSTEM_CONTROL f781fd3b 804eef8e f781ff4c f7820ba5 804eef8e 804eef8e 804eef8e 804eef8e 804eef8e f781fcbe 804eef8e 804eef8e 804eef8e 804eef8e f7821829 f7821200 804eef8e 804eef8e f781fc84 804eef8e 804eef8e 804eef8e f7821f51 f7821649
ГЛАВА 9 kbdclass!KeyboardClassSystemControl [18] IRP_MJ_DEVICE_CHANGE nt!IopInvalidDeviceRequest [19] IRP_MJ_QUERY_QUOTA nt!IopInvalidDeviceRequest [1a] IRP_MJ_SET_QUOTA nt!IopInvalidDeviceRequest [1b] IRP_MJ_PNP kbdclass!KeyboardPnP Подсистема ввода-вывода 599 804eef8e 804eef8e 804eef8e f78206c1 Каждый IRP, пока он активен, хранится в списке IRP, сопоставленном с потоком, который выдал запрос на ввод вывод. Это позволяет подсистеме ввода вывода найти и отменить любые незавершенные IRP, если выдавший их поток завершается. ЭКСПЕРИМЕНТ: просмотр незавершенных IRP потока Команда !thread выводит любые IRP, сопоставленные с потоком. Запус тите отладчик ядра в работающей системе и найдите процесс диспет чера управления сервисами (Services.exe) в выводе, сгенерированном командой !process: lkd> !process 0 0 **** NT ACTIVE PROCESS DUMP **** ... PROCESS 8a238da8 SessionId: 0 Cid: 02a8 Peb: 7ffdf000 ParentCid: 027c DirBase: 14fac000 ObjectTable: e1c3e008 HandleCount: 365. Image: SERVICES.EXE ... Теперь создайте дамп потоков для процесса, выполнив команду !process применительно к объекту «процесс». Вы должны увидеть мно жество потоков, у большинства из которых есть IRP; эти IRP отобра жаются в блоке IRP List информации о потоке (заметьте, что отладчик выводит лишь первые 17 IRP для потока, у которого имеется более 17 незавершенных запросов ввода вывода): kd> !process 8a238da8 PROCESS 8a238da8 SessionId: 0 Cid: 02a8 Peb: 7ffdf000 ParentCid: 027c DirBase: 14fac000 ObjectTable: e1c3e008 HandleCount: 365. Image: SERVICES.EXE VadRoot 8a1be328 Vads 88 Clone 0 Private 346. Modified 37. Locked 0. DeviceMap e10087c0 ... THREAD 8a124870 Cid 02a8.0338 Teb: 7ffd8000 Win32Thread: 00000000 WAIT: (WrQueue) UserMode NonAlertable 8a2dc620 Unknown 8a124960 NotificationTimer см. след. стр.
600 ГЛ А В А 9 БЕЗОПАСНОСТЬ IRP List: 8a20f770: 8a437780: 89b1de68: 8a0e6058: 8a0f1550: 8a3b3c18: 8a429190: 8a49f008: 8a227bc0: 8a2c2c00: (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 (0006,0094) Flags: 00000900 Mdl: 00000000 ... Выберите IRP и просмотрите его командой !irp: lkd> !irp 8a2c2c00 Irp is active with 1 stacks 1 is current (= 0x8a2c2c70) No Mdl Thread 8a124870: Irp stack trace. cmd flg cl Device File CompletionContext >[ 3, 0] 0 1 8a0e5680 8a26e4b8 0000000000000000 pending \Driver\Npfs Args: 00000400 00000000 00000000 00000000 У этого IRP основной номер функции — 3, что соответствует IRP_ MJ_READ. Он содержит один блок стека и адресован устройству, при надлежащему драйверу Npfs (Named Pipe File System). (Информацию о Npfs см. в главе 13.) Управление буфером IRP Когда приложение или драйвер устройства неявно создает IRP с помощью системного сервиса NtReadFile, NtWriteFile или NtDeviceIoControlFile (этим сервисам соответствуют Windows функции ReadFile, WriteFile и DeviceIoCont rol), диспетчер ввода вывода определяет, должен ли он участвовать в управ лении буферами ввода и вывода вызывающего потока. Диспетчер ввода вы вода поддерживает три вида управления буферами. 쐽 Буферизованный вводвывод (buffered I/O) Диспетчер ввода выво да выделяет в пуле неподкачиваемой памяти буфер, равный по размеру буферу вызывающего потока. Создавая IRP при операциях записи, диспет чер ввода вывода копирует данные из буфера вызывающего потока в вы деленный буфер. Завершая обработку IRP при операциях чтения, диспет чер ввода вывода копирует данные из выделенного буфера в пользова тельский буфер и освобождает выделенный буфер. 쐽 Прямой вводвывод (direct I/O) Создавая IRP, диспетчер ввода выво да блокирует пользовательский буфер в памяти (делает его неподкачивае мым). Закончив работу с IRP, диспетчер ввода вывода разблокирует буфер. Диспетчер хранит описание этой памяти в форме MDL (memory descriptor list). MDL указывает объем физической памяти, занятой буфером (подроб
ГЛАВА 9 Подсистема ввода-вывода 601 нее о MDL см. Windows DDK). Устройствам, использующим DMA (прямой доступ к памяти), требуется лишь физическое описание буфера, поэтому таким устройствам достаточно MDL. (Устройства, поддерживающие DMA, передают данные в память компьютера напрямую, не используя процес сор.) Но, если драйверу нужен доступ к содержимому буфера, он может спроецировать его на системное адресное пространство. 쐽 Вводвывод без управления (neither I/O) Диспетчер ввода вывода не участвует в управлении буферами. Ответственность за управление ими возлагается на драйвер устройства. При любом типе управления буферами диспетчер ввода вывода помеща ет в IRP ссылки на буферы ввода и вывода. Тип управления буферами, реа лизуемого диспетчером ввода вывода, зависит от типа управления, запро шенного драйвером для операций конкретного типа. Драйвер регистриру ет нужный ему тип управления буферами для операций чтения и записи в объекте «устройство», который представляет устройство. Операции управ ления вводом выводом на устройстве (выполняемые NtDeviceIoControlFile) задаются определенными в драйвере управляющими кодами ввода вывода. Управляющий код включает тип управления буферами со стороны диспет чера ввода вывода при обработке IRP с данным кодом. Когда вызывающие потоки передают запросы размером менее одной стра ницы (4 Кб на x86 процессорах), драйверы, как правило, используют буфе ризованный ввод вывод, а для запросов большего размера — прямой. Буфер примерно равен размеру страницы, и операция копирования с применени ем буферизованного ввода вывода приводит практически к тем же издержкам, что и прямой ввод вывод, требующий блокирования памяти. Драйверы фай ловой системы обычно используют третий тип управления, так как при копи ровании данных из кэша файловой системы в буфер вызывающего потока это позволяет избавиться от издержек, связанных с управлением буферами. Но большинство драйверов не использует этот вид управления из за того, что указатель на буфер вызывающего потока действителен лишь на то время, пока выполняется этот поток. Если драйверу нужно передать данные с устройства (или на устройство) при выполнении DPC процедуры или ISR, он должен по заботиться о доступности данных вызывающего потока из контекста любого процесса, а значит, у буфера должен быть системный виртуальный адрес. Драйверы, использующие ввод вывод без управления для доступа к буфе рам, которые могут быть расположены в пользовательском пространстве, должны проверять, что адреса буфера действительны и не ссылаются на па мять режима ядра. Если они этого не делают, появляется вероятность краха системы или уязвимости в системе защиты, так как приложения получают доступ к памяти режима ядра или возможность внедрения своего кода в ядро. Функции ProbeForRead и ProbeForWrite, которые ядро предоставляет драйве рам, проверяют, полностью ли умещается буфер в пользовательской части адресного пространства. Чтобы избежать краха из за ссылки на недопусти мый адрес, драйверы могут обращаться к буферам пользовательского режи ма из кода обработки исключений (блоков try/except), который перехваты
602 ГЛ А В А 9 БЕЗОПАСНОСТЬ вает любые попытки доступа по неправильным адресам и транслирует их в коды ошибок для передачи приложению. Запрос ввода-вывода к одноуровневому драйверу В этом разделе вы увидите, как обрабатывается запрос синхронного ввода вывода к одноуровневому драйверу режима ядра. Такая обработка проходит в семь этапов. 1. Запрос на ввод вывод передается через DLL подсистемы. 2. DLL подсистемы вызывает сервис NtWriteFile диспетчера ввода вывода. 3. Диспетчер ввода вывода создает IRP, описывающий запрос, и посылает его драйверу (в данном случае — драйверу устройства), вызывая свою функцию IoCallDriver. 4. Драйвер передает данные из IRP на устройство и инициирует операцию ввода вывода. 5. Драйвер уведомляет о завершении ввода вывода, генерируя прерывание. 6. Когда устройство завершает операцию и вызывает прерывание, драйвер устройства обслуживает прерывание. 7. Драйвер вызывает функцию IoCompleteRequest диспетчера ввода вывода, чтобы уведомить его о завершении обработки IRP, и диспетчер ввода вы вода завершает данный запрос на ввод вывод. Эти семь этапов показаны на рис. 9 10. Рис. 9-10. Обработка синхронного запроса
ГЛАВА 9 Подсистема ввода-вывода 603 Теперь, когда мы знаем, как инициируется ввод вывод, рассмотрим обслу живание прерывания и завершение ввода вывода. Обслуживание прерывания Завершая передачу данных, устройство генерирует прерывание, после чего в дело вступают ядро Windows, диспетчер ввода вывода и драйвер устрой ства. На рис. 9 11 показана первая фаза этого процесса. (Механизм диспет черизации прерываний, включая DPC, описывается в главе 3. Мы кратко повторяем этот материал, потому что DPC играют ключевую роль в обработ ке ввода вывода.) Рис. 9-11. Обслуживание прерывания от устройства (фаза 1) Когда устройство генерирует прерывание, процессор передает управле ние обработчику ловушки ядра, который находит ISR для этого устройства по таблице диспетчеризации прерываний. ISR в Windows обычно обрабаты вают прерывания от устройств в два этапа. При первом вызове ISR, как пра вило, остается на уровне Device IRQL ровно столько времени, сколько нуж но для того, чтобы сохранить состояние устройства и запретить дальнейшие прерывания от него. После этого ISR помещает DPC в очередь и, закрыв пре рывание, завершается. Впоследствии, при вызове DPC процедуры драйвер
604 ГЛ А В А 9 БЕЗОПАСНОСТЬ устройства заканчивает обработку прерывания, а затем вызывает диспетчер ввода вывода для завершения ввода вывода и удаления IRP. Этот драйвер так же может начать выполнение следующего запроса ввода вывода, ждущего в очереди устройства. Преимущество выполнения большей части обработки прерываний от устройств через DPC в том, что это разрешает любые блокируемые преры вания с приоритетами от «Device IRQL» до «DPC/dispatch» — пока не нача лась обработка DPC, имеющего более низкий приоритет. А за счет этого уда ется более оперативно (чем это могло бы быть в ином случае) обслуживать прерывания среднего приоритета. Вторая фаза ввода вывода (обработка DPC) показана на рис. 9 12. Завершение обработки запроса на ввод-вывод После того как DPC процедура драйвера выполнена, до завершения запро са на ввод вывод остается проделать кое какую оставшуюся работу. Третья стадия обработки ввода вывода называется завершением вводавывода (I/O completion) и начинается с вызова драйвером функции IoCompleteRequest для уведомления диспетчера ввода вывода о том, что обработка запроса, указан ного в IRP (и принадлежащих ему блоках стека), закончена. Действия, выпол няемые на этом этапе, различны для разных операций ввода вывода. Напри мер, все сервисы ввода вывода записывают результат операции в блок ста туса ввода вывода (I/O status block) — структуру данных, предоставляемую вызывающим потоком. Некоторые сервисы, выполняющие буферизованный ввод вывод, требуют возврата данных вызывающему потоку через подсисте му ввода вывода. В любом случае подсистема ввода вывода должна копировать отдельные данные из системной памяти в виртуальное адресное пространство процес са, которому принадлежит вызывающий поток. Если IRP выполняется синх ронно, это адресное пространство является текущим и доступно напрямую, но если IRP обрабатывается асинхронно, диспетчер ввода вывода должен отложить завершение IRP до тех пор, пока у него не появится возможность обращаться к нужному адресному пространству. Чтобы получить доступ к виртуальному адресному пространству процесса, которому принадлежит вызывающий поток, диспетчер ввода вывода должен передавать данные «в контексте вызывающего потока», т. е. при выполнении этого потока (иначе говоря, процесс этого потока должен быть текущим, а его адресное про странство — активным на процессоре). Эту задачу диспетчер ввода вывода решает, ставя в очередь данному потоку APC режима ядра (рис. 9 13). Как уже говорилось в главе 3, APC выполняется только в контексте опре деленного потока, а DPC — в контексте любого потока. Это означает, что DPC не затрагивает адресное пространство процесса пользовательского режима. Вспомните также, что приоритет программного прерывания у DPC выше, чем у APC.
ГЛАВА 9 Рис. 9-12. Подсистема ввода-вывода 605 Обслуживание прерывания от устройства (фаза 2) В следующий раз, когда поток начинает выполняться при низком IRQL, ему доставляется отложенный APC. Ядро передает управление APC процеду ре диспетчера ввода вывода, которая копирует данные (если они есть) и код возврата в адресное пространство процесса вызывающего потока, освобож дает IRP, представляющий данную операцию ввода вывода, и переводит опи сатель файла (и любое событие или порт завершения ввода вывода, если таковой объект предоставлен вызывающим потоком) в свободное состояние. Теперь ввод вывод считается завершенным. Вызывающий поток или любые другие потоки, ждущие на описателе файла (или иного объекта), выходят из состояния ожидания и переходят в состояние готовности к выполнению. Вторая фаза завершения ввода вывода показана на рис. 9 14.
606 ГЛ А В А 9 БЕЗОПАСНОСТЬ Рис. 9-13. Завершение обработки запроса на ввод-вывод (фаза 1) Рис. 9-14. Завершение обработки запроса на ввод-вывод (фаза 2)
ГЛАВА 9 Подсистема ввода-вывода 607 И последнее замечание о завершении ввода вывода. Функции асинхрон ного ввода вывода ReadFileEx и WriteFileEx принимают в качестве парамет ра APC пользовательского режима. Если поток передаст этот параметр, то на последнем этапе диспетчер ввода вывода направит соответствующий APC в очередь данного потока. Эта функциональность позволяет вызывающему потоку указывать процедуру, которую нужно вызывать после завершения или отмены запроса ввода вывода. Такие APC выполняются в контексте вызыва ющего потока и доставляются, только если поток переходит в состояние «тревожного» ожидания (как, например, при вызове Windows функции Sleep Ex, WaitForSingleObjectEx или WaitForMultipleObjectsEx). Синхронизация Драйверы должны синхронизировать свое обращение к глобальным данным и регистрам устройств в силу двух причин. 쐽 Выполнение драйвера может быть прервано из за вытеснения потоками с более высоким приоритетом, по истечении выделенного кванта процес сорного времени, а также из за генерации прерывания. 쐽 В многопроцессорных системах Windows может выполнять код драйве ра сразу на нескольких процессорах. Без синхронизации данные могут быть повреждены. Например, код драй вера устройства выполняется при IRQL уровня «passive». Какая то програм ма инициирует операцию ввода вывода, в результате чего возникает аппа ратное прерывание. Оно прерывает выполнение кода драйвера и активизи рует его ISR. Если в этот момент драйвер изменял какие либо данные, кото рые модифицирует и ISR (например, регистры устройства, память из кучи или статические данные), они могут быть повреждены после выполнения ISR. Эту проблему демонстрирует рис. 9 15. Рис. 9-15. Пример повреждения данных, используемых драйвером устройства, в отсутствие синхронизации
608 ГЛ А В А 9 БЕЗОПАСНОСТЬ Во избежание такой ситуации драйвер, написанный для Windows, должен синхронизировать обращение к любым данным, которые он разделяет со своей ISR. Прежде чем обновлять общие данные, драйвер должен заблоки ровать все остальные потоки (или процессоры, если система многопроцес сорная), чтобы запретить им доступ к тем же данным. Ядро Windows предоставляет специальную синхронизирующую проце дуру KeSynchronizeExecution, которую драйверы устройств должны вызывать при доступе к данным, разделяемым с ISR. Эта процедура не допускает вы полнения ISR, пока драйвер обращается к общим данным. В однопроцессор ных системах перед обновлением общих структур данных она повышает IRQL до уровня, сопоставленного с ISR. Но в многопроцессорных системах эта методика не гарантирует полной блокировки, так как код драйвера мо жет выполняться на двух и более процессорах одновременно. Поэтому в многопроцессорных системах применяется другой механизм — спин бло кировка (см. раздел «Синхронизация ядра» главы 3). Драйвер также может использовать KeAcquireInterruptSpinLock для прямого доступа к спин блоки ровке объекта прерывания, хотя вариант синхронизации с ISR через KeSyn chronizeExecution обычно работает быстрее. Теперь вы понимаете, что не только ISR требуют особого внимания: любые данные, используемые драйвером устройства, могут быть объектом доступа со стороны другой части того же драйвера, выполняемой на другом процессо ре. Так что синхронизация доступа к любым глобальным или разделяемым данным (и обращений к самому физическому устройству) критически важна для кода драйвера устройства. Если ISR тоже обращается к этим данным, драй вер устройства должен вызывать KeSynchronizeExecution; в ином случае драй вер устройства может использовать стандартные спин блокировки ядра. Запрос ввода-вывода к многоуровневому драйверу В предыдущем разделе мы рассмотрели обработку запроса на ввод вывод, адресованного простому устройству, которое управляется единственным драйвером устройства. Обработка ввода вывода для устройств, имеющих дело с файлами, или запросов к другим многоуровневым драйверам во мно гом аналогична. Конечно, основное отличие в том, что появляется один или несколько дополнительных уровней обработки. Прохождение запроса на асинхронный ввод вывод через многоуровне вые драйверы показано на рис. 9 16. Данный пример относится к диску, уп равляемому файловой системой. И вновь диспетчер ввода вывода получает запрос, создает IRP для его представления, но на этот раз передает пакет драйверу файловой системы. С этого момента драйвер файловой системы в основном и управляет опера цией ввода вывода. В зависимости от типа запроса файловая система посы лает драйверу диска тот же IRP или генерирует дополнительные IRP и пере дает их этому драйверу по отдельности.
ГЛАВА 9 Подсистема ввода-вывода 609 ЭКСПЕРИМЕНТ: просмотр стека устройства Команда !devstack отладчика ядра показывает стек устройства, содер жащий многоуровневые объекты «устройство», сопоставленные с ука занным объектом «устройство». В данном примере выводится стек ус тройства для объекта «устройство» \device\keyboardclass0, который принадлежит драйверу класса клавиатур: lkd> !devstack keyboardclass0 !DevObj !DrvObj !DevExt ObjectName 8a266d28 \Driver\Ctrl2cap 8a266de0 > 8a09a030 \Driver\Kbdclass 8a09a0e8 KeyboardClass0 8a2672b0 \Driver\nmfilter 8a267368 0000008c 8a09ba78 \Driver\i8042prt 8a09bb30 8a4adce0 \Driver\ACPI 8a4ab9c8 0000006b !DevNode 8a4acee8 : DeviceInst is "ACPI\PNP0303\4&61f3b4b&0" ServiceName is "i8042prt" Строка для KeyboardClass0 выделяется префиксом «>». Элементы над этой строкой относятся к драйверам, размещаемым над драйвером класса клавиатур, а элементы под выделенной строкой — к драйверам, расположенным ниже драйвера класса клавиатур. В целом, IRP пере даются по стеку сверху вниз. Файловая система скорее всего будет повторно использовать IRP, если полученный запрос можно преобразовать в единый запрос к устройству. Например, если приложение выдаст запрос на чтение первых 512 байтов из файла на дискете, файловая система FAT просто вызовет драйвер диска, по просив его считать один сектор с того места на дискете, где начинается нуж ный файл. Для поддержки использования несколькими драйверами IRP содержит набор блоков стека (не путать со стеком потока). Эти блоки данных — по одному на каждый вызываемый драйвер — хранят информацию, необходи мую каждому драйверу для обработки своей части запроса (например, но мер функции, параметры, сведения о контексте драйвера). Как показано на рис. 9 16, по мере передачи IRP от одного драйвера другому заполняются до полнительные блоки стека. IRP можно считать аналогом стека в отношении добавления и удаления данных. Но IRP не сопоставляется ни с каким процес сом, и его размер фиксирован. В самом начале операции ввода вывода дис петчер ввода вывода выделяет память для IRP в одном из ассоциативных списков IRP или в пуле неподкачиваемой памяти.
610 ГЛ А В А 9 Рис. 9-16. БЕЗОПАСНОСТЬ Обработка асинхронного запроса к многоуровневым драйверам ЭКСПЕРИМЕНТ: исследуем IRP В этом эксперименте вы найдете незавершенные IRP в системе и оп ределите тип IRP, устройство, которому он адресован, драйвер, управ ляющий этим устройством, поток, выдавший IRP, и процесс, к которо му относится данный поток. В любой момент в системе есть хотя бы несколько незавершенных IRP. Это вызвано тем, что существует много устройств, которым прило жения могут посылать IRP, а драйвер обрабатывает запрос только при возникновении определенного события, скажем, при появлении дан ных. Один из примеров — чтение с сетевого устройства. Увидеть неза вершенные IRP в системе позволяет команда !irpfind отладчика ядра:
ГЛАВА 9 Подсистема ввода-вывода 611 kd> !irpfind unable to get large pool allocation table  either wrong symbols or pool tagging is disabled Searching NonPaged pool (82502000 : 8a502000) for Tag: Irp? Irp [ Thread ] irpStack: (Mj,Mn) DevObj [Driver] 89695868 [00000000] Irp is complete (CurrentLocation 4 > StackCount 3) 0x43776f56 89712008 [8a29d7c0] irpStack: ( e, 9) 8a19e208 [ \Driver\AFD] 89716008 [8a29d7c0] irpStack: ( e, 9) 8a19e208 [ \Driver\AFD] ... 89cb3928 [8a3acbc0] irpStack: ( 3, 0) 8a09a030 [ \Driver\Kbdclass] 89cb3c88 [89cb1da8] irpStack: ( c, 2) 8a436020 [ \FileSystem\Ntfs] 89cb4640 [8a165498] irpStack: ( e, 9) 8a19e208 [ \Driver\AFD] Строка, выделенная в выводе, описывает IRP, адресованный драйве ру Kbdclass, так что этот IRP скорее всего был выдан потоком необра ботанного ввода для подсистемы Windows, принимающим ввод с кла виатуры. Изучение IRP с помощью команды !irp показывает следующее: kd> !irp 8a1716f0 Irp is active with 3 stacks 3 is current (= 0x8a1717a8) No Mdl System buffer = 8a458180 Thread 8a3acbc0: Irp stack trace. cmd flg cl Device File CompletionContext [ 0, 0] 0 0 00000000 00000000 0000000000000000 [ 0, 0] >[ 3, 0] Args: 00000000 00000000 00000000 00000000 0 0 00000000 00000000 0000000000000000 Args: 00000000 00000000 00000000 00000000 0 1 8a1eccb8 8a1262a8 0000000000000000 pending \Driver\Kbdclass Args: 00000078 00000000 00000000 00000000 Активный блок стека (помечаемый префиксом «>», находится в са мом низу. Основной номер функции равен 3, что соответствует IRP_ MJ_READ. Следующий шаг — выяснить, какому объекту «устройство» адресо ван IRP. Для этого выполните команду !devobj, указав адрес объекта «ус тройство», взятый из активного блока стека: kd> !devobj 8a1eccb8 Device object (8a1eccb8) is for: KeyboardClass1 \Driver\Kbdclass DriverObject 8a24bd78 Current Irp 00000000 RefCount 0 Type 0000000b Flags 00002044 Dacl e1ec01e4 DevExt 8a1ecd70 DevObjExt 8a1ece50 ExtensionFlags (0000000000) см. след. стр.
612 ГЛ А В А 9 БЕЗОПАСНОСТЬ AttachedTo (Lower) 8a2e8ac8 \Driver\TermDD Device queue is not busy. Устройство, которому адресован данный IRP, — KeyboardClass1. На личие объекта «устройство», принадлежащего драйверу Termdd, сооб щает, что этот объект представляет ввод от клиента службы термина лов, а не с физической клавиатуры. (Листинг был получен в системе с Windows XP.) Детальные сведения о потоке и процессе, выдавшем этот IRP, мож но просмотреть командами !thread и !process: kd> !thread 8a3acbc0 THREAD 8a3acbc0 Cid 025c.0288 Teb: 7ffd9000 Win32Thread: e101fab0 WAIT: rRequest) KernelMode Alertable 8a3cdb30 SynchronizationEvent 8a28b4e0 SynchronizationEvent 8a3cc908 NotificationTimer 8a294828 SynchronizationEvent 805453e0 NotificationEvent 8a2e1830 SynchronizationEvent 8a45eeb0 SynchronizationTimer IRP List: 89cb3928: (0006,01b4) Flags: 00000970 Mdl: 00000000 8a1716f0: (0006,01b4) Flags: 00000970 Mdl: 00000000 Not impersonating DeviceMap e10087c0 Owning Process 8a3a08b8 Wait Start TickCount 6844081 Context Switch Count 2130848 LargeStack UserTime 00:00:00.0000 KernelTime 00:00:03.0274 Start Address 0x75b6e8ad Stack Init bafa0000 Current baf9fa68 Base bafa0000 Limit baf9d000 Call 0 Priority 13 BasePriority 13 PriorityDecrement 0 DecrementCount 16 kd> !process 8a3a08b8 0 GetPointerFromAddress: unable to read from 80543ed4 PROCESS 8a3a08b8 SessionId: 0 Cid: 025c Peb: 7ffdf000 ParentCid: 0220 DirBase: 139af000 ObjectTable: e1c0b3d8 HandleCount: 581. Image: CSRSS.EXE Найдя этот поток в Process Explorer (www.sysinternals.com) на вклад ке Threads окна свойств для Csrss.exe, вы убедитесь, что, судя по име нам функций в его стеке, он действительно является потоком необра ботанного ввода (raw input thread) для подсистемы Windows.
ГЛАВА 9 Подсистема ввода-вывода 613 После того как драйвер диска завершает передачу данных, диск генери рует прерывание, и ввод вывод завершается (рис. 9 17). Рис. 9-17. Завершение обработки запроса на ввод-вывод к многоуровневым драйверам
614 ГЛ А В А 9 БЕЗОПАСНОСТЬ В качестве альтернативы повторному использованию единственного IRP файловая система может создать группу сопоставленных IRP (associated IRPs), которые будут обрабатываться параллельно. Например, если данные, которые нужно считать из файла, разбросаны по всему диску, драйвер фай ловой системы может создать несколько IRP, каждый из которых инициирует чтение данных из отдельного сектора. Этот случай иллюстрирует рис. 9 18. Рис. 9-18. Обработка с использованием сопоставленных IRP Драйвер файловой системы передает сопоставленные IRP драйверу уст ройства, который ставит их в очередь устройства. Они обрабатываются по одному, а файловая система отслеживает возвращаемые данные. Когда вы полнение всех сопоставленных IRP заканчивается, подсистема ввода выво да завершает обработку исходного IRP и возвращает управление вызываю щему потоку (рис. 9 19).
ГЛАВА 9 Рис. 9-19. Подсистема ввода-вывода 615 Завершение обработки сопоставленных IRP ПРИМЕЧАНИЕ Все драйверы, управляющие дисковыми файловыми системами в Windows, являются частью как минимум трехуровневого стека драйверов: драйвер файловой системы находится на верхнем уровне, диспетчер томов — на среднем, а драйвер диска — на нижнем. Кроме того, между этими драйверами может размещаться любое чис ло драйверов фильтров. Для ясности в предыдущем примере были по казаны лишь драйверы файловой системы и диска. Подробнее об уп равлении внешней памятью см. главу 10. Порты завершения ввода-вывода Создание высокопроизводительного серверного приложения требует реали зации эффективной модели многопоточности. Как нехватка, так и избыток
616 ГЛ А В А 9 БЕЗОПАСНОСТЬ серверных потоков, обрабатывающих клиентские запросы, приведет к про блемам с производительностью. Например, если сервер создает единствен ный поток для обработки всех запросов, клиенты будут «голодать», так как сервер будет обрабатывать по одному запросу единовременно. Конечно, единственный поток мог бы обрабатывать сразу несколько запросов, пере ключаясь с одной операции ввода вывода на другую. Однако такая архитек тура крайне сложна и не позволяет использовать преимущества многопро цессорных систем. Другая крайность — создание сервером огромного пула потоков, когда для обработки чуть ли не каждого клиентского запроса вы деляется свой поток. Этот сценарий обычно ведет к перегрузке процессоров потоками: множество потоков пробуждается, выполняет обработку данных, блокируется в ожидании ввода вывода, а после обработки запроса снова блокируется в ожидании нового запроса. Одно только наличие слишком большого количества потоков заставило бы планировщик чрезмерно часто переключать контекст, и в итоге он отобрал бы на себя немалую часть про цессорного времени. Задача сервера — свести к минимуму число переключений контекста, что бы избежать излишнего блокирования потоков, и в то же время добиться мак симального параллелизма в обработке за счет множества потоков. С этой точ ки зрения идеальна ситуация, при которой к каждому процессору подключен один активно обрабатывающий клиентские запросы поток, что позволяет обойтись без блокировки потоков, если на момент завершения обработки текущих запросов их ждут другие запросы. Однако такая оптимизация требу ет, чтобы у приложения была возможность активизировать другой поток, ког да поток, обрабатывающий клиентский запрос, блокируется в ожидании вво да вывода (например, для чтения файла в процессе обработки). Объект IoCompletion Приложения используют объект IoCompletion исполнительной системы, ко торый экспортируется в Windows как порт завершения (completion port) — фокальная точка завершения ввода вывода, сопоставляемая с множеством описателей файлов. Если какой нибудь файл сопоставлен с портом заверше ния, то по окончании любой операции асинхронного ввода вывода, связан ной с этим файлом, в очередь порта завершения ставится пакет завершения (completion packet). Ожидание завершения любой из операций ввода вывода в нескольких файлах может быть реализовано простым ожиданием соответ ствующего пакета завершения, который должен появиться в очереди порта завершения. Windows API поддерживает аналогичную функциональность через WaitForMultipleObjects, но порты завершения дают одно большое пре имущество: число потоков, активно обслуживающих клиентские запросы, контролируется самой системой. Создавая порт завершения, приложение указывает максимальное число сопоставленных с портом потоков, которые могут быть активны. Как уже говорилось, в идеале на каждом процессоре должно быть по одному актив ному потоку. Windows использует это значение для контроля числа актив
ГЛАВА 9 Подсистема ввода-вывода 617 ных потоков приложения. Если число активных потоков, сопоставленных с портом, равно заданному максимальному значению, выполнение потока, ждущего на порте завершения, запрещено. По завершении обработки теку щего запроса один из активных потоков проверяет, имеется ли в очереди порта другой пакет. Если да, он просто извлекает этот пакет из очереди и переходит к обработке соответствующих данных; контекст при этом не пе реключается. Использование портов завершения Высокоуровневая схема работы порта завершения представлена на рис. 9 20. Порт завершения создается вызовом Windows функции CreateIoCompletion Port. Потоки, блокированные на порте завершения, считаются сопоставлен ными с ним и пробуждаются по принципу LIFO («последним пришел — пер вым вышел»), т. е. следующий пакет достается потоку, заблокированному последним. Стеки потоков, блокируемых в течение длительного времени, могут быть выгружены в страничный файл. В итоге, если с портом сопостав лено больше потоков, чем нужно для обработки текущих заданий, система автоматически минимизирует объем памяти, занимаемой слишком долго блокируемыми потоками. Рис. 9-20. Так работает порт завершения ввода-вывода Серверное приложение обычно получает клиентские запросы через ко нечные точки, представляемые как описатели файлов. Пример — сокеты Windows Sockets 2 (Winsock2) или именованные каналы. Создавая конечные точки своих коммуникационных связей, сервер сопоставляет их с портом завершения, и серверные потоки ждут входящие запросы, вызывая для это го порта функцию GetQueuedCompletionStatus. Получив пакет из порта завер
618 ГЛ А В А 9 БЕЗОПАСНОСТЬ шения, поток начинает обработку запроса и становится активным. В процес се обработки данных поток может часто блокироваться, например из за необходимости считать данные из файла или записать их в него, а также из за синхронизации с другими потоками. Windows обнаруживает такие дей ствия и выясняет, что одним активным потоком на порте завершения стало меньше. Поэтому, как только поток блокируется и становится неактивным, операционная система пробуждает другой ждущий на порте завершения поток (если в очереди есть пакет). Microsoft рекомендует устанавливать максимальное число активных по токов на порте завершения примерно равным числу процессоров в систе ме. Имейте в виду, что это значение может быть превышено. Допустим, вы задали, что максимальное значение должно быть равно 1. При поступлении клиентского запроса выделенный для его обработки поток становится ак тивным. Поступает второй запрос, но второй поток не может продолжить его обработку, так как лимит уже достигнут. Затем первый поток блокирует ся в ожидании файлового ввода вывода и становится неактивным. Тогда ос вобождается второй поток и, пока он активен, завершается файловый ввод вывод для первого потока, в результате чего первый поток вновь активизи руется. С этого момента и до блокировки одного из потоков число активных потоков превышает установленный лимит на 1. API, предусмотренный для порта завершения, также позволяет серверно му приложению ставить в очередь порта завершения самостоятельно опре деленные пакеты завершения; для этого предназначена функция PostQueued CompletionStatus. Сервер обычно использует эту функцию для уведомления своих потоков о внешних событиях, например о необходимости коррект ного завершения работы. Как работает порт завершения ввода-вывода Windows приложения создают порты завершения вызовом Windows функ ции CreateIoCompletionPort с указанием NULL вместо описателя порта завер шения. Это приводит к выполнению системного сервиса NtCreateIoComple tion. Объект IoCompletion исполнительной системы, построенный на осно ве синхронизующего объекта ядра, называется очередью. Таким образом, системный сервис создает объект «порт завершения» и инициализирует объект «очередь» в памяти, выделенной для порта. (Указатель на порт ссы лается и на объект «очередь», так как последний находится в начальной об ласти памяти порта.) Максимальное число сопоставленных с портом пото ков, которые могут быть активны, указывается в объекте «очередь» при его инициализации; это значение, которое было передано в CreateIoCompletion Port. Для инициализации объекта «очередь» порта завершения NtCreateIo Completion вызывает функцию KeInitializeQueue. Когда приложение обращается к CreateIoCompletionPort для связывания описателя файла с портом, вызывается системный сервис NtSetInformation File, которому передается описатель этого файла. При этом класс информа ции для NtSetInformationFile устанавливается как FileCompletionInformation, и,
ГЛАВА 9 Подсистема ввода-вывода 619 кроме того, эта функция принимает описатель порта завершения и параметр CompletionKey, ранее переданный в CreateIoCompletionPort. Функция NtSet InformationFile производит разыменование описателя файла для получения объекта «файл» и создает структуру данных контекста завершения. Указатель на эту структуру NtSetInformationFile помещает в поле Com pletionContext объекта «файл». По завершении асинхронной операции вво да вывода для объекта «файл» диспетчер ввода вывода проверяет, отличает ся ли поле CompletionContext от NULL. Если да, он создает пакет завершения и ставит его в очередь порта завершения вызовом KeInsertQueue; при этом в качестве очереди, в которую помещается пакет, указывается порт. (Здесь объект «порт завершения» — синоним объекта «очередь».) Когда серверный поток вызывает GetQueuedCompletionStatus, выполняется системный сервис NtRemoveIoCompletion. После проверки параметров и пре образования описателя порта завершения в указатель на порт NtRemoveIo Completion вызывает KeRemoveQueue. Как видите, KeRemoveQueue и KeInsertQueue — это базовые функции, обес печивающие работу порта завершения. Они определяют, следует ли активизи ровать поток, ждущий пакет завершения ввода вывода. Объект «очередь» под держивает внутренний счетчик активных потоков и хранит такое значение, как максимальное число активных потоков. Если при вызове потоком KeRemove Queue текущее число активных потоков равно максимуму или превышает его, данный поток будет включен (в порядке LIFO) в список потоков, ждущих па кет завершения. Список потоков отделен от объекта «очередь». В блоке управ ления потоком имеется поле для указателя на очередь, сопоставленную с объек том «очередь»; если это поле пустое, поток не связан с очередью. Windows отслеживает потоки, ставшие неактивными из за ожидания на каких либо объектах, отличных от порта завершения, по указателю на оче редь, присутствующему в блоке управления потоком. Процедуры планиров щика, в результате выполнения которых поток может быть блокирован (Ke WaitForSingleObject, KeDelayExecutionThread и т. д.), проверяют этот указатель. Если он не равен NULL, они вызывают функцию KiActivateWaiterQueue, кото рая уменьшает счетчик числа активных потоков, сопоставленных с очере дью. Если конечное число меньше максимального и в очереди есть хотя бы один пакет завершения, первый поток из списка потоков очереди пробуж дается и получает самый старый пакет. И напротив, всякий раз, когда после блокировки пробуждается поток, связанный с очередью, планировщик вы полняет функцию KiUnwaitThread, увеличивающую счетчик числа активных потоков очереди. Наконец, в результате вызова Windows функции PostQueuedCompletionStatus выполняется системный сервис NtSetIoCompletion, который просто вставляет с помощью KeInsertQueue специальный пакет в очередь порта завершения. Порт завершения в действии показан на рис. 9 21. Хотя к обработке па кетов завершения готовы два потока, максимум, равный 1, допускает акти визацию только одного потока, связанного с портом завершения. Таким об разом, на этом порте завершения блокируется два потока.
620 ГЛ А В А 9 БЕЗОПАСНОСТЬ Рис. 9-21. Порт завершения ввода-вывода в действии Driver Verifier Утилита Driver Verifier (о которой мы уже рассказывали в главе 7) предостав ляет несколько параметров для проверки правильности операций, связан ных с вводом выводом. На рис. 9 22 в окне Driver Verifier Manager (Диспет чер проверки драйверов) в Windows Server 2003 эти параметры помечены флажками. Даже если вы не указываете никаких параметров, Verifier наблюдает за работой выбранных для верификации драйверов, следя за недопустимыми операциями, в том числе за вызовом функций пула памяти ядра при непра вильном уровне IRQL, попытками повторного освобождения свободной па мяти и запроса блоков памяти нулевого размера. Рис. 9-22. Параметры Driver Verifier, относящиеся к операциям ввода-вывода Параметры проверки ввода вывода перечислены ниже. 쐽 I/O Verification (Проверка вводавывода) Если этот параметр выб ран, диспетчер ввода вывода выделяет память под IRP пакеты для прове ряемых драйверов из специального пула и отслеживает его использова
ГЛАВА 9 Подсистема ввода-вывода 621 ние. Кроме того, Verifier вызывает крах системы по окончании обработ ки IRP с неправильным состоянием и при передаче неверного объекта «устройство» диспетчеру ввода вывода. (В Windows 2000 этот параметр назывался I/O Verification Level 1). 쐽 I/O Verification Level 2 (Проверка вводавывода уровня 2) Этот параметр существует только в Windows 2000; он просто ужесточает про верку операций обработки IRP и использования стека. 쐽 Enhanced I/O Verification (Расширенная проверка вводавыво да) Этот параметр впервые появился в Windows XP и включает мони торинг всех IRP для контроля того, что драйверы корректно помечают их при асинхронной обработке, что они правильно управляют блоками сте ка устройства и что они удаляют каждый объект «устройство» только раз. В дополнение Verifier случайным образом посылает драйверам ложные IRP, связанные с управлением электропитанием и WMI, изменяет порядок перечисления устройств и изменяет состояние IRP, связанных с PnP и электропитанием, по окончании их обработки; последнее позволяет вы явить драйверы, возвращающие неверное состояние из своих процедур диспетчеризации. 쐽 DMA Checking (Проверка DMA) DMA — аппаратно поддерживаемый механизм, позволяющий устройствам передавать данные в физическую память или получать их из нее без участия процессора. Диспетчер ввода вывода поддерживает ряд функций, используемых драйверами для плани рования DMA операций и управления ими. Данный параметр включает проверку правильности применения этих функций и буферов, предостав ляемых диспетчером ввода вывода для DMA операций. 쐽 Disk Integrity Verification (Проверка целостности диска) После включения этого параметра, доступного только в Windows Server 2003, Verifier ведет мониторинг операций чтения и записи на дисках и прове ряет контрольные суммы соответствующих данных. По окончании опе раций чтения с диска Verifier проверяет ранее сохраненные контрольные суммы и вызывает крах системы, если новая и старая контрольные сум мы не совпадают, так как это свидетельствует о повреждении диска на ап паратном уровне. 쐽 SCSI Verification (Проверка SCSI) Этот параметр появился в Windows XP и не виден в диалоговом окне параметров Driver Verifier. Однако он включается, когда вы выбираете для проверки минипорт драйвер SCSI и отмечаете хотя бы один из других параметров. Тогда Verifier следит, как минипорт драйвер SCSI использует функции, предоставляемые драйве ром библиотеки SCSI минипорта — storport.sys или scsiport.sys. При этом проверяется, что драйвер не обрабатывает запрос более одного раза, что он не передает недопустимые аргументы и что на выполнение операций не уходит больше определенного времени. (Подробнее о минипорт драй верах SCSI см. в главе 10.)
622 ГЛ А В А 9 БЕЗОПАСНОСТЬ Driver Verifier предназначен главным образом разработчикам драйверов устройств и помогает им обнаруживать ошибки в своем коде. Однако это еще и мощный инструмент для системных администраторов, позволяющий анализировать причины краха. Подробнее о роли Driver Verifier в анализе краха системы см. в главе 14. Диспетчер Plug and Play (PnP) Диспетчер PnP — основной компонент, от которого зависит способность Windows к распознаванию изменений в аппаратной конфигурации. Благо даря этому от пользователя не требуется знания тонкостей настройки уст ройств и системы при их установке и удалении. Так, диспетчер PnP позво ляет портативному компьютеру с Windows при подключении к стыковочной станции автоматически обнаруживать дополнительные устройства стыко вочной станции и делать их доступными пользователю. Поддержка Plug and Play требует взаимодействия на уровнях оборудова ния, драйверов устройств и операционной системы. Эта поддержка в Win dows базируется на промышленных стандартах перечисления и идентифи кации подключенных к шинам устройств. Например, стандарт USB опреде ляет способ самоидентификации устройств, подключенных к шине USB. На этой основе в Windows реализуются следующие возможности Plug and Play. 쐽 Диспетчер PnP автоматически распознает установленные устройства, и этот процесс включает перечисление устройств при загрузке и обнару жение их добавления или удаления во время работы системы. 쐽 Диспетчер PnP выделяет аппаратные ресурсы, собирая информацию о требованиях устройств к аппаратным ресурсам (прерывания, диапазоны адресов ввода вывода, регистры ввода вывода или ресурсы, специфичные для шин). В ходе арбитража ресурсов (resource arbitration) диспетчер PnP распределяет ресурсы между устройствами с учетом их требований. По скольку устройства могут быть добавлены в систему после распределения ресурсов на этапе загрузки, диспетчер PnP должен уметь перераспреде лять ресурсы. 쐽 Другая функция диспетчера PnP — загрузка соответствующих драйверов. На основе идентификационных данных устройства он определяет, уста новлен ли в системе драйвер, способный управлять этим устройством. Если да, диспетчер PnP указывает диспетчеру ввода вывода загрузить его. Если подходящий драйвер не установлен, диспетчер PnP режима ядра взаимодействует с диспетчером PnP пользовательского режима, чтобы установить устройство. При этом он может попросить пользователя ука зать местонахождение нужных драйверов. 쐽 Диспетчер PnP также реализует механизмы, позволяющие приложениям и драйверам обнаруживать изменения в аппаратной конфигурации. Иногда для работы драйверов и приложений требуется определенное устройство, поэтому в Windows имеются средства, которые дают возмож
ГЛАВА 9 Подсистема ввода-вывода 623 ность таким драйверам и приложениям запрашивать уведомления о на личии, добавлении и удалении устройств. Уровень поддержки Plug and Play Windows нацелена на полную поддержку Plug and Play, но конкретный уро вень поддержки зависит от устройств, подключенных к системе, и установ ленных в ней драйверов. Уровень поддержки Plug and Play может быть сни жен, если хотя бы один драйвер или устройство не отвечает стандарту Plug and Play. Более того, драйвер, не поддерживающий Plug and Play, может ли шить систему возможности использовать другие устройства. В таблице 9 2 показано, к каким результатам приводят различные сочетания устройств и драйверов с поддержкой Plug and Play и без нее. Таблица 9-2. Возможности устройств и драйверов в поддержке Plug and Play Устройство Драйвер PnP-совместимый PnP-несовместимый PnP совместимое Полная поддержка PnP Поддержка PnP невозможна PnP несовместимое Частичная поддержка PnP Поддержка PnP невозможна PnP несовместимое устройство, например унаследованная звуковая плата с ISA шиной, не поддерживает автоматическое определение. Из за этого та ким устройствам запрещены некоторые операции вроде «горячего» подклю чения или перехода в один из режимов сна. Если для такого устройства вруч ную установить PnP совместимый драйвер, он сможет по крайней мере ис пользовать ресурсы, которые диспетчер PnP будет выделять этому устройству. Унаследованные драйверы, например драйверы, разработанные для Win dows NT 4, не совместимы с Plug and Play. Хотя они работают в Windows, диспетчер PnP не сможет динамически перераспределять ресурсы, назна ченные таким устройствам. Допустим, унаследованное устройство исполь зует для ввода вывода диапазон памяти А или В. При загрузке системы дис петчер PnP выделяет этому устройству диапазон А. Если впоследствии в си стему будет добавлено устройство, способное использовать только диапазон А, диспетчер PnP не сможет указать драйверу первого устройства перенаст роить его на диапазон В. Из за этого второе устройство не получит нужные ресурсы и будет недоступно. Унаследованные драйверы также мешают пе реходу системы в один из режимов сна (см. раздел «Диспетчер электропи тания» далее в этой главе). Поддержка Plug and Play со стороны драйвера Для поддержки Plug and Play в драйвере должна быть реализована процеду ра диспетчеризации Plug and Play, а также процедура добавления устройства. Однако драйверы шин должны поддерживать типы запросов Plug and Play, отличные от тех, которые поддерживаются функциональными драйверами и драйверами фильтров. Так, при перечислении устройств в процессе загруз ки диспетчер PnP запрашивает у драйверов шин описание устройств, най
624 ГЛ А В А 9 БЕЗОПАСНОСТЬ денных ими на своих шинах. В это описание входят данные, уникально иден тифицирующие каждое устройство, а также требования устройств к аппарат ным ресурсам. Диспетчер PnP принимает эту информацию и загружает функ циональные драйверы или драйверы фильтров, установленные для обнару женных устройств. Затем он вызывает процедуру добавления устройства каждого драйвера, установленного для каждого устройства. Выполняя процедуру добавления устройства, функциональные драйверы и драйверы фильтров готовятся начать управление своими устройствами, но на самом деле пока еще не взаимодействуют с ними. Они ждут команду start device, которую диспетчер PnP должен передать их процедурам диспетчери зации Plug and Play. До передачи этой команды диспетчер PnP выполняет арбитраж ресурсов, чтобы решить, какие ресурсы выделить тому или иному устройству. В команде startdevice указываются назначенные ресурсы, опре деленные диспетчером PnP при арбитраже ресурсов. Получив команду start device, драйвер может настроить свое устройство на использование указан ных ресурсов. Если программа пытается открыть устройство, которое не готово к началу работы, она получает код ошибки, указывающий на отсут ствие этого устройства. После запуска устройства диспетчер PnP может посылать драйверу до полнительные PnP команды, в том числе относящиеся к удалению устрой ства из системы или перераспределению ресурсов. Например, когда пользо ватель запускает утилиту, показанную на рис. 9 23, — для ее запуска надо щелкнуть правой кнопкой мыши значок платы PC Card на панели задач и выбрать команду Unplug Or Eject Hardware (Отключение или извлечение аппаратного устройства), — и командует Windows извлечь PCMCIA плату, диспетчер PnP посылает уведомление queryremove каждому приложению, зарегистрированному на получение PnP уведомлений об этом устройстве. Как правило, приложения регистрируются на получение уведомлений через свои описатели устройства, которые они закрывают, получая уведомление queryremove. Если ни одно приложение не налагает вето на запрос query remove, диспетчер PnP посылает команду queryremove драйверу, управляю щему извлекаемым устройством. На этом этапе драйвер решает, что ему де лать дальше: запретить удаление устройства или завершить все операции ввода вывода на этом устройстве и прекратить дальнейший прием запросов на ввод вывод, направляемых устройству. Если драйвер отвечает согласием на запрос об удалении и открытых описателей устройства больше нет, дис петчер PnP посылает драйверу команду remove, требующую от него прекра тить обращение к устройству и освободить все ресурсы, выделенные им для данного устройства.
ГЛАВА 9 Рис. 9-23. Подсистема ввода-вывода 625 Утилита для отключения или извлечения платы PC Card Когда диспетчеру PnP нужно перераспределить ресурсы для устройства, он сначала запрашивает драйвер, может ли тот временно приостановить операции на устройстве, и с этой целью посылает команду querystop. Драй вер отвечает на этот запрос согласием, если нет риска потери или повреж дения данных; в ином случае он отклоняет такой запрос. Как и в случае ко манды queryremove, драйвер, согласившись с запросом, заканчивает неза вершенные операции ввода вывода и больше не передает этому устройству запросы на ввод вывод. (Новые запросы на ввод вывод драйвер обычно ста вит в очередь.) Далее диспетчер PnP посылает драйверу команду stop. На этом этапе диспетчер PnP может указать драйверу выделить устройству другие ресурсы, а потом послать команду startdevice. Команды Plug and Play вызывают переход устройства в строго определен ные состояния, которые в упрощенной форме представлены на рис. 9 24. (Некоторые состояния и команды Plug and Play на этой иллюстрации опу щены. Кроме того, этот вариант относится к диаграмме состояний, реали зуемой функциональными драйверами. Диаграмма состояний, реализуемых драйверами шин, гораздо сложнее.) Кстати, на рис. 9 24 показано одно из состояний, которое мы еще не обсудили, — устройство переходит в него после команды surpriseremove диспетчера PnP. Эта команда посылается при неожиданном удалении устройства из системы, например из за его отказа или из за извлечения PCMCIA платы без применения соответствующей ути литы. Команда surpriseremove заставляет драйвер немедленно прекратить всякое взаимодействие с устройством, так как оно больше не подключено к системе, и отменить любые незавершенные запросы ввода вывода.
626 ГЛ А В А 9 Рис. 9-24. БЕЗОПАСНОСТЬ Переходы PnP-состояний устройств Загрузка, инициализация и установка драйвера Драйвер может загружаться в Windows явно и на основе перечисления. Явную загрузку определяет ветвь реестра HKLM\SYSTEM\CurrentControlSet\Services, и на эту тему см. раздел «Сервисные приложения» главы 4. Загрузка на основе перечисления происходит при динамической загрузке диспетчером PnP драй веров для устройств, о наличии которых сообщает драйвер шины. Параметр Start В главе 4 мы объяснили, что у каждого драйвера и Windows сервиса есть свой раздел в ветви реестра Services текущего набора параметров управле ния. В этот раздел входят параметры, указывающие тип образа (например, Windows сервис, драйвер или файловая система), путь к файлу образа драй вера или сервиса и параметры, контролирующие порядок загрузки драйве ра или сервиса. Между загрузкой Windows сервисов и явной загрузкой драй веров есть два главных различия: 쐽 только для драйверов устройств в параметре Start могут быть указаны значения 0 (запуск при загрузке системы) и 1 (запуск системой); 쐽 драйверы устройств могут использовать параметры Group и Tag для конт роля порядка своей загрузки при запуске системы, но в отличие от серви сов не могут определять параметры DependOnGroup или DependOnService. В главе 5 мы рассмотрели этапы процесса загрузки и объяснили, что па раметр Start драйвера, равный 0, означает, что этот драйвер загружается заг рузчиком операционной системы. А если Start равен 1, драйвер загружается диспетчером ввода вывода после инициализации компонентов исполни тельной системы. Диспетчер ввода вывода вызывает инициализирующие процедуры драйверов в том порядке, в каком драйверы загружались при за пуске системы. Как и Windows сервисы, драйверы используют параметр
ГЛАВА 9 Подсистема ввода-вывода 627 Group в своем разделе реестра, чтобы указать группу, к которой они принад лежат; порядок загрузки групп определяется параметром HKLM\SYSTEM\ CurrentControlSet\Control\ServiceGroupOrder\List. Драйвер может еще больше детализировать порядок своей загрузки с помощью параметра Tag, который указывает конкретную позицию драйве ра в группе. Диспетчер ввода вывода сортирует драйверы в группе по значе ниям параметров Tag, определенных в разделах реестра, соответствующих этим драйверам. Драйверы, не имеющие параметра Tag, перемещаются в ко нец списка драйверов группы. Вы могли предположить, что диспетчер вво да вывода сначала инициализирует драйверы с меньшими значениями Tag, потом — с бьльшими, но это не так. Приоритет значений параметров Tag в рамках группы определяется в HKLM\SYSTEM\CurrentControlSet\Control\ GroupOrderList; этот раздел реестра дает Microsoft и разработчикам драйве ров свободу в определении собственной системы целых чисел. Вот правила, по которым драйверы устанавливают значение своего пара метра Start. 쐽 Драйверы, не поддерживающие Plug and Play, настраивают Start так, что бы система загружала их на определенном этапе своего запуска. 쐽 Драйверы, которые должны загружаться системным загрузчиком при за пуске операционной системы, указывают в Start значение 0 (запуск при загрузке системы). Пример — драйверы системных шин и драйвер фай ловой системы, используемый при загрузке системы. 쐽 Драйвер, который не требуется для загрузки системы и распознает уст ройство, не перечисляемое драйвером системной шины, указывает в Start значение, равное 1 (запуск системой). Пример — драйвер последователь ного порта, информирующий диспетчер PnP о присутствии стандартных последовательных портов, которые были обнаружены программой Setup и зарегистрированы в реестре. 쐽 Драйвер, не поддерживающий Plug and Play, или драйвер файловой сис темы, не обязательный для загрузки системы, устанавливает значение Start равным 2 (автозапуск). Пример — драйвер многосетевого UNC про вайдера (Multiple UNC Provider, MUP), поддерживающий UNC имена уда ленных ресурсов (вроде \\REMOTECOMPUTERNAME\SHARE). 쐽 PnP драйверы, не нужные для загрузки системы (например, драйверы сете вых адаптеров), указывают значение Start равным 3 (запуск по требованию). Единственное предназначение параметра Start для PnP драйверов и драй веров перечисляемых устройств — загрузка драйвера с помощью загрузчика операционной системы, если такой драйвер обязателен для успешного запус ка системы. Перечисление устройств Диспетчер PnP начинает перечисление устройств с виртуального драйвера шины с именем Root, который представляет всю систему и выступает в роли драйвера шины для драйверов, не поддерживающих Plug and Play, и для HAL.
628 ГЛ А В А 9 БЕЗОПАСНОСТЬ HAL работает как драйвер шины, перечисляющий устройства, напрямую под ключенные к материнской плате, и такие системные компоненты, как акку муляторы. Определяя основную шину (обычно это PCI шина) и устройства типа аккумуляторов и вентиляторов, HAL на самом деле полагается на опи сание оборудования, зафиксированное программой Setup в реестре еще при установке операционной системы. Драйвер основной шины перечисляет устройства на этой шине, при этом он может найти другие шины, драйверы которых инициализируются дис петчером PnP. Эти драйверы в свою очередь могут обнаруживать другие ус тройства, включая вспомогательные шины. Такой рекурсивный процесс — перечисление, загрузка драйвера (если он еще не загружен), дальнейшее перечисление — продолжается до тех пор, пока не будут обнаружены и скон фигурированы все устройства в системе. По мере поступления сообщений от драйверов шин об обнаруженных устройствах, диспетчер PnP формирует внутреннее дерево, называемое де ревом устройств (device tree) и отражающее взаимосвязи между устройства ми. Узлы этого дерева называются узлами устройств (device nodes, dev nodes). Узел устройств содержит информацию об объектах «устройство», представляющих устройства, и другую PnP информацию, которая записыва ется в узел диспетчером PnP. Упрощенный пример дерева устройств пока зан на рис. 9 25. Эта система ACPI совместима, и поэтому перечислителем основной шины является ACPI совместимый HAL. К основной шине PCI в данной системе подключены шины USB, ISA и SCSI. Рис. 9-25. Пример дерева устройств
ГЛАВА 9 Подсистема ввода-вывода 629 Диспетчер устройств, доступный из оснастки Computer Management (Уп равление компьютером) и с вкладки Hardware (Оборудование) окна свойств системы, отображает простой список устройств в системе, сконфигуриро ванной по умолчанию. Для просмотра устройств в виде иерархического де рева можно выбрать в меню View (Вид) диспетчера устройств команду Devi ces By Connection (Устройства по подключению). Рис. 9 26 иллюстрирует, как выглядит окно диспетчера устройств при выборе этой команды. Рис. 9-26. Диспетчер устройств, показывающий дерево устройств С учетом перечисления устройств загрузка и инициализация драйверов происходит в следующем порядке. 1. Диспетчер ввода вывода вызывает входную процедуру каждого драйвера, запускаемого при загрузке системы. Если у такого драйвера имеются до черние устройства, диспетчер ввода вывода перечисляет эти устройства, сообщая о них диспетчеру PnP. Дочерние устройства конфигурируются и запускаются, если их драйверы являются запускаемыми при загрузке системы. Если у устройства есть драйвер, не запускаемый при загрузке системы, диспетчер PnP создает для этого устройства узел, но не запус кает устройство и не загружает его драйвер. 2. После инициализации драйверов, запускаемых при загрузке системы, диспетчер PnP проходит по дереву устройств, загружая драйверы для уз лов устройств, не загруженных на первом этапе, и запускает их устрой ства. Запуская каждое устройство, диспетчер PnP перечисляет его дочер ние устройства (если таковые есть). Для этого он запускает соответству ющие драйверы и при необходимости перечисляет их дочерние устрой ства. На данном этапе диспетчер PnP загружает драйверы для обнаружен ных устройств независимо от значений параметров Start этих драйве
630 ГЛ А В А 9 БЕЗОПАСНОСТЬ ров (кроме тех драйверов, параметр Start которых содержит значение «отключен»). В конце этого этапа драйверы всех PnP устройств загруже ны и запущены, кроме драйверов не перечисляемых устройств и их до черних устройств. 3. Диспетчер PnP загружает любые еще не загруженные драйверы, запуска емые системой. Эти драйверы определяют свои устройства, не перечис ляемые обычным образом, и сообщают о них. После этого диспетчер PnP загружает драйверы для этих устройств. 4. Наконец, диспетчер управления сервисами (SCM) загружает автоматичес ки запускаемые драйверы. Дерево устройств используется диспетчерами PnP и электропитания в то время, когда они выдают устройствам IRP пакеты, связанные с Plug and Play и управлением электропитанием. Как правило, поток IRP распространяется от верхней части узла устройств вниз, и иногда какой либо драйвер в одном из узлов устройств создает новые IRP для передачи другим узлам (всегда в направлении корня). О потоках IRP пакетов, связанных с Plug and Play и уп равлением электропитанием, мы поговорим позже. ЭКСПЕРИМЕНТ: получаем дамп дерева устройств Команда !devnode отладчика ядра позволяет более подробно изучить дерево устройств. Задав 0 и 1 в качестве параметров, вы получите дамп внутренних структур узлов этого дерева. При этом элементы структур выводятся с отступами, отражающими позиции элементов в общей иерархии. lkd> !devnode 0 1 Dumping IopRootDeviceNode (= 0x8a4b7ee8) DevNode 0x8a4b7ee8 for PDO 0x8a4b7020 InstancePath is "HTREE\ROOT\0" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0x8a4b7a50 for PDO 0x8a4b7b98 InstancePath is "Root\ACPI_HAL\0000" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0x8a4af448 for PDO 0x8a4eb2c8 InstancePath is "ACPI_HAL\PNP0C08\0" ServiceName is "ACPI" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0x8a4af198 for PDO 0x8a4b1350 InstancePath is "ACPI\GenuineIntel__x86_Family_6_ Model_9\_0" ServiceName is "gv3" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d)
ГЛАВА 9 Подсистема ввода-вывода 631 DevNode 0x8a4e8008 for PDO 0x8a4a8950 InstancePath is "ACPI\ThermalZone\THM_" State = DeviceNodeStarted (0x308) Previous State = DeviceNodeEnumerateCompletion (0x30d) DevNode 0x8a4e82b8 for PDO 0x8a4eb640 InstancePath is "ACPI\ACPI0003\2&daba3ff&0" ServiceName is "CmBatt" ... Информация, показываемая для каждого узла устройств, включает InstancePath (имя подраздела для перечисленного устройства в HKLM\ SYSTEM\CurrentControlSet\Enum) и ServiceName (имя подраздела для драйвера устройства в HKLM\SYSTEM\CurrentControlSet\Services). Что бы просмотреть такие ресурсы, как прерывания, порты и диапазоны памяти, назначенные каждому узлу устройств, используйте команду !devnode 0 3. Все устройства, обнаруженные после установки системы, регистрируются в подразделах раздела реестра HKLM\SYSTEM\CurrentControlSet\Enum. Этим подразделам присваиваются имена в виде <Перечислитель>\<ID_устрой ства>\<ID_экземпляра>, где перечислитель — драйвер шины, ID_устрой ства — уникальный идентификатор устройств данного типа, а ID_экземп ляра — уникальный идентификатор данного экземпляра этого устройства. Узлы устройств Узел устройств, который включает минимум два объекта «устройство», по казан на рис. 9 27. Рис. 9-27. Внутренняя структура узла устройств
632 ГЛ А В А 9 БЕЗОПАСНОСТЬ 쐽 Объект «физическое устройство» (physical device object, PDO) Соз дается драйвером шины по заданию диспетчера PnP, когда драйвер ши ны, перечисляя устройства на своей шине, сообщает о наличии какого либо устройства. PDO представляет физический интерфейс устройства. 쐽 Необязательные группы объектовфильтров (filter device objects, FiDO) Одна группа таких объектов размещается между PDO и FDO (соз дается драйверами фильтров шин), вторая — между FDO и первой груп пой FiDO (создается низкоуровневыми драйверами фильтров), третья — над FDO (создается высокоуровневыми драйверами фильтров). 쐽 Объект «функциональное устройство» (functional device object, FDO) Создается функциональным драйвером, который загружается дис петчером PnP для управления обнаруженным устройством. FDO представ ляет логический интерфейс устройства. Функциональный драйвер может выступать и в роли драйвера шины, если к устройству, представленному FDO, подключены другие устройства. Этот драйвер часто создает интер фейс к PDO, соответствующему данному FDO, что позволяет приложени ям и другим драйверам открывать устройство и взаимодействовать с ним. Иногда функциональные драйверы подразделяются на драйвер класса, порт драйвер и минипорт драйвер, совместно управляющие вводом вы водом для FDO. Узлы устройств полагаются на функциональность диспетчера ввода вы вода; поток IRP идет по узлу устройств сверху вниз. Решение об окончании обработки IRP может быть принято на любом уровне узла устройств. Напри мер, функциональный драйвер может обработать запрос на чтение, не пе ресылая IRP драйверу шины. IRP проходит весь путь сверху вниз и далее к узлу устройств, содержащему драйвер шины, только если функциональному драйверу нужна помощь драйвера шины. Загрузка драйверов для узла устройств До сих пор мы так и не ответили на два важных вопроса: как диспетчер PnP определяет, какой функциональный драйвер нужно загрузить для данного устройства и как драйверы фильтров регистрируют свое присутствие, что бы их можно было загружать при создании узла устройств? Ответ на оба вопроса надо искать в реестре. Перечисляя устройства, драй вер шины сообщает диспетчеру PnP идентификаторы обнаруженных уст ройств. Эти идентификаторы специфичны для конкретной шины. Напри мер, для шины USB такой идентификатор состоит из идентификатора изго товителя (vendor ID, VID) и идентификатора продукта (product ID, PID), на значенного устройству изготовителем (подробнее о форматах идентифика торов устройств см. в DDK). В совокупности эти идентификаторы образуют то, что в терминологии спецификации Plug and Play называется идентифи катором устройства (device ID). Диспетчер PnP также запрашивает у драй вера шины идентификатор экземпляра (instance ID), который позволяет различать отдельные экземпляры одного и того же устройства. Идентифи
ГЛАВА 9 Подсистема ввода-вывода 633 катор экземпляра может определять устройство относительно шины (напри мер, USB порт) или представлять глобально уникальный дескриптор (ска жем, серийный номер устройства). Идентификаторы устройства и экземп ляра дают идентификатор экземпляра устройства (device instance ID, DIID), используемый диспетчером PnP для поиска раздела устройства в вет ви реестра HKLM\SYSTEM\CurrentControlSet\Enum. Пример такого раздела для клавиатуры показан на рис. 9 28. В эти разделы помещаются данные, ха рактеризующие устройство, и получаемые из INF файла параметры Service и ClassGUID, с помощью которых диспетчер PnP находит драйверы, нужные для данного устройства. Рис. 9-28. Раздел реестра для клавиатуры, создаваемый в процессе перечисления ЭКСПЕРИМЕНТ: просмотр детальных сведений об узлах устройств в диспетчере устройств По умолчанию апплет Device Manager (Диспетчер устройств), доступ ный с вкладки Hardware (Оборудование) окна свойств системы, не показывает детальных сведений об узле устройств. Однако в Windows XP и Windows Server 2003 вы можете активизировать вкладку Details (Сведения), создав переменную окружения devmgr_show_details и при своив ей значение 1. На этой вкладке отображается целый набор по лей, в том числе идентификатор экземпляра устройства для узла, имя сервиса, фильтры и возможности в управлении электропитанием. Самый простой способ запустить диспетчер устройств с вкладкой Details — открыть окно командной строки и ввести: C:\>set devmgr_show_details=1 C:\>devmgmt.msc см. след. стр.
634 ГЛ А В А 9 БЕЗОПАСНОСТЬ На следующем экранном снимке показано, как выглядит содержи мое этой вкладки для одного из устройств. Параметр ClassGUID позволяет диспетчеру PnP найти раздел класса уст ройства в HKLM\SYSTEM\CurrentControlSet\Control\Class. Раздел класса кла виатур показан на рис. 9 29. Раздел, созданный для устройства в процессе перечисления, и раздел класса предоставляют диспетчеру PnP всю инфор мацию, на основе которой он загружает драйверы, необходимые для узла данного устройства. Загрузка драйверов происходит в следующем порядке. 1. Любые низкоуровневые драйверы фильтров, указанные в параметре Lo werFilters раздела, созданного для устройства в процессе перечисления. 2. Любые низкоуровневые драйверы фильтров, указанные в параметре Lo werFilters раздела класса данного устройства. 3. Функциональный драйвер, заданный в параметре Service раздела, создан ного для устройства в процессе перечисления. Значение этого парамет ра интерпретируется как имя раздела драйвера в HKLM\SYSTEM\Current ControlSet\Services. 4. Любые высокоуровневые драйверы фильтров, указанные в параметре UpperFilters раздела, созданного для устройства в процессе перечисления. 5. Любые высокоуровневые драйверы фильтров, указанные в параметре UpperFilters раздела класса данного устройства. Ссылки на драйверы всегда содержат имена их разделов в HKLM\SYSTEM\ CurrentControlSet\Services.
ГЛАВА 9 Рис. 9-29. Подсистема ввода-вывода 635 Раздел класса клавиатур ПРИМЕЧАНИЕ В DDK раздел, созданный для устройства в процессе перечисления, называется аппаратным (hardware key), а раздел клас са — программным (software key). Устройство «клавиатура», представленное на рис. 9 28 и 9 29, не имеет низкоуровневых драйверов фильтров. Его функциональный драйвер — i8042prt; в разделе класса клавиатур указано два высокоуровневых драйве ра фильтров — kbdclass и ctrl2cap. Установка драйвера Если диспетчер PnP встречает устройство, драйвер которого не установлен, он обращается к диспетчеру PnP пользовательского режима, и тот устанав ливает нужный драйвер. Если устройство обнаруживается при загрузке сис темы, для него определяется узел устройств, но загрузка драйверов отклады вается до запуска диспетчера PnP пользовательского режима (он реализован в \Windows\System32\Umpnpmgr.dll и выполняется как сервис в процессе Services.exe). Компоненты, участвующие в установке драйвера, показаны на рис. 9 30. Серые блоки на этом рисунке соответствуют компонентам, обычно предос тавляемым системой, а остальные блоки — компонентам, предоставляемым установочными файлами. Сначала драйвер шины информирует диспетчер PnP о перечисленном устройстве, сообщая его DIID (1). Диспетчер PnP про веряет, определен ли в реестре подходящий функциональный драйвер. Если нет, он уведомляет диспетчер PnP пользовательского режима (2) о новом устройстве, сообщая его DIID. Диспетчер PnP пользовательского режима пытается автоматически установить драйверы для устройства. Если в процес се установки выводятся диалоговые окна, требующие внимания пользовате ля, а зарегистрированный в данный момент пользователь имеет привилегии
636 ГЛ А В А 9 БЕЗОПАСНОСТЬ администратора (3), то диспетчер PnP пользовательского режима запуска ет Rundll32.exe (хост программу апплетов Control Panel) для выполнения мастера установки оборудования (\Windows\System32\Newdev.dll). Если за регистрированный в данный момент пользователь не имеет привилегий ад министратора (или в системе нет пользователей), а установка устройства требует взаимодействия с пользователем, диспетчер PnP пользовательского режима откладывает установку до того момента, когда в систему войдет при вилегированный пользователь. Для поиска INF файлов, соответствующих драйверам, совместимым с обнаруженным устройством, мастер установки оборудования использует API функции Setup и CfgMgr (диспетчера конфи гурации). При этом пользователю может быть предложено вставить в один из дисководов носитель с нужными INF файлами; кроме того, просматрива ются INF файлы в \Windows\Driver Cache\i386\Driver.cab, где содержатся драйверы, поставляемые с Windows. Рис. 9-30. Компоненты, участвующие в установке драйвера Чтобы найти драйверы для нового устройства, процесс установки полу чает от драйвера шины список идентификаторов оборудования (hardware ID) и идентификаторов совместимых устройств (compatible ID). Эти иден тификаторы описывают все способы, предусмотренные в установочном файле драйвера (INF файле) для идентификации устройства. Списки упоря дочиваются так, чтобы наиболее специфические характеристики устройства описывались первыми. Если совпадения идентификаторов обнаруживают ся в нескольких INF файлах, предпочтение отдается наиболее полным совпа дениям. Аналогичным образом предпочтение отдается INF файлам с цифро вой подписью, а среди них — более новым. Если найденный идентификатор
ГЛАВА 9 Подсистема ввода-вывода 637 соответствует идентификатору совместимого устройства, мастер установки оборудования может запросить носитель с обновленными драйверами для этого устройства. INF файл определяет местонахождение файлов функционального драй вера и содержит команды, которые вводят нужные данные в раздел перечис ления и раздел класса драйвера. INF файл может указать мастеру установки оборудования запустить DLL установщика класса или компонента, участву ющего в установке устройства (4), — эти модули выполняют операции, спе цифичные для класса или устройства, например выводят диалоговые окна, позволяющие настраивать параметры устройства. ЭКСПЕРИМЕНТ: просмотр INF-файла драйвера При установке драйвера или другого программного обеспечения, у которого есть INF файл, система копирует этот файл в каталог \Win dows\Inf. Один из файлов, которые всегда будут в этом каталоге, — Keyboard.inf, поскольку это INF файл для драйвера класса клавиатур. Просмотрите его содержимое, открыв в Notepad. Вы должны увидеть нечто вроде: ; Copyright (c) 19931996, Microsoft Corporation [version] signature="$Windows NT$" Class=Keyboard ClassGUID={4D36E96BE32511CEBFC108002BE10318} Provider=%MS% LayoutFile=layout.inf DriverVer=07/01/2001,5.1.2600.1106 [ClassInstall32.NT] AddReg=keyboard_class_addreg ... Если вы проведете поиск в этом файле по «.sys», то обнаружите за пись, указывающую диспетчеру PnP пользовательского режима уста новить драйверы i8042prt.sys и kbdclass.sys: ... [STANDARD_CopyFiles] i8042prt.sys kbdclass.sys ... Перед установкой драйвера диспетчер PnP пользовательского режима проверяет системную политику проверки цифровых подписей в драйверах. Эта политика хранится в разделе реестра HKLM\SOFTWARE\Microsoft\Driver Signing\Policy, если администратор выбрал общесистемную политику, или в HKCU\Software\Microsoft\Driver Signing\Policy, если в системе применяются
638 ГЛ А В А 9 БЕЗОПАСНОСТЬ политики только по отношению к индивидуальным пользователям. Полити ка проверки цифровых подписей в драйверах настраивается через диалого вое окно Driver Signing Options (Параметры подписывания драйвера), дос тупное с вкладки Hardware (Оборудование) окна свойств системы (рис. 9 31). Если указанные параметры заставляют систему блокировать установку не подписанных драйверов или предупреждать о таких попытках, диспетчер PnP пользовательского режима проверяет в INF файле драйвера запись, ука зывающую на каталог (файл с расширением .cat), где содержится цифровая подпись драйвера. Рис. 9-31. Параметры проверки цифровых подписей в драйверах Лаборатория Microsoft WHQL тестирует драйверы, поставляемые с Win dows и предлагаемые изготовителями оборудования. Драйвер, прошедший тесты WHQL, «подписывается» Microsoft. Это означает, что создается хэш, или уникальное значение, представляющее файлы драйвера, в том числе его об раз, а затем этот хэш подписывается с применением закрытого ключа Micro soft, предназначенного для подписания драйверов. Подписанный хэш поме щается в CAT файл и записывается на дистрибутив Windows или передается изготовителю, который включает его в свой драйвер. ЭКСПЕРИМЕНТ: просмотр CAT-файлов При установке компонента, например драйвера, файлы которого вклю чают CAT файл, Windows копирует этот файл в подкаталог каталога \Windows\System32\Catroot. Перейдите в этот каталог с помощью Exp lorer и найдите подкаталог с CAT файлами. В частности, в Nt5.cat и Nt5inf.cat хранятся подписи для системных файлов Windows. Открыв один из CAT файлов, вы увидите диалоговое окно с двумя вкладками: General (Общие), на которой показывается информация о подписи в данном файле, и Security Catalog (Каталог безопасности), где представлены хэши компонентов, подписанных с использованием
ГЛАВА 9 Подсистема ввода-вывода 639 этого CAT файла. Ниже дан пример CAT файла для видеодрайверов ATI, где приведено содержимое хэша для минипорт драйверов видеоадап тера. Остальные хэши в этом файле относятся к вспомогательным DLL, поставляемым с данными драйверами. При установке драйвера диспетчер PnP пользовательского режима извле кает из CAT файла подпись драйвера, расшифровывает ее с применением открытого ключа Microsoft и сравнивает полученный в результате хэш с хэ шем файла устанавливаемого драйвера. Если хэши совпадают, драйвер счи тается проверенным на соответствие требованиям WHQL. Если проверка заканчивается неудачно, диспетчер PnP пользовательского режима действует так, как это диктует действующая политика: запрещает установку, предупреж дает пользователя о том, что драйвер не подписан, или автоматически уста навливает драйвер. ПРИМЕЧАНИЕ Наличие подписей у драйверов, устанавливаемых про граммами установки, которые самостоятельно настраивают реестр и копируют файлы драйвера в систему, а также у драйверов, динамичес ки загружаемых приложениями, не проверяется. Политика проверки подписей драйверов распространяется только на драйверы, устанав ливаемые с помощью INF файлов. После установки драйвера диспетчер PnP режима ядра (этап 5 на рис. 9 30) запускает драйвер и вызывает его процедуру добавления устройства, чтобы уве домить драйвер о присутствии устройства, для управления которым он был загружен. Далее формируется узел устройства, как мы уже объясняли. ПРИМЕЧАНИЕ В Windows XP и Windows Server 2003 диспетчер PnP пользовательского режима также проверяет, не включен ли устанавли ваемый драйвер в защищенный список драйверов (protected driver list), поддерживаемых Windows Update, и, если включен, блокирует установ
640 ГЛ А В А 9 БЕЗОПАСНОСТЬ ку с выводом предупреждения для пользователя. В этот список вносят ся драйверы, которые имеют известные ошибки или просто несовме стимы, и их установка блокируется. Детали см. по ссылке www.micro soft.com/whdc/winlogo/drvsign/drv_protect.mspx. Диспетчер электропитания Как и PnP функции Windows, управление электропитанием требует аппарат ной поддержки. Она должна отвечать спецификации Advanced Configuration and Power Interface (ACPI) (см. www.teleport.com/~acpi/spec.htm). Согласно этой спецификации BIOS (Basic Input Output System) тоже должна соответство вать стандарту ACPI. Этим требованиям удовлетворяет большинство x86 компьютеров, выпускавшихся с конца 1998 года. ПРИМЕЧАНИЕ Некоторые компьютеры — особенно те, которые были изготовлены несколько лет назад, — не полностью совместимы со стандартом ACPI. Они соответствуют более старому стандарту Advan ced Power Management (APM), определяющему меньшее количество функций управления электропитанием, чем ACPI. Windows поддержи вает ограниченный набор функций управления электропитанием для APM систем, но мы не будем вдаваться в детали этого стандарта и ос новное внимание уделим поведению Windows, установленной на ACPI совместимых компьютерах. Стандарт ACPI определяет различные уровни энергопотребления для си стемы и устройств. Шесть состояний для системы — от S0 (полностью актив ное, или рабочее, состояние) до S5 (полное отключение) — перечислены в таблице 9 3. Каждое из них характеризуется следующими параметрами. 쐽 Энергопотребление (power consumption) требляемой компьютером. Количество энергии, по 쐽 Возобновление работы ПО (software resumption) Состояние про граммного обеспечения при переходе компьютера в «более активное» со стояние. 쐽 Аппаратная задержка (hardware latency) Время, необходимое на то, чтобы вернуть компьютер в полностью активное состояние. Таблица 9-3. Определения состояний системы с различным энергопотреблением Состояние Энергопотребление Возобновление работы ПО Аппаратная задержка S0 (fully on) (полностью активное состояние) Максимальное — Нет S1 (sleeping) (состояние ожидания) Менее S0, но более S2 Система возобновляет ра Менее 2 секунд боту с той точки, где она была прервана (возвра щается в состояние S0)
ГЛАВА 9 Подсистема ввода-вывода 641 Таблица 9-3. (окончание) Возобновление работы ПО Аппаратная задержка Состояние Энергопотребление S2 (sleeping) (состояние ожидания) Менее S1, но более S3 Система возобновляет ра От 2 секунд боту с той точки, где она и более была прервана (возвра щается в состояние S0) S3 (sleeping) (состояние ожидания) Менее S2, процессор отключен S4 (hibernating) Ток подается на кноп (спящий режим) ку включения электро питания и в контур пробуждения (wake circuitry) S5 (fully off) (полное отклю чение) Система возобновляет ра От 2 секунд боту с той точки, где она и более была прервана (возвра щается в состояние S0) Система перезапускается Длительная, не с помощью файла спяще определенная го режима (hibernate file) и возобновляет работу с той точки, где она была прервана переходом в спя щий режим (возвращается в состояние S0) Ток подается на кноп Система загружается ку включения электро заново питания Длительная, неопределенная В состояния ожидания (S1–S4) компьютер кажется отключенным, так как потребляет меньше энергии. Но при этом он сохраняет и в памяти, и на дис ке всю информацию, необходимую для возврата в состояние S0. В состоя ниях S1–S3 для сохранения содержимого памяти нужно достаточное коли чество энергии, поскольку при переходе в S0 (при пробуждении компьюте ра пользователем или устройством) диспетчер электропитания возобновля ет работу системы с той точки, где оно было прервано. Когда система пере ходит в состояние S4, диспетчер электропитания сохраняет содержимое памяти в сжатой форме в файле спящего режима (Hiberfil.sys), который по мещается в корневой каталог системного тома. (Этот файл должен быть та кого размера, чтобы в нем могло уместиться несжатое содержимое всей па мяти; сжатие используется для того, чтобы свести к минимуму операции вво да вывода на диске, а также ускорить переход в спящий режим и выход из него.) Сохранив содержимое памяти, диспетчер электропитания отключает компьютер. При последующем включении компьютера происходит обыч ный процесс загрузки — с тем исключением, что Ntldr проверяет наличие действительного образа памяти, сохраненного в файле спящего режима. Если в этом файле сохранены данные о состоянии системы, Ntldr считыва ет его содержимое в память и возобновляет выполнение с точки, зафикси рованной в Hiberfil.sys. Компьютер никогда не переходит напрямую между состояниями S1 и S4, для этого ему нужно сначала перейти в состояние S0. Как показано на рис. 9 32, переход системы из состояний S1–S5 в состояние S0, называется
642 ГЛ А В А 9 БЕЗОПАСНОСТЬ пробуждением (waking), а переход из состояния S0 в состояния S1–S5 — пе реходом в сон (sleeping). Рис. 9-32. Переходы системы между различными состояниями энергопотребления Хотя система может пребывать в одном из шести состояний энергопотреб ления, ACPI определяет для устройств четыре состояния: D0–D3. В состоянии D0 устройство полностью включено, а в состоянии D3 полностью отключе но. ACPI позволяет драйверам и устройствам самостоятельно определять со стояния D1 и D2 с единственным условием, что устройство в состоянии D1 должно потреблять столько же или меньше энергии, чем в состоянии D0, а в состоянии D2 — столько же или меньше, чем в состоянии D1. Microsoft совме стно с крупными OEM производителями определила набор спецификаций управления электропитанием (см. www.microsoft.com/whdc/resources/respec/ specs/pmref), в которых описываются состояния энергопотребления для всех устройств конкретного класса (основные классы устройств: видеоадаптеры, сеть, SCSI и т. д.). Некоторые устройства могут быть лишь включены или вы ключены, поэтому для них промежуточные состояния не определены. Работа диспетчера электропитания Политика управления электропитанием в Windows определяется диспетче ром электропитания и драйверами устройств. Владельцем системной поли тики управления электропитанием является диспетчер электропитания. Это значит, что он принимает решение о том, в каком состоянии энергопотреб ления должна находиться система в текущий момент. При необходимости выключения либо перехода в ждущий или спящий режим диспетчер элек тропитания указывает устройствам, поддерживающим управление электро питанием, перейти в соответствующее состояние. Этот диспетчер принима ет решение о переходе в другое состояние энергопотребления, исходя из: 쐽 уровня активности системы; 쐽 уровня заряда аккумуляторов; 쐽 наличия запросов приложений на выключение компьютера или переход в ждущий/спящий режим;
ГЛАВА 9 Подсистема ввода-вывода 643 쐽 действий пользователя, например нажатия кнопки включения электропи тания; 쐽 параметров электропитания, заданных в Control Panel. Часть информации, получаемой диспетчером PnP при перечислении ус тройств, связана с поддержкой устройствами функций управления электро питанием. Драйвер сообщает, поддерживает ли устройство состояния D1 и D2, а также какие задержки требуются ему для перехода из состояний D1– D3 в D0 (последняя часть данных необязательна). Чтобы диспетчеру было легче определять, когда систему следует переводить в другое состояние энер гопотребления, драйверы шин также возвращают таблицу сопоставлений между системными состояниями (S0–S5) и состояниями, поддерживаемыми конкретным устройством. В этой таблице указывается состояние устройства с наименьшим энергопотреблением для каждого системного состояния. В таблице 9 4 показан пример таблицы сопоставлений для шины, поддер живающей все четыре возможных состояния устройств. Большинство драй веров полностью выключают свои устройства (D3) при выходе системы из состояния S0, чтобы свести к минимуму энергопотребление, пока машина не используется. Однако некоторые устройства вроде сетевых адаптеров под держивают функцию вывода системы из состояний сна. О наличии подоб ной функции также сообщается при перечислении устройств. Таблица 9-4. Пример таблицы сопоставлений системных состояний с состояниями устройств Состояние системы Состояние устройства S0 (полностью активное) D0 (полностью активное) S1 (ждущий режим) D2 S2 (ждущий режим) D2 S3 (ждущий режим) D2 S4 (спящий режим) D3 (полное отключение) S5 (полное отключение) D3 (полное отключение) Участие драйверов в управлении электропитанием Диспетчер электропитания, принимая решение о переходе системы в другое состояние, посылает команды процедуре драйвера, отвечающей за диспетче ризацию электропитания. Управлять устройством могут несколько драйверов, но только один из них является владельцем политики управления электропи танием устройства. Этот драйвер определяет состояние устройства в зависи мости от состояния энергопотребления системы. Например, при переходе системы из состояния S0 в состояние S1 драйвер может принять решение о переводе устройства из состояния D0 в состояние D1. Вместо того чтобы на прямую оповещать об этом другие драйверы, участвующие в управлении уст ройством, владелец политики управления электропитанием устройства делает это через диспетчер электропитания, вызывая функцию PoRequestPowerIrp.
644 ГЛ А В А 9 БЕЗОПАСНОСТЬ Диспетчер электропитания реагирует посылкой соответствующей команды процедурам драйверов, отвечающим за диспетчеризацию электропитания. Такое поведение позволяет диспетчеру контролировать число активных ко манд управления электропитанием в системе: включение некоторых уст ройств требует значительного количества электроэнергии, поэтому активи зация сразу нескольких таких устройств недопустима. ЭКСПЕРИМЕНТ: просмотр сопоставлений состояний электропитания в драйвере В Windows XP и Windows Server 2003 это можно сделать с помощью диспетчера устройств. Откройте окно свойств для какого либо устрой ства и выберите запись Power State Mappings (Сопоставления энерго сбережения) в раскрывающемся списке на вкладке Details (Сведения). (По умолчанию диспетчер устройств не показывает эту вкладку. Как ее включить, см. в эксперименте «просмотр детальных сведений об узлах устройств в диспетчере устройств» ранее в этой главе.) На иллюстрации ниже показаны такие сопоставления для драйве ра диска. Кроме состояний D0 (полное включение) и D3 (полное от ключение), он поддерживает промежуточное состояние D1, сопостав ленное с S1. Для многих команд управления электропитанием предусмотрены соответствующие команды запросы. Так, при переходе системы в жду щий режим, диспетчер электропитания сначала опрашивает устрой ства о допустимости такого перехода. Устройство, занятое выполнени ем критичных по времени операций или взаимодействующее с другим аппаратным устройством, может отклонить запрос, и система останет ся в прежнем состоянии.
ГЛАВА 9 Подсистема ввода-вывода 645 ЭКСПЕРИМЕНТ: просмотр возможностей и системной политики управления электропитанием Вы можете выяснить возможности своего компьютера в управлении электропитанием с помощью команды !pocaps отладчика ядра. Ниже приведен пример вывода этой команды для ACPI совместимого пор тативного компьютера с Windows Professional. kd> !pocaps PopCapabilities @ 0x8046adc0 Misc Supported Features: PwrButton SlpButton Lid S1 S3 S4 S5 HiberFile FullWake Processor Features: Thermal Throttle (MinThrottle = 03, Scale = 08) Disk Features: SpinDown Battery Features: BatteriesPresent Battery 0  Capacity: 00000000 Granularity: 00000000 Battery 1  Capacity: 00000000 Granularity: 00000000 Battery 2  Capacity: 00000000 Granularity: 00000000 Wake Caps Ac OnLine Wake: Sx Soft Lid Wake: Sx RTC Wake: S3 Min Device Wake: Sx Default Wake: Sx Cтрока Misc Supported Features сообщает, что кроме S0 данная сис тема поддерживает состояния S1, S3, S4 и S5 (S2 не реализовано) и имеет действительный файл спящего режима, в который можно сохра нить содержимое системной памяти при переходе в спящий режим (состояние S4). Диалоговое окно Power Options Properties (Свойства: Электропита ние), показанное на следующей иллюстрации (оно открывается через Control Panel), позволяет настроить различные аспекты системной политики управления электропитанием. Конкретные параметры, до ступные для настройки, зависят от степени поддержки системой функ ций управления электропитанием. ACPI совместимый портативный компьютер с Windows Professional или Home предоставляет максимум возможностей в управлении элек тропитанием. В таких системах можно установить интервалы простоя, по истечении которых отключается монитор, останавливаются жест кие диски и осуществляется переход в ждущий (состояние S1) и спя щий режимы (состояние S4). Кроме того, вкладка Advanced (Дополни тельно) в диалоговом окне Power Options Properties позволяет указать поведение системы при нажатии кнопок включения электропитания и перехода в спящий режим, а также при закрытии крышки ноутбука. см. след. стр.
646 ГЛ А В А 9 БЕЗОПАСНОСТЬ Параметры, установленные в окне Power Options Properties, прямо влияют на системную политику управления электропитанием, пара метры которой можно просмотреть с помощью команды !popolicy от ладчика ядра. Вот как выглядит информация, сообщаемая этой коман дой для той же системы: kd> !popolicy SYSTEM_POWER_POLICY (R.1) @ 0x80469180 PowerButton: Off Flags: 00000003 SleepButton: Sleep Flags: 00000003 LidClose: Hibernate Flags: 00000001 Idle: None Flags: 00000001 OverThrottled: Sleep Flags: c0000004 NoWakes Critical IdleTimeout: 00000000 IdleSensitivity: MinSleep: S1 MaxSleep: LidOpenWake: S0 FastSleep: WinLogonFlags: 00000000 S4Timeout: VideoTimeout: 00000000 VideoDim: SpinTimeout: 00000708 OptForPower: FanTolerance: 64 ForcedThrottle: MinThrottle: 19 Event: Event: Event: Event: Event: 00000000 00000000 00000000 00000000 00000000 Query UI Query UI Query Query Override 32 S3 S1 00000000 6e 01 64 Первые строки описывают, как будет реагировать система на нажа тие кнопок включения электропитания и перехода в спящий режим. В данной системе нажатие кнопки включения электропитания интер претируется как выключение электропитания, нажатие кнопки пере хода в спящий режим переводит систему в ждущий режим, а закрытие крышки ноутбука вызывает переход в спящий режим.
ГЛАВА 9 Подсистема ввода-вывода 647 Значения таймаутов, показанные в конце листинга, выражаются в секундах и выводятся в шестнадцатеричной форме. Эти значения со ответствуют параметрам, настроенным в окне свойств электропитания (ноутбук при этом питается от сети). Как драйвер управляет электропитанием устройства Драйвер не только отвечает на команды диспетчера электропитания, связан ные с изменением состояния системы, но и может сам управлять состояни ем энергопотребления своих устройств. В некоторых случаях драйвер мо жет снизить энергопотребление управляемого им устройства, если оно не активно в течение определенного времени. Драйвер может обнаруживать простаивающие устройства самостоятельно или через механизмы, предо ставляемые диспетчером электропитания. Во втором случае устройство ре гистрируется в диспетчере электропитания вызовом функции PoRegister DeviceForIdleDetection. Эта функция сообщает диспетчеру электропитания пороговые интервалы простоя устройства и указывает, в какое состояние следует переводить устройство, если оно простаивает. Драйвер задает два таймаута: первый — для энергосберегающей конфигурации, второй — для максимально производительной. Вызвав PoRegisterDeviceForIdleDetection, драйвер должен уведомлять диспетчер электропитания об активности уст ройства через функцию PoSetDeviceBusy. Резюме Подсистема ввода вывода определяет модель обработки ввода вывода в Win dows и предоставляет функции, необходимые многим драйверам. Основная сфера ее ответственности — создание IRP, представляющих запросы ввода вывода, передача этих пакетов через различные драйверы и возврат резуль татов вызывающему потоку по завершении ввода вывода. Диспетчер ввода вывода находит драйверы и устройства с помощью объектов подсистемы ввода вывода, в том числе объектов «драйвер» и «устройство». Для большего быстродействия подсистема ввода вывода Windows всегда работает асинх ронно — даже при обработке синхронного ввода вывода, запрошенного из пользовательского режима. К драйверам устройств относятся не только традиционные драйверы, уп равляющие аппаратными устройствами, но и драйверы файловой системы, сетевые драйверы, а также многоуровневые драйверы фильтров. Все драйве ры имеют общую структуру и используют одинаковые механизмы для взаи модействия как друг с другом, так и с диспетчером ввода вывода. Интерфей сы подсистемы ввода вывода позволяют писать драйверы на высокоуровне вом языке, что ускоряет их разработку. Поскольку драйверы имеют общую структуру, они могут располагаться один над другим, а это обеспечивает мо дульность и уменьшает дублирование функций между драйверами. Все драй
648 ГЛ А В А 9 БЕЗОПАСНОСТЬ веры устройств, создаваемые для Windows, должны разрабатываться с учетом необходимости корректной работы в многопроцессорных системах. Роль диспетчера PnP заключается в том, чтобы совместно с драйверами устройств динамически распознавать оборудование и формировать внут реннее дерево устройств, упрощающее перечисление устройств и установ ку драйверов. Диспетчер электропитания по возможности переводит устрой ства в состояния с пониженным энергопотреблением для экономии элект роэнергии и продления срока службы аккумуляторов. Следующие четыре главы мы посвятим смежной тематике: управлению устройствами внешней памяти, файловым системам (особое внимание бу дет уделено NTFS), диспетчеру кэша и поддержке сетей.
Г Л А В А 1 0 Управление внешней памятью Термин внешняя память (storage) относится к носителям, применяемым в самых разнообразных устройствах, в том числе к магнитным лентам, опти ческим дискам, гибким дискам, локальным жестким дискам и сети устройств хранения данных (storage area networks, SAN). Windows предоставляет спе циализированную поддержку для каждого класса носителей внешней памя ти. Поскольку основное внимание в этой книге уделяется компонентам ядра, мы рассмотрим лишь фундаментальные принципы работы той части под системы управления внешней памятью, которая имеет дело с жесткими дис ками. Существенную часть поддержки сменных носителей и удаленных ус тройств внешней памяти Windows реализует в пользовательском режиме. В этой главе мы исследуем, как драйверы устройств режима ядра взаимо действуют с драйверами файловой системы и дисками. Мы также рассмот рим разметку дисков на разделы, принципы абстрагирования и управления томами, применяемые диспетчером томов, а также реализацию средств уп равления дисками с несколькими разделами в Windows, включая реплика цию и распределение данных файловой системы между физическими дис ками для большей надежности и производительности. В заключение мы опи шем, как драйверы файловой системы монтируют свои тома. Базовая терминология Чтобы полностью усвоить материал этой главы, вы должны четко понимать базовую терминологию. 쐽 Диск — физическое устройство внешней памяти, например жесткий диск, 3,5дюймовая дискета или компактдиск (CDROM). 쐽 Диск делится на секторы, блоки фиксированного размера. Размер секто ра определяется аппаратно. Например, размер сектора жесткого диска, как правило, составляет 512 байтов, а размер сектора CDROM — обыч но 2048 байт. 쐽 Раздел (partition) — набор непрерывных секторов на диске. Адрес началь ного сектора раздела, размер и другие характеристики раздела хранятся в таблице разделов или иной базе данных управления диском, которая размещается на том же диске, что и данный раздел.
650 ГЛ А В А 10 БЕЗОПАСНОСТЬ 쐽 Простой том (simple volume) — объект, представляющий секторы одного раздела, которым драйверы файловых систем управляют как единым целым. 쐽 Составной том (multipartition volume) — объект, представляющий сек торы нескольких разделов, которыми драйверы файловых систем управ ляют как единым целым. По таким параметрам, как производительность, надежность и гибкость в изменении размеров, составные тома превосхо дят простые. Драйверы дисков Драйверы устройств, участвующие в управлении конкретным устройством внешней памяти (накопителем), обобщенно называются стеком драйверов внешней памяти (storage stack). На рис. 101 показаны все типы драйверов, которые могут присутствовать в стеке. В этой главе мы описываем поведе ние драйверов устройств, расположенных в стеке ниже уровня файловой системы. (О драйвере файловой системы см. главу 12.) Рис. 10-1. Стек драйверов устройств внешней памяти в Windows
ГЛАВА 9 Управление внешней памятью 651 Ntldr Как вы уже видели в главе 4, первой частью процесса загрузки операцион ной системы Windows дирижирует Ntldr. Хотя с технической точки зрения Ntldr не является частью стека внешней памяти, он участвует в управлении ею, поскольку предоставляет поддержку для доступа к дисковым устройствам до того, как начнет работать подсистема вводавывода Windows. Он находит ся на системном томе и запускается кодом, размещенным в загрузочном сек торе этого тома. Ntldr считывает с системного тома файл Boot.ini и предла гает пользователю выбрать вариант загрузки. Имена разделов в Boot.ini пред ставлены в виде multi(0)disk(0)rdisk(0)partition(1). Эти имена являются час тью стандартной схемы именования разделов Advanced RISC Computing (ARC), используемой микрокодом Alpha и других RISCпроцессоров. Ntldr транслирует имя выбранного пользователем элемента Boot.ini в имя загру зочного раздела и загружает в память системные файлы Windows (начиная с реестра, Ntoskrnl.exe и загрузочных драйверов). Во всех случаях Ntldr ис пользует BIOS для чтения диска, содержащего системный том, но, как опи сано в главе 4, иногда полагается на функции минипортдрайвера диска для чтения с диска, где находится загрузочный том. Драйвер класса дисков, порт- и минипорт-драйверы При инициализации диспетчер вводавывода запускает драйверы жестких дисков. Драйверы устройств внешней памяти в Windows соответствуют ар хитектуре «класспортминипорт». Согласно этой архитектуре, Microsoft предоставляет драйвер класса внешней памяти, который реализует функци ональность, общую для всех устройств внешней памяти, и портдрайвер, который поддерживает функциональность, общую для конкретной шины, например SCSI (Small Computer System Interface) или IDE (Integrated Device Electronics). А изготовители оборудования поставляют минипортдрайверы, подключаемые к портдрайверам и формирующие интерфейс между Win dows и конкретными устройствами. В архитектуре драйверов дисковой памяти только драйверы класса име ют стандартные интерфейсы драйверов устройств Windows. Минипорт драйверы вместо интерфейса драйверов устройств используют интерфейс портдрайверов, который просто реализует набор процедур, служащих ин терфейсом между Windows и минипортдрайверами. Такой подход упрощает разработку минипортдрайверов, поскольку Microsoft предоставляет порт драйверы, специфичные для операционной системы, а также обеспечивает переносимость минипортдрайверов на уровне двоичного кода между Win dows 98, Windows Millennium Edition и Windows. Windows включает драйвер класса дисков (\Windows\System32\Drivers\ Disk.sys), реализующий стандартную функциональность дисков. Windows также предоставляет разнообразные портдрайверы дисков. Например, Scsi port.sys — это портдрайвер дисков, подключаемых к SCSIшине, а Atapi.sys — портдрайвер для систем на базе IDE. В Windows Server 2003 введен порт
652 ГЛ А В А 10 БЕЗОПАСНОСТЬ драйвер Storport.sys, заменяющий Scsiport.sys. Storport.sys был разработан для реализации функциональности высокопроизводительных аппаратных RAIDконтроллеров и адаптеров Fibre Channel. Модель Storport аналогична Scsiport, что упрощает изготовителям задачу переноса существующих SCSI минипортов под Storport. Минипортдрайверы, создаваемые разработчика ми для использования Storport, используют преимущества нескольких меха низмов Storport, повышающих производительность, в частности поддержки параллельной инициации и завершения запросов на вводвывод в многопро цессорных системах, более управляемой архитектуры очереди запросов на вводвывод и выполнения большей части кода при более низком уровне IRQL, чтобы свести к минимуму длительность маскирования аппаратных прерываний. Драйверы Scsiport.sys и Atapi.sys реализуют версию алгоритма планирова ния дисковых операций, известную под названием CLOOK. Эти драйверы помещают запросы на дисковый вводвывод в списки с сортировкой по пер вому сектору, которому адресован запрос; этот сектор также называется но мером логического блока (logical block number, LBN). С помощью функций KeInsertByKeyDeviceQueue и KeRemoveByKeyDeviceQueue (документированных в Windows DDK) они представляют запросы вводавывода как элементы (items) и используют начальный сектор запроса в качестве ключа, требуемо го этими функциями. Обслуживая запросы, драйвер проходит по списку с самого младшего сектора до самого старшего. Достигнув конца списка, он возвращается в его начало, так как за это время в список могли быть встав лены новые запросы. Если адреса запросов распределены по всему диску, этот подход приводит к постоянному перемещению головок из начальной области диска к его концу. Storport.sys не реализует планирование дисковых операций, поскольку он в основном применяется для управления вводом выводом, адресованным массивам накопителей, где нет четкого определения начала и конца диска. С Windows поставляются некоторые минипортдрайверы, включая Aha154x.sys для SCSIконтроллеров семейства Adaptec 1540. В системах, где ус тановлено минимум одно IDEустройство на основе ATAPI, функциональность минипортов предоставляют драйверы Pciidex.sys и Pciide.sys. Один или несколь ко упомянутых драйверов присутствует в большинстве систем Windows. Драйверы iSCSI iSCSI — это транспортный протокол для дисковых устройств, который ин тегрирует протокол SCSI с TCP/IP, благодаря чему компьютеры могут взаи модействовать с блочными накопителями, включая диски, по IPсетям. Ар хитектура сети устройств хранения данных (storage area networking, SAN) обычно базируется на сети Fibre Channel, но администраторы могут исполь зовать iSCSI для создания сравнительно недорогих SAN на основе таких се тевых технологий, как гигабитная Ethernet, что позволяет обеспечить мас штабируемость, защиту от катастроф, эффективное резервное копирование и защиту данных. В Windows поддержка iSCSI реализуется в виде Microsoft
ГЛАВА 9 Управление внешней памятью 653 iSCSI Software Initiator, который можно скачать с сайта Microsoft и который работает в Windows 2000, Windows XP и Windows Server 2003. Microsoft iSCSI Software Initiator включает несколько компонентов. 쐽 Initiator (инициатор) Этот необязательный компонент, состоящий из портдрайвера iSCSI (\Windows\System32\Drivers\Iscsiprt.sys) и мини портдрайвера (\Windows\System32\Drivers\Msiscis.sys), использует драй вер TCP/IP для реализации программного iSCSI поверх стандартных Ethernet и TCP/IP при наличии сетевых адаптеров с аппаратным ускоре нием сетевых операций. 쐽 Initiator Service (служба инициатора) Эта служба, реализованная в \Windows\System32\Iscsiexe.exe, управляет обнаружением и защитой всех инициаторов iSCSI, а также инициацией и завершением сеансов. Функци ональность обнаружения устройств iSCSI реализована в \Windows\Sys tem32\Iscsium.dll и соответствует спецификации протокола Internet Sto rage Name Service (iSNS). 쐽 Управляющие приложения К ним относятся Iscsicli.exe (утилита ко мандной строки для управления соединениями iSCSIустройств и их за щитой) и соответствующий апплет для Control Panel (Панель управления). Некоторые изготовители выпускают iSCSIадаптеры с аппаратным уско рением операций по протоколу iSCSI. Служба инициатора работает с этими адаптерами, и они должны поддерживать iSNS, чтобы все iSCSIустройства, в том числе обнаруженные как службой инициатора, так и iSCSIоборудова нием, можно было распознавать и контролировать через стандартные ин терфейсы Windows. MPIO-драйверы У большинства дисковых устройств только один путь (path) между ними и компьютером — набор адаптеров, кабелей и коммутаторов. В серверах, тре бующих высокого уровня готовности к работе, применяются решения с не сколькими путями — между компьютером и диском существует более одно го набора соединительного оборудования, чтобы при аварии одного пути система все равно могла бы обращаться к диску по альтернативному пути. Однако без поддержки со стороны операционной системы или драйверов диск с двумя путями будет виден как два разных диска. Windows включает поддержку вводавывода по нескольким путям (multipath I/O, MPIO) для уп равления дисками с несколькими путями как одним диском; эта поддержка опирается на сторонние драйверы — модули, специфичные для конкретно го устройства (devicespecific modules, DSM). Эти модули берут на себя всю специфику управления путями, в том числе политику балансировки нагруз ки, на основе которой выбирается путь передачи запросов вводавывода, и механизмы обнаружения ошибок, уведомляющие Windows об аварии того или иного пути. Поддержка MPIO доступна для Windows 2000 Server, Advan ced Server, Datacenter Server и Windows Server 2003 в виде Microsoft MPIO
654 ГЛ А В А 10 БЕЗОПАСНОСТЬ Driver Development Kit, который лицензируется поставщиками аппаратно го и программного обеспечения. В стеке драйверов внешней памяти Windows MPIO (рис. 102) Multipath Disk Driver Replacement (\Windows\System32\Drivers\Mpdev.sys) заменяет функ циональность стандартного драйвера класса Disk.sys. Mpdev.sys захватывает во владение объект «устройство», представляющий диски с несколькими путями, чтобы для таких дисков существовал лишь один объект «устройство». Кроме того, этот драйвер отвечает за поиск подходящего DSM для управления путя ми к устройству. Multipath Bus Driver (\Windows\System32 \Drivers \ Mpio.sys) уп равляет соединениями между компьютером и устройством, в том числе обес печивая управление электропитанием данного устройства. Mpdev.sys уведом ляет Mpio.sys о наличии устройств, которые тот должен контролировать. На конец, Multipath Port Filter (\Windows\System32 \Drivers\Mpsfltr.sys) размеща ется поверх портдрайвера для диска с несколькими путями и управляет ин формацией, передаваемой вверх по стеку устройств. Рис. 10-2. Стек устройств внешней памяти Windows MPIO ЭКСПЕРИМЕНТ: наблюдение за вводом-выводом на физическом диске С помощью механизма Event Tracing for Windows (см. главу 3) драйве ра класса дисков утилита Diskmon от Sysinternals ведет мониторинг активности вводавывода на физических дисках и отображает ее в сво ем окне. Содержимое этого окна обновляется раз в секунду. Для каж дой операции Diskmon показывает время, длительность, номер целе вого диска, тип и смещение, а также длину.
ГЛАВА 9 Управление внешней памятью 655 Объекты «устройство» для дисков Драйвер класса дисков создает объекты «устройство», представляющие дис ки и дисковые разделы. Имена таких объектов имеют вид \Device\HarddiskX\ DRX, где X — номер диска. Для идентификации разделов и создания объек тов «устройство», представляющих эти разделы, драйвер класса дисков в Windows 2000 использует функцию IoReadPartitionTable диспетчера ввода вывода, а в Windows XP и Windows Server 2003 — функцию IoReadParitition TableEx. Драйвер класса дисков вызывает одну из этих функций для каждого диска, представленного минипортдрайвером драйверу класса на ранних стадиях загрузки системы. А функция инициирует дисковый вводвывод на уровне секторов, поддерживаемый драйвером класса, порт и минипорт драйверами, для считывания MBR или GPTтаблицы разделов (об этом мы расскажем позже) и для формирования внутреннего представления жестких разделов диска. Драйвер класса дисков создает объекты «устройство», пред ставляющие все главные разделы (в том числе логические диски внутри до полнительных разделов), которые этот драйвер получает от IoReadPartition Table или IoReadParititionTableEx. Вот пример имени объекта раздела: \Device\Harddisk0\DP(1)0x7e0000x7ff50c00+2 Это имя идентифицирует первый раздел первого диска системы. Два пер вых шестнадцатеричных числа (0x7e000 и 0x7ff50c00) определяют начало и длину раздела, а последнее число — внутренний идентификатор, назначен ный драйвером класса. Для совместимости с приложениями, использующими правила именова ния, принятые в Windows NT 4, драйвер класса дисков формирует для имен в формате Windows NT 4 символьные ссылки на объекты «устройство», соз данные драйвером. Например, драйвер класса создает ссылки \Device\Hard
656 ГЛ А В А 10 БЕЗОПАСНОСТЬ disk0\Partition0 на \Device\Harddisk0\DR0 и \Device\Harddisk0\Partition1 на объект «устройство» первого раздела первого диска. В Windows драйвер класса создает такие же символьные ссылки, представляющие физические диски, созданные в системах под управлением Windows NT 4. Так, ссылка \??\PhysicalDrive0 указывает на \Device\Harddisk0\DR0. На рис. 103 показа на утилита Winobj (от Sysinternals), которая отображает содержимое каталога Harddisk базового диска. Рис. 10-3. Окно Winobj, показывающее содержимое каталога Harddisk базового диска Как вы уже видели в главе 3, Windows API ничего не знает о пространстве имен диспетчера объектов. Windows резервирует два подкаталога простран ства имен, один из которых — подкаталог \Global?? (\?? в Windows 2000). (Другой подкаталог, \BaseNamedObjects, был рассмотрен в главе 3.) В этом подкаталоге объекты «устройство», включая диски, последовательные и па раллельные порты, становятся доступными Windowsприложениям. Так как на самом деле объекты дисков находятся в других подкаталогах, для связы вания имен в \Global?? с объектами, расположенными в других каталогах пространства имен, Windows использует символьные ссылки. Диспетчер вво давывода создает ссылку \Global??\PhysicalDriveX для каждого физического диска системы; такая ссылка указывает на \Device\HarddiskX\Partition0 (где X — числа, начиная с 0). Windowsприложения, напрямую обращающиеся к секторам диска, открывают диск вызовом Windowsфункции CreateFile и ука зывают в качестве параметра имя \\.\PhysicalDriveX (где X — номер диска). Прежде чем передать имя диспетчеру объектов, прикладной уровень Win dows преобразует его в \Global??\PhysicalDriveX.
ГЛАВА 9 Управление внешней памятью 657 Диспетчер разделов Диспетчер разделов (partition manager), \Windows\System32\Drivers\Part mgr.sys, отвечает за уведомление диспетчера Plug and Play (PnP) о наличии разделов; благодаря этому драйверы диспетчера томов (о них чуть позже) могут получать уведомления о создании и удалении разделов. Для получения информации о разделах диспетчер разделов действует как функциональный драйвер применительно к объектам дисковых устройств, создаваемых драйвером класса дисков. При загрузке системы он считывает таблицы разделов подключенных дисков (в Windows 2000 через функцию ядра IoReadPartitionTable, а в Windows XP и Windows Server 2003 через такую же функцию IoReadPartitionTableEx) и сообщает об имеющихся разделах диспетчеру PnP. Драйверы устройств диспетчера томов получают уведомле ние о разделах управляемых ими дисков и на основании сведений обо всех разделах, из которых состоят тома, определяют объекты «том». Диспетчер разделов отслеживает пакеты запросов на вводвывод (I/O request packets, IRP), относящиеся к модификации таблицы разделов, и поэтому может об новлять внутреннюю карту разделов, а затем уведомлять диспетчер PnP о создании и удалении любых разделов. Управление томами В Windows введена концепция базовых (basic) и динамических (dynamic) дисков. Диски с разбиением на разделы исключительно по схеме MBR или GPT в Windows называются базовыми. Поддержка динамических дисков впервые появилась в Windows 2000; они реализуют более гибкую схему раз биения на разделы, чем базовые. Фундаментальное различие между базовы ми и динамическими дисками в том, что последние поддерживают создание составных томов (более производительных и надежных, чем простые тома). По умолчанию Windows управляет всеми дисками как базовыми — динами ческие диски надо создавать вручную или преобразованием из существую щих базовых (если на них достаточно свободного места). Но если вам не нужна функциональность составных томов, Microsoft рекомендует исполь зовать именно базовые диски. ПРИМЕЧАНИЕ Составные тома поддерживаются и на базовых дисках, но только если эти тома переносятся из Windows NT 4 (исключение составляет Windows Server 2003, которая в принципе не поддержива ет составные тома на базовых дисках.) На портативных компьюте рах — в силу ряда причин, в том числе изза наличия только одного жесткого диска, который не предназначен для переноса между компь ютерами, — Windows использует исключительно базовые диски. Кро ме того, динамическими могут быть лишь фиксированные диски. Дис ки, подключенные к шинам IEEE 1394 или USB, а также диски, совмес тно используемые серверным кластером, всегда являются базовыми.
658 ГЛ А В А 10 БЕЗОПАСНОСТЬ Эволюция управления внешней памятью Эволюция управления внешней памятью началась с MSDOS, первой операционной системы Microsoft. Когда емкость жестких дисков уве личилась, в MSDOS нужно было ввести соответствующую поддержку. Поэтому первым шагом Microsoft стала организация в MSDOS поддерж ки нескольких разделов, или логических дисков, на одном физическом диске. MSDOS позволяла форматировать разделы с использованием различных файловых систем (FAT12 или FAT16) и назначать каждому разделу свою букву диска. Количество и размер разделов, которые можно было создавать в MSDOS версий 3 и 4, были жестко ограниче ны, но уже в MSDOS 5 схема разбиения на разделы стала вполне зре лой. MSDOS 5 умела разбивать диски на любое число разделов про извольного размера. Windows NT унаследовала схему разбиения жестких дисков на раз делы, созданную для MSDOS. Сделано это было из двух соображений: для совместимости с MSDOS и Windows 3.x, а также для того, чтобы команда разработчиков Windows NT могла опереться на проверенные средства управления дисками. Базовые концепции MSDOS, относящи еся к разбиению дисков на разделы, в Windows NT были расширены для поддержки функций управления внешней памятью, необходимых операционной системе корпоративного класса, в частности для под держки перекрытия дисков (disk spanning) и большей отказоустойчи вости. В первой версии Windows NT, Windows NT 3.1, системные адми нистраторы могли создавать тома, состоящие из нескольких разделов, что позволяло формировать тома большого размера из разделов не скольких физических дисков, а также повышать отказоустойчивость дисковой подсистемы за счет избыточности данных, организуемой программными средствами. Хотя поддержка разбиения дисков на разделы по схеме MSDOS в версиях Windows NT, предшествовавших Windows 2000, была доста точно гибкой для многих задач управления внешней памятью, у нее все же был ряд недостатков. Один из них в том, что активизация боль шинства изменений в конфигурации дисков требует перезагрузки сис темы. Но современные серверы должны непрерывно работать в тече ние месяцев и даже лет, поэтому любая перезагрузка, даже плановая, крайне нежелательна. Другой недостаток связан с тем, что в Windows NT 4 информация о конфигурации томов, состоящих из нескольких разделов и созданных на основе MSDOSразделов, хранится в реест ре. Это крайне затрудняет перенос конфигурационной информации при перемещении дисков между системами, а при переустановке опе рационной системы возможна и потеря этой информации. Наконец, требование назначать каждому тому уникальные буквы дисков из ди апазона A–Z уже давно досаждало пользователям операционных сис
ГЛАВА 9 Управление внешней памятью 659 тем Microsoft, ограничивая возможное количество локальных и под ключенных сетевых томов. Windows поддерживает три типа разбиения на разделы, которые позволяют преодолевать упомянутые ограничения: MBR (Master Boot Record), GPT (GUID Partition Table) и LDM (Logical Disk Manager). Базовые диски В этом разделе описываются два типа разбиения на разделы — MBR и GPT, используемые Windows для определения томов на базовых дисках, — а так же драйвер диспетчера томов (FtDisk), представляющий тома драйверам файловых систем. Если диспетчер дисков в Windows 2000 рекомендовал вам делать любой неразмеченный диск динамическим, то Windows XP и Win dows Server 2003 автоматически определяют все диски как базовые. Разбиение на разделы по схеме MBR Одно из требований к формату разбиения на разделы в Windows диктуется стандартными реализациями BIOS в системах: первый сектор основного дис ка должен содержать главную загрузочную запись (Master Boot Record, MBR). При запуске компьютера на базе x86процессора BIOS считывает MBR и ин терпретирует ее часть как исполняемый код. Выполнив предварительное кон фигурирование оборудования, BIOS передает управление исполняемому коду в MBR для инициации процесса загрузки операционной системы. В операционных системах Microsoft, включая Windows, MBR также содер жит таблицу разделов. Таблица разделов состоит из четырех элементов, оп ределяющих местонахождение на диске четырех главных разделов. В этой таблице указываются и типы разделов (которые определяют, какую файло вую систему включает тот или иной раздел). Существует множество предоп ределенных типов разделов, например для FAT32 и NTFS. Раздел особого типа, дополнительный (extended partition), содержит еще одну MBR с соб ственной таблицей разделов. Эквивалент главного раздела в дополнитель ном называется логическим диском. Применение дополнительных разделов позволяет операционным системам Microsoft создавать любое количество разделов на диске (а не четыре на один диск). Отличие главного раздела от логических дисков становится очевидным при загрузке Windows. Один из главных разделов основного жесткого дис ка должен быть помечен системой как активный. Код Windows, записывае мый в MBR, загружает в память код первого сектора активного раздела (сис темного тома) и передает ему управление. Первый сектор такого раздела называется загрузочным. Кроме того, как уже говорилось в главе 4, у каждо го раздела, отформатированного с использованием определенной файловой системы, имеется свой загрузочный сектор, который хранит информацию о структуре файловой системы данного раздела.
660 ГЛ А В А 10 БЕЗОПАСНОСТЬ Разбиение на разделы по схеме GPT В рамках инициативы, направленной на создание стандартизированной и расширяемой платформы микрокода, которую операционные системы мог ли бы использовать в процессе своей загрузки, корпорация Intel разработа ла спецификацию EFI (Extensible Firmware Interface). EFI включает среду опе рационной минисистемы, реализуемую в виде микрокода, который, как правило, зашивается в ПЗУ. Эта среда используется операционной системой на ранних этапах для загрузки системных диагностических процедур и за грузочного кода. Первый процессор, поддерживающий EFI, — Intel IA64, по этому версии Windows для IA64 используют EFI, но при желании позволяют выбрать и схему MBR. Детальное описание EFI см. по ссылке http://developer. intel.com/technology/efi. EFI определяет схему разбиения на разделы — таблицу разделов GUID (GUID Partition Table, GPT), которая должна устранить некоторые недостат ки схемы разбиения MBR. Например, адреса секторов, используемых струк турами разделов GPT, вместо 32разрядных стали 64разрядными. 32разряд ные адреса обеспечивают доступ к 2 Тб памяти, но GPT разработана с при целом на обозримое будущее. Среди прочих преимуществ GPT стоит отме тить применение контрольных сумм CRC (cyclic redundancy checksums) для поддержания целостности таблицы разделов, а также резервное копирова ние таблицы разделов. GPT получила такое название изза того, что кроме 36байтового Unicodeимени она назначает каждому разделу свой GUID. На рис. 104 показан пример структуры раздела GPT. Как и в MBRсхеме, первый сектор GPTдиска содержит главную загрузочную запись, которая защищает этот диск от доступа операционных систем, не поддерживающих GPT. Но во втором и последнем секторах диска хранятся заголовки табли цы разделов GPT, а сама таблица размещается сразу за вторым сектором и перед последним сектором. Поддержка расширяемого списка разделов ис ключает необходимость во вложенных разделах, используемых в схеме MBR. Рис. 10-4. Пример структуры GPT-раздела
ГЛАВА 9 Управление внешней памятью 661 ПРИМЕЧАНИЕ Windows не поддерживает создание составных томов на базовых дисках, и новый раздел базового диска эквивалентен тому. Именно поэтому в оснастке Disk Management (Управление дисками) консоли MMC для обозначения тома, созданного на базовом диске, используется термин «раздел» (partition). Диспетчер томов на базовых дисках Драйвер FtDisk (\Windows\System32\Drivers\Ftdisk.sys) создает объекты «уст ройство» дисков для представления томов на базовых дисках и играет основ ную роль в управлении всеми томами на базовых дисках, включая простые тома. Для каждого тома FtDisk создает объект «устройство» вида \Device \Hard diskVolumeX, где X — число, которое идентифицирует том и начинается с 1. На самом деле FtDisk является драйвером шины, поскольку отвечает за перечисление базовых дисков для обнаружения базовых томов и за опове щение о них диспетчера PnP. Определяя существующие разделы на базовых дисках, FtDisk использует диспетчер PnP и драйвер диспетчера разделов (Partmgr.sys). Диспетчер разделов регистрируется у диспетчера PnP, поэто му Windows может уведомить диспетчер разделов о том, что драйвер класса диска создал объект «устройство» раздела. Диспетчер разделов информиру ет FtDisk о новых объектах раздела через закрытый интерфейс и создает объекты «устройство» фильтра (filter device objects), которые потом подклю чает к объектам «устройство» разделов. При наличии объектов «устройство» фильтра Windows посылает диспетчеру разделов уведомление всякий раз, когда удаляется объект «устройство» раздела, что позволяет диспетчеру раз делов обновлять информацию FtDisk. Драйвер класса дисков удаляет объект раздела при удалении раздела с помощью оснастки Disk Management консо ли MMC. Получив сведения о наличии разделов, FtDisk на основе информа ции о конфигурации базовых дисков определяет соответствие между разде лами и томами, а затем создает объекты «устройство» томов. Далее Windows создает в каталоге \Global?? (\?? в Windows 2000) диспет чера объектов символьные ссылки, указывающие на объекты томов, создан ные FtDisk. Когда система или приложение впервые обращается к тому, Win dows монтирует этот том, что позволяет драйверам файловых систем рас познать и захватить во владение тома, отформатированные для поддержи ваемых ими файловых систем (о монтировании см. раздел «Монтирование томов» далее в этой главе). Динамические диски Мы уже упоминали, что динамические диски в Windows нужны для создания составных томов. За поддержку динамических дисков отвечает подсистема диспетчера логических дисков (Logical Disk Manager, LDM), состоящая из компонентов пользовательского режима и драйверов устройств. Microsoft лицензирует LDM у компании VERITAS Software, которая изначально разра ботала технологию LDM для UNIXсистем. Тесно сотрудничая с Microsoft,
662 ГЛ А В А 10 БЕЗОПАСНОСТЬ VERITAS перенесла LDM в Windows, благодаря чему эта операционная сис тема получила более отказоустойчивую схему разбиения на разделы и сред ства поддержки составных томов. Главное отличие схемы разбиения на раз делы LDM в том, что LDM поддерживает одну унифицированную базу дан ных, где хранится информация о разделах на всех динамических дисках системы, в том числе сведения о конфигурации составных томов. ПРИМЕЧАНИЕ UNIXверсия LDM поддерживает и дисковые группы (disk groups): все динамические диски, включаемые системой в груп пу, используют общую базу данных. Однако коммерческое програм мное обеспечение VERITAS для управления логическими дисками в Windows поддерживает создание только одной дисковой группы. База данных LDM База данных LDM размещается в зарезервированном пространстве (разме ром 1 Мб) в конце каждого динамического диска. Именно поэтому Windows требует свободное место в конце базового диска при его преобразовании в динамический. База данных LDM состоит из четырех областей, показанных на рис. 105: сектора заголовка, называемого в LDM «Private Header», табли цы оглавления, записей базы данных и журнала транзакций (пятый раздел на рис. 105 — просто зеркальная копия Private Header). Сектор Private Header размещается за 1 Мб до конца динамического диска и является границей базы данных. Работая с Windows, вы быстро заметите, что для идентифика ции практически всех объектов в ней используются GUID, и диски не состав ляют исключения. GUID — это 128битное число, применяемое различны ми компонентами Windows для уникальной идентификации объектов. LDM назначает GUID каждому динамическому диску, а сектор Private Header ре гистрирует GUID динамического диска, на котором он находится, поэтому данные в Private Header относятся исключительно к конкретному диску. Private Header также хранит указатель на начало таблицы оглавления базы данных и имя дисковой группы, которое формируется конкатенацией име ни компьютера и строки Dg0 (если имя компьютера — Daryl, то имя диско вой группы — DarylDg0). (Как уже говорилось, LDM в Windows поддержива ет только одну дисковую группу, поэтому ее имя всегда оканчивается на Dg0.) Для большей надежности LDM поддерживает копию Private Header в послед нем секторе диска. Таблица оглавления занимает 16 секторов и содержит информацию о структуре базы данных. Область записей базы данных LDM начинается с сек тора заголовка записей базы данных сразу за таблицей оглавления. В этом секторе хранится информация об области записей базы данных, включая число присутствующих в ней записей, имя и GUID дисковой группы, к кото рой относится база данных, и идентификатор последовательности, исполь зуемый LDM для создания следующего элемента в базе данных. Секторы, сле дующие за сектором заголовка записей, содержат записи фиксированного размера (по 128 байтов) с описанием разделов и томов дисковой группы.
ГЛАВА 9 Рис. 10-5. Управление внешней памятью 663 Структура базы данных LDM Элементы базы данных могут быть четырех типов: раздел (partition), диск (disk), компонент (component) и том (volume). Типы элементов определяют три уровня описания томов. LDM связывает элементы с помощью внутрен них идентификаторов объектов. На самом нижнем уровне элементы разде лов (partition entries) описывают нежесткие разделы, которые являются не прерывными областями на диске; идентификаторы, хранящиеся в элементе раздела, связывают его с элементами компонентов и дисков. Элемент дис ка (disk entry) представляет динамический диск в составе группы и включа ет его GUID. Элемент компонента (component entry) служит связующим звеном между одним или несколькими элементами разделов и элементом тома, с которым сопоставлен каждый раздел. Элемент тома хранит GUID этого тома, его суммарный размер, информацию о состоянии и букву дис ка. Элементы дисков, размер которых превышает размер одной записи, за нимают несколько записей; элементы разделов, компонентов и томов ред ко занимают больше одной записи. Простой том в LDM описывается тремя элементами: раздела, компонен та и тома. Ниже показано содержимое простой базы данных LDM, которая определяет один том размером 200 Мб, состоящий из одного раздела. Disk Entry Name: Disk1 GUID: XXXXX... Disk ID: 0x404 Volume Entry Name: Volume1 ID: 0x408 State: ACTIVE Size: 200MB GUID: XXXXX... Drive Hint: H: Component Entry Name: Volume101 ID: 0x409 Parent ID: 0x408 Partition Entry Name: Disk101 ID: 0x407 Parent ID: 0x409 Disk ID: 0x404 Start: 300MB Size: 200MB Элемент раздела описывает область на диске, отведенную тому, элемент компонента связывает элемент раздела с элементом тома, а элемент тома содержит GIUD, используемый Windows на внутреннем уровне для иденти фикации тома. Для составных томов требуется более трех элементов. Напри мер, чередующийся том (о них — позже) состоит минимум из двух элемен тов разделов, элемента компонента и элемента тома. Единственный том, ко торый включает более одного элемента компонента, — зеркальный. Зеркаль ные тома включают два элемента компонентов, каждый из которых пред ставляет половину зеркального тома. Когда вы разбиваете зеркальный том на разделы, LDM может разделить его на уровне компонентов, создав два тома, в каждом из которых будет по одному элементу компонента.
664 ГЛ А В А 10 БЕЗОПАСНОСТЬ Последняя область базы данных LDM отведена под журнал транзакций. Она состоит из нескольких секторов, предназначенных для хранения резерв ной копии информации базы данных в процессе ее изменения. Такая схема гарантирует целостность базы данных даже в случае краха системы или сбоя электропитания, поскольку LDM может восстановить согласованное состо яние базы данных на основе журнала транзакций. ЭКСПЕРИМЕНТ: просмотр базы данных LDM с помощью LDMDump Утилита LDMDump (от Sysinternals) позволяет получить детальную ин формацию о содержимом базы данных LDM. Она принимает номер диска в качестве аргумента командной строки. Выводимая ею инфор мация занимает несколько экранов, поэтому ее следует перенаправить в файл для последующего просмотра в текстовом редакторе (например: ldmdump /d0 > disk.txt). Ниже даны фрагменты выходной информации LDMDump. Первым показывается заголовок базы данных LDM, затем записи этой базы данных, которые описывают 4гигабайтный диск с простым томом размером в 4 Гб. Элемент тома базы данных обозначен как Volume1. В конце вывода LDMDump перечисляет нежесткие разде лы (soft partitions) и определения томов, найденные в базе данных. C:\>ldump /d0 Logical Disk Manager Configuration Dump v1.03 Copyright (C) 20002002 Mark Russinovich PRIVATE HEAD: Signature : Version : Disk Id : Host Id : Disk Group Id : Disk Group Name : Logical disk start : Logical disk size : Configuration start: Configuration size : Number of TOCs : TOC size : Number of Configs : Config size : Number of Logs : Log size : PRIVHEAD 2.11 b78e41692e394a57a98bafd7131392f9 1b77da20c71711d0a5be00a0c91db73c 2ea3c400c92a41729286de46dda1098a Vmware03Dg0 3F 7FF54B (4094 MB) 7FF7E0 800 (1 MB) 1 7FE (1023 KB) 1 5AC (726 KB) 1 DC (110 KB) TOC 0: Signature : TOCBLOCK Sequence : 0x9 Config bitmap start: 0x11 Config bitmap size : 0x5AC
ГЛАВА 9 Управление внешней памятью 665 ... VBLK DATABASE: 0x000004: [000004] <Disk> Name : Disk1 Object Id : 0x0403 Disk Id : b78e41692e394a57a98bafd7131392f9 0x000005: [000002] <DiskGroup> Name : Vmware03Dg0 Object Id : 0x0401 GUID : 2ea3c400c92a41729286de46dda1098a 0x000006: [000006] <Volume> Name : Volume1 Object Id : 0x0406 Volume state: ACTIVE Size : 0x007FB68A (4086 MB) GUID : e6ee6edcd1ba11d8813e806e6f6e6963 Drive Hint : C: ... PARTITION LAYOUT: Disk Disk1: Disk101 Offset: 0x00000000 Length: 0x007FB68A (4086 MB) VOLUME DEFINITIONS: Volume1 Size: 0x007FB68A (4086 MB) Volume101  Disk101 VolumeOffset: 0x00000000 Offset: 0x00000000 Length: 0x007FB68A Схемы разбиения на разделы LDM и GPT или MBR Одно из первых действий при установке Windows на компьютер — создание раздела на основном физическом диске системы. В этом разделе Windows определяет системный том для хранения файлов, нужных на ранних этапах процесса загрузки. Кроме того, Windows Setup требует создать раздел для загрузочного тома, в который она запишет системные файлы Windows и где будет создан системный каталог (\Windows). Системный том можно сделать и загрузочным — тогда вам не понадобится создавать новый раздел для заг рузочного тома. Терминология, используемая Microsoft для системного и загрузочного томов, может сбить с толку. Системным считается том, на ко торый Windows помещает загрузочные файлы, включая загрузчик (Ntldr) и Ntdetect, а загрузочным — том, на котором Windows хранит основные сис темные файлы вроде Ntoskrnl.exe. Хотя данные о разбиении динамического диска на разделы находятся в базе данных, LDM реализует и таблицу разделов в стиле MBR или GPT, что бы загрузочный код Windows мог найти системный и загрузочный тома на динамических дисках. (Например, Ntldr и микрокод IA64 ничего не знают о LDMразделах.) Если диск содержит системный и/или загрузочный тома, они
666 ГЛ А В А 10 БЕЗОПАСНОСТЬ описываются в таблице разделов в стиле MBR или GPT. В ином случае один раздел охватывает всю доступную для использования область диска. LDM помечает его как раздел типа «LDM»; поддержка разделов этого типа впер вые появилась в Windows 2000. В пространстве, определенном в стиле MBR или GPT, LDM создает разделы, организуемые базой данных LDM. Еще одна причина, по которой LDM создает таблицу разделов в стиле MBR или GPT, — чтобы унаследованные утилиты обслуживания дисков, вклю чая работающие в средах с двухвариантной загрузкой, не решили, будто на динамическом диске не определены разделы. Поскольку LDMразделы не описываются таблицей разделов в стиле MBR или GPT, они называются нежесткими (soft partitions), а разделы в стиле MBR или GPT — жесткими (hard partitions). Рис. 106 иллюстрирует струк туру динамического диска, размеченного в стиле MBR. Рис. 10-6. Внутренняя организация динамического диска Диспетчер томов на динамических дисках DLL оснастки Disk Management (DMDiskManager в Windows\System32\Dmd skmgr.dll), показанной на рис. 107, использует DMAdmin, службу LDM Disk Administrator (Windows\System32\Dmadmin.exe) для создания базы данных LDM и изменения ее содержимого. Когда вы запускаете оснастку Disk Mana gement, в память загружается DMDiskManager, который запускает DMAdmin, если она еще не выполняется. DMAdmin считывает с каждого диска базу дан ных LDM и возвращает полученную информацию DMDiskManager. Если DM Admin обнаруживает базу данных из дисковой группы другого компьютера, то отмечает, что эти тома находятся на удаленном диске, и позволяет импор тировать их в базу данных текущего компьютера, если вы хотите их исполь зовать. При изменении конфигурации динамических дисков DMDiskManager информирует DMAdmin о внесенных изменениях, и DMAdmin обновляет свою копию базы данных в памяти. Зафиксировав изменения, DMAdmin передает обновленную базу данных DMIO, драйверу устройства Dmio.sys. DMIO — эквивалент FtDisk для динамических дисков, так что он управляет доступом к базе данных на диске и создает объекты «устройство», представ ляющие тома на динамических дисках. Когда вы закрываете оснастку Disk Management, DMDiskManager останавливает и выгружает службу DMAdmin.
ГЛАВА 9 Рис. 10-7. Управление внешней памятью 667 Оснастка Disk Management (Управление дисками) DMIO не знает, как интерпретировать базу данных, которой он управля ет. За интерпретацию базы данных отвечают DMConfig (Windows\System32\ Dmconfig.dll), загружаемый DMAdmin, и DMBoot (Dmboot.sys), еще один драйвер устройства. DMConfig известно, как считывать и обновлять базу дан ных, а DMBoot — только как ее считывать. DMBoot загружается при загруз ке системы, если другой драйвер LDM, DMLoad (Dmload.sys), обнаруживает в системе минимум один динамический диск. DMLoad определяет наличие динамических дисков, запрашивая DMIO. Если в системе есть хотя бы один динамический диск, DMLoad запускает DMBoot, который сканирует базу дан ных LDM. DMBoot информирует DMIO о составе каждого найденного им тома, что позволяет DMIO создать объекты «устройство» для представления томов. Закончив сканирование, DMBoot тут же выгружается из памяти. По скольку в DMIO не заложена логика для интерпретации базы данных, его размер относительно невелик. Это несомненное преимущество, так как DMIO постоянно находится в памяти. Как и FtDisk, DMIO является драйвером шины и создает объект «устрой ство» для каждого тома динамического диска, присваивая ему имя в виде \Device\HarddiskDmVolumes\PhysicalDmVolumes\BlockVolumeX, где X — иден тификатор тома, назначаемый DMIO. Кроме того, DMIO создает объект «ус тройство» с именем \Device\HarddiskDmVolumes\PhysicalDmVolumes\Raw VolumeX, который представляет необработанный (неструктурированный) вводвывод на томе. Объекты «устройство», созданные DMIO в системе с тре мя томами на динамических дисках, показаны на рис. 108. DMIO также соз дает в пространстве имен диспетчера объектов символьные ссылки на все тома, в том числе по одной ссылке для каждого тома в виде \Device\Hard diskDmVolumes\ComputerNameDg0\VolumeY. DMIO заменяет ComputerName именем компьютера, а Y — идентификатором тома (который отличается от внутреннего идентификатора, назначаемого драйвером DMIO объектам
668 ГЛ А В А 10 БЕЗОПАСНОСТЬ «устройство»). Эти ссылки указывают на объекты блочных устройств в ката логе PhysicalDmVolumes. Рис. 10-8. Объекты «устройство» драйвера DMIO ПРИМЕЧАНИЕ В Windows 2000 имеется еще один драйвер — DiskPerf (\Windows\System32\Drivers\Diskperf.sys); он подключается к объектам «устройство», представляющим физические устройства (например, к \Device\Harddisk0\Partition0), что позволяет ему отслеживать запросы вводавывода, адресованные дискам, и генерировать статистические данные для соответствующих счетчиков оснастки Performance. В Win dows XP и Windows Server 2003 функциональность DiskPerf реализо вана в драйвере диспетчера разделов, так как он уже фильтрует объек ты дисковых устройств для поддержки своих основных функций, о которых мы рассказывали ранее. Управление составными томами FtDisk и DMIO отвечают за представление томов, управляемых драйверами файловой системы, и за перенаправление вводавывода, адресованного то мам, в нижележащие разделы, составляющие тома. В случае простых томов диспетчер томов преобразует смещение в томе в смещение на диске, сумми руя смещение в томе со смещением тома от начала диска. Составные тома более сложны, поскольку составляющие их разделы мо гут быть несмежными и даже находиться на разных дисках. Некоторые типы составных томов используют избыточность данных и требуют еще более сложной трансляции. Таким образом, FtDisk и DMIO должны обрабатывать все запросы вводавывода, адресованные составным томам, и определять, на какие разделы следует направлять тот или иной запрос.
ГЛАВА 9 Управление внешней памятью 669 В Windows поддерживаются следующие типы составных томов: 쐽 перекрытые (spanned volumes); 쐽 зеркальные (mirrored volumes); 쐽 чередующиеся (striped volumes); 쐽 RAID5. Рассмотрев конфигурацию разделов составных томов и логические опе рации для каждого типа составных томов, мы обсудим, как драйверы FtDisk и DMIO обрабатывают IRP, посылаемые драйвером файловой системы со ставному тому. Термин «диспетчер томов» при объяснении составных томов используется для обозначения DMIO, поскольку, как уже говорилось в этой главе, FtDisk поддерживает лишь те составные тома, которые были перене сены из NT 4. Перекрытые тома Перекрытый том — единый логический том, состоящий из нескольких (до 32) свободных разделов на одном или нескольких дисках. Оснастка Disk Management (Управление дисками) консоли MMC объединяет разделы в пе рекрытый том, который затем можно отформатировать для любой файло вой системы, поддерживаемой Windows . На рис. 109 показан 100мегабайт ный перекрытый том с именем D:, созданный из последней трети первого диска и первой трети второго диска. В Windows NT 4 перекрытые тома на зывались наборами томов (volume sets). Рис. 10-9. Перекрытый том Перекрытый том удобен для объединения небольших областей свобод ного дискового пространства в единый том большего объема или для созда ния из нескольких малых дисков одного большого тома. Если перекрытый том отформатирован для NTFS, его можно расширять, добавляя другие сво бодные области или диски, и это не влияет на данные, уже хранящиеся на томе. Расширяемость — одно из самых крупных преимуществ описания всех данных на томе NTFS как единого файла. Размер логического тома NTFS может динамически увеличиваться, поскольку битовая карта, регистрирую щая состояние тома, — не более чем еще один файл, файл битовой карты. Этот файл может быть расширен для учета пространства, добавляемого в том. С другой стороны, динамическое расширение тома FAT потребовало бы расширения самой FAT, что привело бы к смещению всех данных на диске.
670 ГЛ А В А 10 БЕЗОПАСНОСТЬ Диспетчер томов скрывает физическую конфигурацию дисков от файло вых систем, установленных в Windows. Например, на рис. 109 файловая система NTFS рассматривает том D: как обыкновенный 100мегабайтный том. Чтобы определить свободное пространство на этом томе, NTFS обра щается к своей битовой карте. Далее она вызывает диспетчер томов для чте ния или записи данных с конкретного смещения в байтах относительно начала тома. Диспетчер томов последовательно нумерует физические секто ры перекрытого тома от первой области первого диска до последней обла сти последнего диска. Он определяет, какой физический сектор и на каком диске соответствует указанному смещению. Чередующиеся тома Чередующийся том — группа разделов (до 32), каждый из которых разме щается на отдельном диске и объединяется в один логический том. Череду ющиеся тома также называются томами RAID уровня 0, или томами RAID0. На рис. 1010 показан чередующийся том, состоящий из трех разделов, каж дый из которых находится на отдельном диске. (Раздел чередующегося тома не обязательно занимает весь диск; единственное ограничение — все разде лы на каждом диске должны быть одинаковы.) Рис. 10-10. Чередующийся том Файловой системе этот чередующийся том кажется обычным 450мегабайт ным томом, но диспетчер томов оптимизирует хранение и выборку данных на таком томе, распределяя их между физическими дисками. Диспетчер томов обращается к физическим секторам дисков так, как показано на рис. 1011. Рис. 10-11. Логическая нумерация физических секторов в чередующихся томах Поскольку каждая чередующаяся область занимает всего 64 Кб (это зна чение выбрано для того, чтобы отдельные операции чтения и записи не тре бовали обращения сразу к двум дискам), данные болееменее равномерно распределяются между дисками. Таким образом, чередование увеличивает
ГЛАВА 9 Управление внешней памятью 671 вероятность того, что несколько одновременно ожидающих выполнения операций вводавывода потребуют доступа к разным дискам. А поскольку к данным на всех трех дисках можно обращаться одновременно, время задерж ки при дисковом вводевыводе часто снижается, особенно в условиях высо кой нагрузки. Чередующиеся тома упрощают управление томами и позволяют распре делять нагрузку между несколькими дисками, значительно ускоряя вводвы вод. Но это не обеспечивает восстановления данных в случае сбоя диска. В связи с этим диспетчер томов реализует три механизма избыточности: зер кальные тома, тома RAID5 и замена секторов (последний механизм описы вается в главе 12). Эти возможности можно задействовать через оснастку Disk Management. Зеркальные тома В зеркальном томе содержимое раздела на одном диске дублируется в раз деле равного размера на другом диске (рис. 1012). Такие тома иногда назы вают томами RAID уровня 1, или томами RAID1. Рис. 10-12. Зеркальный том Когда программа чтото записывает на диск С:, диспетчер томов помеща ет те же данные в идентичный участок на зеркальный раздел. Если первый диск (или часть данных на нем) окажется поврежденной изза аппаратного или программного сбоя, диспетчер томов автоматически обратится за нуж ными данными к зеркальному разделу. Зеркальный том можно отформати ровать для любой файловой системы, поддерживаемой Windows. При этом драйверы файловых систем остаются независимыми — зеркалирование ни как на них не влияет. Зеркальные тома способствуют увеличению пропускной способности опе раций чтения в сильно загруженных системах. При высокой интенсивности вводавывода диспетчер томов распределяет операции чтения между первич ным и зеркальным разделом (учитывая количество незавершенных запросов вводавывода для каждого диска). Две операции чтения могут быть выполне ны одновременно, т. е. теоретически вдвое быстрее. При модификации фай ла приходится вести запись в оба раздела зеркального набора, но запись на диск выполняется асинхронно, и дополнительная операция записи почти не влияет на быстродействие программ пользовательского режима.
672 ГЛ А В А 10 БЕЗОПАСНОСТЬ Зеркальный том — единственный тип составного тома, допустимого для системного и загрузочного томов. Дело в том, что загрузочный код Windows, включая код MBR и Ntldr, не обладает сложной логикой, необходимой для работы с составными томами. Зеркальные тома составляют исключение, так как загрузочный код воспринимает их как простые тома, считывая данные с той половины зеркального тома, которая помечена как загрузочный или системный диск в таблице разделов MBR. Поскольку загрузочный код не модифицирует данные на диске, он может игнорировать вторую половину зеркального тома. ЭКСПЕРИМЕНТ: наблюдаем за операциями ввода-вывода на зеркальном томе Используя оснастку Performance (Производительность), вы можете убедиться, что при записи на зеркальные тома данные копируются на оба диска, составляющих зеркальный том (зеркало), а операции чте ния, если они не слишком частые, выполняются в основном на одной из половин зеркального тома. Для этого эксперимента вам понадобит ся система с тремя жесткими дисками под управлением серверной ОС Windows 2000 или Windows Server 2003. Если у вас нет такой системы, пропустите инструкции по подготовке эксперимента и переходите сразу к результатам. Создайте зеркальный том с помощью оснастки Disk Management. 1. Запустите Computer Management (Управление компьютером), рас кройте узел Storage (Запоминающие устройства) и выберите пап ку Disk Management (Управление дисками) или откройте Disk Mana gement как оснастку консоли MMC. 2. Щелкните правой кнопкой мыши на свободном пространстве дис ка и выберите команду Create Volume (Создать том). 3. Следуйте инструкциям мастера создания тома, чтобы создать про стой том. (Сначала убедитесь, что на другом диске достаточно сво бодного места для создания тома равного размера.) 4. Щелкните правой кнопкой мыши новый том и из контекстного меню выберите команду Add Mirror (Добавить зеркало). Создав зеркальный том, запустите оснастку Performance (Произво дительность) и добавьте счетчики к объекту PhysicalDisk (Физический диск) для каждого экземпляра диска, содержащего раздел зеркально го тома. Выберите счетчики Disk Reads/Sec (Обращений чтения с дис ка/сек) и Disk Writes/Sec (Обращений записи на диск/сек). На третьем диске, не входящем в состав зеркального тома, выберите большой ка талог и скопируйте его на зеркальный том. Информация в окне осна стки Performance по мере выполнения операции копирования долж на выглядеть примерно так, как показано на иллюстрации.
ГЛАВА 9 Управление внешней памятью 673 Две верхних пересекающихся линии представляют графики для значений Disk Writes/Sec по каждому диску, а две нижних — графики для значений Disk Reads/Sec. Как видите, диспетчер томов (в данном случае — DMIO) записывает данные копируемых файлов в обе поло вины тома, но считывает преимущественно из одной. Это происходит потому, что число незавершенных операций вводавывода при копи ровании невелико и не заставляет диспетчер томов распределять на грузку по операциям чтения между дисками. Тома RAID-5 Том RAID5 — отказоустойчивый вариант обычного чередующегося тома. В томах RAID5 реализуется RAID уровня 5. Эти тома также называются че редующимися томами с записью четности (striped volumes with parity), по скольку они основаны на том же принципе чередования. Отказоустойчи вость достигается за счет резервирования эквивалента одного диска для хра нения информации о четности для всех чередующихся областей. Том RAID5 представлен на рис. 1013. Рис. 10-13. Том RAID-5
674 ГЛ А В А 10 БЕЗОПАСНОСТЬ Как показано на рис. 1013, информация о четности для чередующейся области 1 хранится на диске 1. Она представляет собой побайтовую логи ческую сумму (XOR) первых чередующихся областей на дисках 2 и 3. Инфор мация о четности для чередующейся области 2 хранится на диске 2, а для чередующейся области 3 — на диске 3. Такое циклическое размещение ин формации о четности по дискам представляет собой способ оптимизации вводавывода. Всякий раз, когда данные записываются на какойлибо из дис ков, байты четности, соответствующие изменяемым байтам, должны быть пересчитаны и перезаписаны. Если бы информация о четности постоянно записывалась на один и тот же диск, он был бы все время занят и мог бы стать узким местом для вводавывода. Восстановление диска после сбоя в томе RAID5 основывается на простом арифметическом принципе: если в уравнении с n переменными известны значения n – 1 переменных, то значение оставшейся переменной можно определить вычитанием. Например, в выражении x + y = z, где z обозначает чередующуюся область с четностью, диспетчер томов вычисляет z – y, что бы определить значение x, и z – x, чтобы найти y. Диспетчер томов исполь зует сходную логику для восстановления потерянных данных. Если том RAID5 выходит из строя или данные на одном из его дисков становятся не читаемыми, диспетчер томов реконструирует отсутствующие данные, ис пользуя операцию XOR (побитовое логическое сложение). В случае сбоя диска 1 на рис. 1013 содержимое его чередующихся обла стей 2 и 5 вычисляется побайтовым логическим сложением соответствую щих чередующихся областей на диске 3 с областями четности на диске 2. Содержимое чередующихся областей 3 и 6 определяется побайтовым логи ческим сложением соответствующих областей на диске 2 с областями чет ности на диске 3. Для организации тома RAID5 требуется по крайней мере три диска (а точнее, три одинаковых по размеру раздела на трех дисках). Пространство имен томов Такой аспект управления внешней памятью, как назначение томам букв дис ков, в Windows существенно изменился по сравнению с Windows NT 4. Не смотря на это, Windows поддерживает назначения букв, переносимые при обновлении системы с Windows NT 4 до Windows . Назначенные буквы Win dows NT 4 хранит в разделе реестра HKLM\SYSTEM\Disk. После обновления эта информация сохраняется в других местах, специфичных для Windows, и система больше не ссылается на раздел Disk. Диспетчер монтирования Диспетчер монтирования, драйвер устройства Mountmgr.sys, назначает бук вы томам динамических и базовых дисков, созданных после установки Win dows, а также устройствам CDROM, приводам гибких дисков и съемным ус тройствам. Эта операционная система хранит все буквы дисков, назначен ные томам, в разделе реестра HKLM\SYSTEM\MountedDevices. Заглянув в этот
ГЛАВА 9 Управление внешней памятью 675 раздел, вы увидите параметры с именами вида \??\Volume{X} (где X — GUID) и \DosDevices\C:. Такие параметры есть у каждого тома, но не всем томам назначены буквы дисков. Пример раздела реестра MountedDevices диспетче ра монтирования показан на рис. 1014. Заметьте, что этот раздел, как и раз дел Disk в Windows NT 4, не входит в набор параметров управления и в свя зи с этим не восстанавливается при загрузке последней удачной конфигу рации (см. главу 4). Данные, которые хранятся в виде параметров реестра для букв и имен томов базовых дисков, представляют собой сигнатуру диска в стиле Windows NT 4 и начальное смещение от первого раздела, сопоставленного с томом. Аналогичные данные для томов динамических дисков включают внутренний GUID тома, используемый DMIO. Когда диспетчер монтирования инициали зируется при загрузке системы, он регистрируется в подсистеме поддержки Plug and Play, что позволяет ему в дальнейшем получать уведомления о со здании томов драйвером FtDisk или DMIO. Получив такое уведомление, дис петчер монтирования определяет GUID или сигнатуру диска нового тома и использует GUID тома или сигнатуру его диска как критерий для поиска в своей базе данных, отражающей содержимое раздела реестра MountedDe vices. Если поиск заканчивается неудачей, диспетчер монтирования запра шивает у FtDisk или DMIO (смотря кто из них создал том) предлагаемую бук ву для идентификации тома и сохраняет ее в своей базе данных. FtDisk не дает никаких предложений, а DMIO проверяет возможные назначения в эле менте тома базы данных. Рис. 10-14. Смонтированные устройства, перечисленные в разделе реестра, принадлежащем диспетчеру монтирования Если диспетчер монтирования не получает никаких предложений, он берет первую свободную букву, назначает ее тому, создает для нее символьную ссыл ку — например, \Global??\D: в Windows XP и Windows Server 2003 или \??\D: в Windows 2000 — и обновляет раздел реестра MountedDevices. Когда свободных
676 ГЛ А В А 10 БЕЗОПАСНОСТЬ букв нет, буква не назначается, но создается символьная ссылка \Global??\Volu me{X}, определяющая GUID нового тома в том случае, если у него еще нет GUID. Этот GUID отличается от GUID томов, используемых DMIO. Точки монтирования Точки монтирования (mount points) позволяют связывать тома через каталоги NTFS, делая эти тома доступными без назначения букв дисков. Например, NTFSкаталог C:\Projects может монтировать другой том (NTFS или FAT), со держащий каталоги и файлы ваших проектов. Если в томе ваших проектов есть файл с именем \CurrentProject\Description.txt, то после монтирования путь к нему выглядит как C:\Projects\CurrentProject\Description.txt. Точки мон тирования стали возможны благодаря технологии точек повторного разбо ра (reparse point technology), о которой мы подробно поговорим в главе 12. Точка повторного разбора — это блок произвольных данных с неким фиксированным заголовком, который Windows сопоставляет с файлом или каталогом NTFS. Приложение или система определяет формат и поведение точки повторного разбора, в том числе значение уникального тэга, который идентифицирует точку повторного разбора, принадлежащую приложению или системе, и указывает размер (до 16 Кб) и смысл данных этой точки. Уни кальные тэги хранятся в фиксированном сегменте точек повторного разбо ра. Любое приложение, реализующее точку повторного разбора, должно предоставлять драйвер фильтра файловой системы, который наблюдает за кодами возврата файловых операций, связанных с повторным разбором и выполняемых на томах NTFS, и предпринимает действия, соответствующие этим кодам. NTFS возвращает код статуса повторного разбора всякий раз, когда обрабатывает файловую операцию применительно к файлу или ката логу, с которым сопоставлена точка повторного разбора. Драйвер файловой системы NTFS, диспетчер вводавывода и диспетчер объектов — каждый из них реализует свою часть функциональности точек повторного разбора. Диспетчер объектов инициирует операции разбора путей файлов, взаимодействуя с драйверами файловых систем через диспет чер вводавывода, и должен повторно инициировать операции, для которых диспетчер вводавывода возвращает код статуса повторного разбора. Дис петчер вводавывода поддерживает модификацию путей, которая может понадобиться точкам монтирования и другим точкам повторного разбора, а драйвер файловой системы NTFS должен связывать данные точек повтор ного разбора с файлами и каталогами. Поэтому диспетчер вводавывода можно рассматривать как драйвер фильтра файловой системы, который поддерживает функциональность повторного разбора для многих точек, определенных Microsoft. Пример приложения, поддерживающего точки повторного разбора, — система Hierarchical Storage Management (HSM) вроде службы Windows Remote Storage Service (RSS), которая включена в Windows 2000 Server и Windows Server 2003; она использует такие точки для обозначения файлов, перемещаемых администратором в хранилище на ленточных накопителях. Когда пользова
ГЛАВА 9 Управление внешней памятью 677 тель пытается обратиться к автономному файлу, драйвер фильтра HSM обна руживает код статуса повторного разбора, возвращаемый NTFS, вызывает сер висы пользовательского режима, чтобы получить автономный файл из хра нилища, удаляет из файла точку повторного разбора и инициирует повтор ную попытку выполнения файловой операции. Точно так же точки повторно го разбора используются драйвером фильтра RSS (Rsfilter.sys). Если файл или каталог, для которого диспетчер вводавывода получает от NTFS код статуса повторного разбора, не сопоставлен с одной из предопре деленных в Windows точек повторного разбора, значит, его точка не обра батывается ни одним драйвером фильтра. Тогда диспетчер вводавывода со общает диспетчеру объектов об ошибке, которая передается приложению, обратившемуся к этому файлу или каталогу, в виде «file cannot be accessed by the system» («файл недоступен системе»). Точки монтирования — это точки повторного разбора, в которых имя тома (\Global??\Volume{X}) хранится как данные повторного разбора. Назна чая или удаляя пути для томов в оснастке Disk Management, вы создаете точ ки монтирования. Создавать и просматривать точки монтирования можно и с помощью встроенной утилиты командной строки Mountvol.exe (\Win dows\System32\Mountvol.exe). Диспетчер монтирования поддерживает на каждом томе NTFS удаленную базу данных, в которой регистрирует все точки монтирования, определен ные для тома. Файл этой базы данных, $MountMgrRemoteDatabase, размеща ется в корневом каталоге NTFS. При перемещении диска между системами и в средах с двухвариантной загрузкой (различных систем Windows) пере мещаются и точки монтирования — благодаря наличию удаленной базы дан ных диспетчера монтирования. NTFS отслеживает точки монтирования в файле метаданных \$Extend\$Reparse (ни один из файлов метаданных NTFS не доступен приложениям). Поскольку NTFS хранит информацию о точках монтирования в файле метаданных, при соответствующем запросе Windows приложения Windows может легко перечислить точки монтирования, опре деленные для тома. ЭКСПЕРИМЕНТ: рекурсивные точки монтирования Этот эксперимент с использованием утилиты Filemon (www.sysinter nals.com) демонстрирует любопытное поведение системы, вызываемое рекурсивной точкой монтирования. Рекурсивной называется точка монтирования, связанная с тем томом, где она находится. Рекурсивное перечисление каталогов, выполняемое на рекурсивной точке монти рования, позволяет наглядно увидеть, как NTFS обрабатывает точки монтирования. Для создания и просмотра точки монтирования проделайте следу ющее. 1. Откройте окно командной строки или Windows Explorer и создай те на NTFSдиске каталог с именем \Recurse. см. след. стр.
678 ГЛ А В А 10 БЕЗОПАСНОСТЬ 2. В оснастке Disk Management (Управление дисками) консоли MMC щелкните том правой кнопкой мыши и выберите из контекстного меню команду Change Drive Letter And Path (Изменить букву диска или путь к диску). 3. В появившемся диалоговом окне введите путь к созданному вами каталогу (например, I:\Recurse). 4. Запустите Filemon. В меню Drives оставьте галочку только для тома, на котором создана точка монтирования. Теперь вы готовы к трассировке рекурсивной точки монтирования. Откройте окно командной строки и введите dir /s I:\Recurse. Следи те за ссылками на Recurse, регистрируемыми Filemon при трассиров ке файловых операций. Вы заметите, что сначала идет обращение к I:\Recurse, затем к I:\Recurse\Recurse и т. д. Приложение перечисляет каталоги на каждом уровне рекурсии, но всякий раз, когда встречает точку монтирования, оно закапывается все глубже и глубже, пытаясь выполнить очередное перечисление катало гов. NTFS возвращает код статуса повторного разбора, который сигна лизирует диспетчеру объектов о необходимости возврата на предыду щий уровень рекурсии и повторной попытки операции. Наконец, вер нувшись в корневой каталог, приложение исследует файл или каталог, найденный им при глубокой рекурсии. Приложение никогда не полу чает код статуса повторного разбора изза того, что диспетчер объек тов сам обрабатывает статусные коды повторного разбора при полу чении их от NTFS. Filemon показывает запрос на открытие файла или каталога как IRP_ MJ_CREATE, запрос на закрытие файла или каталога — как IRP_MJ_CLO SE, а запрос сведений о каталогах — как IRP_MJ_DIRECTORY _CONTROL, выполняемый с помощью функции FileBothDirectoryInfo (см. колонку Other).
ГЛАВА 9 Управление внешней памятью 679 Чтобы предотвратить переполнение буферов и вхождение в беско нечный цикл, командный процессор и Windows Explorer останавливают рекурсию по достижении 32го уровня вложенности или при превыше нии длины пути в 256 символов — смотря что произойдет быстрее. Монтирование томов Тот факт, что Windows присваивает тому букву диска, еще не означает, что этот том содержит данные, организованные в формате файловой системы, извест ной Windows. Процесс распознавания тома заключается в том, что какаялибо файловая система объявляет раздел своим; первый раз этот процесс проис ходит при обращении ядра, драйвера устройства или приложения к какому либо файлу или каталогу в данном томе. После того как драйвер файловой системы уведомляет о взятии на себя ответственности за управление разде лом, диспетчер вводавывода направляет все адресованные этому тому запро сы данному драйверу. Операции монтирования в Windows проходят в три этапа: регистрация драйвера файловой системы, обновление блоков парамет ров тома (volume parameter blocks, VPB) и запросы на монтирование. ПРИМЕЧАНИЕ В Windows Server 2003 Enterprise и Datacenter Edition автоматическое монтирование отключено, чтобы не допустить агрес сивного монтирования томов, подключенных к сети устройств хране ния данных (System Area Network, SAN). Для включения или отключе ния автоматического монтирования можно использовать утилиту ко мандной строки Diskpart, поставляемую с Windows Server 2003, а для монтирования томов вручную — утилиту Mountvol, также поставляе мую с этой системой. Процесс монтирования курирует диспетчер вводавывода, которому из вестны доступные драйверы файловых систем, поскольку они регистриру ются у него при инициализации. Для регистрации драйверов файловых сис тем на локальных (не сетевых) дисках предназначена функция IoRegister FileSystem, предоставляемая диспетчером вводавывода. Когда драйвер фай ловой системы регистрируется, диспетчер вводавывода сохраняет ссылку на драйвер в списке, который используется при операциях монтирования. Каждый объект «устройство» содержит структуру данных VPB, но диспет чер вводавывода обращает внимание только на VPB объектов томов. VPB слу жит для связи между объектом тома и объектом «устройство», созданным драйвером файловой системы для представления экземпляра файловой сис темы, смонтированной для данного тома. Если ссылка VPB на файловую сис тему пуста, значит, том не смонтирован ни одной файловой системой. Дис петчер вводавывода проверяет VPB объекта тома всякий раз, когда выполня ется APIфункция открытия файла или каталога на этом объекте «устройство». Например, если диспетчер монтирования назначает второму тому систе мы букву D, он создает символьную ссылку \Global??\D:, представляющую объект \Device\HarddiskVolume2. Windowsприложение, пытающееся открыть
680 ГЛ А В А 10 БЕЗОПАСНОСТЬ файл \Temp\Test.txt на диске D:, указывает имя D:\Temp\Test.txt, которое под система Windows преобразует в \Global??\D:\Temp\Test.txt перед вызовом NtCreateFile — процедуры ядра, отвечающей за открытие файла. NtCreateFile использует диспетчер объектов для разбора имени, и диспетчер объектов об наруживает объект «устройство» \Device\HarddiskVolume2 с еще не разрешен ным путем \Temp\Test.txt. На этом этапе диспетчер вводавывода проверяет, есть ли в VPB объекта \Device\HarddiskVolume2 ссылка на файловую систему. Если нет, диспетчер вводавывода выдает зарегистрированному драйверу фай ловой системы запрос на монтирование, чтобы выяснить, распознает ли он формат монтируемого тома как формат своей файловой системы. ЭКСПЕРИМЕНТ: просмотр VPB Увидеть содержимое VPB позволяет команда !vpb отладчика ядра. По скольку на VPB указывает объект «устройство» тома, сначала нужно найти этот объект. Для этого создайте дамп объекта «драйвер» диспет чера томов, найдите объект «устройство», представляющий том, про смотрите его содержимое и вы обнаружите поле VPB. Если в системе есть динамический диск, используйте команду !drvobj применительно к драйверу DMIO, а если нет — применитель но к драйверу FtDisk. Вот пример: kd> !drvobj ftdisk Driver object (818aec50) is for: \Driver\Ftdisk Driver Extension List: (id , addr) Device Object list: 818a5290 817e96f0 817e98b0 817e9030 818a73b0 818a7810 8182d030 Команда !drvobj перечисляет адреса объектов «устройство», принад лежащих драйверу. В этом примере таких объектов — семь. Один из них представляет программный интерфейс драйвера устройства, ос тальные — объекты томов. Поскольку объекты показываются в поряд ке, обратном порядку их создания, а первым создается объект «устрой ство» интерфейса драйвера устройства, то первый перечисленный объект «устройство» является объектом тома. Теперь введите команду !devobj отладчика ядра, указав в качестве параметра адрес объекта тома. kd> !devobj 818a5290 Device object (818a5290) is for: HarddiskVolume6 \Driver\Ftdisk DriverObject 818aec50 Current Irp 00000000 RefCount 3 Type 00000007 Flags 00001050 Vpb 818a5da8 Dacl e1000384 DevExt 818a5348 DevObjExt 818a53f8 Dope 818a50a8 DevNode 818a5ae8 ExtensionFlags (0xa8000000) DOE_RAW_FDO, DOE_DESIGNATED_FDO Unknown flags 0x08000000
ГЛАВА 9 Управление внешней памятью 681 AttachedDevice (Upper) 86b52b58 \Driver\VolSnap Device queue is not busy. Команда !devobj показывает поле VPB объекта тома. (Данному объекту «устройство» присвоено имя HarddiskVolume6.) Теперь можно выполнить команду !vpb: kd> !vpb 818a5da8 Vpb at 0x818a5da8 Flags: 0x1 mounted DeviceObject: 0x850dcac0 RealDevice: 0x818a5290 RefCount: 3 Volume Label: BACKUP В итоге мы выяснили, что объект тома смонтирован драйвером файловой системы, который присвоил ему имя BACKUP. VPBполе RealDevice указывает обратно на объект тома, а поле DeviceObject ука зывает на объект «устройство» смонтированной файловой системы. По соглашению, драйвер файловой системы при распознавании форма та монтируемого тома должен анализировать загрузочную запись тома, хра нящуюся в его первом секторе. Загрузочные записи файловых систем Micro soft содержат поле, описывающее тип формата файловой системы. Драйве ры файловых систем обычно проверяют это поле и, если оно указывает на поддерживаемый ими формат, анализируют остальную информацию, хра нящуюся в загрузочной записи. Эта информация обычно включает имя фай ловой системы и данные, необходимые для поиска критически важных фай лов метаданных тома. Например, NTFS распознает том, только если поля типа и имени определяют именно NTFS, а файлы метаданных, описываемые загрузочной записью, находятся в согласованном состоянии. Если драйвер файловой системы подтверждает распознавание, диспетчер вводавывода заполняет VPB и передает запрос на открытие с оставшейся частью пути (т. е. \Temp\Test.txt) драйверу файловой системы. Последний выполняет запрос, интерпретируя данные в соответствии с форматом сво ей файловой системы. После того как поля VPB объекта «устройство» тома заполнены нужной информацией, диспетчер вводавывода передает все пос ледующие запросы, адресованные данному тому, драйверу смонтированной файловой системы. Если ни один драйвер файловой системы не объявляет этот том своим, владельцем становится Raw — встроенный в Ntoskrnl.exe драйвер файловой системы, который сообщает о неудаче в ответ на любые попытки открыть файл в данном разделе. Рис. 1015 иллюстрирует упрощен ную схему потока вводавывода, направляемого на смонтированный том (здесь не показано взаимодействие драйвера файловой системы с диспетче рами кэша и памяти). Вместо того чтобы загружать все драйверы файловых систем независимо от наличия соответствующих томов, Windows пытается свести к минимуму
682 ГЛ А В А 10 БЕЗОПАСНОСТЬ нагрузку на память, используя для предварительного распознавания файло вой системы суррогатный драйвер File System Recognizer (Windows \System32\ Drivers\Fs_rec.sys). Этот драйвер знает о формате каждой файловой системы, поддерживаемой Windows, ровно столько, чтобы суметь проанализировать загрузочную запись и определить, можно ли ее сопоставить с какойнибудь файловой системой Windows. При загрузке системы File System Recognizer регистрируется как драйвер файловой системы, а при вызове диспетчером вводавывода в процессе монтирования файловой системы для нового тома он загружает драйвер соответствующей файловой системы, если такой драй вер еще не загружен. После этого File System Recognizer перенаправляет IRP монтирования драйверу и позволяет ему захватить том во владение. Рис. 10-15. Поток ввода-вывода на смонтированном томе Кроме загрузочного тома, чей драйвер монтируется при инициализации ядра, драйверы файловых систем монтируют большинство томов в момент запуска Chkdsk для проверки целостности файловой системы на этапе загруз ки системы. Загрузочная версия Chkdsk является встроенным приложением (в отличие от Windowsприложений) и называется Autochk.exe (\Windows \System32\Autochk.exe). Диспетчер сеансов (\Windows\System32 \Smss.exe) запускает ее, поскольку она указана в параметре HKLM\SYSTEM\Current ControlSet\Control\Session Manager\BootExecute. Chkdsk перебирает все назна ченные буквы диска, чтобы выяснить, требует ли соответствующий том про верки целостности. Один и тот же сменный носитель может монтироваться более чем раз. Драйверы файловых систем Windows реагируют на смену носителей и зап
ГЛАВА 9 Управление внешней памятью 683 рашивают идентификатор тома. Если они обнаруживают, что идентифика тор тома сменился, драйверы демонтируют диск и монтируют его заново. Операции ввода-вывода на томах Драйверы файловых систем управляют хранящимися в томах данными, но требуют поддержки диспетчера томов для взаимодействия с драйверами ус тройств внешней памяти при передаче данных. Драйверы файловых систем получают ссылки на объекты томов в процессе монтирования и посылают через них запросы диспетчеру томов. Приложения — если им нужно напря мую обращаться к данным тома — тоже могут посылать запросы диспетче ру томов, обходя драйвер файловой системы. К числу таких приложений относятся, например, программы восстановления удаленных файлов и ути лита DiskProbe из ресурсов Windows. Когда драйвер файловой системы или приложение посылает объекту «ус тройство», представляющему том, запрос вводавывода, диспетчер ввода вывода перенаправляет этот запрос (поступающий в виде IRP) диспетчеру томов, создавшему целевой объект «устройство». Таким образом, если при ложению нужно считать загрузочный сектор, например, второго простого тома в системе, оно открывает объект \Device\HarddiskVolume2 и посылает ему запрос на чтение 512 байтов по нулевому смещению на устройстве. Дис петчер вводавывода передает запрос приложения в виде IRP диспетчеру томов, владеющему данным объектом «устройство», и уведомляет его, что IRP адресован устройству HarddiskVolume2. Поскольку том логически представляет непрерывную область одного или более физических дисков, диспетчер томов должен преобразовывать смеще ния, относительные началу тома, в смещения, относительные началу диска. Если том 2 состоит из одного раздела, который начинается с 4096го секто ра диска, то, прежде чем передать запрос драйверу класса дисков, диспетчер томов соответственно корректирует параметры IRP. Для выполнения ввода вывода на физическом диске и чтения запрошенных данных в буфер прило жения, указанный в IRP, драйвер класса дисков использует минипортдрайвер. Роль диспетчера томов в обработке запросов к составным томам помо гут прояснить следующие примеры. Если чередующийся том состоит из двух разделов (1 и 2), представленных объектом \Device\HarddiskDmVolumes\ PhysicalDmVolumes\BlockVolume3 (рис. 1016), и администратор назначил чередующейся области букву диска D:, то диспетчер вводавывода определяет ссылку \Global??\D:, указывающую на \Device\HarddiskDmVolumes\Computer NameDg0\Volume3, где ComputerName — имя компьютера. Вспомните, что эта ссылка также является символьной и указывает на соответствующий объект тома в каталоге PhysicalDmVolumes (в данном случае — на BlockVolu me3). Объект «устройство», принадлежащий DMIO, перехватывает дисковый вводвывод файловой системы на \Device\HarddiskDmVolumes\PhysicalDm Volumes\BlockVolume3, и драйвер DMIO корректирует параметры запроса перед тем, как передать его драйверу класса дисков. В результате изменений, внесенных DMIO, запрос настраивается так, чтобы он ссылался на нужное
684 ГЛ А В А 10 БЕЗОПАСНОСТЬ смещение, относительное началу целевой чередующейся области раздела 1 или 2. Если вводвывод затрагивает оба раздела тома, DMIO должен выдать два дополнительных запроса вводавывода — по одному к каждому диску. Рис. 10-16. Операции ввода-вывода DMIO В случае записи на зеркальный том DMIO делит каждый запрос так, что операция записи выполняется над каждой половиной зеркального тома. А при запросе на чтение с зеркального тома DMIO использует одну из по ловин зеркального тома и обращается к другой половине, только если пер вая попытка чтения заканчивается неудачно. Служба виртуального диска Компания, которая выпускает продукты, имеющие отношение к внешней памяти, например RAIDадаптеры, жесткие диски или массивы накопителей, вынуждена реализовать собственные приложения для установки этих уст ройств и управления ими. Применение разных управляющих приложений для разных устройств внешней памяти имеет очевидные недостатки с точ ки зрения системного администрирования, например приходится изучать множество интерфейсов и нельзя использовать стандартные Windowsути литы для управления сторонними устройствами внешней памяти. В Windows Server 2003 введена служба виртуального диска (Virtual Disk Service, VDS) (\Windows\System32\Vds.exe), которая предоставляет систем ным администраторам унифицированный высокоуровневый интерфейс
ГЛАВА 9 Управление внешней памятью 685 внешней памяти; благодаря этому устройствами внешней памяти от разных поставщиков можно управлять через одни и те же пользовательские интер фейсы (UI). Схема VDS представлена на рис. 1017. VDS экспортирует API, основанный на COM и позволяющий приложениям и сценариям создавать и форматировать диски, а также управлять аппаратными RAIDадаптерами. Скажем, утилита может задействовать VDS API для запроса списка физичес ких дисков, сопоставленных с номером логического блока RAID (logical unit number, LUN). Windowsсредства управления дисками, включая оснастку Disk Management консоли MMC, Diskpart и Diskraid (поставляется с Windows Ser ver 2003 Deployment Kit), тоже используют VDS API. Рис. 10-17. Архитектура VDS VDS предоставляет два интерфейса: один — для провайдеров програм много уровня, другой — для провайдеров аппаратного уровня. 쐽 Провайдеры программного уровня (software providers) реализуют интер фейсы к таким высокоуровневым абстракциям устройств внешней памя ти, как диски, разделы дисков и тома. Примеры операций, поддерживае мых этими интерфейсами, — расширение и удаление томов, включение и отключение зеркалирования, форматирование томов и присвоение им букв дисков. VDS ищет зарегистрированные программные провайдеры в HKLM\System\CurrentControlSet\Services\Vds\SoftwareProviders. Windows
686 ГЛ А В А 10 БЕЗОПАСНОСТЬ Server 2003 включает VDS Dynamic Disk Provider (\Windows\System32\ Vdsdyndr.dll), применяемый в качестве интерфейса для динамических дисков, и VDS Basic Provider (\Windows\System32\Vdsbas.dll), используе мый в качестве интерфейса для базовых дисков. 쐽 Провайдеры аппаратного уровня (hardware providers) реализуются изго товителями оборудования в виде DLL, которые регистрируются в разде ле реестра HKLM\System\CurrentControlSet\Services\Vds\HardwareProvi ders и которые транслируют аппаратнонезависимые VDSкоманды в ко манды, специфичные для конкретного оборудования. Провайдер аппа ратного уровня позволяет управлять подсистемой внешней памяти, на пример аппаратным RAIDмассивом или платами адаптеров/контролле ров, и поддерживает такие операции, как создание, расширение, удале ние, маскирование и отмена маскирования LUN. Когда приложение инициирует соединение с VDS API и служба VDS еще не запущена, процесс Svchost — хост службы RPC запускает процесс загруз чика VDS (\Windows\System32\Vdsldr.exe), а тот — процесс службы VDS, пос ле чего завершается. После закрытия последнего соединения с VDS API за вершается и процесс службы VDS. Служба теневого копирования тома Одно из ограничений многих утилит резервного копирования связано с от крытыми файлами. Если приложение открывает какойнибудь файл для мо нопольного доступа, утилита резервного копирования не может получить доступа к содержимому этого файла. Но даже если подобная утилита способ на обращаться к уже открытому файлу, нет никаких гарантий, что его резерв ная копия не окажется в рассогласованном состоянии. Допустим, приложение обновляет начальную часть файла, а потом чтото пишет в его конце. Утили та резервного копирования, которая сохраняет файл в ходе этих операций, может записать такой образ файла, который отражает еще не модифициро ванную начальную часть файла и уже измененную концевую часть. При пос ледующем восстановлении этого файла приложение сочтет, что файл повреж ден, поскольку оно допускает ситуации, в которых начальная часть уже изме нена, а концевая — еще нет, но только не наоборот. Именно поэтому большин ство утилит резервного копирования пропускает открытые файлы. В связи с этим в Windows XP появилась служба теневого копирования то мов (Volume Shadow Copy Service) (\Windows\System32\Vssvc.exe), которая позволяет встроенной утилите резервного копирования записывать согласо ванные представления всех файлов, в том числе открытых. Эта служба высту пает в роли командного центра расширяемого механизма резервного копи рования, давая возможность независимым поставщикам программного обес печения (independent software vendors, ISV) подключать свои провайдеры и модули записи («writers»). Модуль записи — это программный компонент, позволяющий приложениям с поддержкой теневого копирования томов при нимать уведомления о замораживании и размораживании операций записи,
ГЛАВА 9 Управление внешней памятью 687 чтобы они могли создавать внутренне согласованные резервные копии сво их файлов данных. А провайдеры позволяют ISV интегрировать уникальные схемы работы с внешней памятью со службой теневого копирования томов. Например, приложение, использующее устройства внешней памяти с зерка лированием, могло бы определять теневую копию как замороженную поло вину зеркалированного тома. Взаимосвязи между службой теневого копиро вания томов, модулями записи и провайдерами показаны на рис. 1018. Рис. 10-18. Служба теневого копирования томов, модули записи и провайдеры Microsoft Shadow Copy Provider (\Windows\System32\Drivers\Volsnap.sys) — это провайдер, поставляемый с Windows для поддержки программных сним ков томов. Он представляет собой драйвер фильтра внешней памяти, разме щаемый между драйверами файловых систем и драйверами томов (они опе рируют с наборами секторов на жестком диске, представляющими логичес кие диски), и поэтому видит любые запросы на вводвывод, адресованные дисковому тому. Утилита резервного копирования, приступая к копирова нию, указывает драйверу Microsoft Shadow Copy Provider создать теневые копии всех томов, на которых содержатся копируемые файлы и каталоги. Драйвер замораживает все операции вводавывода на этих томах и для каж дого из них создает теневую копию. Если, например, том в пространстве имен диспетчера объектов имеет имя \Device\HarddiskVolume0, то теневой том получает имя в виде \Device\HarddiskVolumeShadowCopyN, где N — уни кальный идентификатор.
688 ГЛ А В А 10 БЕЗОПАСНОСТЬ ЭКСПЕРИМЕНТ: просмотр объектов «устройство», принадлежащих драйверу Microsoft Shadow Copy Provider Чтобы просмотреть такие объекты, связанные с каждым томом, в Win dows XP или Windows Server 2003, используйте отладчик ядра. В лю бой системе есть хотя бы один том, и следующая команда выводит информацию об объекте «устройство» для первого тома в системе: 0: kd> !devobj \device\harddiskvolume1 Device object (86b9daf8) is for: HarddiskVolume1 \Driver\Ftdisk DriverObject 86b6af38 Current Irp 00000000 RefCount 2 Type 00000007 Flags 00001050 Vpb 86b90008 Dacl e1000384 DevExt 86b9dbb0 DevObjExt 86b9dc98 Dope 86ba33e8 DevNode 86b71320 ExtensionFlags (0xa8000000) DOE_RAW_FDO, DOE_DESIGNATED_FDO Unknown flags 0x08000000 AttachedDevice (Upper) 86b687f8 \Driver\VolSnap Device queue is not busy. Поле AttachedDevice в выводе команды !devobj сообщает адрес объек та «устройство» и имя владеющего им драйвера, который подключен к этому объекту (фильтрует его). Каждый объект «устройства» для тома должен принадлежать драйверу Volsnap, как в показанном примере. Вместо того чтобы открывать копируемые файлы на исходном томе, ути лита резервного копирования открывает их на теневом. Последний отража ет представление тома, привязанное к определенной временной точке (pointintime view of a volume). Поэтому, когда драйвер теневого копирова ния томов обнаруживает попытку записи на исходный том, он считывает копию подлежащих перезаписи секторов в раздел памяти, поддерживаемый страничным файлом (paging filebacked memory section) и сопоставленный с соответствующим теневым томом. Обращения для чтения к модифициру емым секторам теневого тома драйвер обслуживает через упомянутый выше раздел памяти, а обращения для чтения к немодифицированным секторам — считыванием данных с исходного тома. Поскольку утилита резервного ко пирования не сохраняет страничный файл и системный каталог \System Volume Information (вместе со всеми подкаталогами и файлами), драйвер снимков, используя APIфункции дефрагментации, определяет местонахож дение этих файлов и каталогов и не регистрирует вносимые в них измене ния. Опираясь на данный механизм, утилита резервного копирования в Windows XP и Windows Server 2003 решает все проблемы копирования, свя занные с открытыми файлами. Рис. 1019 иллюстрирует, как ведут себя приложение, обращающееся к тому, и утилита резервного копирования, обращающаяся к теневой копии этого тома. Когда приложение пишет в сектор по истечении времени сня тия снимка, драйвер Volsnap создает резервную копию, как на иллюстрации, где он копирует секторы a, b и c для тома C:. Аналогично, когда приложение
ГЛАВА 9 Управление внешней памятью 689 считывает сектор c, Volsnap направляет операцию чтения тому C:, а когда утилита резервного копирования считывает тот же сектор, Volsnap получа ет содержимое этого сектора из снимка. Если операция чтения требует об ращения к немодифицированному сектору, например к d, то Volsnap направ ляет ее исходному тому. Рис. 10-19. Так работает Volsnap ЭКСПЕРИМЕНТ: просмотр объектов «устройство» теневых томов Вы можете убедиться в наличии таких объектов в пространстве имен диспетчера объектов, запустив Windowsутилиту резервного копирова ния [в меню Start (Пуск) откройте Accessories (Стандартные) и System Tools (Служебные)] и выбрав достаточный объем данных для резервного копирования, чтобы успеть запустить Winobj и просмотреть объекты в подкаталоге \Device. Драйверы файловых систем должны корректно обрабатывать два запроса на управление вводомвыводом (IOCTL), связанные с теневым копированием томов: IOCTL_VOLSNAP_FLUSH_AND_HOLD_WRITES и IOCTL_VOLSNAP_RELEASE_WRITES. Смысл этих запросов не требует объяснений — он понятен из их имен. API копирования теневых то мов позволяет посылать IOCTLзапросы логическим дискам, для кото рых создаются снимки, с тем чтобы все операции записи, иницииро ванные перед получением снимка, успели завершиться до создания теневой копии и чтобы файловые данные, записываемые из теневой копии, были согласованы по времени. см. след. стр.
690 ГЛ А В А 10 БЕЗОПАСНОСТЬ Теневые копии для общих папок Поддержка теневого копирования томов позволяет Windows Server 2003 предоставлять конечным пользователям доступ к резервным вер сиям томов для восстановления старых версий файлов и папок, кото рые могли быть случайно удалены или изменены. Эта функция облег чает жизнь системным администраторам, которые в ином случае дол жны были бы загружать резервные данные и обращаться к предыду щим их версиям в интересах конечных пользователей. В окне свойств для тома в Windows Server 2003 есть вкладка Shadow Copies (Теневые копии), на которой администратор может разрешить создание снимков томов по расписанию, как показано на следующей иллюстрации. Администраторы также могут ограничить простран ство, выделяемое под снимки, чтобы система автоматически удаляла самые старые снимки.
ГЛАВА 9 Управление внешней памятью 691 В клиентских системах, где нужна функциональность Shadow Co pies for Shared Folders, следует установить расширение Explorer — Pre vious Versions Client — которое поставляется с Windows Server 2003 в каталоге \Windows\System32\Clients\Twclient и которое также можно скачать с сайта Microsoft (это расширение включено в Windows XP Service Pack 2 и выше). Когда клиентская Windowsсистема с установ ленным расширением подключается к общей папке на томе, для кото рого имеются снимки, в окне свойств папок и файлов, находящихся в этой общей папке, появляется вкладка Previous Versions. На этой вклад ке перечисляются снимки, имеющиеся на сервере, и пользователь мо жет просмотреть соответствующие версии файла или папки. Резюме В этой главе мы рассмотрели организацию, компоненты и принципы управ ления внешней дисковой памятью в Windows. В следующей главе мы обсу дим диспетчер кэша — компонент исполнительной системы, неразрывно связанный с драйверами файловых систем.
Г Л А В А 1 1 Диспетчер кэша Диспетчер кэша (cache manager) — это набор функций режима ядра и сис темных потоков, во взаимодействии с диспетчером памяти обеспечивающих кэширование данных для всех драйверов файловых систем Windows (как локальных, так и сетевых). В этой главе мы поясним, как работает диспет чер кэша, что представляют собой его внутренние структуры данных и функ ции, как определяется размер кэшей при инициализации системы, как он взаимодействует с другими компонентами операционной системы и каким образом можно наблюдать за его активностью с помощью счетчиков про изводительности. Мы также рассмотрим пять флагов Windowsфункции CreateFile, влияющих на кэширование файлов. ПРИМЕЧАНИЕ В этой главе описываются лишь те внутренние функ ции диспетчера кэша, которые нужны для объяснения принципов его работы. Программные интерфейсы диспетчера кэша документирова ны в Windows Installable File System (IFS) Kit. Подробнее об IFS Kit см. http://www.microsoft.com/whdc/devtools/ifskit. Основные возможности диспетчера кэша Диспетчер кэша: 쐽 поддерживает все файловые системы Windows (как локальные, так и се тевые), исключая необходимость реализации в каждой файловой систе ме собственного кода управления кэшем; 쐽 с помощью диспетчера памяти контролирует, какие части и каких фай лов находятся в физической памяти (обеспечивая компромисс между потребностями в физической памяти пользовательских процессов и опе рационной системы); 쐽 в отличие от большинства других систем кэширования, которые кэширу ют данные на основе логических блоков (смещений внутри дисковых томов), кэширует данные на основе виртуальных блоков (смещений внут ри файлов), что позволяет реализовать алгоритм интеллектуального опе режающего чтения и обеспечить высокоскоростной доступ к кэшу без участия драйверов файловых систем (этот метод кэширования называет ся быстрым вводомвыводом);
ГЛАВА 9 Диспетчер кэша 693 쐽 распознает параметры, передаваемые приложениями при открытии фай лов (например, прямой или последовательный доступ, временный файл или постоянный и т. д.); 쐽 поддерживает восстанавливаемые файловые системы (например, регис трирующие транзакции), что дает возможность восстанавливать данные после аварий. Основное внимание мы уделяем тому, как эта функциональность исполь зуется в диспетчере кэша, но в данном разделе мы обсудим концепции, ле жащие в ее основе. Единый централизованный системный кэш В некоторых операционных системах данные кэшируются каждой файло вой системой индивидуально. Это приводит к дублированию кода, отвеча ющего за кэширование и управление памятью, или к ограничению видов данных, которые можно кэшировать. В противоположность этому подходу Windows предлагает централизованный механизм кэширования всех дан ных, хранящихся во внешней памяти — на локальных жестких и гибких дис ках, сетевых файлсерверах или CDROM. Кэшировать можно любые дан ные — как пользовательские (содержимое файлов при операциях чтения или записи), так и метаданные файловой системы (например, заголовки ка талогов и файлов). Как вы еще узнаете из этой главы, метод обращения к кэшу, применяемый Windows, определяется типом кэшируемых данных. Диспетчер памяти Одно весьма необычное свойство диспетчера кэша заключается в том, что он никогда не знает, какая часть кэшируемых данных действительно находится в физической памяти. Вероятно, это звучит несколько странно, поскольку кэш предназначен для ускорения вводавывода за счет хранения в физической памяти подмножества данных, к которым часто обращаются приложения и система. Все дело в том, что диспетчер кэша обращается к данным, проеци руя представления файлов на виртуальные адресные пространства с помощью стандартных объектов «раздел» (в терминах Windows API — объектов «проек ция файла»; см. главу 7). По мере доступа к адресам проецируемых представ лений файлов диспетчер памяти подгружает нерезидентные блоки в физичес кую память. А при необходимости диспетчер памяти может выгружать данные из кэша обратно в файлы, проецируемые на кэш. Используя кэширование на основе проецирования файлов на виртуальное адресное пространство, диспетчер кэша избегает генерации пакетов запро са вводавывода (IRP) при обращении к данным кэшируемых файлов. Вместо этого он просто копирует данные по виртуальным адресам, по которым про ецируются кэшируемые данные, а диспетчер памяти при необходимости под гружает данные в память (или выгружает их из нее). Этот процесс позволяет диспетчеру памяти подбирать глобальный баланс между объемом памяти, выделенной системному кэшу, и объемом памяти, нужной пользовательским
694 ГЛ А В А 11 БЕЗОПАСНОСТЬ процессам. (Диспетчер кэша также инициирует вводвывод, например отло женную запись, но сама запись страниц осуществляется диспетчером памя ти.) Как вы узнаете из следующего раздела, такая архитектура дает возмож ность процессам, открывающим кэшируемые файлы, видеть те же данные, что и процессам, проецирующим эти файлы на свои адресные пространства. Когерентность кэша Одна из важных функций диспетчера кэша — гарантировать любому процес су, обращающемуся к кэшируемым данным, получение самой последней вер сии этих данных. Ситуация, при которой один процесс открывает файл (и, сле довательно, делает его кэшируемым), тогда как другой напрямую проецирует этот файл на свое адресное пространство (через Windowsфункцию MapView OfFile), может обернуться проблемой. Эта потенциальная проблема не возни кает в Windows, поскольку и диспетчер кэша, и приложения, проецирующие файлы на свои адресные пространства, используют одни и те же сервисы под системы управления памятью. Так как диспетчер памяти гарантирует, что у него имеется только одно представление каждого уникального проецируемого фай ла (независимо от количества объектов «раздел», или проекций файла), он про ецирует все представления файла (даже если они перекрываются) на един ственный набор страниц физической памяти, как показано на рис. 111. Рис. 11-1. Схема когерентного кэширования
ГЛАВА 9 Диспетчер кэша 695 Поэтому, если, например, на пользовательское адресное пространство процесса 1 проецируется представление 1 файла и процесс 2 обращается к тому же представлению через системный кэш, то процесс 2 будет видеть любые изменения в этом представлении по мере их внесения процессом 1, а не после сброса измененных данных из кэша на диск. Диспетчер памяти сбрасывает не все страницы, проецируемые на пользовательские простран ства, а лишь те, о которых он знает, что они изменены (установлен бит из менения). Поэтому любой процесс, обращающийся к файлу, всегда видит его самую последнюю версию, даже если одни процессы открыли этот файл через подсистему вводавывода, а другие проецируют его на свои адресные пространства с помощью соответствующих Windowsфункций. ПРИМЕЧАНИЕ В силу некоторых причин сетевым редиректорам труднее поддерживать когерентность кэша, чем локальным файловым системам, и они должны реализовать дополнительные операции сбро са и очистки кэша. На эту тему см. главу 12. Кэширование виртуальных блоков Диспетчеры кэша многих операционных систем (включая Novell NetWare, OpenVMS и ранние версии UNIX) кэшируют данные на основе логических блоков. В этом случае диспетчер кэша отслеживает, какие блоки дискового раздела находятся в кэше. Диспетчер кэша Windows, напротив, использует кэширование виртуальных блоков. Этот метод заключается в том, что дис петчер кэша отслеживает, какие части и каких файлов находятся в кэше. Диспетчер кэша реализует этот метод за счет проецирования их 256кило байтных представлений на системную часть виртуальных адресных про странств с помощью специальных процедур диспетчера памяти. Основные преимущества такого подхода описываются ниже. 쐽 Появляется возможность реализации интеллектуального опережающего чтения (intellegent readahead), так как диспетчер кэша следит за тем, ча сти каких файлов находятся в кэше, и это позволяет ему предсказывать, к какой следующей порции данных обратится вызывающая программа. 쐽 Подсистема вводавывода может запрашивать данные, уже находящиеся в кэше, в обход файловой системы (быстрый вводвывод). Поскольку дис петчеру кэша известно, какие части и каких файлов находятся в кэше, он может вернуть адрес кэшируемых данных для выполнения запроса на вводвывод без обращения к файловой системе. Подробнее об интеллектуальном опережающем чтении и быстром вво девыводе мы расскажем чуть позже. Кэширование потоков данных В диспетчер кэша заложена поддержка не только кэширования файлов, но и кэширования потоков данных (stream caching) — последовательности байтов в файле. В файлах таких файловых систем, как NTFS, может быть более одно
696 ГЛ А В А 11 БЕЗОПАСНОСТЬ го потока данных. Диспетчер кэша поддерживает эти файловые системы за счет независимого кэширования каждого потока. NTFS способна использо вать эту функциональность (см. главу 12). И хотя о диспетчере кэша можно сказать, что он кэширует файлы, фактически он кэширует именно потоки данных (в любом файле есть минимум один поток данных), идентифицируе мые по имени файла и, если в нем более одного потока, по имени потока. Поддержка восстанавливаемых файловых систем Восстанавливаемые файловые системы вроде NTFS способны реконструиро вать структуру дискового тома после аварии системы. Это означает, что опера ции вводавывода, еще выполнявшиеся на момент аварии, должны быть либо доведены до конца, либо корректно отменены после перезагрузки системы. Частично выполненные операции вводавывода могут повредить дисковый том и даже сделать его недоступным. Во избежание такой проблемы восстанавли ваемая файловая система ведет файл журнала, в котором регистрирует каждое предполагаемое обновление структуры файловой системы (метаданные фай ловой системы) — еще до того, как оно будет выполнено. Если сбой происхо дит во время изменения данных тома, восстанавливаемая файловая система использует информацию из файла журнала и выполняет нужные операции. ПРИМЕЧАНИЕ Термин метаданные относится только к изменениям в структуре файловой системы в результате создания, переименования и удаления файлов и каталогов. Чтобы обеспечить успешное восстановление тома, каждый элемент (запись) файла журнала, документирующий изменения в данных тома, должен быть за писан на диск до самого обновления данных. Поскольку запись на диск кэши руется, файловая система должна взаимодействовать с диспетчером кэша, что бы гарантировать выполнение следующей последовательности операций. 1. Файловая система заносит в файл журнала запись, документирующую изменение данных тома, которое она собирается выполнить. 2. Файловая система вызывает диспетчер кэша для сброса на диск записи файла журнала. 3. Файловая система записывает в кэш обновленные данные тома, т. е. мо дифицирует свои кэшируемые метаданные. 4. Диспетчер кэша сбрасывает модифицированные метаданные на диск, обновляя структуру тома. (На самом деле записи файла журнала, как и модифицированные метаданные, сбрасываются на диск пакетами.) Записывая данные в кэш, файловая система предоставляет номер логичес кой последовательности (logical sequence number, LSN), который идентифици рует запись файла журнала, соответствующую обновлению кэша. Диспетчер кэша отслеживает эти номера, регистрируя наименьший и наибольший LSN (представляющие первую и последнюю записи файла журнала); такие номера сопоставляются с каждой страницей кэша. Кроме того, потоки данных, защи щенные записями журнала транзакций, помечаются NTFS как «не записывае
ГЛАВА 9 Диспетчер кэша 697 мые», чтобы подсистема записи спроецированных страниц не сбросила эти страницы на диск до того, как туда будут сброшены соответствующие записи файла журнала. (Обнаружив помеченную таким образом страницу, подсисте ма записи спроецированных страниц перемещает ее в специальный список страниц, которые диспетчер кэша сбрасывает на диск в подходящий момент.) Когда диспетчер кэша готов сбросить на диск группу измененных страниц, он определяет наибольший LSN, сопоставленный со сбрасываемыми на диск страницами, и сообщает его файловой системе. Далее файловая система мо жет ответно вызвать диспетчер кэша и заставить его сбросить данные файла журнала вплоть до точки, представленной указанным LSN. Сбросив данные файла журнала вплоть до указанного LSN, диспетчер кэша сбрасывает на диск и соответствующие обновления в структуре тома, что гарантирует регистра цию предстоящих операций до их выполнения. Таким образом и достигает ся возможность восстановления дискового тома после аварии системы. Управление виртуальной памятью кэша Поскольку диспетчер кэша Windows кэширует файлы на основе виртуальных блоков, ему передается регион в системной части виртуальных адресных про странств (а не область физической памяти). Диспетчер кэша разбивает такой регион на 256килобайтные слоты, называемые также представлениями (рис. 112). (Подробнее о структуре системного пространства см. главу 7.) Рис. 11-2. Адресное пространство системного кэша
698 ГЛ А В А 11 БЕЗОПАСНОСТЬ При первой операции вводавывода (чтения или записи) над файлом диспетчер кэша проецирует на свободный слот адресного пространства системного кэша 256килобайтное представление области файла, выровнен ной по границе 256 Кб и содержащей запрошенные данные. Например, если из файла считывается 10 байтов по смещению 300 000 байтов от его нача ла, то проецируемое представление будет начинаться со смещения 262 144 (вторая область файла, выровненная по границе 256 Кб) и займет 256 Кб. Диспетчер кэша проецирует представления файлов на слоты адресного про странства кэша по принципу карусели: первое запрошенное представление — на первый 256килобайтный слот, второе — на второй и т. д. (рис. 113). В этом примере первым был спроецирован файл B, вторым — А, третьим — С, поэто му проецируемая часть файла В занимает первый слот кэша. Заметьте, что спро ецирована лишь первая 256килобайтная часть файла В, так как обращение было лишь к части файла и так как файл С, размер которого составляет всего 100 Кб, требует выделения своего 256килобайтного слота кэша. Рис. 11-3. Файлы различного размера, спроецированные в системный кэш Диспетчер кэша гарантирует, что представление проецируется на то вре мя, пока оно активно (хотя представления могут оставаться спроецирован ными после того, как становятся неактивными). Однако представление по мечается как активное, только когда выполняется операция чтения или за писи над соответствующим файлом. Если процесс, открывающий файл вы зовом CreateFile, не указывает флаг FILE_FLAG_RANDOM_ACCESS, диспетчер кэша прекращает проецировать неактивные представления этого файла при проецировании его новых представлений. Страницы отключенных проек ций посылаются в список простаивающих или модифицированных страниц (в зависимости от того, были ли они изменены); при этом диспетчер кэша, используя специальный интерфейс диспетчера памяти, может указать, в ка ком месте списка следует разместить эти страницы — в конце или в начале.
ГЛАВА 9 Диспетчер кэша 699 Страницы, соответствующие представлениям файлов, открытых с флагом FILE_FLAG_SEQUENTIAL_SCAN, перемещаются в начало списков, а все ос тальные — в конец. Такая схема способствует повторному использованию страниц, которые принадлежат файлам, открытым для последовательного чтения, и заставляет использовать малые объемы физической памяти при копировании больших файлов. Если диспетчеру кэша требуется спроецировать представление файла, а свободных слотов в кэше нет, он отключает неактивное представление, спроецированное последним, и использует освободившийся слот. В отсут ствие таких представлений возвращается ошибка вводавывода с сообщени ем о том, что системных ресурсов для выполнения данной операции недо статочно. Эта ситуация крайне маловероятна, так как возникает только при одновременном доступе к тысячам файлов. Размер кэша В следующих разделах мы объясним, как Windows вычисляет размер систем ного кэша. Как и в большинстве других вычислений, связанных с управле нием памятью, размер системного кэша определяется несколькими факто рами, в том числе объемом памяти и конкретным выпуском Windows. LargeSystemCache Как вы увидите в дальнейшем, параметр LargeSystemCache в разделе реестра HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Memory Manage ment влияет как на виртуальный размер кэша, так и на физический. По умол чанию в Windows 2000 Professional и Windows XP это значение равно 0, а в системах Windows Server — 1. В Windows 2000 Server данное значение можно регулировать через GUI, изменяя свойства службы файлового сервера; для это го надо открыть окно свойств сетевого соединения и выбрать File And Printer Sharing For Microsoft Networks (Служба доступа к файлам и принтерам сетей Microsoft). Эта служба имеется и в Windows 2000 Professional, но там ее пара метры настраивать нельзя. На рис. 114 показано диалоговое окно, через ко торое в Windows 2000 Server можно изменить объем памяти, выделяемой для локальных и сетевых приложений сетевой службой сервера. В Windows 2000 Server с установленными Terminal Services (Службы терми нала) переключатель Maximize Data Throughput For File Sharing (Макс. пропуск ная способность доступа к общим файлам), показанный на рис. 114, активен по умолчанию, т. е. параметр LargeSystemCache равен 1. При выборе любого другого переключателя параметр LargeSystemCache становится равным 0. Каждый из переключателей диалогового окна File And Printer Sharing For Microsoft Networks Properties влияет не только на поведение системного кэша, но и на службу файлового сервера.
700 ГЛ А В А 11 БЕЗОПАСНОСТЬ Рис. 11-4. Диалоговое окно File and Printer Sharing for Microsoft Networks Properties, позволяющее изменять свойства сетевой службы сервера В Windows XP и Windows Server 2003 модифицировать параметр Large SystemCache можно через диалоговое окно Performance Options (Параметры быстродействия), которое открывается щелчком кнопки Settings (Параметры) в разделе Performance (Быстродействие) на вкладке Advanced (Дополнитель но) апплета System (Система) из Control Panel (Панель управления). В этом диалоговом окне перейдите на очередную вкладку Advanced (Дополнительно). Если в разделе Memory Usage (Использование памяти) вы выбираете System Cache (системного кэша), параметру LargeSystemCache присваивается значе ние 1, а если вы выбираете Programs (программ) — 0 (рис. 115). Рис. 11-5. Настройка LargeSystemCache в Windows XP и Windows Server 2003
ГЛАВА 9 Диспетчер кэша 701 Виртуальный размер кэша Виртуальный размер системного кэша является функцией объема установ ленной физической памяти. По умолчанию это значение равно 64 Мб. Если в системе более 4032 страниц (16 Mб) физической памяти, виртуальный размер кэша устанавливается равным 128 Мб плюс 64 Мб на каждые допол нительные 4 Мб физической памяти. Используя этот алгоритм, можно под считать виртуальный размер системного кэша на компьютере, например, с 64 Мб физической памяти: 128 Мб + (64 Мб – 16 Мб) / 4 Мб * 64 Мб = 896 Мб Минимальный и максимальный виртуальные размеры системного кэша на разных платформах, а также его стартовый и конечный адреса показаны в таблице 111. Если на платформе x86 рассчитанный системой виртуальный размер кэша превышает 512 Мб, он ограничивается 512 Мб; однако при па раметре LargeSystemCache, равном 1, в той же ситуации кэшу назначается до 960 Мб виртуальной памяти из дополнительного диапазона адресов, назы ваемого дополнительной памятью кэша (cache extra memory). Основное преимущество выделения под кэш большего объема виртуальной памяти заключается в том, что это позволяет уменьшить число операций проеци рования и отмены проецирования представлений при обращении к разным файлам и разным представлениям файлов. Таблица 11-1. Размер и местонахождение системного кэша данных Минимальный/ максимальный виртуальный размер Платформа Диапазон адресов x86, 2гигабайтное системное пространство 0xC1000000–E0FFFFFF, 0xA4000000–BFFFFFFF 64–960 Мб x86, 1гигабайтное системное пространство 0xC1000000–DBFFFFFF 64–432 Мб x86, 1гигабайтное системное пространство при наличии Terminal Services 0xC1000000–DCFFFFFF 64–448 Мб x64 0xFFFFF98000000000– FFFFFA800000000064 64 Мб – 1024 Гб IA64 0xE000000600000000– E00001060000000064 64 Мб – 1024 Гб В таблице 112 перечислены системные переменные, которые содержат виртуальный размер и адрес системного кэша.
702 ГЛ А В А 11 БЕЗОПАСНОСТЬ Таблица 11-2. Системные переменные, хранящие виртуальный размер и адрес системного кэша Системная переменная Описание MmSystemCacheStart Начальный виртуальный адрес кэша MmSystemCacheEnd Конечный виртуальный адрес кэша MiSystemCacheStartExtra Начальный виртуальный адрес дополнительной памяти кэша, превышающего 512 Мб (только на платформе x86) MiSystemCacheEndExtra Конечный виртуальный адрес дополнительной памяти кэша, превышающего 512 Мб (только на платформе x86) MmSizeOfSystemCacheInPages Максимальный размер системного кэша в страницах ЭКСПЕРИМЕНТ: просмотр виртуального размера кэша Виртуальный размер кэша не показывается какимлибо счетчиком производительности, так что единственный способ узнать его значе ние — получить содержимое переменной ядра MmSizeOfSystemCache InPages: kd> dd MmSizeOfSystemCacheInPages l 1 80539a8c 00020000 В этом примере использована x86система под управлением Win dows XP с параметром LargeSystemCache, равным 0; как видите, вирту альный размер кэша в такой системе составляет 0x20000 страниц. Поскольку на платформе x86 размер страниц равен 4 Кб, под вирту альный кэш выделено 512 Мб из 2гигабайтного системного адресного пространства. Размер рабочего набора кэша Как уже упоминалось, одно из ключевых отличий архитектуры диспетчера кэша Windows от таковой в других операционных системах — делегирова ние управления физической памятью диспетчеру памяти. Ввиду этого раз мером кэша управляет уже имеющийся в операционной системе код, отве чающий за обработку расширения и усечения рабочего набора, а также за управление списками модифицированных и простаивающих страниц. У системного кэша нет собственного рабочего набора — он использует единый системный набор, в который входят кэш данных, пул подкачиваемой памяти, а также подкачиваемый код Ntoskrnl и драйверов. Как упоминалось в главе 7, этот рабочий набор имеет внутреннее название рабочий набор системного кэша, но системный кэш является лишь одним из его элементов. Поэтому мы будем использовать термин «системный рабочий набор». Так же в главе 7 мы обратили ваше внимание на то, что при присвоении пара метру реестра LargeSystemCache значения 1 диспетчер памяти отдает пред
ГЛАВА 9 Диспетчер кэша 703 почтение системному рабочему набору по сравнению с рабочими набора ми процессов, выполняемых в системе. Выяснить физический размер системного кэша, сравнить его с суммар ным физическим размером системного рабочего набора, а также получить информацию об ошибках страниц для системного рабочего набора позво ляют счетчики производительности или системные переменные, перечис ленные в таблице 113. Таблица 11-3. Счетчики и системные переменные, хранящие информацию о физическом размере системного кэша и ошибках страниц Объект: счетчик Системная переменная Описание Memory: System Cache Resident Bytes (Память: Резидентных байт сис темного кэша) MmSystemCachePage Физическая память, занятая под системный кэш Memory: Cache Bytes MmSystemCacheWs.Working Суммарный размер системно (Память: Байт кэшпамяти) SetSize го рабочего набора, включая кэш, пул подкачиваемой па мяти, подкачиваемый код и проецируемые системой представления. Это не размер кэша, как можно подумать по названию счетчика! Memory: Cache Bytes Peak MmSystemCacheWs.Peak [Память: Байт кэшпамяти (пик)] Memory: Cache Faults/Sec (Память: Ошибок кэшпамяти/сек) MmSystemCacheWs.Page FaultCount Пиковый размер системного рабочего набора Число ошибок страниц, гене рируемых системным рабо чим набором (а не только кэшем) ЭКСПЕРИМЕНТ: просмотр рабочего набора кэша Как показано на листинге ниже, команда !filecache отладчика ядра вы водит дамп информации о физической памяти, используемой кэшем, текущем и пиковом размерах рабочего набора, количестве действи тельных страниц, сопоставленных с представлениями, и, где это воз можно, имена файлов, проецируемых на представления. (Драйверы файловых систем кэшируют метаданные с помощью безымянных файловых потоков.) lkd> !filecache ***** Dump file cache****** Reading and sorting VACBs ... Removed 657 nonactive VACBs, processing 1389 active VACBs ... File Cache Information Current size 132308 kb Peak size 145764 kb 1389 Control Areas см. след. стр.
704 ГЛ А В А 11 БЕЗОПАСНОСТЬ Skipping view @ c1040000  no VACB, but PTE is valid! Loading file cache database (100% of 131072 PTEs) SkippedPageTableReads = 0 File cache has 21510 valid pages Usage Summary (in Kb): Control Valid Standby /Dirty Shared Locked Name 89be09c8 272 0 0 0 default_message_database.db 8a267ad8 4 0 0 0 $Directory 8a37d140 3504 1196 0 0 $Mft 8a35c928 4320 1676 0 0 outlook.pst 8a2acbb8 4 0 0 0 $Directory 8a42c908 564 0 0 0 $BitMap 8a42bd28 12 0 0 0 $Mft 8a29ed88 4 0 0 0 $Directory 8a467008 48 0 0 0 $Directory 8a42b828 124 0 0 0 No Name for File 8a467c58 8 0 0 0 $Directory 8a357f18 136 20 0 0 archive.pst 8a4a7248 52 0 0 0 $Directory 8a42a928 388 0 0 0 $Directory 8a457a10 4 0 0 0 $Directory 8a3f17a8 4 0 0 0 WIASERVC.LOG 89ede0e8 4 0 0 0 $Directory 8a491708 11900 136 0 0 $Mft 8a429fa0 4 0 0 0 $Directory 8a4318d8 2304 26624 0 0 $LogFile 8a438bc0 4 0 0 0 $Directory 8a4286a8 4 0 0 0 $Directory 8a491c50 8 0 0 0 $Directory 8a455de0 4 0 0 0 $Directory 8a3d0f00 4 0 0 0 $Directory 8a44d7a0 3420 0 0 0 $Mft 8a35ba10 1312 0 16 0 SHDOCVW.DLL 8a324130 4 0 0 0 $Directory 8a42c110 4 0 0 0 $Directory 8a41dd80 4 0 0 0 $Directory 88dfff38 4 0 0 0 $Directory 8a4a7640 4 0 0 0 $Directory 8a464d00 4 0 0 0 $Directory Физический размер кэша Хотя системный рабочий набор включает объем физической памяти, про ецируемой на представления в виртуальном адресном пространстве кэша, он не обязательно отражает общий объем файловых данных, кэшируемых в физической памяти. Между этими двумя значениями нередко бывают рас
ГЛАВА 9 Диспетчер кэша 705 хождения, потому что часть файловых данных может находиться в принад лежащем диспетчеру памяти списке простаивающих или модифицирован ных страниц. Вспомните из главы 7, что при усечении рабочего набора или замене стра ниц диспетчер памяти может переместить измененные страницы из рабоче го набора в список простаивающих или модифицированных страниц — в зависимости от того, куда должны быть записаны данные, содержащиеся на такой странице, перед ее повторным использованием — в страничный файл или в какойто другой. Если бы у диспетчера памяти не было таких списков, то всякий раз, когда какойнибудь процесс обращался бы к данным, ранее удаленным из его рабочего набора, диспетчеру памяти приходилось бы считывать их с диска. А так диспетчер памяти может просто вернуть нуж ную страницу в рабочий набор процесса (если она, конечно, присутствует в одном из этих списков). То есть списки служат кэшами данных из странич ного файла, исполняемых образов или файлов данных. Значит, общий объем файловых данных, кэшируемых в системе, складывается не только из разме ра системного рабочего набора, но и из размеров списков простаивающих и модифицированных страниц. Вот пример, иллюстрирующий, как диспетчер кэша способен привести к кэшированию в физической памяти гораздо большего объема файловых данных, чем может содержаться в системном рабочем наборе. Рассмотрим систему, выступающую в роли выделенного файлсервера. В этой системе имеется 8 Гб физической памяти, и виртуальный размер кэша составляет 960 Мб (максимальный размер в x86системах). Таким образом, предельный раз мер файловых данных, которые можно напрямую спроецировать в вирту альную память кэша, составляет 960 Мб. Клиентское приложение обращается к файловым данным на сервере через сеть. Драйвер файлсервера (\Win dows\System32\Drivers\Srv.sys) (см. главу 12) использует интерфейсы диспет чера кэша для чтения и записи файловых данных в интересах клиента. Если клиенты считывают несколько тысяч файлов, каждый размером по 1 Мб, диспетчеру кэша придется повторно использовать представления при про ецировании 961го файла. При последующих операциях чтения он будет отменять проецирование представлений для старых файлов и заново про ецировать их для новых. Когда диспетчер кэша отменяет проецирование какоголибо представления, диспетчер памяти не отбрасывает файловые данные в рабочем наборе кэша, соответствующие этому представлению, а перемещает их в список простаивающих страниц. В отсутствие запросов на выделение физической памяти под любые другие задачи список простаива ющих страниц может занимать почти всю физическую память за вычетом системного рабочего набора. Иначе говоря, практически все 8 Гб физичес кой памяти сервера будут задействованы для кэширования файловых дан ных, как показано на рис. 116.
706 ГЛ А В А 11 БЕЗОПАСНОСТЬ Рис. 11-6. Пример использования почти всей физической памяти под файловый кэш Поскольку общий объем кэшируемых файловых данных складывается из размеров системного рабочего набора, списка модифицированных страниц и списка простаивающих страниц, а эти размеры контролируются диспет чером памяти, в какомто смысле его можно назвать истинным диспетчером кэша. Подсистема диспетчера кэша просто предоставляет удобные интер фейсы для доступа к файловым данным через диспетчер памяти и опреде ляет политики опережающего чтения (readahead) и отложенной записи (writebehind), которые влияют на то, какие данные диспетчер памяти будет удерживать в физической памяти. Для более точного отображения полного объема файловых данных, кэ шируемых в системе, диспетчер задач и Process Explorer предоставляют па раметр System Cache (Системный кэш), отражающий суммарный размер сис темного рабочего набора и списков простаивающих и модифицированных страниц. Пример для Process Explorer представлен на рис. 117. Рис. 11-7. Диалоговое окно System Information в Process Explorer
ГЛАВА 9 Диспетчер кэша 707 Структуры данных кэша Для отслеживания кэшируемых файлов диспетчер кэша использует следую щие структуры данных. 쐽 Каждый 256килобайтный слот системного кэша описывается VACB. 쐽 У каждого отдельно открытого кэшируемого файла есть закрытая карта кэша с информацией, применяемой для контроля опережающего чтения. 쐽 Каждый кэшируемый файл имеет общую структуру карты кэша, которая указывает на слоты системного кэша, содержащие проецируемые пред ставления файла. Эти структуры и их взаимосвязи описываются в следующих разделах. Общесистемные структуры данных кэша Диспетчер кэша отслеживает состояние спроецированных на системный кэш представлений с помощью массива структур данных, называемых бло ками управления виртуальными адресами (virtual address control blocks, VACB). При инициализации системы диспетчер кэша выделяет часть пула неподкачиваемой памяти под VACB, необходимые для описания системно го кэша. Адрес массива VACB запоминается в переменной CcVacbs. Каждый VACB описывает одно 256килобайтное представление в системном кэше (рис. 118). Структура VACB показана на рис. 119. Рис. 11-8. Системный массив VACB Рис. 11-9. Структура VACB
708 ГЛ А В А 11 БЕЗОПАСНОСТЬ Как видно на рис. 119, в первом поле VACB содержится виртуальный ад рес данных системного кэша. Второе поле является указателем на общую (совместно используемую) структуру карты кэша, которая идентифицирует кэшируемый файл. Третье поле определяет смещение начала представления (внутри файла). Наконец, VACB содержит счетчик ссылок на представление, т. е. число активных операций чтения или записи над данным представле нием. При выполнении операции вводавывода над файлом счетчик ссылок VACB увеличивается на 1, а по окончании такой операции уменьшается на 1. Когда счетчик ссылок не равен 0, VACB считается активным. В случае обра щения к метаданным файловой системы счетчик активных операций отра жает число драйверов файловых систем, которые владеют заблокированны ми в памяти страницами данного представления. Структуры данных кэша, индивидуальные для каждого файла Каждому открытому описателю файла соответствует объект «файл» (см. гла ву 9). Если файл кэшируется, его объект «файл» указывает на структуру зак рытой карты кэша (private cache map), которая содержит два адреса, по ко торым в последний раз происходило чтение данных. Кроме того, все закры тые карты кэша для открытых экземпляров файла связаны друг с другом. У каждого кэшируемого файла (в противоположность объекту «файл») есть структура общей карты кэша (shared cache map), которая описывает состояние кэшируемого файла, в том числе его размер и (из соображений безопасности) длину его действительных данных. (О назначении поля дли ны действительных данных файла см. раздел «Кэширование с обратной за писью и отложенная запись» далее в этой главе). Общая карта кэша также указывает на объектраздел (поддерживаемый диспетчером памяти и описы вающий проекцию файла на виртуальную память), список закрытых карт памяти, сопоставленных с этим файлом, и все VACB, описывающие представ ления файлов, проецируемые в данный момент на системный кэш. Взаимо связи между этими структурами данных показаны на рис. 1110. При запросе на чтение данных из какоголибо файла диспетчер кэша должен ответить на два вопроса. 1. Находится ли файл в кэше? 2. Если да, то какие VACB (если таковые есть) ссылаются на запрошенный адрес? Иначе говоря, диспетчер кэша должен выяснить, проецируется ли пред ставление файла (с нужным смещением) на системный кэш. Если ни один VACB не содержит нужное смещение в файле, запрошенные данные в насто ящий момент не проецируются на системный кэш. Для учета представлений данного файла, проецируемых на системный кэш, диспетчер кэша поддерживает массив указателей на VACB — массив индексов VACB (VACB index array). Первый элемент массива индексов VACB ссылается на первые 256 Кб файла, второй — на следующие 256 Кб и т. д.
ГЛАВА 9 Диспетчер кэша 709 Схема на рис. 1111 иллюстрирует четыре раздела из трех файлов, проеци руемых в данный момент на системный кэш. Когда процесс обращается к файлу по заданному адресу, диспетчер кэша ищет подходящий элемент в массиве индексов VACB для этого файла, что бы определить, проецируются ли на кэш запрошенные данные. Если элемент массива отличен от 0 (и, следовательно, содержит указатель на VACB), нуж ная область файла находится в кэше. VACB в свою очередь указывает на ад рес, по которому на системный кэш проецируется представление файла. А если элемент массива равен 0, диспетчер кэша должен найти в системном кэше свободный слот (а значит, свободный VACB) для проецирования необ ходимого представления. Рис. 11-10. Структуры данных кэша, индивидуальные для файлов Для оптимизации своего размера общая карта кэша содержит массив индексов VACB из 4 элементов. Поскольку каждый VACB описывает 256 Кб, элементы этого компактного массива индексов фиксированного размера могут указывать на элементы массива VACB, которые в совокупности способ ны описывать файл размером до 1 Мб. Если размер файла превышает 1 Мб, из неподкачиваемого пула выделяется память под отдельный массив индек сов VACB; его размер определяется делением размера файла на 256 Кб с пос ледующим округлением результата до ближайшего большего целого значе ния. После этого общая карта кэша указывает на данную структуру.
710 ГЛ А В А 11 Рис. 11-11. БЕЗОПАСНОСТЬ Массивы индексов VACB Если длина файла превышает 32 Мб, то для еще большей оптимизации массив индексов VACB, созданный в пуле неподкачиваемой памяти, стано вится разреженным многоуровневым массивом индексов (sparse multilevel index array), в котором каждый массив индексов состоит из 128 элементов. Число уровней, необходимых для файла, вычисляется по формуле: (Разрядность значения, отражающего длину файла – 18) / 7 Полученное значение надо округлить до ближайшего большего целого. Число 18 в уравнении обусловлено тем, что VACB представляет 256 Кб, а 256 Кб — это 218. Наконец, число 7 присутствует в уравнении потому, что каж дый уровень массива состоит из 128 элементов, а 128 — это 27. Следователь но, файл максимальной длины, которая может быть описана как 263 (макси мальный размер, поддерживаемый диспетчером кэша), потребует всего 7 уровней. Массив является разреженным, так как диспетчер кэша создает вет ви лишь для активных представлений на самом низком уровне массива ин дексов. На рис. 1112 показан пример многоуровневого массива VACB для разреженного файла, размер которого требует для описания 3 уровня. Такая схема нужна для эффективной обработки разреженных файлов, ко торые могут достигать очень больших размеров и в которых лишь малая часть может быть занята действительными данными; поэтому в массиве выделяет ся ровно столько места, сколько нужно для проецируемых в данный момент представлений файла. Например, разреженный файл размером 32 Гб, у кото рого только 256 Кб проецируются на виртуальное адресное пространство кэша, потребует массив VACB с тремя массивами индексов, поскольку лишь одна ветвь массива имеет проекцию, а для файла длиной 32 Гб (235 байтов) нужен трехуровневый массив. Если бы диспетчер кэша не оптимизировал
ГЛАВА 9 Диспетчер кэша 711 многоуровневые массивы VACB, для этого файла пришлось бы создать массив VACB со 128 000 элементов, что эквивалентно 1000 массивам индексов. Рис. 11-12. Многоуровневые массивы VACB ЭКСПЕРИМЕНТ: просмотр общей и закрытых карт кэша Команда dt отладчика ядра позволяет увидеть определения структур данных общей и закрытой карт кэша в работающей системе. Вопер вых, выполните команду !filecache и найдите запись в выводе VACB с именем известного вам файла. В нашем примере таковым будет спра вочный файл из Debugging Tools for Windows: 8653c828 120 160 0 0 debugger.chm Первый адрес указывает местонахождение структуры данных обла сти управления (control area), с помощью которой диспетчер памяти отслеживает диапазон адресов. (Более подробные сведения см. в гла ве 7.) В области управления хранится указатель на объект «файл», со см. след. стр.
712 ГЛ А В А 11 БЕЗОПАСНОСТЬ ответствующий представлению в кэше. Объект «файл» идентифициру ет экземпляр открытого файла — в данном случае справочного фай ла из Debugging Tools for Windows. Теперь, чтобы увидеть структуру области управления, введите следующую команду с адресом идентифи цированного вами элемента в этой области: lkd> !ca 8653c828 ControlArea @8653c828 Segment: e1bce428 Section Ref 1 User Ref 0 File Object 85d927a8 Flink Pfn Ref WaitForDel ModWriteCount 0 46 0 0 Blink Mapped Views Flush Count System Views 0 4 0 0 Flags (8008080) File WasPurged Accessed File: \Program Files\Debugging Tools for Windows\debugger.chm Потом изучите объект «файл», на который ссылается область управ ления: lkd> dt _File_object 85d927a8 nt!_FILE_OBJECT +0x000 Type : 5 +0x002 Size : 112 +0x004 DeviceObject : 0x86b78e30 +0x008 Vpb : 0x86b90d80 +0x00c FsContext : 0xe3b629e0 +0x010 FsContext2 : 0xe3b62b38 +0x014 SectionObjectPointer : 0x85e7a334 +0x018 PrivateCacheMap : 0x862f5a50 +0x01c FinalStatus : 0 +0x020 RelatedFileObject : (null) +0x024 LockOperation : 0 '' ... Закрытая карта кэша находится по смещению 0x18: lkd> dt _private_cache_map nt!_PRIVATE_CACHE_MAP +0x000 NodeTypeCode +0x000 Flags +0x000 UlongFlags +0x004 ReadAheadMask +0x008 FileObject +0x010 FileOffset1 +0x018 BeyondLastByte1 +0x020 FileOffset2 +0x028 BeyondLastByte2 +0x030 ReadAheadOffset 0x862f5a50 : : : : : : : : : : 766 _PRIVATE_CACHE_MAP_FLAGS 0x2fe 0xffff 0x85d927a8 _LARGE_INTEGER 0x10b28 _LARGE_INTEGER 0x12206 _LARGE_INTEGER 0x10b28 _LARGE_INTEGER 0x12206 [2] _LARGE_INTEGER 0x0
ГЛАВА 9 Диспетчер кэша 713 +0x040 ReadAheadLength : [2] 0 +0x048 ReadAheadSpinLock : 0 +0x04c PrivateLinks : _LIST_ENTRY [ 0x862f5a10  0x862f5a10 ] Наконец, вы можете найти общую карту кэша в структуре Section ObjectPointers объекта «файл», а затем просмотреть ее содержимое: lkd> dt _Section_object_pointers 0x85e7a334 nt!_SECTION_OBJECT_POINTERS +0x000 DataSectionObject : 0x8653c828 +0x004 SharedCacheMap : 0x862f5978 +0x008 ImageSectionObject : (null) lkd> dt _shared_cache_map +0x000 NodeTypeCode +0x002 NodeByteSize +0x004 OpenCount +0x008 FileSize +0x010 BcbList +0x018 SectionSize +0x020 ValidDataLength +0x028 ValidDataGoal +0x030 InitialVacbs +0x040 Vacbs +0x044 FileObject +0x048 ActiveVacb ... 0x862f5978 nt!_SHARED_CACHE_MAP : 767 : 304 : 1 : _LARGE_INTEGER 0x19970a : _LIST_ENTRY [ 0x862f5988  0x862f5988 ] : _LARGE_INTEGER 0x1c0000 : _LARGE_INTEGER 0x19970a : _LARGE_INTEGER 0x19970a : [4] (null) : 0x85d42c00 > 0x86bba610 : 0x85d927a8 : 0x86bba610 Интерфейсы файловых систем При первом обращении к файловым данным для чтения или записи драй вер файловой системы должен определить, проецируются ли нужные части файла на системный кэш. Если нет, драйвер файловой системы должен вы звать функцию CcInitializeCacheMap для подготовки индивидуальных для каждого файла структур данных кэша. Далее драйвер файловой системы вызывает одну из нескольких функций для доступа к данным файла. Существует три основных метода доступа к кэ шируемым данным, каждый из которых рассчитан на применение в опре деленной ситуации: 쐽 копирование (copy method) — пользовательские данные копируются между буферами кэша в системном пространстве и буфером процесса в пользовательском пространстве; 쐽 проецирование и фиксация (mapping and pinning method) — данные счи тываются и записываются прямо в буферы кэша по виртуальным адресам; 쐽 обращение к физической памяти (physical memory access method) — данные считываются и записываются прямо в буферы кэша по физическим адресам.
714 ГЛ А В А 11 БЕЗОПАСНОСТЬ Чтобы избежать бесконечного цикла при обработке диспетчером памя ти ошибки страницы, драйверы файловых систем должны поддерживать два варианта чтения файлов — с кэшированием и без. В таких случаях диспет чер памяти вызывает файловую систему для получения данных из файла (че рез драйвер устройства) и запрашивает операцию чтения без кэширования, устанавливая в IRP флаг «no cache». Рис. 1113 иллюстрирует типичное взаимодействие между диспетчером кэша, диспетчером памяти и драйверами файловой системы в ответ на поль зовательские операции файлового вводавывода (чтения или записи). Дис петчер кэша вызывается файловой системой через интерфейсы копирова ния (функции CcCopyRead и CcCopyWrite). Чтобы обработать, например, опе рацию чтения, инициированную через CcFastCopyRead или CcCopyRead, дис петчер кэша создает представление в кэше для проецирования части запро шенного файла и считывает файловые данные в пользовательский буфер, копируя их из представления. Операция копирования генерирует ошибки страниц по мере обращения к каждой ранее недействительной странице в представлении, и в ответ диспетчер памяти инициирует вводвывод без кэ ширования, используя драйвер файловой системы для выборки данных, со ответствующих части файла, спроецированной на ту страницу, которая ока залась недействительной. Рис. 11-13. Взаимодействие файловой системы с диспетчерами кэша и памяти В следующих трех разделах мы рассмотрим все три ранее упомянутых механизма доступа к кэшу, их предназначение и принципы использования. Копирование данных в кэш и из него Поскольку системный кэш находится в системном пространстве, он проеци руется на адресное пространство каждого процесса. Однако, как и любые другие страницы системного пространства, страницы кэша недоступны в пользовательском режиме, поскольку иначе в защите появилась бы потен циальная дыра. (Например, процесс, не имеющий соответствующих прав,
ГЛАВА 9 Диспетчер кэша 715 мог бы считать данные из файла, который находится в какойлибо части системного кэша.) Таким образом, операции чтения и записи пользователь ских приложений в файлы должны обслуживаться процедурами режима ядра, которые копируют данные между буферами кэша в системном про странстве и буферами приложения, расположенными в адресном простран стве процесса. Функции, которые драйверы файловой системы могут ис пользовать для выполнения этих операций, перечислены в таблице 114. Таблица 11-4. Функции режима ядра для копирования данных в кэш и из него Функция Описание CcCopyRead Копирует заданный диапазон байтов из системного кэша в пользовательский буфер CcFastCopyRead Более быстрый вариант CcCopyRead, но ограничен использова нием 32разрядных смещений внутри файла и синхронного чтения CcCopyWrite Копирует заданный диапазон байтов из пользовательского буфера в системный кэш CcFastCopyWrite Более быстрый вариант CcCopyWrite, но ограничен использова нием 32разрядных смещений внутри файла и синхронной (не сквозной) записи (применим только в NTFS) Активность операций чтения из кэша можно увидеть через счетчики про изводительности и системные переменные, представленные в таблице 115. Таблица 11-5. Счетчики и системные переменные, отражающие активность операций чтения из кэша Объект: счетчик Системная переменная Описание Cache: Copy Read Hits % (CcCopyReadWait (Кэш: % попаданий при + CcCopyReadNoWait) / чтении с копированием) (CcCopyReadWait +(CcCopyReadWaitMiss + CcCopyReadNoWait) + CcCopyReadNoWaitMiss) Процентная доля операций чтения с копированием из кэшированных частей файлов (чтение с копированием все равно может вызывать подкач ку — счетчик Memory: Cache Faults/Sec сообщает об интен сивности генерации ошибок страниц для системного рабо чего набора, но включает как аппаратные, так и программ ные ошибки страниц и поэто му не отражает реальную ин тенсивность вводавывода изза подкачки, вызванной ошибками страниц кэша) Cache: Copy Reads/Sec CcCopyReadWait + (Кэш: Чтений с копиро CcCopyReadNoWait ванием/сек) Суммарное число операций чтения с копированием из кэша см. след. стр.
716 ГЛ А В А 11 Таблица 11-5. БЕЗОПАСНОСТЬ (окончание) Объект: счетчик Системная переменная Описание Cache: Sync Copy Reads/Sec (Кэш: Син хронных чтений с копированием/сек) CcCopyReadWait Число синхронных операций чтения с копированием из кэша Cache: Async Copy Reads/Sec (Кэш: Асин хронных чтений с копированием/сек) CcCopyReadNoWait Число асинхронных операций чтения с копированием из кэша Кэширование с применением интерфейсов проецирования и фиксации По мере чтения и записи данных в дисковые файлы пользовательскими при ложениями драйверы файловых систем должны считывать и записывать данные, описывающие сами файлы (метаданные, или данные о структуре тома). Так как драйверы файловых систем выполняются в режиме ядра, они могут модифицировать данные непосредственно в системном кэше при ус ловии уведомления об этом диспетчера кэша. Для поддержки такой опти мизации диспетчер кэша предоставляет функции, перечисленные в табли це 116. Эти функции позволяют драйверам файловых систем находить в виртуальной памяти нужные метаданные и напрямую модифицировать их без использования промежуточных буферов. Таблица 11-6. Функции поиска адресов метаданных Функция Описание CcMapData Проецирует диапазон байтов для чтения CcPinRead Проецирует диапазон байтов для чтения/записи и фиксирует его CcPreparePinWrite Проецирует и фиксирует диапазон байтов для записи (чтение недопустимо) CcPinMappedData Фиксирует ранее спроецированный буфер CcSetDirtyPinnedData Уведомляет диспетчер кэша о модификации данных CcUnpinData Отменяет фиксацию страниц, после чего они могут быть удалены из памяти Если драйверу файловой системы нужно считать метаданные из кэша, он вызывает интерфейс диспетчера кэша, отвечающий за проецирование, чтобы получить виртуальный адрес требуемых данных. Диспетчер кэша подгружает в память все запрошенные страницы и возвращает управление драйверу фай ловой системы. После этого драйвер может напрямую обращаться к данным. Если драйверу файловой системы необходимо модифицировать страни цы кэша, он вызывает сервисы диспетчера кэша, отвечающие за фиксацию модифицируемых страниц в памяти. На самом деле эти страницы не блоки руются в памяти (как это происходит в тех случаях, когда драйвер устрой
ГЛАВА 9 Диспетчер кэша 717 ства блокирует страницы для передачи данных с использованием прямого доступа к памяти). По большей части драйвер файловой системы помечает их поток метаданных как «no write», сообщая подсистеме записи модифи цированных страниц диспетчера памяти (см. главу 7) не сбрасывать страни цы на диск до тех пор, пока не будет явно указано иное. После отмены фик сации страниц диспетчер кэша сбрасывает на диск все измененные страни цы и освобождает представление кэша, которое было занято метаданными. Интерфейсы проецирования и фиксации решают одну сложную пробле му реализации файловых систем — управление буферами. В отсутствие воз можности прямых операций над кэшированными метаданными файловая система была бы вынуждена предугадывать максимальное число буферов, которое понадобится ей для обновления структуры тома. Обеспечивая фай ловой системе прямой доступ к ее метаданным и их изменение непосред ственно в кэше, диспетчер кэша устраняет потребность в буферах и просто обновляет структуру тома в виртуальной памяти, предоставленной диспет чером памяти. Единственным ограничением файловой системы в этом слу чае является объем доступной памяти. Вы можете наблюдать за интенсивностью операций, связанных с фикса цией и проецированием в кэше, с помощью счетчиков производительнос ти и системных переменных, перечисленных в таблице 117. Таблица 11-7. Счетчики и системные переменные для наблюдения за интенсивностью операций фиксации и проецирования Объект: счетчик Системная переменная Cache: Data Map Hits % (CcMapDataWait + CcMap (Кэш: % попаданий при DataNoWait) / (CcMapData отображении данных) Wait + CcMapDataNoWait) + (CcMapDataWaitMiss + CcMapDataNoWaitMiss) Cache: Data Maps/Sec (Кэш: Отображений данных/сек) CcMapDataWait + CcMapDataNoWait Описание Процентная доля операций проецирования данных приме нительно к кэшированным час тям файлов (чтение с копиро ванием все равно может вызы вать подкачку) Суммарное число операций проецирования данных из кэша Cache: Sync Data CcMapDataWait Maps/Sec (Кэш: Син хронных отображений данных/сек) Число операций синхронного проецирования данных из кэша Cache: Async Data CcMapDataNoWait Maps/Sec (Кэш: Асин хронных отображений данных/сек) Число операций асинхронного проецирования данных из кэша Cache: Data Map Pins/Sec (Кэш: Фикса ций при отображении данных/сек) CcPinMappedDataCount Число запросов на фиксацию спроецированных данных см. след. стр.
718 ГЛ А В А 11 Таблица 11-7. БЕЗОПАСНОСТЬ (окончание) Объект: счетчик Системная переменная Cache: Pin Read Hits % (CcPinReadWait + CcPinRead (Кэш: % попаданий NoWait) / (CcPinReadWait + фиксации при чтении) CcPinReadNoWait) + (CcPinReadWaitMiss + CcPinReadNoWaitMiss) Описание Процентная доля операций чтения применительно к фик сированным в кэше частям файлов (чтение с копировани ем все равно может вызывать подкачку) Cache: Pin Reads/Sec (Кэш: Фиксаций при чтении/сек) CcPinReadWait + CcPinReadNoWait Суммарное число операций чтения из фиксированных страниц кэша Cache: Sync Pin Reads/Sec (Кэш: Син хронных фиксаций при чтении/сек) CcPinReadWait Число синхронных операций чтения из фиксированных страниц кэша Cache: Async Pin Reads/Sec (Кэш: Асин хронных фиксаций при чтении/сек) CcPinReadNoWait Число асинхронных операций чтения из фиксированных страниц кэша Кэширование с применением прямого доступа к памяти В дополнение к интерфейсам проецирования и фиксации, используемым при прямом обращении к кэшированным метаданным, диспетчер кэша пре доставляет третий интерфейс — прямой доступ к памяти (direct memory access, DMA). Функции DMA применяются для чтения или записи страниц кэша без промежуточных буферов, например сетевой файловой системой при передаче данных по сети. Интерфейс DMA возвращает файловой системе физические адреса кэши руемых пользовательских данных (а не виртуальные, которые возвращают ся интерфейсами проецирования и фиксации), и эти адреса могут быть ис пользованы для прямой передачи данных из физической памяти на сетевое устройство. Хотя при передаче небольших порций данных (1–2 Кб) можно пользоваться обычными интерфейсами копирования на основе буферов, при передаче больших объемов данных интерфейс DMA значительно повы шает быстродействие сетевого сервера, обрабатывающего файловые запро сы от удаленных систем. Для описания ссылок на физическую память служит список дескрипто ров памяти (memory descriptor list, MDL) (см. главу 7). DMAинтерфейс дис петчера кэша состоит их четырех функций (таблица 118).
ГЛАВА 9 Диспетчер кэша 719 Таблица 11-8. Функции DMA-интерфейса Функция Описание CcMdlRead Возвращает MDL, описывающий заданный диапазон байтов CcMdlReadComplete Освобождает MDL CcMdlWrite Возвращает MDL, описывающий заданный диапазон байтов (возможно, содержащий нулевые значения) CcMdlWriteComplete Освобождает MDL и отмечает диапазон для записи Вы можете исследовать активность, связанную с MDLчтением из кэша, через счетчики производительности или системные переменные, перечис ленные в таблице 119. Таблица 11-9. Счетчики и системные переменные, позволяющие наблюдать за интенсивностью операций MDL-чтения из кэша Объект: счетчик Системная переменная Cache: MDL Read (CcMdlReadWait + Hits % (Кэш: % попа CcMdlReadNoWait) / даний чтений MDL) (CcMdlReadWait + CcMdlReadNoWait) + (CcMdlReadWaitMiss + (CcMdlReadWaitMiss + CcMdlReadNoWaitMiss) Cache: MDL Reads/Sec (Кэш: Чтений MDL/сек) CcMdlReadWait + CcMdlReadNoWait Cache: Sync MDL CcMdlReadWait Reads/Sec (Кэш: Синхронных чтений MDL/сек) Cache: Async MDL Reads/Sec (Кэш: Асинхронных чте ний MDL/сек) CcMdlReadNoWait Описание Процентная доля операций MDL чтения применительно к кэширо ванным частям файлов (ссылки на страницы, разрешаемые MDL чтением, все равно могут вызывать подкачку) Суммарное число операций MDL чтения из кэша Число операций синхронного MDLчтения из кэша Число операций асинхронного MDLчтения из кэша Быстрый ввод-вывод Операции чтения и записи, выполняемые над кэшируемыми файлами, по возможности обрабатываются с применением высокоскоростного механиз ма — быстрого вводавывода (fast I/O). Как уже говорилось в главе 9, быст рый вводвывод обеспечивает чтение и запись кэшируемых файлов без ге нерации IRP. При использовании этого механизма диспетчер вводавывода вызывает процедуру быстрого вводавывода, принадлежащую драйверу фай ловой системы, и определяет, можно ли удовлетворить вводвывод непосред ственно из кэша без генерации IRP. Поскольку диспетчер кэша в архитектуре системы размещается поверх подсистемы виртуальной памяти, драйверы файловых систем могут исполь зовать этот диспетчер для доступа к данным путем простого копирования их
720 ГЛ А В А 11 БЕЗОПАСНОСТЬ в страницы (или из страниц), проецируемые на тот файл, на который ссы лается пользовательская программа, без генерации IRP. Быстрый вводвывод возможен не всегда. Например, первая операция чтения или записи требует подготовки файла к кэшированию (его проеци рования на кэш и создания структур данных кэша, описанных в разделе «Структуры данных кэша» ранее в этой главе). Быстрый вводвывод не при меняется и в том случае, если вызывающий поток указывает асинхронное чтение или запись, поскольку этот поток может быть приостановлен в ходе операций вводавывода, связанных с подкачкой и необходимых для копиро вания буферов в системный кэш (и из него), и фактически синхронного выполнения запрошенной операции асинхронного вводавывода. Однако даже при синхронном вводевыводе драйвер файловой системы может ре шить, что обработка запрошенной операции по механизму быстрого ввода вывода недопустима, если, например, в нужном файле заблокирован какой то диапазон байтов (в результате вызова Windowsфункции LockFile). По скольку диспетчер кэша не знает, какие части и каких файлов блокированы, драйвер файловой системы должен проверить возможность чтения или за писи запрошенных данных, а это требует генерации IRP. Алгоритм приня тия решений показан на рис. 1114. Рис. 11-14. Алгоритм принятия решений по быстрому вводу-выводу
ГЛАВА 9 Диспетчер кэша 721 Обслуживание чтения или записи с использованием быстрого вводавы вода включает следующие операции. 1. Поток выполняет операцию чтения или записи. 2. Если файл кэшируется и указан синхронный вводвывод, запрос переда ется входной точке быстрого вводавывода драйвера файловой системы. Если файл не кэшируется, драйвер файловой системы готовит файл к кэшированию, чтобы выполнить следующий запрос на чтение или запись за счет быстрого вводавывода. 3. Если процедура драйвера файловой системы, отвечающая за быстрый вводвывод, определяет, что быстрый вводвывод возможен, она вызыва ет процедуру чтения или записи диспетчера кэша для прямого доступа к данным кэша. (Если быстрый вводвывод невозможен, драйвер файловой системы возвращает управление подсистеме вводавывода, которая затем генерирует IRP и в конечном счете вызывает в файловой системе обыч ную процедуру чтения.) 4. Диспетчер кэша транслирует переданное смещение в файле в виртуаль ный адрес данных в кэше. 5. При операциях чтения диспетчер кэша копирует данные из кэша в буфер процесса, а при операциях записи — из буфера процесса в кэш. 6. Выполняется одна из следующих операций: • при операциях чтения из файла, при открытии которого не был уста новлен флаг FILE_FLAG_RANDOM_ACCESS, в закрытой карте кэша вы зывающего потока обновляется информация, необходимая для опере жающего чтения; • при операциях записи устанавливается бит изменения у всех модифи цированных страниц кэша, чтобы подсистема отложенной записи сбросила эти страницы на диск; • для файлов, требующих сквозной записи, все измененные данные не медленно сбрасываются на диск. ПРИМЕЧАНИЕ Быстрый вводвывод возможен не только в тех случа ях, когда запрошенные данные уже находятся в физической памяти. Как видно из пп. 5 и 6 предыдущего списка, диспетчер кэша просто обра щается по виртуальным адресам уже открытого файла, где он предпо лагает найти нужные данные. Если происходит промах кэша, диспетчер памяти динамически подгружает эти данные в физическую память. Счетчики производительности и системные переменные, перечисленные в таблице 1110, позволяют наблюдать за операциями быстрого вводавыво да в системе.
722 ГЛ А В А 11 БЕЗОПАСНОСТЬ Таблица 11-10. Счетчики и системные переменные, отражающие активность быстрого ввода-вывода Объект: счетчик Системная переменная Cache: Sync Fast CcFastReadWait Reads/Sec (Кэш: Син хронных быстрых чтений/сек) Описание Число операций синхронного чтения, обработанных как запросы быстрого вводавывода Cache: Async Fast Reads/Sec (Кэш: Асинхронных быст рых чтений/сек) CcFastReadNoWait Число операций асинхронного чтения, обработанных как запросы быстрого вводавывода (это значе ние всегда равно 0, так как асин хронное быстрое чтение в Windows не выполняется) Cache: Fast Read Resource Misses/Sec (Кэш: Промахов ресурса быстрого чтения/сек) CcFastReadResourceMiss Число операций быстрого ввода вывода, не выполненных изза конфликтов ресурсов (это возмож но только при использовании FAT — в NTFS этого не бывает) Cache: Fast Read Not CcFastReadNotPossible Possibles/Sec (Кэш: Не осуществленных быстрых чтений/сек) Число операций быстрого ввода вывода, которые не удалось выпол нить (по решению драйвера фай ловой системы, например, изза того, что какойто диапазон бай тов в файле блокирован) Опережающее чтение и отложенная запись Здесь вы увидите, как диспетчер кэша реализует чтение и запись файловых данных в интересах драйверов файловых систем. Учтите, что диспетчер кэша участвует в файловом вводевыводе только при открытии файла без флага FILE_FLAG_NO_BUFFERING и последующем чтении или записи через Windowsфункции вводавывода (например, функции ReadFile и WriteFile). Кроме того, диспетчер кэша не имеет дела с проецируемыми файлами, а так же с файлами, открытыми с флагом FILE_FLAG_NO_BUFFERING. Интеллектуальное опережающее чтение Для реализации интеллектуального опережающего чтения (intelligent read ahead) диспетчер кэша использует принцип пространственной локальнос ти (spatial locality); исходя из данных, которые вызывающий процесс считы вает в данный момент, диспетчер кэша пытается предсказать, какие данные тот будет считывать в следующий раз. Поскольку системный кэш опирается на использование виртуальных адресов, непрерывных для конкретного фай ла, их непрерывность в физической памяти не имеет значения. Реализация опережающего чтения файлов при кэшировании на основе логических бло ков была бы гораздо сложнее и потребовала бы тесной координации между драйверами файловых систем и кэшем, поскольку такая система кэширова ния опирается на относительные позиции затребованных данных на диске,
ГЛАВА 9 Диспетчер кэша 723 а файлы вовсе не обязательно хранятся в непрерывных областях диска. Ак тивность, связанную с опережающим чтением, можно исследовать с помо щью счетчика производительности Cache: Read Aheads/Sec (Кэш: Упрежда ющих чтений/сек) или системной переменной CcReadAheadIos. Считывание следующего блока файла, к которому происходит последо вательное обращение, дает очевидные преимущества. Чтобы распространить эти преимущества и на случаи произвольного (прямого) доступа к данным (в направлении вперед или назад), диспетчер кэша запоминает последние два запроса на чтение в закрытой карте кэша, сопоставленной с описателем файла, к которому обращается программа. Этот метод называется асинхрон ным опережающим чтением с хронологией. Диспетчер кэша пытается выя вить какуюто закономерность в операциях прямого чтения вызывающей программы. Например, если вызывающая программа считывает сначала страницу 4000, затем 3000, диспетчер кэша предполагает, что в следующий раз будет затребована страница 2000, и заблаговременно считывает ее в кэш. ПРИМЕЧАНИЕ Хотя предсказание возможно лишь на основе после довательности из трех операций чтения минимум, в закрытой карте кэша запоминаются только две из них. Чтобы еще больше повысить эффективность опережающего чтения, Win dowsфункция CreateFile поддерживает флаг последовательного доступа к файлу, FILE_FLAG_SEQUENTIAL_SCAN. Если этот флаг задан, диспетчер кэша не ведет хронологию чтения для предсказаний, выполняя вместо этого пос ледовательное опережающее чтение. Но по мере считывания файла в рабо чий набор кэша диспетчер кэша удаляет проекции неактивных представле ний файла и командует диспетчеру памяти переместить страницы, принад лежавшие удаленным проекциям, в начало списка простаивающих или мо дифицированных страниц (если страницы изменены), чтобы впоследствии их можно было быстро использовать повторно. Он также заранее считыва ет двукратный объем данных (например, 128 Кб вместо 64 Кб). По мере того как вызывающий поток продолжает считывать данные, диспетчер кэша счи тывает дополнительные блоки данных, всегда опережая вызывающий поток на один блок, равный текущему запрошенному. В этом случае опережающее чтение выполняется диспетчером кэша асин хронно, так как это делается в контексте отдельного потока, выполняемого параллельно с вызывающим потоком. Когда диспетчер кэша вызывается для выдачи кэшированных данных, он сначала обращается к запрошенной вир туальной странице, чтобы удовлетворить запрос, а затем ставит в очередь си стемного рабочего потока еще один запрос на вводвывод для выборки допол нительной порции данных. Далее рабочий поток выполняется в фоновом ре жиме и считывает дополнительные данные, упреждая следующий запрос вы зывающего потока. Заранее считанные страницы загружаются в память парал лельно выполнению пользовательской программы, так что на момент выда чи ее потоком очередного запроса эти данные уже находятся в памяти.
724 ГЛ А В А 11 БЕЗОПАСНОСТЬ В случае приложений, для которых невозможно предсказать схему чте ния данных, функция CreateFile предусматривает флаг FILE_FLAG_RANDOM_ ACCESS. Этот флаг запрещает диспетчеру кэша предсказание адресов следу ющих операций чтения и тем самым отключает опережающее чтение. Этот флаг также предотвращает агрессивное удаление диспетчером кэша проек ций представлений файла по мере обращения к его (файла) данным, что ми нимизирует число операций проецирования/удаления проекций, выполня емых над файлом при повторном обращении приложения к тем же облас тям файла. Кэширование с обратной записью и отложенная запись Диспетчер кэша реализует кэш с обратной отложенной записью (writeback cache with lazy write). Это означает, что данные, записываемые в файлы, сна чала хранятся в страницах кэша в памяти, а потом записываются на диск. Таким образом, записываемые данные в течение некоторого времени накап ливаются, после чего сбрасываются на диск пакетом, что уменьшает общее число операций дискового вводавывода. Для сброса страниц кэша диспетчер кэша должен явно вызвать диспетчер памяти, поскольку в ином случае тот записывает на диск содержимое памяти только при нехватке физической памяти. Но, если процесс модифицирует кэшируемые данные, пользователь ожидает, что изменения будут свое временно отражены на диске. Выбор частоты сброса кэша очень важен. Если слишком часто сбрасывать кэш, быстродействие системы снизится изза дополнительного вводавыво да. А при слишком редком сбросе кэша появится риск потери модифициро ванных файловых данных в случае аварии системы и нехватки физической памяти (которая будет занята чрезмерно большим количеством модифици рованных страниц). Чтобы избежать этих крайностей, раз в секунду в системном рабочем потоке выполняется функция отложенной записи диспетчера кэша, которая сбрасывает на диск (точнее, ставит в очередь на запись) одну восьмую часть измененных страниц системного кэша. Если измененные страницы появля ются быстрее, чем сбрасываются, подсистема отложенной записи дополни тельно сбрасывает соответствующее дополнительное количество изменен ных страниц. Реальные операции вводавывода выполняются системными рабочими потоками из пула общесистемных критичных рабочих потоков. ПРИМЕЧАНИЕ Диспетчер кэша предоставляет драйверам файловой системы средства, позволяющие отслеживать, когда и сколько данных было записано в файл. После того как подсистема отложенной запи си сбрасывает на диск измененные страницы, диспетчер кэша уведом ляет об этом файловую систему, чтобы она обновила свое значение для длины действительных данных файла. (Диспетчер кэша и файло вые системы раздельно отслеживают длину действительных данных для файла в памяти.)
ГЛАВА 9 Диспетчер кэша 725 Наблюдать за активностью подсистемы отложенной записи позволяют счетчики производительности или системные переменные, перечисленные в таблице 1111. Таблица 11-11. Счетчики и системные переменные, отражающие активность подсистемы отложенной записи Объект: счетчик Системная переменная Описание Cache: Lazy Write Flushes/Sec (Кэш: Сбросов ленивой записи/сек) CcLazyWriteIos Количество сбросов, выполнен ных подсистемой отложенной записи Cache: Lazy Write Pages/Sec (Кэш: Страниц ‘ленивой’ записи/сек) CcLazyWritePages Количество страниц, записанных подсистемой отложенной записи Отключение отложенной записи для файла Если вы создаете временный файл вызовом Windowsфункции CreateFile с флагом FILE_ATTRIBUTE_TEMPORARY, подсистема отложенной записи не станет записывать измененные страницы этого файла на диск, пока не воз никнет существенная нехватка физической памяти или пока файл не будет явно сброшен на диск. Эта особенность подсистемы отложенной записи повышает быстродействие системы: данные, которые в конечном счете мо гут быть отброшены, на диск сразу не записываются. Приложения обычно удаляют временные файлы вскоре после закрытия. Принудительное включение в кэше сквозной записи на диск Поскольку некоторые приложения не терпят ни малейших задержек между записью в файл и реальным обновлением данных на диске, диспетчер кэша поддерживает кэширование со сквозной записью (writethrough caching), включаемое для каждого объекта «файл» индивидуально; при этом измене ния записываются на диск по мере их внесения. Чтобы включить кэширо вание со сквозной записью, при вызове функции CreateFile надо установить флаг FILE_FLAG_WRITE_THROUGH. В качестве альтернативы поток может явно сбрасывать на диск измененные данные вызовом Windowsфункции FlushFileBuffers. Вы можете наблюдать за операциями сброса кэша в резуль тате запросов на сквозной вводвывод или явных вызовов FlushFileBuffers через счетчики производительности или системные переменные, перечис ленные в таблице 1112.
726 ГЛ А В А 11 БЕЗОПАСНОСТЬ Таблица 11-12. Счетчики и системные переменные для наблюдения за операциями сброса кэша Объект: счетчик Системная переменная Cache: Data Flushes/Sec CcDataFlushes (Кэш: Сбросов данных/сек) Cache: Data Flush Pages/Sec (Кэш: Страниц сброса данных/сек) CcDataPages Описание Число сбросов страниц кэша (изза вызова FlushFileBuffers или сквозной записи) Число страниц кэша, сброшен ных явно (вызовом FlushFile Buffers) или изза сквозной записи Сброс проецируемых файлов Если подсистема отложенной записи должна записать на диск данные из представления, проецируемого и на адресное пространство другого процес са, ситуация несколько усложняется. Дело в том, что диспетчеру кэша извест ны лишь страницы, модифицированные им самим. (О страницах, модифици рованных другим процессом, знает только этот процесс, так как биты изме нения этих страниц находятся в элементах таблиц страниц, принадлежащих исключительно процессу.) Чтобы справиться с этой ситуацией, диспетчер памяти посылает диспетчеру кэша соответствующее уведомление в тот мо мент, когда пользователь проецирует какойлибо файл. При сбросе такого файла из кэша (например, в результате вызова Windowsфункции FlushFile Buffers) диспетчер кэша записывает на диск модифицированные страницы из кэша, а затем проверяет, не спроецирован ли этот файл другим процессом. Если да, диспетчер кэша сбрасывает все представление раздела для того, что бы записать любые страницы, которые мог модифицировать второй процесс. Если пользователь заканчивает проецировать представление файла, открыто го и в кэше, модифицированные страницы помечаются как измененные, что бы при последующем сбросе представления подсистемой отложенной запи си эти страницы были записаны на диск. Такой алгоритм действует всякий раз, когда возникает следующая последовательность событий. 1. Пользователь удаляет проекцию представления. 2. Процесс сбрасывает файловые буферы. При ином порядке событий предсказать, какие страницы будут записа ны на диск, нельзя. ЭКСПЕРИМЕНТ: наблюдение за операциями сброса кэша Вы можете увидеть, как диспетчер кэша проецирует представления в системный кэш и сбрасывает страницы на диск, запустив оснастку Performance (Производительность) и добавив счетчики Data Maps/sec (Отображений данных/сек) и Lazy Write Flushes/sec (Сбросов ленивой записи/сек), а затем скопировав большой файл из одного места в дру гое. На следующей иллюстрации показаны графики, относящиеся к Data Maps/sec (верхний) и к Lazy Write Flushes/sec (нижний).
ГЛАВА 9 Диспетчер кэша 727 Дросселирование записи Файловая система и диспетчер кэша должны определять, повлияет ли зап рос кэшированной записи на производительность системы, и исходя из это го планировать отложенные операции записи. Сначала файловая система через функцию CcCanIWrite выясняет у диспетчера кэша, можно ли записать определенное число байтов прямо сейчас без ущерба для производительнос ти, и при необходимости блокирует запись. Далее она настраивает обратный вызов диспетчера кэша для автоматической записи данных на диск, когда запись вновь будет разрешена вызовом CcDeferWrite. Получив уведомление о предстоящей операции записи, диспетчер кэша определяет, сколько изме ненных страниц находится в кэше и какой объем физической памяти до ступен. Если свободных физических страниц мало, диспетчер кэша немед ленно блокирует поток файловой системы, выдавший запрос на запись дан ных в кэш. Подсистема отложенной записи сбрасывает часть измененных страниц на диск, после чего разрешает продолжить выполнение блокиро ванного потока файловой системы. Такой механизм, называемый дроссели рованием записи (write throttling), предотвращает падение быстродействия системы изза нехватки памяти при операциях записи большого объема дан ных, инициируемых файловой системой или сетевым сервером. ПРИМЕЧАНИЕ Дросселирование записи оказывает глобальное влия ние на систему, так как ресурс, на котором основан этот механизм, — свободная физическая память — является глобальным. И если интен сивная запись на медленное устройство вызывает дросселирование, это распространяется на операции записи и на другие устройства.
728 ГЛ А В А 11 БЕЗОПАСНОСТЬ Пороговое число измененных страниц (dirty page threshold) — это коли чество страниц, хранимых системным кэшем в памяти, по достижении ко торого пробуждается поток подсистемы отложенной записи для сброса страниц на диск. Это значение вычисляется при инициализации системы и зависит от объема физической памяти и параметра реестра LargeSystem Cache, как мы уже объясняли. Алгоритм расчета порогового числа измененных страниц представлен в таблице 1113. Результат расчета с использованием этого алгоритма игно рируется, если максимальный размер системного рабочего набора превы шает 4 Мб, — а именно так зачастую и происходит. (Определение малого, среднего и большого объема системной памяти см. в главе 7.) Когда макси мальный размер рабочего набора превышает 4 Мб, пороговое число изме ненных страниц устанавливается равным максимальному размеру систем ного рабочего набора за вычетом 2 Мб. Таблица 11-13. Алгоритм расчета порогового числа измененных страниц Объем системной памяти Пороговое число измененных страниц Малый Число физических страниц / 8 Средний Число физических страниц / 4 Большой Сумма двух вышеуказанных значений Дросселирование записи также полезно для сетевых редиректоров, пере дающих данные по медленным коммуникационным каналам. Вообразите, например, локальный процесс, записывающий большой объем данных в уда ленную файловую систему по каналу, работающему со скоростью 9600 бод. Данные не попадут на удаленный диск, пока подсистема отложенной запи си диспетчера кэша не сбросит кэш на диск. Если редиректор накапливает много измененных страниц, одновременно сбрасываемых на диск, на при нимающей стороне может истечь время ожидания данных до окончания их передачи. Развитие событий по такому сценарию можно предотвратить с помощью функции диспетчера кэша CcSetDirtyPageThreshold, позволяющей сетевым редиректорам устанавливать лимит на количество измененных страниц, которые можно накапливать без сброса на диск. Ограничивая чис ло измененных страниц, редиректор гарантирует, что операции сброса кэша не вызовут таймаута. ПРИМЕЧАНИЕ В Windows XP и выше сетевые редиректоры не зада ют пороговое значение измененных страниц, вместо этого полагаясь на системные значения по умолчанию. ЭКСПЕРИМЕНТ: просмотр параметров дросселирования записи Команда !defwrites отладчика ядра выводит дамп значений переменных ядра, используемых диспетчером кэша для определения момента дрос селирования операций записи.
ГЛАВА 9 Диспетчер кэша 729 kd> !defwrites *** Cache Write Throttle Analysis *** CcTotalDirtyPages: CcDirtyPageThreshold: MmAvailablePages: MmThrottleTop: MmThrottleBottom: MmModifiedPageListHead.Total: 758 770 42255 250 30 689 ( 3032 Kb) ( 3080 Kb) ( 169020 Kb) ( 1000 Kb) ( 120 Kb) ( 2756 Kb) CcTotalDirtyPages within 64 (max charge) pages of the threshold, writes may be throttled Check critical workqueue for the lazy writer, !exqueue 16 Как видите, число измененных страниц близко к пороговому зна чению, при котором начинается дросселирование записи (CcDirty PageThreshold), и поэтому, если бы в ходе эксперимента процесс попы тался записать более 12 страниц (48 Кб), эти операции были бы отло жены до тех пор, пока подсистема отложенной записи не уменьшила бы число измененных страниц. Системные потоки Как уже говорилось, диспетчер кэша выполняет отложенную запись и опе режающее чтение, передавая запросы в общий пул критичных системных рабочих потоков. Однако в системах с малым и средним объемом памяти он использует на один поток меньше общего количества критичных системных рабочих потоков, а в системах с большим объемом памяти — на два. Внутренне диспетчер кэша организует свои запросы в два списка (кото рые все равно обслуживаются одним и тем же набором рабочих потоков исполнительной системы): 쐽 экспрессочередь (express queue) — для операций опережающего чтения; 쐽 регулярная очередь (regular queue) — для отложенной записи измененных данных, подлежащих сбросу, обратной записи и отложенного закрытия файлов. Чтобы отслеживать рабочие элементы, направленные рабочим потокам, диспетчер кэша создает собственный ассоциативный список (индивидуаль ный для каждого процессора и имеющий фиксированную длину) структур рабочих элементов, поставленных в очереди рабочих потоков (ассоциатив ные списки обсуждаются в главе 7). Число элементов в очереди рабочего потока определяется объемом системной памяти и для систем Windows Professional составляет 32, 64 или 128 в системах с малым, средним или боль шим объемом памяти соответственно (для систем Windows Server с большим объемом памяти — 256).
730 ГЛ А В А 11 БЕЗОПАСНОСТЬ Резюме Диспетчер кэша предоставляет быстродействующий интеллектуальный ме ханизм для уменьшения интенсивности дискового вводавывода и увеличе ния общей пропускной способности системы. Осуществляя кэширование на основе виртуальных блоков, диспетчер кэша может выполнять интеллекту альное опережающее чтение. Используя для обращения к файловым данным механизм проецирования файлов, диспетчер кэша предоставляет специаль ный механизм для быстрого вводавывода, который уменьшает нагрузку на процессор при выполнении операций чтения и записи и позволяет возло жить все управление физической памятью на диспетчер памяти. А это избав ляет от дублирования кода и повышает эффективность работы операцион ной системы.
Г Л А В А 1 2 Файловые системы В начале этой главы мы даем обзор файловых систем, поддерживаемых Windows, а также описываем типы драйверов файловых систем и принци пы их работы, в том числе способы взаимодействия с другими компонента ми операционной системы, например с диспетчерами памяти и кэша. Затем поясняем, как пользоваться утилитой Filemon (www.sysinternals.com) для ана лиза проблем, связанных с доступом к файловой системе. Мы рассмотрим «родной» для Windows формат файловой системы NTFS и особенности этой файловой системы — сжатие данных, способность к восстановлению, под держку квот и шифрование. Чтобы полностью усвоить материал этой главы, вы должны понимать тер минологию, введенную в главе 10, в том числе термины «том» и «раздел». Кро ме того, вам должны быть знакомы следующие дополнительные термины. 쐽 Секторы — аппаратно адресуемые блоки носителя. Размер секторов на жестких дисках в x86системах почти всегда равен 512 байтам. Таким об разом, если операционная система должна модифицировать 632й байт диска, она записывает 512байтовый блок данных во второй сектор диска. 쐽 Форматы файловых систем определяют принципы хранения данных на носителе и влияют на характеристики файловой системы. Например, файловая система, формат которой не допускает сопоставления прав доступа с файлами и каталогами, не поддерживает защиту. Формат фай ловой системы также может налагать ограничения на размеры файлов и емкости поддерживаемых устройств внешней памяти. Наконец, некото рые форматы файловых систем эффективно реализуют поддержку либо больших, либо малых файлов и дисков. 쐽 Кластеры — адресуемые блоки, используемые многими файловыми сис темами. Размер кластера всегда кратен размеру сектора (рис. 121). Фай ловая система использует кластеры для более эффективного управления дисковым пространством: кластеры, размер которых превышает размер сектора, позволяют разбить диск на блоки меньшей длины — управлять такими блоками легче, чем секторами. Потенциальный недостаток клас теров большего размера — менее эффективное использование дисково го пространства, или внутренняя фрагментация, которая возникает изза того, что размеры файлов редко бывают кратны размеру кластера.
732 ГЛ А В А 12 Рис. 12-1. БЕЗОПАСНОСТЬ Секторы и кластер на диске 쐽 Метаданные — это данные, хранящиеся на томе и необходимые для под держки управления файловой системой. Как правило, они недоступны приложениям. Метаданные включают, например, информацию, опреде ляющую местонахождение файлов и каталогов на томе. Файловые системы Windows Windows поддерживает файловые системы: 쐽 CDFS; 쐽 UDF; 쐽 FAT12, FAT16 и FAT32; 쐽 NTFS. Как вы еще увидите, каждая из этих файловых систем оптимальна для определенной среды. CDFS CDFS, или файловая система CDROM (только для чтения), обслуживается драйвером \Windows\System32\Drivers\Cdfs.sys, который поддерживает над множества форматов ISO9660 и Joliet. Если формат ISO9660 сравнительно прост и имеет ряд ограничений, например имена с буквами верхнего реги стра в кодировке ASCII и максимальной длиной в 32 символа, то формат Joliet более гибок и поддерживает Unicodeимена произвольной длины. Если на диске присутствуют структуры для обоих форматов (чтобы обеспечить максимальную совместимость), CDFS использует формат Joliet. CDFS присущ ряд ограничений: 쐽 максимальная длина файлов не должна превышать 4 Гб; 쐽 число каталогов не может превышать 65 535. CDFS считается унаследованным форматом, поскольку индустрия уже приняла в качестве стандарта для носителей, предназначенных только для чтения, формат Universal Disk Format (UDF). UDF Файловая система UDF в Windows является UDFсовместимой реализацией OSTA (Optical Storage Technology Association). (UDF является подмножеством
ГЛАВА 9 Файловые системы 733 формата ISO13346 с расширениями для поддержки CDR, DVDR/RW и т. д.) OSTA определила UDF в 1995 году как формат магнитооптических носите лей, главным образом DVDROM, предназначенный для замены формата ISO 9660. UDF включен в спецификацию DVD и более гибок, чем CDFS. Драйвер UDF поддерживает UDF версий 1.02 и 1.5 в Windows 2000, а также версий 2.0 и 2.01 в Windows XP и Windows Server 2003. Файловые системы UDF облада ют следующими преимуществами: 쐽 длина имен файлов и каталогов может быть до 254 символов в ASCIIко дировке или до 127 символов в Unicodeкодировке; 쐽 файлы могут быть разреженными (sparse); 쐽 размеры файлов задаются 64битными значениями. Хотя формат UDF разрабатывался с учетом особенностей перезаписыва емых носителей, драйвер UDF в Windows (\Windows\System32\Drivers\ Udfs.sys) поддерживает носители только для чтения. Кроме того, в Windows не реализована поддержка других возможностей UDF, в частности именован ных потоков, списков управления доступом и расширенных атрибутов. FAT12, FAT16 и FAT32 Windows поддерживает файловую систему FAT по трем причинам: для воз можности обновления операционной системы с прежних версий Windows до современных, для совместимости с другими операционными системами при многовариантной загрузке и как формат гибких дисков. Драйвер фай ловой системы FAT в Windows реализован в \Windows\System32\Drivers\ Fastfat.sys. В название каждого формата FAT входит число, которое указывает разряд ность, применяемую для идентификации кластеров на диске. 12разрядный идентификатор кластеров в FAT12 ограничивает размер дискового раздела 212 (4096) кластерами. В Windows используются кластеры размером от 512 байтов до 8 Кб, так что размер тома FAT12 ограничен 32 Мб. Поэтому Win dows использует FAT12 как формат 5 и 3,5дюймовых дискет, способных хранить до 1,44 Мб данных. ПРИМЕЧАНИЕ Все файловые системы FAT резервируют на томе пер вые два кластера и последние 16, так что число доступных для исполь зования кластеров на томе, например FAT12, чуть меньше 4096. FAT16 — за счет 16разрядных идентификаторов кластеров — может ад ресовать до 216 (65 536) кластеров. В Windows размер кластера FAT16 варьи руется от 512 байтов до 64 Кб, поэтому размер FAT16тома ограничен 4 Гб. Размер кластеров, используемых Windows, зависит от размера тома (табли ца 121). Если вы форматируете том размером менее 16 Мб для FAT с помо щью команды format или оснастки Disk Management (Управление дисками), Windows вместо FAT16 использует FAT12.
734 ГЛ А В А 12 Таблица 12-1. БЕЗОПАСНОСТЬ Размеры кластеров в FAT16 в Windows по умолчанию Размер тома (Мб) Размер кластера 0–32 512 байтов 33–64 1 Кб 65–128 2 Кб 129–256 4 Кб 257–511 8 Кб 512–1023 16 Кб 1024–2047 32 Кб 2048–4095 64 Кб Том FAT делится на несколько областей (рис. 122). Таблица размещения файлов (file allocation table, FAT), от которой и произошло название файло вой системы FAT, имеет по одной записи для каждого кластера тома. Поскольку таблица размещения файлов критична для успешной интерпретации содер жимого тома, FAT поддерживает две копии этой таблицы. Так что, если драй вер файловой системы или программа проверки целостности диска (вроде Chkdsk) не сумеет получить доступ к одной из копий FAT (например, изза плохого сектора на диске), она сможет использовать вторую копию. Рис. 12-2. Организация FAT Записи в таблице FAT определяют цепочки размещения файлов и катало гов (рис. 123), где отдельные звенья представляют собой указатели на следу ющий кластер с данными файла. Элемент каталога для файла хранит началь ный кластер файла. Последний элемент цепочки размещения файла содержит зарезервированное значение 0xFFFF для FAT16 и 0xFFF для FAT12. Записи FAT, описывающие свободные кластеры, содержат нулевые значения. На рис. 123 показан файл FILE1, которому назначены кластеры 2, 3 и 4; FILE2 фрагменти рован и использует кластеры 5, 6 и 8; а FILE3 занимает только кластер 7. Чте ние файла с FATтома может потребовать просмотра больших блоков табли цы размещения файлов для поиска всех его цепочек размещения. Рис. 12-3. Пример цепочек размещения файлов в FAT
ГЛАВА 9 Файловые системы 735 В начале тома FAT12 или FAT16 заранее выделяется место для корневого каталога, достаточное для хранения 256 записей (элементов), что ограничи вает число файлов и каталогов в корневом каталоге (в FAT32 такого ограни чения нет). Элемент каталога FAT, размер которого составляет 32 байта, хра нит имя файла, его размер, начальный кластер и метку времени (время со здания, последнего доступа и т. д.). Если имя файла состоит из Unicodeсим волов или не соответствует правилам именования по формуле «8.3», приня тым в MSDOS, оно считается длинным и для его хранения выделяются до полнительные элементы каталога. Вспомогательные элементы предшеству ют главному элементу для файла. На рис. 124 показан пример элемента ка талога для файла с именем «The quick brown fox». Система создала представ ление этого имени в формате «8.3», THEQUI~1.FOX (в элементе каталога вы не увидите «.», поскольку предполагается, что точка следует после восьмого символа), и использовала два дополнительных элемента для хранения длин ного Unicodeимени. Каждая строка на рис. 124 состоит из 16 байтов. Рис. 12-4. Элементы каталога FAT FAT32 — более новая файловая система на основе формата FAT; она под держивается Windows 95 OSR2, Windows 98 и Windows Millennium Edition. FAT32 использует 32разрядные идентификаторы кластеров, но при этом резервирует старшие 4 бита, так что эффективный размер идентификатора кластера составляет 28 бит. Поскольку максимальный размер кластеров FAT32 равен 32 Кб, теоретически FAT32 может работать с 8терабайтными томами. Windows ограничивает размер новых томов FAT32 до 32 Гб, хотя поддерживает существующие тома FAT32 большего размера (созданные в других операционных системах). Большее число кластеров, поддерживаемое FAT32, позволяет ей управлять дисками более эффективно, чем FAT16. FAT32 может использовать 512байтовые кластеры для томов размером до 128 Мб. Размеры кластеров на томах FAT32 по умолчанию показаны в таблице 122.
736 ГЛ А В А 12 Таблица 12-2. БЕЗОПАСНОСТЬ Размер кластеров на томах FAT32 по умолчанию Размер раздела Размер кластера (Кб) От 32 Мб до 8 Гб 4 8–16 Гб 8 16–32 Гб 16 32 Гб 32 Помимо большего предельного числа кластеров преимуществом FAT32 перед FAT12 и FAT16 является тот факт, что место хранения корневого ката лога FAT32 не ограничено предопределенной областью тома, поэтому его размер не ограничен. Кроме того, для большей надежности FAT32 хранит вторую копию загрузочного сектора* . В FAT32, как и в FAT16, максимальный размер файла равен 4 Гб, поскольку длина файла в каталоге описывается 32 битным числом. ПРИМЕЧАНИЕ В Windows XP введена поддержка FAT32 на устрой ствах DVDRAM. NTFS Как мы уже говорили в начале главы, NTFS — встроенная («родная») файло вая система Windows. NTFS использует 64разрядные номера кластеров. Это позволяет NTFS адресовать тома размером до 16 экзабайт (16 миллиардов Гб). Однако Windows ограничивает размеры томов NTFS до значений, при которых возможна адресация 32разрядными кластерами, т. е. до 128 Тб (с использованием кластеров по 64 Кб). В таблице 123 перечислены размеры кластеров на томах NTFS по умолчанию (эти значения можно изменить при форматировании тома NTFS). Таблица 12-3. Размеры кластеров на томах NTFS по умолчанию Размер тома Размер кластера 512 Мб и менее 512 байтов 513–1024 Мб 1 Кб 1025–2048 Мб 2 Кб Более 2048 Мб 4 Кб NTFS поддерживает ряд дополнительных возможностей — защиту файлов и каталогов, дисковые квоты, сжатие файлов, символьные ссылки на основе каталогов и шифрование. Одно из важнейших свойств NTFS — восстанавли ваемость. При неожиданной остановке системы целостность метаданных тома FAT может быть утрачена, что вызовет повреждение структуры каталогов и зна чительного объема данных. NTFS ведет журнал изменений метаданных путем протоколирования транзакций, поэтому целостность структур файловой сис темы может быть восстановлена без потери информации о структуре файлов или каталогов. (Однако данные файлов могут быть потеряны.) * Точнее — загрузочной записи, которая включает несколько секторов. Подробную информацию о FAT32 см. в книге «Ресурсы Microsoft Windows 98». — Прим. перев.
ГЛАВА 9 Файловые системы 737 Подробнее о структурах данных и дополнительных возможностях NTFS мы поговорим позже. Архитектура драйвера файловой системы Драйвер файловой системы (file system driver, FSD) управляет форматом фай ловой системы. Хотя FSD выполняются в режиме ядра, у них есть целый ряд особенностей по сравнению со стандартными драйверами режима ядра. Возможно, самой важной особенностью является то, что они должны реги стрироваться у диспетчера вводавывода и более интенсивно взаимодейство вать с ним. Кроме того, для большей производительности FSD обычно по лагаются на сервисы диспетчера кэша. Таким образом, FSD используют бо лее широкий набор функций, экспортируемых Ntoskrnl, чем стандартные драйверы. Если для создания стандартных драйверов режима ядра требует ся Windows DDK, то для создания драйверов файловых систем понадобится Windows Installable File System (IFS) Kit (подробнее о DDK см. главу 1; под робнее о IFS Kit см. www.microsoft.com/whdc/devtools/ifskit). В Windows два типа драйверов файловых систем: 쐽 локальные FSD, управляющие дисковыми томами, подключенными непо средственно к компьютеру; 쐽 сетевые FSD, позволяющие обращаться к дисковым томам, подключен ным к удаленным компьютерам. Локальные FSD К локальным FSD относятся Ntfs.sys, Fastfat.sys, Udfs.sys, Cdfs.sys и Raw FSD (интегрированный в Ntoskrnl.exe). На рис. 125 показана упрощенная схема взаимодействия локальных FSD c диспетчером вводавывода и драйверами устройств внешней памяти. Как мы поясняли в разделе «Монтирование то мов» главы 10, локальный FSD должен зарегистрироваться у диспетчера вво давывода. После регистрации FSD диспетчер вводавывода может вызывать его для распознавания томов при первом обращении к ним системы или одного из приложений. Процесс распознавания включает анализ загрузоч ного сектора тома и, как правило, метаданных файловой системы для про верки ее целостности. Все поддерживаемые Windows файловые системы резервируют первый сектор тома как загрузочный. Загрузочный сектор содержит достаточно информации, чтобы FSD мог идентифицировать свой формат файловой системы тома и найти любые метаданные, хранящиеся на этом томе. Распознав том, FSD создает объект «устройство», представляющий смон тированную файловую систему. Диспетчер вводавывода связывает объект «устройство» тома, созданный драйвером устройства внешней памяти (да лее — объект тома), с объектом «устройство», созданным FSD (далее — объект FSD), через блок параметров тома (VPB). Это приводит к тому, что диспетчер вводавывода перенаправляет через VPB запросы вводавывода, адресованные объекту тома, на объект FSD (подробнее о VPB см. главу 10).
738 ГЛ А В А 12 Рис. 12-5. БЕЗОПАСНОСТЬ Локальный FSD Для большей производительности локальные FSD обычно используют диспетчер кэша, который кэширует данные файловой системы, в том числе ее метаданные. Они также интегрируются с диспетчером памяти, что позво ляет корректно реализовать проецирование файлов. Например, всякий раз, когда приложение пытается обрезать файл, они должны запрашивать дис петчер памяти, чтобы убедиться, что за точкой отсечения файл не проеци руется ни одним процессом. Windows не разрешает удалять данные файла, проецируемого приложением. Локальные FSD также поддерживают операции демонтирования файло вой системы, позволяющие операционной системе отсоединять FSD от объекта тома. Демонтирование происходит каждый раз, когда приложение напрямую обращается к содержимому тома или когда происходит смена носителя, сопоставленного с томом. При первом обращении приложения к носителю после демонтирования диспетчер вводавывода повторно иници ирует операцию монтирования тома для этого носителя. Удаленные FSD Удаленные FSD состоят из двух компонентов: клиента и сервера. Удаленный FSD на клиентской стороне позволяет приложениям обращаться к удален ным файлам и каталогам. Клиентский FSD принимает запросы вводавыво да от приложений и транслирует их в команды протокола сетевой файло вой системы, посылаемые через сеть компоненту на серверной стороне, ко торым обычно является удаленный FSD. Серверный FSD принимает коман ды, поступающие по сетевому соединению, и выполняет их. При этом он выдает запросы на вводвывод локальному FSD, управляющему томом, на котором расположен нужный файл или каталог. Windows включает клиентский удаленный FSD, LANMan Redirector (реди ректор), и серверный удаленный FSD, LANMan Server (сервер) (\Windows\ System32\Drivers\Srv.sys). Редиректор реализован в виде комбинации порт и минипортдрайверов, где портдрайвер (\Windows\System32\Drivers \Rdbss.sys) представляет собой библиотеку подпрограмм, а минипортдрайвер (\Win
ГЛАВА 9 Файловые системы 739 dows\System32\Drivers\Mrxsmb.sys) использует сервисы, реализуемые порт драйвером. Еще один минипортдрайвер редиректора — WebDAV (\Win dows\System32\Drivers\Mrxdav.sys), который реализует клиентскую часть поддержки доступа к файлам по HTTP. Модель «портминипорт» упрощает разработку редиректора, потому что портдрайвер, совместно используемый всеми минипортдрайверами удаленных FSD, берет на себя многие рутин ные операции, требуемые при взаимодействии между клиентским FSD и дис петчером вводавывода Windows. В дополнение к FSDкомпонентам LANMan Redirector и LANMan Server включают Windowsслужбы рабочей станции и сервера соответственно. Взаимодействие между клиентом и сервером при доступе к файлам на серверной стороне через редиректор и серверные FSD показано на рис. 126. Рис. 12-6. Обмен файлами по протоколу CIFS Для форматирования сообщений, которыми обмениваются редиректор и сервер, Windows использует протокол CIFS (Common Internet File System). CIFS — это версия протокола Microsoft SMB (Server Message Block). (Подроб нее о CIFS см. книгу «Сети TCP/IP. Ресурсы Microsoft Windows 2000 Server» и сайт www.cifs.com.) Как и локальные FSD, удаленные FSD на клиентской стороне обычно ис пользуют сервисы диспетчера кэша для локального кэширования файловых данных, относящихся к удаленным файлам и каталогам. Однако удаленный FSD на клиентской стороне должен реализовать протокол поддержки коге рентности распределенного кэша, называемый oplock (opportunistic locking), гарантирующий, что любое приложение при обращении к удаленному фай лу получит те же данные, что и приложения на других компьютерах в сети. Хотя удаленные FSD на серверной стороне участвуют в поддержании коге
740 ГЛ А В А 12 БЕЗОПАСНОСТЬ рентности клиентских кэшей, они не кэшируют данные локальных FSD, по скольку те сами кэшируют свои данные. Когда клиент пытается обратиться к файлу на сервере, он должен сначала запросить oplock. Вид доступного клиенту кэширования, определяется типом oplock, предоставляемого сервером. Существует три основных типа oplock. 쐽 Level I oplock предоставляется при монопольном доступе клиента к фай лу. Клиент, удерживающий для файла oplock этого типа, может кэширо вать операции как чтения, так и записи. 쐽 Level II oplock — разделяемая блокировка файла. Клиенты, удерживающие oplock этого типа, могут кэшировать операции чтения, но запись в файл делает Level II oplock недействительным. 쐽 Batch oplock — самый либеральный тип oplock. Он позволяет клиенту не только читать и записывать файл, но и открывать и закрывать его, не зап рашивая дополнительные oplock. Batch oplock, как правило, использует ся только для поддержки выполнения пакетных (командных) файлов, которые могут неоднократно закрываться и открываться в процессе вы полнения. В отсутствие oplock клиент не может осуществлять локальное кэширова ние ни операций чтения, ни операций записи; вместо этого он должен полу чать данные с сервера и посылать все изменения непосредственно на сервер. Проиллюстрировать работу oplock поможет пример на рис. 127. Перво му клиенту, открывающему файл, сервер автоматически предоставляет Level I oplock. Редиректор на клиентской стороне кэширует файловые данные при чтении и записи в кэше файловой системы локальной машины. Если тот же файл открывает второй клиент, он также запрашивает Level I oplock. Теперь уже два клиента обращаются к одному и тому же файлу, поэтому сервер дол жен принять меры для согласования представления данных файла обоим клиентам. Если первый клиент произвел запись в файл (этот случай и пока зан на рис. 127), сервер отзывает oplock и больше не предоставляет его ни одному клиенту. После отзыва oplock первый клиент сбрасывает все кэши рованные данные файла обратно на сервер. Рис. 12-7. Пример работы oplock
ГЛАВА 9 Файловые системы 741 Если бы первый клиент не произвел запись, его oplock был бы понижен до Level II oplock, т. е. до oplock того же типа, который сервер предоставля ет второму клиенту. В этом случае оба клиента могли бы кэшировать опера ции чтения, но после операции записи любым из клиентов сервер отозвал бы их oplock, и последующие операции были бы некэшируемыми. Однаж ды отозванный, oplock больше не предоставляется для этого экземпляра от крытого файла. Однако, если клиент закрывает файл и повторно открывает его, сервер заново решает, какой oplock следует предоставить клиенту. Реше ние сервера зависит от того, открыт ли файл другими клиентами и произ водил ли хоть один из них запись в этот файл. ЭКСПЕРИМЕНТ: просмотр списка зарегистрированных файловых систем Диспетчер вводавывода, загружая в память драйвер устройства, обыч но присваивает имя объекту «драйвер», который создается для представ ления этого драйвера. Этот объект помещается в каталог \Drivers дис петчера объектов. Объекты «драйвер» любого загружаемого диспетче ром вводавывода драйвера с атрибутом Type, равным SERVICE_FILE _SYSTEM_DRIVER (2), помещаются этим диспетчером в каталог \File System. Таким образом, утилита типа Winobj (www.sysinternals.com) по зволяет увидеть зарегистрированные файловые системы, как показано на следующей иллюстрации. (Заметьте, что некоторые драйверы фай ловых систем помещают в каталог \FileSystem и объекты «устройство».) Еще один способ увидеть зарегистрированные файловые систе мы — запустить программу System Information (Сведения о системе). В Windows 2000 запустите оснастку Computer Management (Управле ние компьютером) и выберите Drivers (Драйверы) в Software Environ ment (Программная среда) в узле System Information (Сведения о сис теме); в Windows XP и Windows Server 2003 запустите Msinfo32 и вы берите System Drivers (Системные драйверы) в узле Software Environ см. след. стр.
742 ГЛ А В А 12 БЕЗОПАСНОСТЬ ment (Программная среда). Отсортируйте список драйверов, щелкнув колонку Type (Тип), и драйверы с атрибутом SERVICE_FILE_SYSTEM_ DRIVER окажутся в начале списка. Заметьте: если драйвер регистрируется как SERVICE_FILE_SYSTEM_ DRIVER, это еще не означает, что он служит локальным или удаленным FSD. Например, Npfs (Named Pipe File System), присутствующий на только что показанной иллюстрации, на самом деле является драйве ром сетевого API — он поддерживает именованные каналы, но реали зует закрытое пространство имен и поэтому в какойто мере подобен драйверу файловой системы. Пространство имен Npfs исследуется в одном из экспериментов в главе 13. Работа файловой системы Система и приложения могут обращаться к файлам двумя способами: напря мую (через функции вводавывода вроде ReadFile и WriteFile) и косвенно, путем чтения или записи части своего адресного пространства, где находит ся раздел проецируемого файла (подробнее о проецируемых файлах см. главу 7). Упрощенная схема на рис. 128 иллюстрирует компоненты, участву ющие в работе файловой системы, и способы их взаимодействия. Как види те, есть несколько путей вызова FSD: 쐽 из пользовательского или системного потока, выполняющего явную опе рацию файлового вводавывода; 쐽 из подсистем записи модифицированных и спроецированных страниц, принадлежащих диспетчеру памяти; 쐽 неявно из подсистемы отложенной записи, принадлежащей диспетчеру кэша; 쐽 неявно из потока опережающего чтения, принадлежащего диспетчеру кэша; 쐽 из обработчика ошибок страниц, принадлежащего диспетчеру памяти.
ГЛАВА 9 Файловые системы 743 Рис. 12-8. Компоненты, участвующие в операциях ввода-вывода файловой системы Явный файловый ввод-вывод Наиболее очевидный способ доступа приложения к файлам — вызов Windows функций вводавывода, например CreateFile, ReadFile и WriteFile. Приложение открывает файл с помощью CreateFile, а затем читает, записывает и удаляет его, передавая описатель файла, возвращенный CreateFile, другим Windowsфункци ям. CreateFile, реализованная в Kernel32.dll, вызывает встроенную функцию NtCreateFile и формирует полное имя файла, обрабатывая символы «.» и «..» и предваряя путь строкой «\??» (например, \??\C:\Daryl \Todo.txt). Чтобы открыть файл, системный сервис NtCreateFile вызывает функцию ObOpenObjectByName, которая выполняет разбор имени, начиная с корнево го каталога диспетчера объектов и первого компонента полного имени («??»). В главе 3 дано подробное описание разрешения имен диспетчером объектов, а здесь мы поясним, как происходит поиск букв диска для томов. Первое, что делает диспетчер объектов, — транслирует \?? в каталог про странства имен, индивидуальный для сеанса, в котором выполняется данный процесс; на этот каталог ссылается поле DosDevicesDirectory в структуре кар ты устройств (device map structure) в объекте «процесс». В системах Windows 2000 без Terminal Services поле DosDevicesDirectory ссылается на каталог \??, а в системах Windows 2000 без Terminal Services карта устройств ссылается
744 ГЛ А В А 12 БЕЗОПАСНОСТЬ на индивидуальный для каждого сеанса каталог, где хранятся объекты «сим вольная ссылка», представляющие все действительные буквы дисков для то мов. Однако в Windows XP и Windows Server 2003 в таком каталоге обычно содержатся лишь имена томов для общих сетевых ресурсов, поэтому в этих ОС диспетчер объектов, не найдя имя (в данном примере — C:) в индивиду альном для сеанса каталоге, переходит к поиску в каталоге, на который ссы лается поле GlobalDosDevicesDirectory карты устройств, сопоставленной с индивидуальным для сеанса каталогом. GlobalDosDevicesDirectory всегда ука зывает на каталог \Global??, где Windows XP и Windows Server 2003 хранят буквы дисков для локальных томов. (Подробнее о пространстве имен сеан са см. одноименный раздел в главе 3.) Символьная ссылка для буквы диска, присвоенной тому, указывает на объект тома в каталоге \Device, поэтому диспетчер объектов, распознав объект тома, передает остаток строки с именем в функцию IopParseDevice, зарегист рированную диспетчером вводавывода для объектов «устройство». (На томах динамических дисков символьная ссылка указывает на промежуточную ссыл ку, которая в свою очередь указывает на объект тома.) На рис. 129 показано, как происходит доступ к объектам томов через пространство имен диспет чера объектов. В данном случае (система Windows 2000 без Terminal Services) символьная ссылка \??\C: указывает на объект тома \Device\HarddiskVolume1. Рис. 12-9. Разрешение букв дисков Заблокировав контекст защиты вызывающего потока и получив инфор мацию о защите из его маркера, IopParseDevice генерирует пакет запроса
ГЛАВА 9 Файловые системы 745 вводавывода (IRP) типа IRP_MJ_CREATE, создает объект «файл», в котором запоминается имя открываемого файла, и по ссылке в VPB объекта тома на ходит объект «устройство» смонтированной файловой системы тома. Далее, используя IoCallDriver, она передает IRP драйверу файловой системы, кото рому принадлежит данный объект «устройство». Когда FSD получает IRP типа IRP_MJ_CREATE, он ищет указанный файл, проверяет права доступа и, если файл есть и пользователь имеет права на запрошенный вид доступа к файлу, возвращает код успешного завершения. Диспетчер объектов создает в таблице описателей, принадлежащей процес су, описатель объекта «файл», который передается назад по цепочке вызовов, в конечном счете достигая приложения в виде параметра, возвращаемого CreateFile. Если файловой системе не удается создать файл, диспетчер вво давывода удаляет созданный для него объект «файл». Мы опустили здесь детали, относящиеся к тому, как FSD находит откры ваемый на томе файл. В выполнении ReadFile ядро участвует в той же мере, что и в выполнении CreateFile, но в этом случае системному сервису NtRead File не приходится искать имя — он вызывает диспетчер объектов для транс ляции описателя, переданного ReadFile, в указатель на объект «файл». Если описатель открытого файла указывает на наличие у вызывающего потока прав на чтение файла, NtReadFile создает IRP типа IRP_MJ_READ и посылает его драйверу файловой системы, в которой находится файл. NtReadFile по лучает объект FSD, хранящийся в объекте «файл», и вызывает IoCallDriver. Диспетчер вводавывода находит FSD с помощью объекта FSD и передает IRP этому драйверу файловой системы. Если считываемый файл может быть кэширован (т. е. при открытии фай ла в функцию CreateFile не передан флаг FILE_FLAG_NO_BUFFERING), FSD проверяет, инициировано ли кэширование для этого объекта «файл». Если да, поле PrivateCacheMap объекта «файл» указывает на структуру закрытой карты кэша (см. главу 11). В ином случае поле PrivateCacheMap будет пустым. Кэширование объекта «файл» инициируется FSD при первой операции за писи или чтения над этим объектом, для чего FSD вызывает функцию CcIni tializeCacheMap диспетчера кэша, и диспетчер кэша создает закрытую и об щую карты кэша, а также объект «раздел» (если это еще не сделано). Убедившись, что кэширование файла разрешено, FSD копирует данные запрошенного файла из виртуальной памяти диспетчера кэша в буфер, ука затель на который передан функции ReadFile вызывающим потоком. Файло вая система выполняет копирование в рамках блока try/except, что позволяет перехватывать все ошибки, которые могут возникнуть, если приложение указало неверный буфер. Для копирования файловая система использует функцию CcCopyRead диспетчера кэша, которая принимает в качестве пара метров объект «файл», смещение внутри файла и длину данных. Диспетчер кэша, выполняя CcCopyRead, получает указатель на общую кар ту кэша, хранящуюся в объекте «файл». Вспомните из главы 11, что эта кар та хранит указатели на блоки управления виртуальными адресами (VACB) и что один элемент VACB соответствует 256килобайтному блоку файла. Если
746 ГЛ А В А 12 БЕЗОПАСНОСТЬ VACBуказатель для считываемой части файла пуст, CcCopyRead создает VACB, резервируя в виртуальном адресном пространстве диспетчера кэша 256ки лобайтное представление, и проецирует на это представление указанную порцию файла (с помощью MmMapViewInSystemCache). Затем CcCopyRead просто копирует данные файла из спроецированного представления в пе реданный ей буфер (буфер, изначально переданный в ReadFile). Если фай ловых данных в физической памяти нет, операция копирования вызывает ошибки страниц, обслуживаемые MmAccessFault. Когда возникает ошибка страницы, MmAccessFault изучает виртуальный адрес, вызвавший ошибку, и находит дескриптор виртуального адреса (VAD) в дереве VAD вызвавшего ошибку процесса (подробнее о дереве VAD см. гла ву 7). В данном случае VAD описывает представление считываемого файла, проецируемое диспетчером кэша, поэтому для обработки ошибки страницы, вызванной действительным виртуальным адресом, MmAccessFault вызывает MiDispatchFault, которая сначала находит область управления (на нее указы вает VAD) и уже через нее отыскивает объект «файл», представляющий откры тый файл. (Если файл открывался более чем один раз, возможно наличие списка объектов «файл», связанных указателями в закрытых картах кэша.) Найдя объект «файл», MiDispatchFault вызывает функцию IoPageRead дис петчера вводавывода, чтобы создать IRP (типа IRP_MJ_READ), и посылает этот IRP к FSD, владеющему объектом «устройство», на который указывает объект «файл». Таким образом, осуществляется повторный вход в файловую систему для чтения данных, запрошенных через CcCopyRead, но на этот раз в IRP присутствует флаг, который сообщает о необходимости некэшируемо го и связанного с подкачкой вводавывода. Этот флаг сигнализирует FSD, что он должен извлечь данные непосредственно с диска, и тот так и поступает, определяя, какие кластеры диска содержат запрошенные данные, и посылая соответствующие IRP диспетчеру томов, владеющему объектом тома, на ко тором находится файл. Поле блока параметров тома (VPB) объекта FSD ука зывает на объект тома. Диспетчер виртуальной памяти ждет, когда FSD завершит чтение, а потом возвращает управление диспетчеру кэша, который продолжает операцию копирования, прерванную ошибкой страницы. По окончании работы CcCo pyRead драйвер файловой системы возвращает управление потоку, вызвав шему NtReadFile; на этот момент данные из запрошенного файла уже скопи рованы в буфер потока. WriteFile работает аналогичным образом с тем исключением, что систем ный сервис NtWriteFile генерирует IRP типа IRP_MJ_WRITE, а FSD вызывает не CcCopyRead, а CcCopyWrite. Последняя, как и CcCopyRead, проверяет, спро ецированы ли на кэш части записываемого файла, и копирует в кэш содер жимое буфера, переданного в WriteFile. Если файловые данные уже хранятся в системном рабочем наборе, выше описанный сценарий немного меняется. Если файловые данные находятся в кэше, CcCopyRead не вызывает ошибки страниц. Кроме того, в определен ных обстоятельствах NtReadFile и NtWriteFile — вместо того чтобы немедлен
ГЛАВА 9 Файловые системы 747 но создать IRP и послать его FSD — вызывают в FSD точку входа для быстро го вводавывода. Вот некоторые из этих обстоятельств: считываемая часть файла должна находиться в первых 4 Гб файла, в файле не должно быть блокировок, а считываемая или записываемая часть файла не должна выхо дить за пределы его текущей длины. В большинстве FSD точки быстрого вводавывода вызывают в диспетче ре кэша функции CcFastCopyRead и CcFastCopyWrite для чтения и записи. Эти варианты стандартных процедур копирования требуют, чтобы перед копи рованием файловые данные были спроецированы на кэш файловой систе мы. Если это условие не выполнено, CcFastCopyRead и CcFastCopyWrite сооб щают о невозможности быстрого вводавывода; тогда функции NtReadFile и NtWriteFile возвращаются к созданию IRP. (Более полное описание быстро го вводавывода см. в разделе «Быстрый вводвывод» главы 11.) Подсистемы записи модифицированных и спроецированных страниц Для сброса модифицированных страниц при нехватке доступной памяти периодически пробуждаются потоки принадлежащих диспетчеру памяти подсистем записи модифицированных и спроецированных страниц. Эти потоки вызывают функцию IoSynchronousPageWrite, чтобы создать IRP типа IRP_MJ_WRITE и записать страницы либо в страничный файл, либо в файл, модифицированный после того, как он был спроецирован. Как и в IRP, соз даваемом MiDispatchFault, в этих IRP устанавливается флаг некэшируемого и связанного с подкачкой вводавывода. Поэтому для записи содержимого памяти на диск FSD обходит кэш файловой системы и выдает IRP непосред ственно драйверу устройства внешней памяти. Подсистема отложенной записи Поток подсистемы отложенной записи, принадлежащей диспетчеру кэша, тоже участвует в записи модифицированных страниц, поскольку периоди чески сбрасывает на диск измененные представления разделов файлов, про ецируемых на кэш. Операция сброса, выполняемая диспетчером кэша вызо вом MmFlushSection, заставляет диспетчер памяти записать на диск все мо дифицированные страницы в сбрасываемой части раздела. Как и подсисте мы записи модифицированных и спроецированных страниц, MmFlushSection посылает данные FSD через IoSynchronousPageWrite. Поток, выполняющий опережающее чтение Диспетчер кэша включает поток, отвечающий за попытку чтения данных из файлов до того, как их явным образом запросит приложение, драйвер или системный поток. Чтобы определить объем подлежащих чтению данных, поток опережающего чтения использует хронологию операций чтения, ко торая хранится в закрытой карте кэша объекта «файл». Выполняя опережа ющее чтение, этот поток просто проецирует на кэш ту часть файла, которую он хочет считать (при необходимости создавая VACB), и обращается к спро ецированным данным. Если при попытках обращения возникают ошибки
748 ГЛ А В А 12 БЕЗОПАСНОСТЬ страниц, активизируется обработчик ошибок страниц, который подгружа ет нужные страницы в системный рабочий набор. Обработчик ошибок страниц Мы описывали использование обработчика ошибок страниц в контексте явного файлового вводавывода и опережающего чтения диспетчера кэша. Но этот обработчик активизируется и всякий раз, когда приложение обра щается к виртуальной памяти, являющейся представлением проецируемого файла, и встречает страницы, которые представляют часть файла, но не вхо дят в рабочий набор приложения. Обработчик MmAccessFault диспетчера памяти предпринимает те же действия, что и при генерации ошибок стра ниц в результате выполнения CcCopyRead или CcCopyWrite, и через IoPage Read посылает соответствующие IRP файловой системе, в которой хранит ся нужный файл. Драйверы фильтров файловой системы Драйвер фильтра, занимающий в иерархии более высокий уровень, чем драйвер файловой системы, называется драйвером фильтра файловой сис темы (file system filter driver). (О драйверах фильтров см. главу 9.) Его спо собность видеть все запросы к файловой системе и при необходимости мо дифицировать или выполнять их, делает возможным создание таких прило жений, как службы репликации удаленных файлов, шифрования файлов, резервного копирования и лицензирования. В любой коммерческий анти вирусный сканер, проверяющий файлы на «лету», входит драйвер файловой системы, который перехватывает IRPпакеты с командами IRP_MJ_CREATE, выдаваемыми при каждом открытии файла приложением. Прежде чем пере дать такой IRP драйверу файловой системы, которому адресована данная команда, антивирусный сканер проверяет открываемый файл на наличие вирусов. Если файл чист, антивирусный сканер передает IRP дальше по це почке, но если файл заражен, сканер обращается к своему сервисному про цессу для удаления или лечения этого файла. Если вылечить файл нельзя, драйвер фильтра отклоняет IRP (обычно с ошибкой «доступ запрещен»), что бы вирус не смог активизироваться. В этом разделе мы опишем работу двух специфических драйверов филь тров файловой системы: Filemon и System Restore. Filemon — утилита для мо ниторинга активности файловой системы (с сайта www.sysinternals.com), ис пользуемая во многих экспериментах в этой книге, — является примером пассивного драйвера фильтра, который не модифицирует поток IRP между приложениями и драйверами файловой системы. System Restore (Восстанов ление системы) — функциональность, введенная в Windows XP, — исполь зует драйвер фильтра файловой системы для наблюдения за изменениями в ключевых системных файлах и создает их резервные копии, чтобы эти фай лы можно было возвращать в те состояния, которые были у них в моменты создания точек восстановления.
ГЛАВА 9 Файловые системы 749 ПРИМЕЧАНИЕ В Windows XP Service Pack 2 и Windows Server 2003 включен Filesystem Filter Manager (\Windows\System32\Drivers\Fltmgr. sys) как часть модели «портминипорт» для драйверов фильтров фай ловой системы. Этот компонент будет доступен и для Windows 2000. Filesystem Filter Manager кардинально упрощает разработку драйверов фильтров, предоставляя интерфейс минипортдрайверов фильтров к подсистеме вводавывода Windows, а также поддерживая сервисы для запроса имен файлов, подключения к томам и взаимодействия с дру гими фильтрами. Компанииразработчики, в том числе Microsoft, бу дут писать новые фильтры файловых систем на основе инфраструк туры, предоставляемой Filesystem Filter Manager, и переносить на нее существующие фильтры. Filemon Утилита Filemon извлекает драйвер устройства «фильтр файловой системы» (Filem.sys) из своего исполняемого образа (Filemon.exe) при первом ее запус ке после загрузки, устанавливает этот драйвер в памяти, а затем удаляет его образ с диска. Через GUI утилиты Filemon вы можете указывать ей вести мо ниторинг активности файловой системы на локальных томах, общих сете вых ресурсах, именованных каналах и почтовых ящиках (mail slots). Полу чив команду начать мониторинг тома, драйвер создает объект «устройство» фильтра и подключает его к объекту «устройству», который представляет смонтированную файловую систему на томе. Например, если драйвер NTFS смонтировал том, драйвер Filemon подключит к объекту «устройство» дан ного тома свой объект «устройство», используя функцию IoAttachDeviceTo DeviceStackSafe диспетчера вводавывода. После этого IRP, адресованный нижележащему объекту «устройство», перенаправляется диспетчером ввода вывода драйверу, которому принадлежит подключенный объект «устрой ство» (в данном случае — Filemon). Перехватив IRP, драйвер Filemon записывает информацию о команде в этом IRP, в том числе имя целевого файла и другие параметры, специфич ные для команды (например, размер и смещение считываемых или записы ваемых данных), в буфер режима ядра, созданный в неподкачиваемой памя ти. Дважды в секунду Filemon GUI посылает IRP объекту «устройство» интер фейса Filemon, который запрашивает копию буфера, содержащего сведения о самых последних операциях, и отображает их в окне вывода. Применение Filemon подробно описывается в разделе «Анализ проблем в файловой сис теме» далее в этой главе. System Restore System Restore (Восстановление системы) — сервис, в рудиментарной форме впервые появившийся в Windows Me (Millennium Edition), позволяет восста навливать систему до предыдущего известного состояния в ситуациях, в ко торых иначе пришлось бы переустанавливать какоето приложение или даже
750 ГЛ А В А 12 БЕЗОПАСНОСТЬ всю операционную систему. (System Restore нет в Windows 2000 и Windows Server 2003.) Например, если вы установили одно или несколько приложений или внесли какието изменения в реестр либо системный файл и это вызва ло проблемы в работе приложений или крах системы, вы можете использо вать System Restore для отката системных файлов и реестра в предыдущее со стояние. System Restore особенно полезен, когда вы устанавливаете приложе ние, вносящее нежелательные изменения в системные файлы. Программы установки, совместимые с Windows XP, интегрируются с System Restore и соз дают точку восстановления до начала процесса установки. Ядро System Restore содержится в сервисе SrService, который вызывается из DLL (\Windows\System32\Srsvc.dll), выполняемой в экземпляре универсально го процесса — хоста сервисов (\Windows\System32\Svchost.exe). (Описание Svchost см. в главе 4.) Роль этого сервиса заключается как в автоматическом создании точек восстановления, так и в экспорте соответствующего API дру гим приложениям, например программам установки. (Кстати, вы можете вруч ную инициировать создание точки восстановления.) System Restore считыва ет свои конфигурационные параметры из раздела реестра HKLM\System\ CurrentControlSet\Services\SR\Parameters, в том числе указывающие, сколько места на диске должно быть свободно для работы этого сервиса и через ка кой интервал следует автоматически создавать точки восстановления. По умолчанию данный сервис создает точку восстановления перед установкой неподписанного драйвера устройства и через каждые 24 часа работы систе мы. Если в упомянутом выше разделе реестра задан DWORDпараметр RPGlo balInterval, он переопределяет этот интервал и задает минимальное время в секундах между моментами автоматического создания точек восстановления. Создавая новую точку восстановления, сервис System Restore сначала соз дает каталог для этой точки, затем делает снимок состояния критически важ ных системных файлов, включая кусты реестра, относящиеся к системе и пользовательским профилям, конфигурационную информацию WMI, файл метабазы IIS (если IIS установлена) и регистрационную базу данных COM. Потом драйвер восстановления системы, \Windows\System32\Drivers \Sr.sys, начинает отслеживать изменения в файлах и каталогах, сохраняя копии уда ляемых или модифицируемых файлов в точке восстановления, а также от мечая другие изменения, например создание и удаление каталогов, в журнале регистрации изменений. Данные точки восстановления поддерживаются для каждого тома инди видуально, поэтому журналы изменений и сохраненные файлы хранятся в каталогах \System Volume Information\_restore{XXXXXXXX}, где символы X представляют назначенный системой GUID соответствующего тома. Такой каталог содержит подкаталоги точек восстановления с именами в виде RPn, где n — уникальный идентификатор точки восстановления. Файлы, входя щие в начальный снимок точки восстановления, хранятся в каталоге Snap shot точки восстановления. Резервным копиям файлов, созданным драйвером System Restore, присва иваются уникальные имена (вроде A0000135.dll), и эти файлы помещаются
ГЛАВА 9 Файловые системы 751 в соответствующий каталог. С точкой восстановления может быть сопостав лено несколько журналов изменений, каждый из которых получает имя в виде Change.log.N, где N — уникальный идентификатор журнала изменений. В каждой записи этого журнала содержатся данные, которые позволяют от менить изменения, внесенные в какойлибо файл или каталог. Например, если вы удалите файл, то соответствующая этой операции запись будет хра нить имя его копии в точке восстановления (допустим, A0000135.dll), а так же исходные длинное и краткое имена этого файла. Сервис System Restore создает новый журнал изменений, когда размер текущего достигает 1 Мб. Рис. 1210 отражает ход обработки запросов к файловой системе в то вре мя, как драйвер System Restore обновляет точку восстановления, реагируя на какиелибо изменения. Рис. 12-10. Так работает драйвер фильтра System Restore Рис. 1211 иллюстрирует содержимое каталога, созданного System Restore и включающего несколько подкаталогов точек восстановления, а также со держимое подкаталога, который соответствует точке восстановления 1. За метьте, что каталоги \System Volume Information недоступны ни по пользо вательской учетной записи, ни по учетной записи администратора — к ним можно обращаться только по учетной записи Local System. Чтобы увидеть этот каталог, используйте утилиту PsExec с сайта www.sysinternals.com, как показано ниже: C:\WINDOWS\SYSTEM32>psexec s cmd PsExec v1.55  Execute processes remotely Copyright (C) 20012004 Mark Russinovich Sysinternals  www.sysinternals.com
752 ГЛ А В А 12 БЕЗОПАСНОСТЬ Microsoft Windows XP [Version 5.1.2600] (C) Copyright 19852001 Microsoft Corp. C:\WINDOWS\system32>cd \system* C:\System Volume Information>cd _rest* C:\System Volume Information\_restore{987E03310F01427CA58A7A2E4AABF84D}> Попав в каталог System Restore, вы можете просмотреть его содержимое командой DIR или перейти в подкаталоги, сопоставленные с точками вос становления. Рис. 12-11. Каталог, созданный System Restore, и содержимое точки восстановления Каталог точки восстановления на загрузочном томе также содержит дво ичный файл _filelst.cfg, который включает расширения файлов, изменения в которых следует фиксировать в точке восстановления, и список каталогов (хранящих, например, временные файлы), изменения в которых следует иг норировать. Этот список, документированный в Platform SDK, указывает System Restore отслеживать только файлы, отличные от файлов данных. (Вряд ли вам понравится, если при откате системы изза проблемы с каким нибудь приложением сервис System Restore удалит важный для вас документ Microsoft Word.)
ГЛАВА 9 Файловые системы 753 ЭКСПЕРИМЕНТ: изучение объектов «устройство», принадлежащих фильтру System Restore Для мониторинга изменений в файлах и каталогах драйвер фильтра System Restore должен подключить объекты «устройство» фильтра к объектам «устройство» FAT и NTFS, представляющим тома. Кроме того, он подключает объект «устройство» фильтра к объектам «устройство», представляющим драйверы файловой системы, чтобы узнавать о мон тировании новых томов файловой системой и соответственно под ключать к ним объекты «устройство» фильтра. Объекты «устройство» System Restore можно просмотреть с помощью отладчика ядра: lkd> !drvobj \filesystem\sr Driver object (81543850) is for: \FileSystem\sr Driver Extension List: (id , addr) Device Object list: 814ee370 81542dd0 81543728 В этом примере вывода у драйвера System Restore три объекта «ус тройство». Последний из них в списке называется SystemRestore — он служит интерфейсом, которому компоненты System Restore пользова тельского режима направляют свои команды: lkd> !devobj 81543728 Device object (81543728) is for: SystemRestore \FileSystem\sr DriverObject 81543850 Current Irp 00000000 RefCount 1 Type 00000022 Flags 00000040 Dacl e128feac DevExt 00000000 DevObjExt 815437e0 ExtensionFlags (0x80000000) DOE_DESIGNATED_FDO Device queue is not busy. Первый и второй объекты подключены к объектам «устройство» файловой системы NTFS: lkd> !devobj 814ee370 Device object (814ee370) is for: \FileSystem\sr DriverObject 81543850 Current Irp 00000000 RefCount 0 Type 00000008 Flags 00000000 DevExt 814ee428 DevObjExt 814ee570 ExtensionFlags (0x80000000) DOE_DESIGNATED_FDO AttachedTo (Lower) 81532020 \FileSystem\Ntfs Device queue is not busy. lkd> !devobj 81542dd0 Device object (81542dd0) is for: \FileSystem\sr DriverObject 81543850 Current Irp 00000000 RefCount 0 Type 00000008 Flags 00000000 DevExt 81542e88 DevObjExt 81542fd0 ExtensionFlags (0x80000000) DOE_DESIGNATED_FDO см. след. стр.
754 ГЛ А В А 12 БЕЗОПАСНОСТЬ AttachedTo (Lower) 815432e8 \FileSystem\Ntfs Device queue is not busy. Один из объектов «устройство» NTFS является интерфейсом для драйвера файловой системы NTFS, так как его имя — NTFS: lkd> !devobj 815432e8 Device object (815432e8) is for: Ntfs \FileSystem\Ntfs DriverObject 81543410 Current Irp 00000000 RefCount 1 Type 00000008 Flags 00000040 Dacl e1297154 DevExt 00000000 DevObjExt 815433a0 ExtensionFlags (0x80000000) DOE_DESIGNATED_FDO AttachedDevice (Upper) 81542dd0 \FileSystem\sr Device queue is not busy. Другой из них представляет смонтированный NTFSтом на C:, и, поскольку в системе только один том, у этого объекта нет имени: lkd> !devobj 81532020 Device object (81532020) is for: \FileSystem\Ntfs DriverObject 81543410 Current Irp 00000000 RefCount 0 Type 00000008 Flags 00000000 DevExt 815320d8 DevObjExt 81532880 ExtensionFlags (0x80000000) DOE_DESIGNATED_FDO AttachedDevice (Upper) 814ee370 \FileSystem\sr Device queue is not busy. Когда пользователь сообщает системе о необходимости восстановления, мастер System Restore (\Windows\System32\Restore\Rstrui.exe) создает пара метр RestoreInProgress типа DWORD в разделе реестра System Restore и при сваивает ему значение 1. Затем он инициирует перезагрузку системы, вызы вая Windowsфункцию ExitWindowsEx. После перезагрузки процесс Winlogon (\Windows\System32\Winlogon.exe) обнаруживает, что нужно выполнить восстановление, копирует сохраненные файлы в исходные каталоги и с по мощью файлов журнала отменяет изменения, внесенные в системные фай лы и каталоги. По окончании этого процесса загрузка системы возобновля ется. Перезагрузка необходима не только для большей безопасности восста новления, но и для активизации восстановленных кустов реестра. В Platform SDK документированы две APIфункции System Restore, SRSet RestorePoint и SRRemoveRestorePoint, предназначенные для программ установ ки. Разработчики должны продумать расширения файлов, используемые их приложениями, чтобы они не сохраняли пользовательские данные в файлах тех типов, которые защищаются сервисом System Restore. Иначе пользователь может потерять свои данные при откате системы до точки восстановления. Анализ проблем в файловой системе В главе 4 было показано, как система и приложения хранят данные в реестре. Если в реестре появляются какието проблемы, скажем, изза неправильно
ГЛАВА 9 Файловые системы 755 сконфигурированной защиты или недостающих параметров/разделов реес тра, то они могут быть причиной многих сбоев в работе системы и приложе ний. Помимо этого, система и приложения используют файлы для хранения данных и обращаются к образам DLL и исполняемых файлов. Значит, ошиб ки в конфигурации защиты NTFS и отсутствие какихлибо файлов или ката логов также являются распространенной причиной сбоев в работе системы и приложений. А все потому, что система и приложения часто полагаются на возможность беспрепятственного доступа к таким файлам и начинают вести себя непредсказуемым образом, если эти файлы оказываются недоступны. Утилита Filemon отражает все файловые операции по мере их выполне ния, что превращает ее в идеальный инструмент для анализа сбоев системы и приложений изза проблем в файловой системе. Пользовательский интер фейс Filemon практически идентичен таковому в Regmon, и Filemon вклю чает те же средства фильтрации, выделения и поиска, что и Regmon. Первый запуск Filemon в системе требует учетной записи с теми же привилегиями, что и в случае Regmon: Load Driver и Debug. После загрузки драйвер остает ся резидентным в памяти, поэтому для последующих запусков Filemon дос таточно привилегии Debug. Базовый и расширенный режимы Filemon При запуске Filemon начинает работу в базовом режиме, в котором отобра жаются те операции в файловой системе, которые наиболее полезны для анализа проблем. В этом режиме Filemon не показывает определенные опе рации в файловой системе, в том числе: 쐽 обращения к файлам метаданных NTFS; 쐽 операции в процессе System; 쐽 вводвывод, связанный со страничным файлом; 쐽 вводвывод, генерируемый процессом Filemon; 쐽 неудачные попытки быстрого вводавывода. Кроме того, в базовом режиме Filemon сообщает об операциях файлового вводавывода, используя описательные имена, а не типы IRP, которые на са мом деле представляют их. В частности, операции IRP_MJ_WRITE и FASTIO_ WRITE отображаются как Write, а операции IRP_MJ_CREATE — как Open (при открытии существующих файлов) или Create (при создании новых файлов). ЭКСПЕРИМЕНТ: наблюдение за активностью файловой системы в простаивающей системе Драйверы файловых систем Windows поддерживают уведомление об изменениях в файлах, что позволяет приложениям узнавать о таких изменениях в файловой системе без постоянного ее опроса. Для это го предназначены Windowsфункции ReadDirectoryChangesW, FindFirst ChangeNotification и FindNextChangeNotification. Таким образом, запус кая Filemon в простаивающей системе, вы не увидите повторяющих ся обращений к файлам и каталогам, поскольку такая активность не см. след. стр.
756 ГЛ А В А 12 БЕЗОПАСНОСТЬ обязательно должна негативно отразиться на общей производитель ности системы. Запустите Filemon и через несколько секунд проверьте в журнале вывода, есть ли попытки периодического опроса. Обнаружив соответ ствующую строку, щелкните ее правой кнопкой мыши и выберите из контекстного меню Process Properties для просмотра детальных сведе ний о процессе, который выполняет операции опроса. Методики анализа проблем с применением Filemon Два основных метода анализа проблем с применением Filemon идентичны та ковым при использовании Regmon: поиск последней операции в трассировоч ной информации Filemon перед тем, как в приложении произошел сбой, или сравнение трассировочной информации Filemon для сбойного приложения с аналогичными сведениями для работающей системы. Подробнее об этих спо собах см. раздел «Методики анализа проблем с применением Regmon» главы 4. Обращайте внимание на записи в выводе Filemon со значениями FILE NOT FOUND, NO SUCH FILE, PATH NOT FOUND, SHARING VIOLATION и ACCESS DENIED в столбце Result. Первые три значения указывают на то, что прило жение или система пытается открыть несуществующий файл или каталог. Во многих случаях эти ошибки не свидетельствуют о серьезной проблеме. На пример, если вы запускаете какуюто программу из диалогового окна Run (За пуск программы), не задавая полный путь к ней, Explorer будет искать эту про грамму в каталогах, перечисленных в переменной окружения PATH, пока не найдет нужный образ или не закончит просмотр всех перечисленных ката логов. Каждая попытка найти образ в каталоге, где такого образа нет, отража ется в выводе Filemon строкой, аналогичной приведенной ниже: 5:28:26 PMEXPLORER.EXE:1568FASTIO_QUERY_OPENC:\Documents and Settings\ mark.AUSTIN\Start Menu\test.exe FILE NOT FOUND Attributes: Error Ошибки, связанные с отклонением попыток доступа, — частая причина сбоев приложений при работе с файловой системой, и они возникают, ког да у приложения нет соответствующего разрешения на открытие файла или каталога. Некоторые приложения не проверяют коды ошибок или не обра батывают ошибки, изза чего происходит их крах или аварийное заверше ние, а некоторые выводят при этом сообщения о других ошибках, которые лишь маскируют истинную причину неудачи файловой операции. Прорехи в защите изза переполнения буфера представляют серьезную угрозу безопасности, но код результата BUFFER OVERFLOW — просто спо соб, используемый драйвером файловой системы, чтобы сообщить прило жению о нехватке места в выделенном буфере для сохранения полученных данных. Разработчики приложений применяют этот способ, чтобы опреде лить правильный размер буфера, так как драйвер файловой системы заод но сообщает и эту информацию. За операциями с кодом результата BUFFER OVERFLOW обычно следуют операции с успешным результатом.
ГЛАВА 9 Файловые системы 757 ЭКСПЕРИМЕНТ: выявление истинной причины ошибки с помощью Filemon Иногда приложения выводят сообщения об ошибках, которые не рас крывают истинную причину проблемы. Такие сообщения могут запу тать и заставить вас тратить время на диагностику несуществующих проблем. Если сообщение об ошибке относится к проблеме в файло вой системе, Filemon покажет, какие нижележащие ошибки могли бы предшествовать этому сообщению. В данном эксперименте вы установите разрешение для каталога, а затем попытаетесь выполнить в нем операцию сохранения файла из Notepad, что приведет к появлению сообщения о совсем другой ошиб ке. Filemon покажет истинную ошибку и причину вывода в Notepad именно такого сообщения. 1. Запустите Filemon и установите включающий фильтр для «note pad.exe». 2. Откройте Explorer и создайте каталог Test в одном из каталогов NTFSтома. (В данном примере используется корневой каталог.) 3. Измените разрешения для каталога Test так, чтобы запретить любой вид доступа к нему. Не исключено, что вам придется открыть диа логовое окно Advanced Security Settings (Дополнительные парамет ры безопасности) и задать параметры на вкладке Permissions (Раз решения), чтобы удалить наследуемые разрешения защиты. Когда вы примените измененные разрешения, Explorer должен будет предупредить вас о том, что никто не получит доступа к этой папке. 4. Запустите Notepad (Блокнот) и введите в нем какойнибудь текст. Потом выберите команду Save (Сохранить) из меню File (Файл). В поле File Name (Имя файла) диалогового окна Save As (Сохранить как) введите c:\test\test.txt (если вы создали папку на томе C:). см. след. стр.
758 ГЛ А В А 12 БЕЗОПАСНОСТЬ 5. Notepad выведет следующее сообщение об ошибке. 6. Это сообщение подразумевает, что каталог C:\Test не существует. 7. В трассировочной информации Filemon вы должны увидеть при мерно то же, что и на следующей иллюстрации. Вывод в нижней части иллюстрации был сгенерирован непосред ственно перед появлением этого сообщения об ошибке. Строка 331 показывает, что Notepad пытался открыть C:\Test и получил отказ в до ступе. Сразу после этого, как видно из строки 332, он попытался от крыть каталог C:\Test\Test.txt (на это указывает флаг Directory в столбце Other на той же строке) и получил ошибку «файл не найден», потому что такого каталога нет. Сообщение Notepad «Path does not exist» (Путь не существует) согласуется с последней ошибкой, но не с первой. По этому кажется, что Notepad сначала пытался открыть каталог, а когда это не удалось, он почемуто решил, что имя C:\Test\Test.txt соответ ствует каталогу, а не файлу. Не сумев открыть такой каталог, Notepad вывел сообщение об ошибке, но истинной причиной, как показывает Filemon, был отказ в доступе. Filemon широко применяется Microsoft и другими организациями для ре шения трудных или почти неуловимых проблем. Рассмотрим один из приме ров, где Filemon помог докопаться до истинной причины некорректного со общения об ошибке, генерируемого службой Windows Installer. Когда поль зователь пытался установить программу из ее файла Windows Installer Package, служба Windows Installer сообщала об ошибке, показанной на рис. 1212; в нем утверждалось, что этой службе не удается записать чтолибо в папку Temp. Пользователь убедился, что вопреки этому утверждению каталог, выделенный для временных файлов и заданный в его профиле (эту информацию он по
ГЛАВА 9 Файловые системы 759 лучил, набрав в консольном окне команду set temp), находится на томе, где достаточно свободного места, и имеет разрешения по умолчанию. Рис. 12-12. Сообщение об ошибке от Microsoft Windows Installer Тогда пользователь запустил Filemon для трассировки операций в файловой системе, которые приводят к этой ошибке, и обнаружил ее причину (см. выде ленную строку на рис. 1213). Из этих данных стало ясно, что служба Windows Installer обращалась не к каталогу временных файлов, заданному в профиле пользователя, а к \Windows\Installer. Строка со значением ACCESS DENIED ука зала на то, что служба Windows Installer выполнялась под учетной записью ло кальной системы, поэтому пользователь так изменил разрешения на доступ к \Windows\Installer, чтобы учетная запись локальной системы предоставляла права на доступ к этому каталогу для записи. Это и решило проблему. Рис. 12-13. Вывод Filemon для службы Microsoft Windows Installer Еще один пример анализа проблем с помощью Filemon. В этом случае пользователь запускал Microsoft Word, и буквально через несколько секунд набора текста окно Word закрывалось без всякого уведомления. Трассиро вочная информация Filemon, часть которой представлена на рис. 1214, по казала, что перед самым завершением Word повторно считывал одну и ту же часть файла с именем Mssp3es.lex. (Когда процесс завершается, система ав томатически закрывает все открытые им описатели. Именно это и отража ют строки с номерами от 25460.) Пользователь выяснил, что файлы с рас ширением .lex относятся к Microsoft Office Proofing Tools, и переустановил этот компонент, после чего проблема исчезла. Рис. 12-14. Microsoft Word читает файл с расширением .lex
760 ГЛ А В А 12 БЕЗОПАСНОСТЬ В третьем примере при каждом запуске Microsoft Excel выводилось сооб щение об ошибке, показанное на рис. 1215. Из трассировочной информа ции Filemon на рис. 1216, полученной в ходе запуска Excel, обнаружилось, что Excel считывает файл 59403e20 из подкаталога Xlstart каталога, в кото рый установлен Microsoft Office. Пользователь изучил документацию на Excel и выяснил, что Excel пытается автоматически открывать любые файлы, хра нящиеся в каталоге Xlstart. Однако этот файл не имел никакого отношения к Excel, поэтому открыть его не удавалось и в итоге появлялось сообщение об ошибке. Удаление этого файла устранило проблему. Рис. 12-15. Сообщение об ошибке при запуске Microsoft Excel Рис. 12-16. Трассировка в Filemon процесса запуска Microsoft Excel Последний пример связан с выявлением устаревших DLL. Пользователь запускал Microsoft Access 2000, и эта программа зависала, как только он пы тался импортировать какойнибудь файл Microsoft Excel. В другой системе с Microsoft Access 2000 тот же файл импортировался успешно. После трас сировки операции импорта в обеих системах файлы журналов сравнивались с помощью Windiff. Результаты сравнения представлены на рис. 1217. Отбросив незначимые расхождения вроде разных имен временных фай лов (строка 19) и разный регистр букв в именах файлов (строка 26), пользо ватель обнаружил первое существенное различие в результатах трассиров ки в строке 37. В системе, где импорт заканчивался неудачей, Microsoft Access загружал копию Accwiz.dll из каталога \Winnt\System32, тогда как в системе, где импорт проходил успешно, эта программа считывала Accwiz.dll из \Prog ra~1\Files\Microsoft\Office. Пользователь изучил копию Accwiz.dll в \Winnt\ System32 и заметил, что она относится к более старой версии Microsoft Ac cess, но порядок поиска DLL в системе приводил к тому, что этот экземпляр обнаруживался первым и до экземпляра нужной версии в каталоге, где ус
ГЛАВА 9 Файловые системы 761 тановлен Microsoft Access 2000, дело не доходило. Удалив эту копию и заре гистрировав корректную версию, пользователь решил проблему. Рис. 12-17. Сравнение журналов трассировки Microsoft Access в двух системах Это лишь некоторые примеры, демонстрирующие, как с помощью Filemon выявлять истинные причины проблем в файловой системе, о которых при ложения не всегда сообщают корректно. В остальной части главы мы сосре доточимся на описании «родной» для Windows файловой системы — NTFS. Цели разработки и особенности NTFS В следующем разделе мы расскажем о требованиях, определявших разработ ку NTFS, и о дополнительных возможностях этой файловой системы. Требования к файловой системе класса «high end» С самого начала разработка NTFS велась с учетом требований, предъявляемых к файловой системе корпоративного класса. Чтобы свести к минимуму поте ри данных в случае неожиданного выхода системы из строя или ее краха, фай ловая система должна гарантировать целостность своих метаданных. Для защи ты конфиденциальных данных от несанкционированного доступа файловая система должна быть построена на интегрированной модели защиты. Наконец, она должна поддерживать защиту пользовательских данных за счет програм мной избыточности данных в качестве недорогой альтернативы аппаратным решениям. Здесь вы узнаете, как эти возможности реализованы в NTFS. Восстанавливаемость В соответствии с требованиями к надежности хранения данных и доступа к ним NTFS обеспечивает восстановление файловой системы на основе кон
762 ГЛ А В А 12 БЕЗОПАСНОСТЬ цепции атомарной транзакции (atomic transaction). Атомарные транзак ции — это метод обработки изменений в базе данных, при котором сбои в работе системы не нарушают корректности или целостности базы данных. Суть атомарных транзакций заключается в том, что некоторые операции над базой данных, называемые транзакциями, выполняются по принципу «все или ничего». (Транзакцию можно определить как операцию вводавывода, изменяющую данные файловой системы или структуру каталогов тома.) Отдельные изменения на диске, составляющие транзакцию, выполняются атомарно: в ходе транзакции на диск должны быть внесены все требуемые изменения. Если транзакция прервана аварией системы, часть изменений, уже внесенных к этому моменту, нужно отменить. Такая отмена называется откатом (roll back). После отката база данных возвращается в исходное согласованное состояние, в котором она была до начала транзакции. NTFS использует атомарные транзакции для реализации возможности восстановления файловой системы. Если некая программа инициирует опе рацию вводавывода, которая изменяет структуру NTFSтома, т. е. модифици рует структуру каталогов, увеличивает длину файла, выделяет место под но вый файл и др., то NTFS обрабатывает такую операцию как атомарную тран закцию. NTFS гарантирует, что транзакция будет либо полностью выполне на, либо отменена, если хотя бы одну из операций не удастся завершить из за сбоя системы. О том, как это делается в NTFS, см. раздел «Поддержка вос становления в NTFS» далее в этой главе. Кроме того, NTFS использует избыточность для хранения критически важной информации файловой системы, так что, если на диске появится сбойный сектор, она все равно сможет получить доступ к этой информации. Это одна из особенностей NTFS, отличающих ее от FAT и HPFS («родной» файловой системы OS/2). Защита Защита в NTFS построена на модели объектов Windows. Файлы и каталоги защищены от доступа пользователей, не имеющих соответствующих прав (подробнее о защите в Windows см. главу 8). Открытый файл реализуется в виде объекта «файл» с дескриптором защиты, хранящимся на диске как часть файла. Прежде чем процесс сможет открыть описатель какоголибо объек та, в том числе объекта «файл», система защиты Windows должна убедиться, что у этого процесса есть соответствующие полномочия. Дескриптор защи ты в сочетании с требованием регистрации пользователя при входе в сис тему гарантирует, что ни один процесс не получит доступа к файлу без раз решения системного администратора или владельца файла. Избыточность данных и отказоустойчивость Восстанавливаемость NTFS действительно гарантирует, что файловая систе ма тома останется доступной, но не дает гарантии полного восстановления пользовательских файлов. Последнее возможно за счет поддержки избыточ ности данных.
ГЛАВА 9 Файловые системы 763 Избыточность данных для пользовательских файлов реализуется через многоуровневую модель драйверов Windows (см. главу 9), которая поддер живает отказоустойчивые диски. При записи данных на диск NTFS взаимо действует с диспетчером томов, а тот — с драйвером жесткого диска. Дис петчер томов может зеркалировать, или дублировать, данные одного диска на другом и таким образом позволяет при необходимости использовать дан ные с избыточной копии. Поддержка таких функций обычно называется RAID уровня 1. Диспетчеры томов также могут записывать данные в череду ющиеся области (stripes) на три и более дисков, используя один диск для хранения информации о четности. Если данные на одном диске потеряны или стали недоступными, драйвер может реконструировать содержимое диска с помощью логической операции XOR. Такая поддержка называется RAID уровня 5 (подробнее о чередующихся и зеркальных томах, а также о томах RAID5 см. главу 10). Дополнительные возможности NTFS NTFS — это не только восстанавливаемая, защищенная, надежная и эффек тивная файловая система, способная работать в системах повышенной от ветственности. Она поддерживает ряд дополнительных возможностей (не которые из них доступны приложениям через APIфункции, другие являют ся внутренними): 쐽 множественные потоки данных; 쐽 имена на основе Unicode; 쐽 универсальный механизм индексации; 쐽 динамическое переназначение плохих кластеров; 쐽 жесткие связи и точки соединения; 쐽 сжатие и разреженные файлы; 쐽 протоколирование изменений; 쐽 квоты томов, индивидуальные для каждого пользователя; 쐽 отслеживание ссылок; 쐽 шифрование; 쐽 поддержка POSIX; 쐽 дефрагментация 쐽 поддержка доступа только для чтения. Обзор этих возможностей приводится в следующих разделах. Множественные потоки данных В NTFS каждая единица информации, сопоставленная с файлом (имя и вла делец файла, метка времени и т. д.), реализована в виде атрибута файла (ат рибута объекта NTFS). Каждый атрибут состоит из одного потока данных (stream), т. е. из простой последовательности байтов. Это позволяет легко добавлять к файлу новые атрибуты (и соответственно новые потоки). По
764 ГЛ А В А 12 БЕЗОПАСНОСТЬ скольку данные являются всего лишь одним из атрибутов файла и посколь ку можно добавлять новые атрибуты, файлы и каталоги NTFS могут содер жать несколько потоков данных. В любом файле NTFS по умолчанию имеется один безымянный поток данных. Приложения могут создавать дополнительные, именованные пото ки данных и обращаться к ним по именам. Чтобы не изменять Windows функции API вводавывода, которым имя файла передается как строковый аргумент, имена потоков данных задаются через двоеточие (:) после имени файла, например: myfile.dat:stream2 Каждый поток имеет свой выделенный размер (объем зарезервированно го для него дискового пространства), реальный размер (использованное число байтов) и длину действительных данных (инициализированная часть потока). Кроме того, каждому потоку предоставляется отдельная файловая блокировка, позволяющая блокировать диапазоны байтов и поддерживать параллельный доступ. Множественные потоки данных использует, например, компонент под держки файлового сервера Apple Macintosh, поставляемый с Windows Server. Системы Macintosh используют два потока данных в каждом файле: один — для хранения данных, другой — для хранения информации о ресурсах (тип файла, значок, представляющий файл в пользовательском интерфейсе, и т. д.). Поскольку NTFS поддерживает множественные потоки данных, пользо ватель Macintosh может скопировать целую папку Macintosh на сервер Win dows, а другой пользователь Macintosh может скопировать ее с сервера без потери информации о ресурсах. Windows Explorer — еще одно приложение, использующее такие потоки. Когда вы щелкаете правой кнопкой мыши файл NTFS и выбираете команду Properties, на экране появляется диалоговое окно, вкладка Summary (Сводка) которого позволяет сопоставить с файлом такую информацию, как заголо вок, тема, имя автора и ключевые слова. Windows Explorer хранит эту инфор мацию в альтернативном потоке под названием Summary Information, добав ляемом к файлу. Другие приложения тоже могут использовать множественные потоки данных. Например, утилита резервного копирования могла бы с помощью дополнительного потока данных сохранять метки времени, связанные с ре зервным копированием файлов, а утилита архивирования — реализовать иерархическое хранилище, в котором файлы, созданные ранее заданной даты или не востребованные в течение указанного периода, перемещались бы на ленточные накопители. При этом она могла бы скопировать файл на ленту, установить его поток данных по умолчанию равным 0 и добавить но вый поток данных, указывающий название и местонахождение картриджа, в котором хранится файл.
ГЛАВА 9 Файловые системы 765 ЭКСПЕРИМЕНТ: просмотр потоков Большинство приложений Windows не рассчитано на работу с допол нительными именованными потоками, но команды echo и more под держивают эту функциональность. Таким образом, самый простой способ понаблюдать за потоками данных в действии — создать име нованный поток с помощью echo, а затем вывести его на экран с по мощью more. В результате выполнения команд, показанных ниже, соз дается файл test с потоком stream. C:\>echo hello > test:stream C:\>more < test:stream hello C:\> При перечислении содержимого каталога размер файла test не от ражает данные, хранящиеся в дополнительном потоке, поскольку в этом случае NTFS возвращает размер только безымянного потока дан ных. C:\>dir test Volume in drive C is WINDOWS Volume Serial Number is 39913040 Directory of C:\ 08/01/00 02:37p 1 File(s) 0 test 0 bytes 112,558,080 bytes free Утилита Streams (www.sysinternals.com) позволяет определить, в ка ких файлах и каталогах есть дополнительные потоки данных: C:\>streams test Streams v1.5  Enumerate alternate NTFS data streams Copyright (C) 19992003 Mark Russinovich Sysinternals  www.sysinternals.com C:\Temp\test: :stream:$DATA 8 Имена на основе Unicode Как и Windows в целом, NTFS полностью поддерживает Unicode, используя Unicodeсимволы для хранения имен файлов, каталогов и томов. Unicode, 16 битная кодировка символов, обеспечивает уникальное представление любо го символа основных языков мира, что упрощает обмен информацией между странами. Поскольку в Unicode имеется уникальное представление каждого символа, последний не зависит от того, какая кодовая страница загружена в
766 ГЛ А В А 12 БЕЗОПАСНОСТЬ операционную систему. Длина имени каждого каталога или файла в пути может достигать 255 символов; в нем могут быть символы Unicode, пробе лы и несколько точек. Универсальный механизм индексации Архитектура NTFS позволяет индексировать атрибуты файлов на дисковом томе. Это дает возможность файловой системе вести эффективный поиск файлов по неким критериям, например находить все файлы в определенном каталоге. Файловая система FAT индексирует имена файлов, но не сортиру ет их, что замедляет просмотр больших каталогов. Некоторые функции NTFS используют преимущества универсальной ин дексации, в том числе консолидированных дескрипторов защиты, где де скрипторы защиты файлов и каталогов на томе хранятся в едином внутреннем потоке без дубликатов; при этом они индексируются с использованием внут реннего идентификатора защиты, определяемого NTFS. Об индексации с по мощью этих средств см. раздел «Структура NTFS на диске» далее в этой главе. Динамическое переназначение плохих кластеров Обычно, если программа пытается считать данные из плохого сектора дис ка, операция чтения заканчивается неудачей, а данные соответствующего кла стера становятся недоступными. Однако, если диск отформатирован как от казоустойчивый том NTFS, специальный драйвер Windows динамически счи тывает «хорошую» копию данных, хранившихся в плохом секторе, и посыла ет NTFS предупреждение о плохом секторе. NTFS выделяет новый кластер, за меняющий тот, в котором находится плохой сектор, и копирует данные в этот кластер. Плохой кластер помечается как аварийный и больше не использует ся. Восстановление данных и динамическое переназначение плохих класте ров особенно полезно для файловых серверов и отказоустойчивых систем, а также для всех приложений, в которых потеря данных недопустима. Если на момент появления плохого сектора диспетчер томов не был загружен, NTFS все равно заменяет кластер и не допускает его повторного использования, хотя восстановить данные из плохого сектора уже не удастся. Жесткие связи и точки соединения Жесткие связи (hard links) позволяют ссылаться на один и тот же файл по нескольким путям (для каталогов жесткие связи не поддерживаются). Если вы создаете жесткую связь с именем C:\Users\Documents\Spec.doc, которая ссылается на существующий файл C:\My Documents\Spec.doc, то с одним дисковым файлом будут связаны два пути, и вы сможете обращаться к это му файлу, используя оба пути. Процессы могут создавать жесткие связи вы зовом Windowsфункции CreateHardLink или POSIXфункции ln. В дополнение к жестким связям NTFS поддерживает другой тип перенап равления — точки соединения (junctions), также называемые символьными ссылками (symbolic links). Они позволяют перенаправлять трансляцию име ни файла или каталога из одного каталога в другой. Например, если путь
ГЛАВА 9 Файловые системы 767 C:\Drivers — ссылка, которая перенаправляет в C:\Windows\System32\Drivers, то приложение, читающее C:\Drivers\Ntfs.sys, на самом деле читает C:\Win dows\System\Drivers\Ntfs.sys. Точки соединения представляют собой удобное средство «подъема» каталогов, расположенных слишком глубоко в дереве каталогов, на более высокий уровень, не нарушая исходной структуры или содержимого дерева каталогов. Так, в предыдущем примере каталог драйве ров «поднят» на два уровня по сравнению с реальным. Точки соединения неприменимы к удаленным каталогам — они используются только для ката логов на локальных томах. Точки соединения опираются на механизм NTFS «точки повторного раз бора» (см. раздел «Точки повторного разбора» далее в этой главе). Точка по вторного разбора (reparse point) — это файл или каталог, с которым сопо ставлен блок данных, называемых данными повторного разбора (reparse data); они представляют собой пользовательские данные о файле или ката логе, например о его состоянии или местонахождении. Эти данные могут быть считаны из точки повторного разбора приложением, которое создало их, драйвером файловой системы или диспетчером вводавывода. Обнару жив точку повторного разбора при поиске файла или каталога, NTFS возвра щает код статуса повторного разбора, который сигнализирует драйверам фильтров файловой системы, подключенным к дисковому тому, и диспетче ру вводавывода о необходимости анализа данных повторного разбора. Каж дый тип точек повторного разбора имеет уникальный тэг повторного раз бора (reparse tag) — он позволяет компоненту, отвечающему за интерпрета цию данных конкретной точки повторного разбора, распознавать свои точ ки разбора, не проверяя их данные. Далее владелец тэга повторного разбо ра (драйвер фильтра файловой системы или диспетчер вводавывода) может выбрать один из следующих вариантов дальнейших действий. 쐽 Владелец тэга повторного разбора может манипулировать полным име нем файла, при анализе которого обнаружена точка повторного разбо ра, и инициировать вводвывод по измененному пути. Точки соединения используют этот вариант, например, для перенаправления каталогов. 쐽 Владелец тэга повторного разбора может удалить из файла точку повтор ного разбора, какимлибо образом изменить файл, а затем инициировать новую операцию файлового вводавывода. По такому принципу точки по вторного разбора используются системой Hierarchical Storage Management (HSM). HSM архивирует файлы, перемещая их содержимое на ленточные накопители и оставляя вместо содержимого файлов точки повторного разбора. Когда какойлибо процесс обращается к архивированному фай лу, драйвер фильтра HSM (\Windows\System32\Drivers\Rsfilter.sys) удаляет из этого файла точку повторного разбора, считывает его данные с архивно го носителя и инициирует повторное обращение к файлу. Windowsфункций для создания точек повторного разбора нет. Вместо них процессы должны использовать управляющий код FSCTL_SET_REPARSE_ POINT файловой системы в сочетании с Windowsфункцией DeviceIoControl.
768 ГЛ А В А 12 БЕЗОПАСНОСТЬ Процесс может запросить содержимое точки повторного разбора с помо щью управляющего кода FSCTL_GET_REPARSE_POINT. В атрибутах файла, сопоставленного с точкой повторного разбора, присутствует флаг FILE_AT TRIBUTE_REPARSE_POINT, что позволяет приложениям проверять наличие точек повторного разбора вызовом Windowsфункции GetFileAttributes. ЭКСПЕРИМЕНТ: создание точки соединения В Windows нет средств для создания точек соединения, но вы можете создать такую точку с помощью утилиты Junction (www.sysinternals.com) или Linkd из ресурсов Windows. Утилита Linkd позволяет просмотреть определения существующих точек соединения, а Junction — вывести информацию о точках соединения и точках повторного разбора. Сжатие и разреженные файлы NTFS поддерживает сжатие файловых данных. Поскольку NTFS выполняет процедуры сжатия и декомпрессии прозрачно, нет необходимости модифи цировать приложения для того, чтобы они могли пользоваться преимуще ствами этой функции. Каталог также может быть сжат, что влечет за собой сжатие и тех файлов, которые будут впоследствии созданы в этом каталоге. Приложения сжимают и разархивируют файлы, передавая DeviceIoControl управляющий код FSCTL_SET_COMPRESSION. Для запроса состояния сжатия файла или каталога используется управляющий код FSCTL_GET_COMPRES SION. У сжатого файла или каталога установлен флаг FILE_ATTRIBUTE_COM PRESSED, поэтому приложения могут определять состояние сжатия файла или каталога вызовом GetFileAttributes. Второй тип сжатия известен под названием разреженные файлы (sparse files). Если файл помечен как разреженный, NTFS не выделяет на томе место для тех частей файла, которые определены приложением как пустые. При чте нии приложением пустых областей разреженного файла NTFS просто возвра щает буферы, заполненные нулевыми значениями. Этот тип сжатия полезен для клиентсерверных приложений, в которых реализовано протоколирова ние с циклическими буферами (circularbuffer logging): сервер регистрирует информацию в файле, а клиент асинхронно считывает ее. Поскольку инфор мация, уже считанная клиентом, больше не нужна, продолжать хранить ее в файле не требуется. Если такой файл является разреженным, клиент может определять считанные им области как пустые, тем самым освобождая место на томе. А сервер может добавлять новую информацию в файл, не опасаясь, что он в конечном счете займет все свободное пространство на томе. Как и в случае сжатых файлов, NTFS прозрачно управляет разреженны ми файлами. Приложения указывают состояние разреженности файла, пе редавая DeviceIoControl управляющий код FSCTL_SET_SPARSE. Чтобы опреде лить диапазон файла как пустой, приложения используют код FSCTL_SET_ ZERO_DATA, а чтобы запросить у NTFS описание того, какие части файла являются разреженными, — код FSCTL_QUERY_ALLOCATED_RANGES. Разре
ГЛАВА 9 Файловые системы 769 женные файлы применяются, в частности, в журнале изменений NTFS, о ко тором мы расскажем в следующем разделе. Протоколирование изменений Приложениям многих типов нужно отслеживать изменения файлов и ката логов тома. Например, программа автоматического резервного копирования первоначально выполняет полное резервное копирование, а в дальнейшем копирует только измененные файлы. Очевидный способ мониторинга изме нений тома — его сканирование с записью состояния файлов и каталогов и анализ отличий при следующем сканировании. Однако этот процесс может негативно повлиять на производительность системы — особенно на ком пьютерах, хранящих тысячи и десятки тысяч файлов. Альтернативный подход для приложения заключается в том, чтобы заре гистрироваться на получение уведомлений об изменении содержимого ка талогов. Для этого предназначена Windowsфункция FindFirstChangeNotifica tion или ReadDirectoryChangesW. В качестве входного параметра приложение указывает имя нужного каталога, и функция сообщает о любом изменении в содержимом этого каталога. Хотя этот подход более эффективен, чем ска нирование тома, он требует непрерывной работы приложения. При этом приложениям все равно может понадобиться сканирование каталогов, так как FindFirstChangeNotification сообщает лишь о факте изменений, а не о кон кретных изменениях. В то же время ReadDirectoryChangesW принимает от приложения буфер, который FSD заполняет записями об изменениях. Но при переполнении буфера приложение должно быть готово вернуться к скани рованию каталога. NTFS предусматривает третий подход, в котором преодолены недостат ки первых двух: приложение может настроить журнал изменений NTFS с помощью функции DeviceIoControl и управляющего кода FSCTL_CREATE_ USN_JOURNAL; тогда NTFS будет регистрировать информацию об изменени ях файлов и каталогов во внутреннем файле — журнале изменений (change journal). Этот журнал обычно достаточно велик, что дает приложению шанс обработать все без исключения изменения. Для чтения записей в журнале изменений предназначен управляющий код FSCTL_QUERY_USN_JOURNAL; при этом можно указать, чтобы функция DeviceIoControl не завершалась до тех пор, пока в журнале не появятся новые записи. Квоты томов, индивидуальные для каждого пользователя Системным администраторам часто бывает нужно отслеживать или ограни чивать дисковое пространство, занимаемое пользователями на общих томах в сети. Поэтому NTFS поддерживает управление дисковым пространством на основе квот, позволяя выделять квоты каждому пользователю. NTFS можно настроить на запись в системный журнал события, возникающего в тот мо мент, когда пользователь превышает пороговое значение, близкое к лими ту. При попытке пользователя занять больше места, чем разрешает его кво та, NTFS также регистрирует соответствующее событие в системном журна
770 ГЛ А В А 12 БЕЗОПАСНОСТЬ ле и, кроме того, завершает файловый вводвывод приложения, вызвавшего нарушение квоты, с кодом ошибки «disk full» («диск заполнен»). NTFS отслеживает использование тома благодаря тому факту, что помеча ет файлы и каталоги идентификаторами защиты (SID) пользователей, создав ших эти объекты на томе (определение SID см. в главе 8). Сумма логических размеров файлов и каталогов, принадлежащих пользователю, сравнивается с квотой, определенной администратором. Поэтому пользователь не может превысить свою квоту, создав пустой разреженный файл и потом заполняя его ненулевыми значениями. Кстати, хотя 50килобайтный файл может быть сжат до 10 Кб, при учете используется его исходный размер — 50 Кб. По умолчанию отслеживание квот на томах отключено. Чтобы разрешить отслеживание квот, указать пороговые значения для выдачи предупреждений, задать ограничения и настроить реакцию NTFS на достижение одного из этих пороговых значений, используйте вкладку Quota (Квота) окна свойств тома (рис. 1218). Диалоговое окно Quota Entries (Записи квот), которое можно открыть с этой вкладки, позволяет администратору задавать различные лими ты и поведение NTFS для каждого пользователя. Приложения, которым тре буется управление на основе квот NTFS, используют COMинтерфейсы квот, в том числе IDiskQuotaControl, IDiskQuotaUser и IDiskQuotaEvents. Рис. 12-18. Окно свойств дискового тома Отслеживание ссылок В пространстве имен оболочки Windows (например, на рабочем столе) мож но создавать ярлыки (shortcuts) файлов, находящихся в пространстве имен файловой системы. Такие ярлыки используются, например, в меню Start.
ГЛАВА 9 Файловые системы 771 Аналогичным образом OLEсвязи позволяют встраивать документы одних приложений в документы, созданные другими приложениями. OLEсвязи поддерживаются всеми приложениями из пакета Microsoft Office, включая PowerPoint, Excel и Word. Хотя OLEсвязи дают возможность легко соединять файлы друг с другом и с пространством имен оболочки, управлять ими в прошлом было нелегко. Если пользователь Windows NT 4, Windows 95 или Windows 98 перемещал источник OLEсвязи или ярлыка оболочки (источником называется файл или каталог, на который ссылается OLEсвязь или ярлык), связь разрывалась, и система предпринимала попытку найти источник связи эвристическим методом. В Windows файловая система NTFS включает поддержку отслежи вания распределенных связей (distributed linktracking), обеспечивающую целостность ярлыков оболочки и OLEсвязей при перемещении источников на другой том NTFS в пределах одного домена. Отслеживание связей в NTFS реализуется на основе необязательного атри бута файла, известного под названием идентификатор объекта (object ID). Приложение может назначить такой идентификатор файлу с помощью управ ляющих кодов файловой системы FSCTL_CREATE_OR_GET_OBJECT_ID (назна чает идентификатор, если он еще не назначен) и FSCTL_SET_OBJECT_ID. Идентификаторы объектов можно запросить с помощью управляющих кодов FSCTL_CREATE_OR_GET_OBJECT_ID и FSCTL_GET_OBJECT_ID. Код FSCTL_ DELETE_OBJECT_ID позволяет удалять идентификаторы объектов из файлов. Шифрование Корпоративные пользователи часто хранят на своих компьютерах конфи денциальную информацию. Хотя данные на серверах компаний обычно на дежно защищены, информация, хранящаяся на портативном компьютере, может попасть в чужие руки в случае потери или кражи компьютера. Права доступа к файлам NTFS в таком случае не защитят данные, поскольку пол ный доступ к томам NTFS можно получить независимо от их защиты — дос таточно воспользоваться программами, умеющими читать файлы NTFS вне среды Windows. Более того, права доступа к файлам NTFS становятся беспо лезны при использовании другой системы Windows и учетной записи адми нистратора. Вспомните из главы 8, что учетная запись администратора об ладает привилегиями захвата во владение и резервного копирования, любая из которых позволяет получить доступ к любому защищенному объекту в обход его параметров защиты. NTFS поддерживает механизм Encrypting File System (EFS), с помощью которого пользователи могут шифровать конфиденциальные данные. EFS, как и механизм сжатия файлов, полностью прозрачен для приложений. Это означает, что данные автоматически расшифровываются при чтении их приложением, работающим под учетной записью пользователя, который имеет права на просмотр этих данных, и автоматически шифруются при изменении их авторизованным приложением.
772 ГЛ А В А 12 БЕЗОПАСНОСТЬ ПРИМЕЧАНИЕ NTFS не допускает шифрования файлов, расположен ных в корневом каталоге системного тома или в каталоге \Windows, поскольку многие находящиеся там файлы нужны в процессе загруз ки, когда EFS еще не активна. EFS использует криптографические сервисы, предоставляемые Windows в пользовательском режиме, и состоит из драйвера устройства режима ядра, тесно интегрированного с NTFS и DLLмодулями пользовательского режи ма, которые взаимодействуют с подсистемой локальной аутентификации (LSASS) и криптографическими DLL. Доступ к зашифрованным файлам можно получить только с помощью закрытого ключа из криптографической пары EFS (которая состоит из за крытого и открытого ключей), а закрытые ключи защищены паролем учет ной записи. Таким образом, без пароля учетной записи, авторизованной для просмотра данных, доступ к зашифрованным EFS файлам на потерянных или краденых портативных компьютерах нельзя получить никакими сред ствами (кроме грубого перебора паролей). Windowsфункции EncryptFile и DecryptFile позволяют шифровать и де шифровать файлы, а FileEncryptionStatus — получать атрибуты файла или каталога, связанного с EFS, — например, чтобы определить, зашифрован ли данный файл или каталог. Поддержка POSIX Как говорилось в главе 2, одно из требований к Windows состояло в том, что она должна полностью поддерживать стандарт POSIX 1003.1. Стандарт POSIX требует от файловой системы поддержки имен файлов и каталогов, чувстви тельных к регистру букв, цепочечных разрешений (traversal permissions) (для доступа к файлу нужны права на доступ к каждому каталогу на пути к этому файлу), метки времени изменения файла (отличной от метки времени по следней модификации файла в MSDOS) и жестких связей. Вся эта функци ональность в NTFS реализована. Дефрагментация Многие верят в то, что NTFS якобы автоматически оптимизирует размеще ние файлов на диске, не допуская их фрагментации. Хотя она стремится за писывать файлы в непрерывные области, со временем файлы на томе могут стать фрагментированными — особенно когда свободного пространства мало. Файл является фрагментированным, если его данные занимают не смежные кластеры. Так, на рис. 1219 показан фрагментированный файл, состоящий из трех фрагментов. Но, как и большинство файловых систем (включая версию FAT в Windows), NTFS не предпринимает специальных мер по поддержанию непрерывного размещения файлов на диске — разве что резервирует область дискового пространства, называемую зоной главной таблицы файлов (master file table, MFT), где и хранится MFT. (NTFS разреша ет выделять место под файлы из зоны MFT, когда на томе остается мало сво
ГЛАВА 9 Файловые системы 773 бодного пространства.) Подробнее о MFT см. раздел «Главная таблица фай лов» далее в этой главе. Рис. 12-19. Фрагментированный и непрерывный файлы Для упрощения разработки независимых средств дефрагментации дисков в Windows включен API дефрагментации, с помощью которого подобные утилиты могут перемещать файловые данные так, чтобы файлы занимали непрерывные кластеры. Этот API реализован на основе управляющих кодов файловой системы: FSCTL_GET_VOLUME_BITMAP (возвращает карту свобод ных и занятых кластеров тома), FSCTL_GET_RETRIEVAL_POINTERS (возвра щает карту кластеров, занятых файлом) и FSCTL_MOVE_FILE (перемещает файл). В Windows имеется встроенная программа дефрагментации, доступная через утилиту Disk Defragmenter (\Windows\System32\Dfrg.msc). Ей присущ ряд ограничений, в частности в Windows 2000 эту утилиту нельзя запускать из командной строки или автоматически запускать по заданному расписа нию. В Windows XP и Windows Server 2003 у программы дефрагментации появился интерфейс командной строки, \Windows\System32\Defrag.exe, по зволяющий запускать процесс дефрагментации интерактивно или по распи санию, но она попрежнему не сообщает детальных отчетов и не поддержи вает такие возможности, как исключение определенных файлов или катало гов из процесса дефрагментации. Сторонние утилиты дефрагментации дис ков, как правило, предлагают более богатую функциональность. В Windows XP поддержка дефрагментации для NTFS была переписана, чтобы снять часть ограничений, которые были в Windows 2000. Так, в Win dows 2000 поддержка дефрагментации NTFS опиралась на диспетчер кэша, что создавало ряд ограничений, например невозможность перемещения файловых блоков размером более 256 Кб или дефрагментации файлов ме таданных NTFS. (Заметьте, что 256 Кб — это размер представлений, поддер живаемых диспетчером кэша. Подробнее о диспетчере кэша см. главу 11.) В реализации дефрагментации NTFS в Windows XP и Windows Server 2003 су ществует лишь одно ограничение — нельзя дефрагментировать страничные файлы и файлы журналов NTFS. Поддержка доступа только для чтения До Windows XP драйвер файловой системы NTFS поддерживал монтирова ние тома исключительно на записываемом носителе, куда он должен был
774 ГЛ А В А 12 БЕЗОПАСНОСТЬ помещать файлы журналов транзакций. Драйверы NTFS в Windows XP и Windows Server 2003 могут монтировать тома на носителях только для чте ния; эта функциональность нужна во встраиваемых системах, в которых ба зовые образы файловой системы (base file system images) доступны только для чтения. Драйвер файловой системы NTFS Как отмечалось в главе 9, подсистема вводавывода Windows устроена так, что NTFS и другие файловые системы представляют собой загружаемые драйверы устройств режима ядра. Они неявно вызываются приложениями, использующими Windows или другие API вводавывода (например, POSIX). Как показано на рис. 1220, подсистемы окружения вызывают системные сервисы, которые в свою очередь находят соответствующие загруженные драйверы и вызывают их. (О диспетчеризации системных сервисов см. раз дел «Диспетчеризация системных сервисов» главы 3.) \ Рис. 12-20. Компоненты подсистемы ввода-вывода в Windows Драйверы передают друг другу запросы вводавывода, вызывая диспетчер вводавывода исполнительной системы. Использование диспетчера ввода вывода в качестве промежуточного звена обеспечивает независимость каж дого драйвера, что позволяет загружать и выгружать его без последствий для других драйверов. Кроме того, драйвер NTFS взаимодействует с тремя дру гими компонентами исполнительной системы (рис. 1221), тесно связанны ми с файловыми системами.
ГЛАВА 9 Рис. 12-21. Файловые системы 775 NTFS и связанные с ней компоненты Сервис файла журнала (log file service, LFS) является частью NTFS и предо ставляет функции для поддержки журнала изменений на диске. Файл журна ла LFS используется при восстановлении тома NTFS в случае аварии системы (подробнее о LFS см. раздел «Сервис файла журнала» далее в этой главе). Диспетчер кэша — компонент исполнительной системы, предоставляю щий общесистемные сервисы кэширования для NTFS и драйверов других файловых систем, в том числе сетевых (т. е. для серверов и редиректоров). Все файловые системы, реализованные в Windows, получают доступ к кэши рованным файлам, проецируя их на системное адресное пространство, а затем считывая соответствующие участки виртуальной памяти. С этой целью диспетчер кэша предоставляет диспетчеру памяти специализированный интерфейс файловых систем. Когда программа пытается обратиться к какой либо части файла, не загруженной в кэш (промах кэша), диспетчер памяти вызывает NTFS для обращения к драйверу диска и загрузки нужных файло вых данных. Диспетчер кэша оптимизирует дисковый вводвывод, вызывая диспетчер памяти (для сброса на диск содержимого кэша в фоновом режи ме) из потоков подсистемы отложенной записи. NTFS участвует в модели объектов Windows, реализуя файлы в виде объек тов. Такая реализация допускает совместное использование файлов и их за щиту диспетчером объектов, который управляет всеми объектами уровня исполнительной системы (о диспетчере объектов см. главу 3). Приложение создает файлы и обращается к ним так же, как и к любым другим объектам Windows, — через описатели объектов. К тому времени, когда запрос вводавывода достигает NTFS, диспетчер объектов и система защиты уже убедились в наличии у вызывающего процесса прав на запро шенные им виды доступа к объекту «файл». Система защиты сравнила мар кер доступа вызывающего процесса с элементами ACL этого объекта «файл» (подробнее об ACL см. главу 8), а диспетчер вводавывода преобразовал опи
776 ГЛ А В А 12 БЕЗОПАСНОСТЬ сатель файла в указатель на объект «файл». NTFS использует информацию из объекта «файл» для обращения к файлу на диске. На рис. 1222 показаны структуры данных, связывающие описатель фай ла со структурой файловой системы на диске. NTFS получает адрес файла на диске из объекта «файл» по нескольким указателям. Как видно из рис. 1222, объект «файл», представляющий один вызов системного сервиса для открытия файла, указывает на блок управле ния потоком данных (stream control block, SCB) для атрибута, который вы зывающая программа пытается считать или записать. В нашем случае про цесс открыл как безымянный атрибут данных, так и именованный поток (альтернативный атрибут данных) файла. SCB представляют отдельные ат рибуты файла и содержат информацию о том, как искать конкретные атри буты внутри файла. Все SCB файла указывают на общую структуру дан ных — блок управления файлом (file control block, FCB). FCB содержит ука затель на запись файла в главной таблице файлов (MFT), о которой мы по говорим в следующем разделе. Рис. 12-22. Структуры данных NTFS
ГЛАВА 9 Файловые системы 777 Структура NTFS на диске Здесь мы рассмотрим структуру тома NTFS, включая способы разбиения дис кового пространства и его организации в кластеры, принципы хранения на диске реальных файловых данных и информации об атрибутах, а также по ясним, как работает механизм сжатия данных в NTFS. Тома Структура NTFS начинается с тома. Том (volume) соответствует логическо му разделу на диске и создается при форматировании диска или его части под NTFS. Оснастка Disk Management (Управление дисками) консоли MMC также позволяет создать том RAID, охватывающий несколько дисков. На диске может быть один или несколько томов. NTFS обрабатывает каж дый том независимо от других. Три примера конфигурации 150мегабайт ного жесткого диска показаны на рис. 1223. Рис. 12-23. Примеры конфигураций диска Том состоит из набора файлов и свободного пространства, оставшегося в данном разделе диска. В FAT том также содержит области, специально от форматированные для использования файловой системой. Но в томе NTFS все данные файловой системы вроде битовых карт, каталогов и даже началь ного загрузочного кода хранятся как обычные файлы. ПРИМЕЧАНИЕ У NTFSтомов в Windows 2000 дисковый формат вер сии 3.0; в Windows XP и Windows Server 2003 в этот формат были вне сены незначительные изменения, и теперь используется его версия 3.1. Номер версии тома хранится в файле метаданных $Volume. Кластеры Размер кластера на томе NTFS, или кластерный множитель (cluster factor), устанавливается при форматировании тома командой format или в оснаст ке Disk Management (Управление дисками). Размер кластера по умолчанию определяется размером тома, но всегда содержит целое число физических секторов с дискретностью N2 (т. е. 1 сектор, 2 сектора, 4 сектора, 8 секторов и т. д.). Кластерный множитель выражается числом байтов в кластере, напри мер 512 байт, 1 Кб или 2 Кб. Внутренне NTFS работает только с кластерами. (Однако NTFS инициирует низкоуровневые операции вводавывода на томе, выравнивая передаваемые
778 ГЛ А В А 12 БЕЗОПАСНОСТЬ данные по размеру сектора и подгоняя их объем под значение, кратное раз меру секторов.) NTFS использует кластер как единицу выделения простран ства для поддержания независимости от размера физического сектора. Это позволяет NTFS эффективно работать с очень большими дисками, исполь зуя кластеры большего размера, и поддерживать нестандартные диски с раз мером секторов, отличным от 512 байтов. Применение бóльших кластеров на бóльших томах уменьшает фрагментацию и ускоряет выделение свобод ного пространства за счет небольшого проигрыша в эффективности исполь зования дискового пространства. Команда format или оснастка Disk Manage ment выбирает кластерный множитель в зависимости от размера тома, но это значение можно изменить. NTFS адресуется к конкретным местам на диске, используя логические номера кластеров (logical cluster numbers, LCN). Для этого все кластеры на томе просто нумеруются по порядку — от начала до конца. Для преобразо вания LCN в физический адрес на диске NTFS умножает LCN на кластерный множитель и получает байтовое смещение от начала тома, воспринимаемое интерфейсом драйвера диска. На данные внутри файла NTFS ссылается по виртуальным номерам кластеров (virtual cluster numbers, VCN), нумеруя кластеры, которые принадлежат конкретному файлу (от 0 до m). VCN не обя зательно должны быть физически непрерывными. Главная таблица файлов В NTFS все данные, хранящиеся на томе, содержатся в файлах. Это относит ся и к структурам данных, используемым для поиска и выборки файлов, к начальному загрузочному коду и битовой карте, в которой регистрируется состояние пространства всего тома (метаданные NTFS). Хранение всех ви дов данных в файлах позволяет файловой системе легко находить и поддер живать данные, а каждый файл может быть защищен дескриптором защиты. Кроме того, при появлении плохих секторов на диске, NTFS может переме стить файлы метаданных. Главная таблица файлов (MFT) занимает центральное место в структуре NTFSтома. MFT реализована как массив записей о файлах. Размер каждой записи фиксирован и равен 1 Кб (см. раздел «Записи о файлах» далее в этой главе). Логически MFT содержит по одной строке на каждый файл тома, включая строку для самой MFT. Кроме MFT, на каждом томе NTFS имеется набор файлов метаданных с информацией, необходимой для реализации структуры файловой системы. Имена всех файлов метаданных NTFS начи наются со знака доллара ($), хотя эти знаки скрыты. Так, имя файла MFT — $Mft. Остальные файлы NTFSтома являются обычными файлами и катало гами (рис. 1224).
ГЛАВА 9 Рис. 12-24. Файловые системы 779 Записи MFT для файлов метаданных NTFS Обычно каждая запись MFT соответствует отдельному файлу. Но если у файла много атрибутов или он сильно фрагментирован, для него может по надобиться более одной записи. Тогда первая запись MFT, хранящая адреса других записей, называется базовой (base file record). ЭКСПЕРИМЕНТ: просмотр MFT Утилита Nfi из OEM Support Tools (входит в отладочные средства Win dows; ее можно скачать с support.microsoft.com/support/kb/articles/Q253/ 0/66.asp) позволяет получить дамп содержимого MFT тома NTFS и преобразовать номер кластера тома или номер сектора физического диска (не для RAIDтомов) в имя соответствующего файла (если клас тер или сектор занят файлом). Первые 16 элементов MFT зарезерви рованы для файлов метаданных, но записи для файлов необязатель ных метаданных (которые присутствуют только при использовании на томе соответствующих возможностей) находятся вне этой облас ти: \$Extend\$Quota, \$Extend\$ObjId, \$Extend\$UsnJrnl и \$Extend\$Re parse. Следующий дамп получен для тома, на котором используются точки повторного разбора ($Reparse), квоты ($Quota) и идентифика торы объектов ($ObjId). C:\>nfi G:\ NTFS File Sector Information Utility. см. след. стр.
780 ГЛ А В А 12 БЕЗОПАСНОСТЬ Copyright (C) Microsoft Corporation 1999. All rights reserved. File 0 Master File Table ($Mft) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA (nonresident) logical sectors 3252447 (0x200xccdf) $BITMAP (nonresident) logical sectors 1623 (0x100x17) File 1 Master File Table Mirror ($MftMirr) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA (nonresident) logical sectors 20487282048735 (0x1f42d80x1f42df) File 2 Log File ($LogFile) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA (nonresident) logical sectors 20487362073343 (0x1f42e00x1fa2ff) File 3 DASD ($Volume) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $OBJECT_ID (resident) $SECURITY_DESCRIPTOR (resident) $VOLUME_NAME (resident) $VOLUME_INFORMATION (resident) $DATA (resident) File 4 Attribute Definition Table ($AttrDef) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $SECURITY_DESCRIPTOR (resident) $DATA (nonresident) logical sectors 512256512263 (0x7d1000x7d107) File 5 Root Directory $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $SECURITY_DESCRIPTOR (resident) $INDEX_ROOT $I30 (resident) $INDEX_ALLOCATION $I30 (nonresident)
ГЛАВА 9 Файловые системы 781 logical sectors 20734162073423 (0x1fa3480x1fa34f) $BITMAP $I30 (resident) File 6 Volume Bitmap ($BitMap) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA (nonresident) logical sectors 20734242073675 (0x1fa3500x1fa44b) File 7 Boot Sectors ($Boot) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $SECURITY_DESCRIPTOR (resident) $DATA (nonresident) logical sectors 015 (0x00xf) File 8 Bad Cluster List ($BadClus) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA (resident) $DATA $Bad (nonresident) File 9 Security ($Secure) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA $SDS (nonresident) logical sectors 20739322074447 (0x1fa54c0x1fa74f) logical sectors 523160523163 (0x7fb980x7fb9b) $INDEX_ROOT $SDH (resident) $INDEX_ROOT $SII (resident) $INDEX_ALLOCATION $SDH (nonresident) logical sectors 18761521876159 (0x1ca0b80x1ca0bf) $INDEX_ALLOCATION $SII (nonresident) logical sectors 2431 (0x180x1f) $BITMAP $SDH (resident) $BITMAP $SII (resident) File 10 Upcase Table ($UpCase) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA (nonresident) logical sectors 20736762073931 (0x1fa44c0x1fa54b) см. след. стр.
782 ГЛ А В А 12 БЕЗОПАСНОСТЬ File 11 Extend Table ($Extend) $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $INDEX_ROOT $I30 (resident) File 12 (unknown/unnamed) $STANDARD_INFORMATION (resident) $SECURITY_DESCRIPTOR (resident) $DATA (resident) File 13 (unknown/unnamed) $STANDARD_INFORMATION (resident) $SECURITY_DESCRIPTOR (resident) $DATA (resident) File 14 (unknown/unnamed) $STANDARD_INFORMATION (resident) $SECURITY_DESCRIPTOR (resident) $DATA (resident) File 15 (unknown/unnamed) $STANDARD_INFORMATION (resident) $SECURITY_DESCRIPTOR (resident) $DATA (resident) File 24 \$Extend\$Quota $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $INDEX_ROOT $O (resident) $INDEX_ROOT $Q (resident) File 25 \$Extend\$ObjId $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $INDEX_ROOT $O (resident) File 26 \$Extend\$Reparse $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $INDEX_ROOT $R (resident)
ГЛАВА 9 Файловые системы 783 При первом обращении к тому NTFS должна смонтировать его, т. е. счи тать с диска метаданные и сформировать внутренние структуры данных, необходимые для обработки обращений к файловой системе. Чтобы смон тировать том, NTFS ищет в загрузочном секторе физический адрес MFT на диске. Запись о самой MFT является первым элементом в этой таблице, вто рая запись указывает на файл в середине диска ($MftMirr), который называ ется зеркальной копией MFT и содержит копию первых нескольких записей MFT. Если по какимлибо причинам считать часть MFT не удастся, для поис ка файлов метаданных будет использована именно эта копия MFT. Найдя запись для MFT, NTFS получает из ее атрибута данных информацию о сопоставлении VCN и LCN и сохраняет ее в памяти. В каждой группе (run) хранится сопоставление VCNLCN и длина этой группы — вот и вся инфор мация, необходимая для того, чтобы найти LCN по VCN. Эта информация сообщает NTFS, где на диске искать группы, образующие MFT. (О группах см. раздел «Резидентные и нерезидентные атрибуты» далее в этой главе.) Затем NTFS обрабатывает записи MFT еще для нескольких файлов метаданных и открывает эти файлы. Наконец, NTFS выполняет операцию восстановления файловой системы (см. раздел «Восстановление» далее в этой главе) и откры вает остальные файлы метаданных. С этого момента пользователь может обращаться к данному дисковому тому. ПРИМЕЧАНИЕ Для упрощения восприятия материала в тексте и на схемах в этой главе группа обозначается как сущность, содержащая VCN, LCN и длину группы. Но на самом деле NTFS сжимает эту инфор мацию на диске в пары «LCN — следующий VCN». Зная начальный VCN, NTFS может определить длину группы простым вычитанием началь ного VCN из следующего VCN. В процессе работы системы NTFS ведет запись в другой важный файл метаданных — файл журнала с именем $LogFile. NTFS использует его для регистрации всех операций, влияющих на структуру тома NTFS, в том чис ле для регистрации создания файлов и выполнения любых команд вроде Copy, модифицирующих структуру каталогов. Файл журнала используется и при восстановлении тома NTFS после аварии системы. Еще один элемент MFT зарезервирован для корневого каталога (также обозначаемого как «\»). Его запись содержит индекс файлов и каталогов, хранящихся в корне структуры каталогов NTFS. Когда NTFS впервые получа ет запрос на открытие файла, она начинает его поиск с записи корневого каталога. Открыв файл, NTFS сохраняет файловую ссылку MFT для этого файла и поэтому в следующий раз, когда понадобится считать или записать тот же файл, сможет напрямую обратиться к его записи в MFT. NTFS регистрирует распределение дискового пространства в файле би товой карты (bitmap file) с именем $Bitmap. Атрибут данных для файла би товой карты содержит битовую карту, каждый бит которой представляет кластер тома и сообщает, свободен кластер или выделен.
784 ГЛ А В А 12 БЕЗОПАСНОСТЬ Файл защиты (security file) с именем $Secure хранит базу данных деск рипторов защиты, действующих в пределах тома. Дескрипторы защиты фай лов и каталогов NTFS можно настраивать индивидуально, но для экономии места NTFS хранит настройки дескрипторов защиты в общем файле, кото рый позволяет файлам и каталогам с одинаковыми параметрами защиты ссылаться на один и тот же дескриптор защиты. Такая оптимизация дает су щественную экономию в большинстве сред, потому что в них целые дере вья каталогов имеют одинаковые параметры защиты. Другой системный файл, загрузочный (boot file), с именем $Boot хранит код начальной загрузки Windows. Для успешного запуска системы код на чальной загрузки должен находиться на диске в определенном месте. При форматировании команда format определяет это место в виде файла, созда вая для него запись в MFT. При этом NTFS следует своим правилам, соглас но которым все данные хранятся на диске в виде файлов. Загрузочный файл, как и файлы метаданных NTFS, может быть защищен индивидуальным дес криптором защиты. В такой модели «на диске есть только файлы» код на чальной загрузки может быть изменен путем обычного файлового ввода вывода, хотя загрузочный файл защищен от редактирования. NTFS поддерживает файл плохих кластеров (badcluster file) с именем $BadClus, в котором регистрируются все сбойные участки дискового тома, и файл тома (volume file) с именем $Volume, который содержит имя тома, вер сию NTFS, под которую отформатирован том, и бит, устанавливаемый при какомлибо повреждении диска. Если этот бит установлен, диск должен быть восстановлен утилитой Chkdsk. Файл сопоставления имен с буквами в верх нем регистре (uppercase file) с именем $UpCase включает таблицу трансля ции букв между верхним и нижним регистрами. NTFS также поддерживает файл, содержащий таблицу определения атрибутов (attribute definition table), с именем $AttrDef; в нем определяются типы атрибутов, поддержива емые томом, и указывается, являются ли они индексируемыми, следует ли их восстанавливать в ходе операции восстановления системы и т. д. Некоторые файлы метаданных NTFS хранит в каталоге расширенных метаданных $Extend, в том числе помещая туда файл идентификаторов объектов ($ObjId), файл квот ($Quota), файл журнала регистрации изме нений ($UsnJrnl) и файл точек повторного разбора ($Reparse). В этих фай лах содержится информация, относящаяся к дополнительным возможнос тям NTFS. Файл идентификаторов объектов хранит идентификаторы объек тов «файл», файл квот — значения квот и информацию о поведении томов, на которых используются квоты, файл точек повторного разбора — список файлов и каталогов, включающих данные точек повторного разбора, а в файле журнала изменений регистрируются изменения файлов и каталогов.
ГЛАВА 9 Файловые системы 785 ЭКСПЕРИМЕНТ: просмотр информации NTFS Для просмотра информации о NTFSтоме, в том числе о размещении и размере MFT и зоны MFT, вы можете использовать в Windows 2000 утилиту NTFSInfo (с сайта www.sysinternals.com), а в Windows XP или Windows Server 2003 — встроенную программу командной строки Fsutil.exe: C:\Windows\System32>fsutil fsinfo NTFS Volume Serial Number : Version : Number Sectors : Total Clusters : Free Clusters : Total Reserved : Bytes Per Sector : Bytes Per Cluster : Bytes Per FileRecord Segment : Clusters Per FileRecord Segment : Mft Valid Data Length : Mft Start Lcn : Mft2 Start Lcn : Mft Zone Start : Mft Zone End : ntfsinfo c: 0xe82828e72828b68a 3.1 0x0000000001e461b7 0x00000000003c8c36 0x00000000000164c8 0x00000000000001b0 512 4096 1024 0 0x0000000006413800 0x00000000000c5294 0x000000000002f427 0x00000000003bf7e0 0x00000000003bf800 Структура файловых ссылок Файл на томе NTFS идентифицируется 64битным значением, которое на зывается файловой ссылкой (file reference). Файловая ссылка состоит из но мера файла и номера последовательности. Номер файла равен позиции его записи в MFT минус 1 (или позиции базовой записи в MFT минус 1, если файл требует несколько записей). Номер последовательности в файловой ссылке увеличивается на 1 при каждом повторном использовании позиции записи в MFT, что позволяет NTFS проверять внутреннюю целостность фай ловой системы. Файловую ссылку иллюстрирует рис. 1225. Рис. 12-25. Файловая ссылка Записи о файлах NTFS рассматривает файл не просто как хранилище текстовых или двоич ных данных, а как совокупность пар атрибутов и их значений, одна из ко торых содержит данные файла (соответствующий атрибут называется не именованным атрибутом данных). Другие атрибуты включают имя файла,
786 ГЛ А В А 12 БЕЗОПАСНОСТЬ метку времени и, возможно, дополнительные именованные атрибуты дан ных. Запись MFT для небольшого файла показана на рис. 1226. Рис. 12-26. Запись MFT для небольшого файла Каждый атрибут файла хранится в файле как отдельный поток байтов. Строго говоря, NTFS читает и записывает не файлы, а потоки атрибутов. NTFS поддерживает следующие операции над атрибутами: создание, удале ние, чтение (как диапазон байтов) и запись (как диапазон байтов). Сервисы чтения и записи обычно имеют дело с неименованным атрибутом данных. Однако вызывающая программа может указать другой атрибут данных, ис пользуя синтаксис именованных потоков данных. В таблице 124 перечислены атрибуты для файлов на томах NTFS (не у каждого файла есть все эти атрибуты). Таблица 12-4. Атрибуты файлов в NTFS Атрибут Имя атрибута Описание Информация о томе $VOLUME_ INFORMATION, $VOLUME_NAME Эти атрибуты имеются только в файле метаданных $Volume. Они хранят версию и метку тома Стандартная информация $STANDARD_ INFORMATION Атрибуты файла «только для чтения», «ар хивный» и др., метки времени создания и последней модификации, число каталогов, ссылающихся на данный файл (счетчик жестких связей) Имя файла $FILE_NAME Имя файла в Unicodeсимволах. У файла может быть несколько атрибутов имени, например, если существует жесткая связь с данным файлом или если для его длинно го имени автоматически сгенерировано краткое имя, используемое программами MSDOS и 16разрядной Windows
ГЛАВА 9 Файловые системы 787 Таблица 12-4. (окончание) Атрибут Имя атрибута Описание Дескриптор защиты $SECURITY_ DESCRIPTOR Этот атрибут обеспечивает обратную сов местимость с прежними версиями NTFS. Версия NTFS, реализованная в Windows, хранит все дескрипторы защиты в файле метаданных $Secure для совместного ис пользования файлами и каталогами с оди наковыми параметрами защиты. Прежние версии NTFS хранили закрытую информа цию о дескрипторе защиты в каждом файле и каталоге Данные $DATA Содержимое файла. В NTFS файл имеет один неименованный атрибут данных, и, возможно, дополнительные именованные атрибуты данных, т. е. в файле может быть несколько потоков данных. В каталоге нет атрибута данных по умолчанию, но могут присутствовать необязательные именован ные атрибуты данных Корень индекса, выделенная группа индексов и битовая карта индексов $INDEX_ROOT, Эти атрибуты используются для выделения $INDEX_ALLOCA места под имена файлов и создания бито TION, $BITMAP вой карты индексов для больших каталогов (только каталогов) Список атрибутов $ATTRIBUTE_LIST Список атрибутов, составляющих файл, и файловые ссылки на запись MFT, в которой находятся все атрибуты. Этот редко исполь зуемый атрибут присутствует, когда файл требует более одной записи MFT Идентификатор объекта $OBJECT_ID 64байтовый идентификатор файла или ка талога, в котором младшие 16 байтов (128 битов) уникальны для тома. Сервисы отсле живания связей назначают идентификато ры объектов ярлыкам оболочки и файлам— источникам OLEсвязей. NTFS предостав ляет APIфункции, позволяющие открывать файлы и каталоги не по именам, а по иден тификаторам Информация $REPARSE_POINT повторного разбора Этот атрибут хранит данные точки повтор ного разбора, сопоставленной с файлом; присутствует в точках соединения и монти рования Расширенные атрибуты $EA, $EA_INFOR MATION Расширенные атрибуты, иногда используе мые для обратной совместимости с прило жениями OS/2 Информация EFS $EFS В этом атрибуте EFS хранит данные, ис пользуемые для управления шифрованием файла, например шифрованную версию ключа, необходимого для расшифровки файла, и список пользователей, имеющих право на доступ к этому файлу
788 ГЛ А В А 12 БЕЗОПАСНОСТЬ В таблице 124 даны имена атрибутов, но на самом деле атрибуты соот ветствуют числовым кодам типов, используемым NTFS для упорядочения атрибутов в записи о файле. Файловые атрибуты в записи MFT размещают ся в порядке возрастания числовых значений этих кодов. Некоторые типы атрибутов встречаются в записи дважды — например, если у файла несколь ко атрибутов данных или несколько имен. Каждый атрибут в записи о файле идентифицируется кодом типа атри бута, имеет значение и необязательное имя. Значение атрибута представля ет собой байтовый поток. Так, значением атрибута $FILE_NAME является имя файла, значением атрибута $DATA — произвольный набор байтов, сохранен ный пользователем в файле. У большинства атрибутов нет имен, хотя у $DATA и атрибутов, связанных с индексом, они обычно есть. Имена позволяют различать атрибуты файла, относящиеся к одному типу. Например, в файле с именованным потоком данных есть два атрибута $DATA: неименованный атрибут $DATA, хранящий неименованный по умолчанию поток данных, и именованный атрибут $DATA с именем дополнительного потока данных. Имена файлов NTFS и FAT допускают длину каждого имени файла в пути до 255 символов. Эти имена могут содержать Unicodeсимволы, точки и пробелы. Однако дли на имен файлов в FAT, встроенной в MSDOS, ограничена 8 символами (не Unicode), за которыми следует расширение из трех символов, отделенное точкой. Рис. 1227 иллюстрирует различные пространства имен файлов, поддерживаемые Windows, и показывает, как они перекрываются. Рис. 12-27. Пространства имен файлов, поддерживаемые Windows POSIX требует самого большого пространства имен из всех подсистем, поддерживаемых Windows. Поэтому пространство имен NTFS эквивалентно пространству имен POSIX. Подсистема POSIX может создавать имена, неви димые приложениям Windows и MSDOS, в том числе имена с концевыми точками и концевыми пробелами. Создание файла в большом пространстве
ГЛАВА 9 Файловые системы 789 имен POSIX обычно не является проблемой, потому что вы создаете такой файл для использования подсистемой POSIX или ее клиентской системой. Но взаимосвязь между 32разрядными Windowsприложениями и програм мами MSDOS и 16разрядной Windows намного теснее. Область, отведенная Windows на рис. 1226, представляет имена файлов, которые подсистема Win dows может создавать на томе NTFS, хотя такие имена невидимы программам MSDOS и 16разрядной Windows. В эту группу входят имена файлов, не со ответствующие формату «8.3» (длинные имена, имена с Unicodeсимволами, с несколькими точками или начинающиеся с точки, а также имена с внутрен ними пробелами). При создании файла с таким именем NTFS автоматически генерирует для него альтернативное имя в стиле MSDOS. Windows показывает такие имена при использовании команды dir с ключом /x. Имена MSDOS — полнофункциональные псевдонимы файлов NTFS и хранятся в том же каталоге, что и длинные имена. На рис. 1228 показана запись MFT для файла с автоматически сгенерированным MSDOSименем. Рис. 12-28. Запись MFT с атрибутом имени файла для MS-DOS Имя NTFS и сгенерированное имя MSDOS хранятся в той же записи и относятся к одному и тому же файлу. Имя MSDOS можно использовать для открытия, чтения, записи и копирования файла. Если пользователь переиме новывает файл, заменяя длинное имя на краткое или наоборот, новое имя заменяет оба существовавших варианта. Если новое имя является недопус тимым для MSDOS, NTFS генерирует для файла другое MSDOSимя. ПРИМЕЧАНИЕ Аналогичным образом реализуются жесткие связи POSIX. При создании жесткой связи с POSIXфайлом NTFS добавляет в запись MFT дополнительный атрибут имени файла. Однако эти две ситуации имеют одно отличие. Когда пользователь удаляет файл PO SIX, у которого было несколько имен (жестких связей), запись о фай ле и сам файл остаются. Файл и его запись удаляются только после удаления последнего имени (жесткой связи). Если у файла есть и имя NTFS, и автоматически сгенерированное имя MSDOS, пользователь может удалить файл по любому из этих имен. Вот алгоритм, применяемый NTFS при генерации краткого MSDOSиме ни из длинного. 1. Удалить из длинного имени все символы, недопустимые в именах MS DOS, включая пробелы и Unicodeсимволы. Удалить начальную и конце вую точки, а также все внутренние точки, кроме последней.
790 ГЛ А В А 12 БЕЗОПАСНОСТЬ 2. Урезать часть строки перед точкой (если она есть) до шести символов и добавить строку «~n» (где n — порядковый номер, который начинается с 1; он нужен, чтобы различать файлы, урезание имен которых дает одинаковый результат). Урезать строку после точки (если она есть) до трех символов. 3. Преобразовать полученный набор символов в верхний регистр. MSDOS нечувствительна к регистру букв в именах файлов, но эта операция гаран тирует, что NTFS не сгенерирует для файла новое имя, отличающееся от старого лишь регистром. 4. Если сгенерированное имя дублирует уже имеющееся в каталоге, увели чить порядковый номер в строке «~n» на 1 (или на большее значение). В таблице 125 показаны длинные имена файлов с рис. 1226 и их MS DOSверсии, сгенерированные NTFS. Приведенный выше алгоритм и приме ры на рис. 1226 должны дать вам представление об именах в стиле MSDOS, генерируемых NTFS. ПРИМЕЧАНИЕ Вы можете отключить генерацию кратких имен, при своив параметру реестра HKLM\System\CurrentControlSet\Control\File System\ NtfsDisable8dot3NameCreation значение типа DWORD, равное 1, хотя обычно это не рекомендуется (изза вероятной несовместимо сти приложений, которые полагаются на такую функциональность). Таблица 12-5. Краткие имена, генерируемые NTFS Длинное имя Краткое имя, сгенерированное NTFS LongFileName LONGFI~1 UnicodeName.✦✤✰✬ UNICOD~1 File.Name.With.Dots FILENA~1.DOT File.Name2.With.Dots FILENA~2.DOT Name With Embedded Spaces NAMEWI~1 .BeginningDot BEGINN~1 Резидентные и нерезидентные атрибуты Если файл невелик, все его атрибуты и их значения (например, файловые данные) умещаются в одной записи файла. Когда значение атрибута хранит ся непосредственно в MFT, атрибут называется резидентным (например, все атрибуты на рис. 1227 являются резидентными). Некоторые атрибуты все гда резидентны — по ним NTFS находит нерезидентные атрибуты. Так, атри буты «стандартная информация» и «корень индекса» всегда резидентны. Каждый атрибут начинается со стандартного заголовка, в котором содер жится информация об атрибуте, используемая NTFS для базового управле ния атрибутами. В заголовке, который всегда является резидентным, регис трируется, резидентно ли значение данного атрибута. В случае резидентных атрибутов заголовок также содержит смещение значения атрибута от нача ла заголовка и длину этого значения (рис. 1229).
ГЛАВА 9 Рис. 12-29. Файловые системы 791 Заголовок и значение резидентного атрибута Когда значение атрибута хранится непосредственно в MFT, обращение к нему занимает значительно меньше времени. Вместо того чтобы искать файл в таблице, а затем считывать цепочку кластеров для поиска файловых данных (как, например, поступает FAT), NTFS обращается к диску только один раз и немедленно считывает данные. Как видно из рис. 1230, атрибуты небольшого каталога, а также неболь шого файла, могут быть резидентными в MFT. Для небольшого каталога ат рибут «корень индекса» содержит индекс файловых ссылок на файлы и под каталоги этого каталога. Рис. 12-30. Запись в MFT для небольшого каталога Конечно, многие файлы и каталоги нельзя втиснуть в запись MFT с фик сированным размером в 1 Кб. Если некий атрибут, например файловые дан ные, слишком велик и не умещается в записи MFT, NTFS выделяет для него отдельные кластеры за пределами MFT. Эта область называется группой (run) или экстентом (extent). Если размер значения атрибута впоследствии расши ряется (например, при добавлении в файл дополнительных данных), NTFS выделяет для новых данных еще одну группу. Атрибуты, значения которых хранятся в группах, а не в MFT, называются нерезидентными. Файловая сис тема сама решает, будет атрибут резидентным или нерезидентным, и обеспе чивает пользовательским процессам прозрачный доступ к этим данным. В случае нерезидентного атрибута (им может быть атрибут данных боль шого файла) в его заголовке содержится информация, нужная NTFS для по иска значения атрибута на диске. На рис. 1231 показан нерезидентный ат рибут данных, хранящийся в двух группах.
792 ГЛ А В А 12 Рис. 12-31. БЕЗОПАСНОСТЬ Запись в MFT для большого файла с двумя группами данных Среди стандартных атрибутов нерезидентными бывают лишь те, чей раз мер может увеличиваться. Для файлов такими атрибутами являются данные и список атрибутов (не показанный на рис. 1231). Атрибуты «стандартная информация» и «имя файла» всегда резидентны. В большом каталоге также могут быть нерезидентные атрибуты (или ча сти атрибутов), как видно из рис. 1232. В этом примере в записи MFT не хватает места для хранения индекса файлов, составляющих этот большой каталог. Часть индекса хранится в атрибуте корня индекса, а остальное — в нерезидентных группах, называемых индексными буферами (index buffers). Атрибуты корня индекса, выделенной группы индексов (index allocation) и битовой карты показаны здесь в упрощенной форме (подробнее о них см. следующий раздел). Атрибуты стандартной информации и имени файла всегда резидентны. Заголовок и по крайней мере часть значения атрибута корня индекса в случае каталогов также резидентны. Рис. 12-32. Запись MFT для большого каталога с нерезидентным индексом имен файлов Когда атрибуты файла (или каталога) не умещаются в записи MFT и для них требуется отдельное место, NTFS отслеживает выделяемые группы по средством пар сопоставлений VCNLCN. LCN представляют последователь ность кластеров на всем томе, пронумерованных от 0 до n. VCN нумеруют от 0 до m только кластеры, принадлежащие конкретному файлу. Пример нумерации кластеров в группах нерезидентного атрибута данных приведен на рис. 1233.
ГЛАВА 9 Рис. 12-33. Файловые системы 793 VCN для нерезидентного атрибута данных Если бы этот файл занимал больше двух групп, нумерация в третьей груп пе началась бы с VCN 8. Как показано на рис. 1234, заголовок атрибута дан ных содержит сопоставления VCNLCN для обоих групп, что позволяет NTFS легко находить выделенные под них области на диске. Рис. 12-34. Сопоставления VCN-LCN для нерезидентного атрибута данных Хотя на рис. 1233 показаны только группы данных, в группах могут хра ниться и другие атрибуты, если они не умещаются в записи MFT. Когда у фай ла так много атрибутов, что они не умещаются в записи MFT, для хранения дополнительных атрибутов (или заголовков в случае нерезидентных атрибу тов) используется вторая запись MFT. При этом добавляется атрибут, называ емый списком атрибутов (attribute list). Список атрибутов содержит имя и код типа каждого атрибута файла, а также файловую ссылку на запись MFT, в которой находится данный атрибут. Атрибут «список атрибутов» предназ начен для тех случаев, когда файл становится настолько большим или фраг ментированным, что одной записи MFT уже недостаточно для хранения боль шого объема сведений о сопоставлениях VCNLCN, нужных для поиска всех групп. Список атрибутов обычно нужен файлам, у которых более 200 групп.
794 ГЛ А В А 12 БЕЗОПАСНОСТЬ Сжатие данных и разреженные файлы NTFS поддерживает сжатие по отдельным файлам, по каталогам и по томам (NTFS сжимает только пользовательские данные, не трогая метаданные фай ловой системы). Выяснить, сжат ли том, можно через Windowsфункцию GetVolumeInformation. Чтобы получить реальный размер сжатого файла, ис пользуйте Windowsфункцию GetCompressedFileSize. Наконец, проверить или изменить параметры сжатия для файла или каталога позволяет Windows функция DeviceIoControl (см. управляющие коды файловой системы FSCTL_ GET_COMPRESSION и FSCTL_SET_COMPRESSION в описании этой функции в Platform SDK). Учтите, что изменение степени сжатия применительно к файлу выполняется немедленно, а применительно к каталогу или тому — нет. Во втором случае степень сжатия, заданная для каталога или тома, становит ся степенью сжатия по умолчанию для всех новых файлов и подкаталогов, создаваемых в каталоге или на томе. Следующий раздел является введением в сжатие данных в NTFS на при мере простого случая компрессии разреженных данных. После него мы об судим сжатие обычных и разреженных файлов. Сжатие разреженных данных Разреженными (sparse) называются данные (часто большого размера), в ко торых лишь малая часть отлична от нулевых значений. Пример разрежен ных данных — разреженная матрица. Как уже говорилось, для обозначения кластеров файла NTFS использует виртуальные номера кластеров (VCN) — от 0 до т. Каждый VCN соответствует логическому номеру кластера (LCN), который определяет местонахождение кластера на диске. На рис. 1235 по казаны группы (занимаемые участки дискового пространства) обычного (несжатого файла), а также их VCN и LCN. Рис. 12-35. Группы несжатого файла Данный файл хранится в трех группах, каждая по 4 кластера, и таким об разом занимает 12 кластеров. Запись MFT для этого файла представлена на рис. 1236. Как мы уже отмечали, для экономии места на диске атрибут дан ных в записи MFT содержит только одно сопоставление VCNLCN для каж дой группы, а не для каждого кластера. Тем не менее каждому VCN от 0 до 11 сопоставлен свой LCN. Первый элемент начинается с VCN 0 и охватывает 4 кластера, второй начинается с VCN 4, также охватывая 4 кластера, и т. д. Та кой формат типичен для несжатого файла.
ГЛАВА 9 Рис. 12-36. Файловые системы 795 Запись MFT для несжатого файла Один из способов сжатия файла, применяемых NTFS, состоит в удалении из него длинных цепочек нулей. Если файл разрежен, он обычно сжимается до размера, составляющего лишь часть дискового пространства, необходимо го для его хранения в нормальном виде. При последующей записи в этот файл NTFS выделяет пространство только для групп с ненулевыми данными. На рис. 1237 изображены группы сжатого разреженного файла. Обра тите внимание на то, что для некоторых диапазонов VCN файла (16–31 и 64–127) дисковое пространство не выделено. Рис. 12-37. Группы сжатого файла, содержащего разреженные данные В записи MFT для этого сжатого файла пропущены блоки VCN кластеров, со держащих нули, т. е. для них не выделено дисковое пространство. Так, первый элемент данных на рис. 1238 начинается с VCN 0 и охватывает 16 кластеров. Второй элемент перескакивает на VCN 32 и охватывает еще 16 кластеров.
796 ГЛ А В А 12 Рис. 12-38. БЕЗОПАСНОСТЬ Запись MFT для сжатого файла, содержащего разреженные данные Когда программа читает данные из сжатого файла, NTFS проверяет запись MFT, чтобы выяснить, имеется ли сопоставление VCNLCN для считываемо го участка файла. Если программа обращается в невыделенную «дыру» в фай ле, значит, данные этой части файла состоят из нулей, и тогда NTFS возвра щает нули, не обращаясь к диску. Если программа записывает в «дыру» не нулевые данные, NTFS автоматически выделяет дисковое пространство и записывает туда эти данные. Такой метод очень эффективен для разрежен ных файлов, содержащих много нулевых данных. Сжатие неразреженных данных Предыдущий пример сжатия разреженного файла довольно надуманный. Он описывает «сжатие» в том случае, когда целые области файла заполнены ну лями, но на остальные файловые данные сжатие не оказывает никакого вли яния. В большинстве файлов данные не являются разреженными, тем не ме нее их можно компрессировать по какомунибудь алгоритму сжатия. В NTFS пользователи могут сжимать отдельные файлы или все файлы в каталоге. (Новые файлы, создаваемые в сжатом каталоге, сжимаются автома тически. Файлы, существовавшие в каталоге до его сжатия, должны быть сжа ты индивидуально.) Сжимая файл, NTFS разбивает его необработанные дан ные на единицы сжатия (compression units) длиной по 16 кластеров. Неко торые последовательности данных в файле могут сжиматься недостаточно сильно или вообще не сжиматься, поэтому для каждой единицы сжатия NTFS определяет, будет ли при ее сжатии получен выигрыш хотя бы в один клас тер. Если сжатие не позволяет освободить даже один кластер, NTFS выделя ет 16кластерную группу и записывает единицу сжатия на диск, не компрес сируя ее данные. Если же данные можно сжать до 15 или менее кластеров, NTFS выделяет на диске ровно столько кластеров, сколько нужно для хране ния сжатых данных, после чего записывает данные на диск. Рис. 1239 ил люстрирует сжатие файла, состоящего из четырех групп. Незакрашенные области отражают дисковое пространство, которое файл будет занимать после сжатия. Первая, вторая и четвертая группы сжимаются, а третья — нет. Но даже с одной несжатой группой достигается экономия 26 кластеров дис ка, т. е. длина файла уменьшается на 41%.
ГЛАВА 9 Рис. 12-39. Файловые системы 797 Группы данных сжатого файла ПРИМЕЧАНИЕ Хотя на схемах, приведенных в этой главе, показаны непрерывные LCN, единицы сжатия не обязательно располагаются в физически смежных кластерах. Группы, занимающие несмежные кла стеры, заставляют NTFS создавать несколько более сложные записи MFT, чем показанные на рис. 1239. При записи данных в сжатый файл NTFS гарантирует, что каждая группа будет начинаться на виртуальной 16кластерной границе. Таким образом, начальный VCN каждой группы кратен 16, и длина группы не превышает 16 кластеров. При работе со сжатым файлом NTFS единовременно считывает и записывает минимум одну единицу сжатия. Но при записи сжатых данных NTFS пытается помещать единицы сжатия в физически смежные области, так чтобы их можно было считывать в ходе одной операции вводавывода. Раз мер единицы сжатия в 16 кластеров выбран для уменьшения внутренней фрагментации: чем больше размер единицы сжатия, тем меньше дискового пространства нужно для хранения данных. Размер единицы сжатия, равный 16 кластерам, основан на компромиссе между минимизацией размера сжа тых файлов и замедлением операций чтения для программ, использующих прямой (произвольный) доступ к содержимому файлов. При каждом прома хе кэша приходится декомпрессировать эквивалент 16 кластеров (вероят ность промаха кэша при прямом доступе к файлу выше, чем при последова тельном). На рис. 1240 представлена запись MFT для сжатого файла, пока занного на рис. 1239. Одно из различий между этим сжатым файлом и сжатым разреженным файлом из более раннего примера в том, что в данном случае три группы имеют длину менее 16 кластеров. Считывание этой информации из записи MFT позволяет NTFS определить, сжаты ли данные в этом файле. Каждая группа короче 16 кластеров содержит сжатые данные, которые NTFS долж на разархивировать при первом чтении группы в кэш. Группа, длина кото
798 ГЛ А В А 12 БЕЗОПАСНОСТЬ рой равна точно 16 кластерам, не содержит сжатых данных, а значит, не тре бует декомпрессии. Рис. 12-40. Запись MFT для сжатого файла Если группа содержит сжатые данные, NTFS разархивирует их во времен ный буфер и копирует в буфер вызывающей программы. Кроме того, NTFS помещает декомпрессированные данные в кэш, поэтому последующее чте ние из этой группы выполняется так же быстро, как и простое чтение из кэша. Все изменения файла NTFS записывает в кэш, позволяя подсистеме отложенной записи асинхронно сжимать и записывать измененные данные на диск. Такая стратегия гарантирует, что запись в сжатый файл вызовет при мерно ту же задержку, что и запись в несжатый файл. NTFS размещает сжатый файл на диске по возможности в смежных об ластях. Как указывают LCN, первые две группы сжатого файла на рис. 1238 являются физически смежными, равно как и две последних. Если две и бо лее группы расположены последовательно, NTFS выполняет опережающее чтение с диска — как и в случае обычных файлов. Поскольку чтение и деком прессия непрерывных файловых данных выполняются асинхронно и еще до того, как программа запросит эти данные, то в последующих операциях чте ния информация извлекается непосредственно из кэша, что значительно ускоряет процесс чтения. Разреженные файлы Разреженные файлы (тип файлов NTFS, отличающийся от ранее описанных файлов, которые содержат разреженные данные) по сути являются сжатыми файлами, неразреженные данные которых NTFS не сжимает. Однако NTFS об рабатывает данные группы из записи MFT разреженного файла так же, как и в случае сжатых файлов, состоящих из разреженных и неразреженных данных. Файл журнала изменений Файл журнала изменений, \$Extend\$UsnJrnl, является разреженным файлом, который NTFS создает, только когда приложение активизирует регистрацию изменений. Журнал хранит записи изменений в потоке данных $J. Эти запи си включают следующую информацию об изменениях файлов или каталогов: 쐽 время изменения; 쐽 тип изменения (удаление, переименование, увеличение размера и т. д.);
ГЛАВА 9 Файловые системы 799 쐽 атрибуты файла или каталога; 쐽 имя файла или каталога; 쐽 номер файловой ссылки файла или каталога; 쐽 номер файловой ссылки родительского каталога файла. Поскольку журнал является разреженным, он никогда не переполняется; когда его размер на диске достигает определенного максимума, NTFS начи нает просто обнулять файловые данные, предшествующие текущему блоку информации об изменениях, как показано на рис. 1241. Но, чтобы предот вратить постоянное изменение размера журнала, NTFS уменьшает его, толь ко когда он в два раза превосходит установленный максимум. Рис. 12-41. Выделение пространства для журнала изменений ($UsnJrnl) Индексация В NTFS каталог — это просто индекс имен файлов, т. е. совокупность имен файлов (с соответствующими файловыми ссылками), организованная таким образом, чтобы обеспечить быстрый доступ. Для создания каталога NTFS индексирует атрибуты «имя файла» из этого каталога. Запись MFT для кор невого каталога тома показана на рис. 1242. С концептуальной точки зрения, элемент MFT для каталога содержит в сво ем атрибуте «корень индекса» отсортированный список файлов каталога. Но для больших каталогов имена файлов на самом деле хранятся в индексных буферах размером по 4 Кб, которые содержат и структурируют имена фай лов. Индексные буферы реализуют структуру данных типа «b+ tree», которая позволяет свести к минимуму число обращений к диску при поиске какого либо файла, особенно в больших каталогах. Атрибут «корень индекса» содер жит первый уровень структуры b+ tree (подкаталоги корневого каталога) и
800 ГЛ А В А 12 БЕЗОПАСНОСТЬ указывает на индексные буферы, содержащие следующий уровень (другие подкаталоги или файлы). Рис. 12-42. Индекс имен файлов для корневого каталога тома На рис. 1242 в атрибуте «корень индекса» и индексных буферах показа ны только имена файлов (например, файл6), но каждая запись индекса содер жит и файловую ссылку на запись MFT, описывающую данный файл, плюс метку времени и информацию о размере файла. NTFS дублирует метку време ни и информацию о размере файла из записи MFT для файла. Такой подход, используемый файловыми системами FAT и NTFS, требует записи обновлен ной информации в два места. Но даже при этом просмотр каталогов суще ственно ускоряется, поскольку файловая система может сообщать метки вре мени и размеры файлов, не открывая каждый файл в каталоге. Атрибут «выделенная группа индексов» сопоставляет VCN групп индекс ных буферов с LCN, которые указывают, в каком месте диска находятся ин дексные буферы, а битовая карта используется для учета того, какие VCN в индексных буферах заняты, а какие свободны. На рис. 1242 на каждый VCN, т. е. на каждый кластер, приходится по одной записи для файла, но на самом деле кластер содержит несколько записей. Каждый индексный буфер разме ром 4 Кб может содержать 20–30 записей для имен файлов. Структура данных b+ tree — это разновидность сбалансированного дере ва, идеальная для организации отсортированных данных, хранящихся на диске, так как позволяет минимизировать количество обращений к диску при поиске заданного элемента. В MFT атрибут корня индекса для каталога содержит несколько имен файлов, выступающих в качестве индексов для второго уровня b+ tree. С каждым именем файла в атрибуте корня индекса связан необязательный указатель индексного буфера. Этот индексный буфер содержит имена файлов, которые с точки зрения лексикографии меньше данного имени. Например, на рис. 1242 файл4 — это элемент первого уров ня b+ tree. Он указывает на индексный буфер, содержащий имена файлов,
ГЛАВА 9 Файловые системы 801 которые лексикографически меньше имени в этом элементе, — файл0, файл1 и файл3. Обратите внимание, что использованные в этом примере имена (файл1, файл2 и др.) не являются буквальными, — они просто иллю стрируют относительное размещение файлов, лексикографически упорядо ченных в соответствии с показанной последовательностью. Хранение имен файлов в структурах вида b+ tree дает несколько преиму ществ. Поиск в каталоге выполняется быстрее, так как имена файлов хранятся в отсортированном порядке. А когда высокоуровневое программное обеспече ние перечисляет файлы в каталоге, NTFS возвращает уже отсортированные имена. Наконец, поскольку b+ tree имеет тенденцию к росту в ширину, а не в глубину, скорость поиска не уменьшается с увеличением размера каталога. Кроме индексации имен, NTFS обеспечивает универсальную индексацию данных, и некоторая функциональность NTFS (в том числе идентификации объектов, отслеживания квот и консолидированной защиты) использует индексацию для управления внутренними данными. Идентификаторы объектов Кроме идентификатора объекта, назначенного файлу или каталогу и храня щегося в атрибуте $OBJECT_ID записи MFT, NTFS также запоминает соответ ствие между идентификаторами объектов и номерами их файловых ссылок в индексе $O файла метаданных \$Extend\$ObjId. Элементы индекса сортиру ются по значениям идентификатора объекта, благодаря чему NTFS может быстро находить файл по его идентификатору. Таким образом, используя не документированную функциональность, приложения могут открывать файл или каталог по идентификатору объекта. На рис. 1243 показана взаимосвязь между файлом метаданных $Objid и атрибутами $OBJECT_ID в MFTзаписях. Рис. 12-43. Взаимосвязь $ObjId и $OBJECT_ID
802 ГЛ А В А 12 БЕЗОПАСНОСТЬ Отслеживание квот NTFS хранит информацию о квотах в файле метаданных \$Extend\$Quota, который состоит из индексов $O и $Q. Структура этих индексов показана на рис. 1244. NTFS не только присваивает каждому дескриптору защиты уникаль ный внутренний идентификатор защиты, но и назначает каждому пользова телю уникальный идентификатор. Когда администратор задает квоты для пользователя, NTFS создает идентификатор этого пользователя, соответству ющий его SID. NTFS создает в индексе $O запись, сопоставляющую SID с иден тификатором пользователя, и сортирует этот индекс по идентификаторам пользователей; в индексе $Q создается запись, управляющая квотами (quota control entry). Эта запись содержит лимиты, выделенные пользователю, а так же объем дискового пространства, отведенный ему на данном томе. Рис. 12-44. Индексация $Quota Когда приложение создает файл или каталог, NTFS получает SID пользо вателя этого приложения и ищет соответствующий идентификатор пользо вателя в индексе $O. Этот идентификатор записывается в атрибут $STAN DARD_INFORMATION нового файла или каталога. Затем NTFS просматрива ет запись квот в индексе $Q и определяет, не превышает ли выделенное дис ковое пространство установленные для данного пользователя лимиты. Ког да новое дисковое пространство, выделяемое пользователю, превышает по роговое значение, NTFS предпринимает соответствующие меры, например, записывает событие в журнал System (Система) или отклоняет запрос на создание файла или каталога. Консолидированная защита NTFS всегда поддерживала средства защиты, которые позволяют админист ратору указывать, какие пользователи могут обращаться к определенным файлам и каталогам, а какие — не могут. В версиях NTFS до Windows 2000 каждый файл и каталог хранит дескриптор защиты в своем атрибуте защи ты. Но в большинстве случаев администратор применяет одинаковые пара
ГЛАВА 9 Файловые системы 803 метры защиты к целому дереву каталогов, что приводит к дублированию дескрипторов защиты во всех файлах и подкаталогах этого дерева катало гов. В многопользовательских средах, например в Windows 2000 Server со службой Terminal Services, такое дублирование может потребовать слишком большого пространства на диске, поскольку дескрипторы защиты будут со держать элементы для множества учетных записей. NTFS в Windows 2000 и более поздних версиях ОС оптимизируют использование дискового про странства дескрипторами защиты за счет применения централизованного файла метаданных $Secure, в котором хранится только один экземпляр каж дого дескриптора защиты на данном томе. Файл $Secure содержит два атрибута индексов ($SDH и $SII), а также атри бут потока данных $SDS, как показано на рис. 1245. NTFS назначает каждо му уникальному дескриптору защиты на томе внутренний для NTFS иденти фикатор защиты (не путать с SID, который уникально идентифицирует учет ные записи компьютеров и пользователей) и хэширует дескриптор защиты по простому алгоритму. Хэш является потенциально неуникальным «стено графическим» представлением дескриптора. Элементы в индексе $SDH увязы вают эти хэши с местонахождением дескриптора защиты внутри атрибута данных $SDS, а элементы индекса $SII сопоставляют NTFSидентификаторы защиты с местонахождением дескриптора защиты в атрибуте данных $SDS. Рис. 12-45. Индексация $Secure Когда вы применяете дескриптор защиты к файлу или каталогу, NTFS по лучает хэш этого дескриптора и просматривает индекс $SDH, пытаясь найти совпадение. NTFS сортирует элементы индекса $SDH по хэшам дескрипторов защиты и хранит эти элементы в структуре вида b+ tree. Обнаружив совпаде ние для дескриптора в индексе $SDH, NTFS находит смещение дескриптора защиты от смещения элемента и считывает дескриптор из атрибута $SDS. Если хэши совпадают, а дескрипторы — нет, NTFS ищет следующее совпадение в
804 ГЛ А В А 12 БЕЗОПАСНОСТЬ индексе $SDH. Когда NTFS находит точное совпадение, файл или каталог, к которому вы применяете дескриптор защиты, может ссылаться на существу ющий дескриптор в атрибуте $SDS. Тогда NTFS считывает NTFSидентифика тор защиты из элемента $SDH и сохраняет его в атрибуте $STANDARD_ IN FORMATION файла или каталога. Атрибут $STANDARD_INFORMATION, имею щийся у всех файлов и каталогов, хранит базовую информацию о файле, в том числе его атрибуты, временные метки и идентификатор защиты. Если NTFS не обнаруживает в индексе $SDH элемент с дескриптором за щиты, совпадающим с тем, который вы применяете, значит, ваш дескриптор уникален в пределах данного тома, и NTFS присваивает ему новый внутрен ний идентификатор защиты. Такие идентификаторы являются 32битными значениями, но SID обычно в несколько раз больше, поэтому представление SID в виде NTFSидентификаторов защиты экономит место в атрибуте $STAN DARD_INFORMATION. NTFS включает дескриптор защиты в атрибут $SDS, который сортируется в структуру вида b+ tree по NTFSидентификатору за щиты, а потом добавляет его в элементы индексов $SDH и $SII, ссылающие ся на смещение дескриптора в данных $SDS. Когда приложение пытается открыть файл или каталог, NTFS использует индекс $SII для поиска дескриптора защиты этого файла или каталога. NTFS считывает внутренний идентификатор защиты файла или каталога из атри бута $STANDARD_INFORMATION записи MFT. Затем по индексу $SII файла $Secure она находит элемент с нужным идентификатором в атрибуте $SDS. По смещению в атрибуте $SDS NTFS считывает дескриптор защиты и завер шает проверку прав доступа. NTFS хранит последние 32 дескриптора защи ты, к которым было обращение, вместе с их элементами $SII в кэше, чтобы впоследствии была возможность обращаться только к файлу $Secure. NTFS не удаляет элементы в файле $Secure, даже если на них не ссылают ся никакие файлы или каталоги на томе. Это приводит лишь к незначитель ному увеличению места, занимаемого файлом $Secure, так как на большин стве томов, даже если они используются уже весьма долго, уникальных де скрипторов защиты сравнительно немного. Механизм универсальной индексации позволяет NTFS повторно исполь зовать дескрипторы защиты для файлов и каталогов с одинаковыми пара метрами защиты. По индексу $SII NTFS быстро находит дескриптор защиты в файле $Secure при проверках прав доступа, а по индексу $SDH определяет, хранится ли применяемый к файлу или каталогу дескриптор защиты в фай ле $Secure, и, если да, использует этот дескриптор повторно. Точки повторного разбора Как уже упоминалось, точка повторного разбора представляет собой блок данных повторного разбора, определяемых приложениями; длина такого блока может быть до 16 Кб. В нем содержится 32битный тэг повторного разбора, который хранится в атрибуте $REPARSE_POINT файла или катало га. Всякий раз, когда приложение создает или удаляет точку повторного раз бора, NTFS обновляет файл метаданных \$Extend\$Reparse, в котором она
ГЛАВА 9 Файловые системы 805 хранит элементы, идентифицирующие номера записей о файлах и катало гах с точками повторного разбора. Централизованное хранение записей позволяет NTFS предоставлять приложениям интерфейсы для перечисления либо всех точек повторного разбора на томе, либо только точек заданного типа, например точек монтирования (подробнее о точках монтирования см. главу 10). Файл \$Extend\$Reparse использует NTFSмеханизм универсальной индексации, сортируя элементы файлов (в индексе с именем $R) по тэгам повторного разбора. Поддержка восстановления в NTFS Поддержка восстановления в NTFS гарантирует, что в случае отказа элект ропитания или аварии системы ни одна операция файловой системы (транзакция) не останется незавершенной; при этом структура дискового тома будет сохранена. NTFS включает утилиту Chkdsk, которая позволяет устранять последствия катастрофических повреждений диска, вызванных аппаратными ошибками вводавывода (например, изза аварийных секторов на диске, электрических аномалий или сбоев в работе диска) либо ошибка ми в программном обеспечении. Наличие средств восстановления NTFS уменьшает потребность в использовании Chkdsk. Как уже упоминалось в разделе «Восстанавливаемость», NTFS использует схему на основе обработки транзакций. Эта стратегия гарантирует полное восстановление диска, которое производится исключительно быстро (за считанные секунды) даже в случае самых больших дисков. NTFS ограничи вается восстановлением данных файловой системы, гарантируя, что пользо ватель по крайней мере никогда не потеряет весь том изза повреждения файловой системы. Но, если приложение не выполнило определенных дей ствий, например не сбросило на диск кэшированные файлы, NTFS не гаран тирует полное восстановление пользовательских данных в случае краха. За щита пользовательских данных на основе технологии обработки транзак ций предусматривается в большинстве СУБД для Windows, например в Micro soft SQL Server. Microsoft не стала реализовать восстановление пользователь ских данных на уровне файловой системы, так как приложения обычно под держивают свои схемы восстановления, оптимизированные под тот тип дан ных, с которыми они работают. В следующих разделах рассказывается об эволюции средств обеспечения надежности файловой системы, и в этом контексте вводится концепция вос станавливаемых файловых систем с подробным обсуждением схемы прото колирования транзакций, за счет которой NTFS регистрирует изменения в структурах данных файловой системы. Кроме того, мы поясним, как NTFS восстанавливает том в случае сбоя системы. Эволюция архитектуры файловых систем Создание восстанавливаемой файловой системы можно рассматривать как еще один шаг в эволюции архитектуры файловых систем. В прошлом были
806 ГЛ А В А 12 БЕЗОПАСНОСТЬ распространены два основных подхода к организации поддержки ввода вывода и кэширования в файловых системах: точная запись (careful write) и отложенная (lazy write). В файловых системах, которые разрабатывались для VAX/VMS (права на нее перешли от DEC к Compaq) и некоторых других закрытых операционных систем, использовался алгоритм точной записи, тогда как в файловой системе HPFS операционной системы OS/2 и большин стве файловых систем UNIX применялась схема отложенной записи. Далее мы кратко рассмотрим два типа файловых систем, наиболее рас пространенные в настоящее время, и присущие им внутренние противоре чия между безопасностью и производительностью. В третьем подразделе будет описан подход к восстановлению, принятый в NTFS, и его отличие от двух вышеупомянутых стратегий. Файловые системы с точной записью В случае аварии операционной системы или сбоя электропитания операции вводавывода, выполняемые в данный момент, немедленно прерываются. В зависимости от того, какие операции вводавывода выполнялись и насколь ко далеко продвинулось их выполнение, такое прерывание может нарушить целостность файловой системы. В данном контексте нарушение целостно сти — это повреждение файловой системы: например, имя файла появляет ся в списке каталога, но файловая система не знает, где он находится, или не может обратиться к его содержимому. В самых тяжелых случаях повреж дение файловой системы может привести к потере всего тома. Файловая система с точной записью не пытается предотвратить наруше ния целостности. Вместо этого она упорядочивает операции записи так, что авария системы в худшем случае вызовет предсказуемые, некритичные рас согласования, которые файловая система сможет в любой момент устранить. Когда файловая система (какого бы типа она ни была) получает запрос на обновление содержимого диска, она должна выполнить несколько под операций, прежде чем обновление будет завершено. В файловой системе, ис пользующей стратегию точной записи, эти подоперации всегда записыва ют свои данные на диск последовательно. При выделении дискового про странства, например для файла, файловая система сначала устанавливает некоторые биты в своей битовой карте, после чего выделяет место для фай ла. Если сбой питания происходит сразу после того, как были установлены эти биты, файловая система точной записи теряет доступ к той части дис ка, которая была представлена установленными битами, но существующие данные не разрушаются. Упорядочение операций записи также означает, что запросы на вводвы вод выполняются в порядке их поступления. Если один процесс выделяет дисковое пространство и вскоре после этого другой процесс создает файл, файловая система с точной записью завершает выделение дискового про странства до того, как начнет создавать файл, — иначе перекрытие подопе раций из двух запросов вводавывода могло бы привести к нарушению це лостности.
ГЛАВА 9 Файловые системы 807 ПРИМЕЧАНИЕ Файловая система FAT в MSDOS использует алгоритм сквозной записи, при котором обновления записываются на диск не медленно. В отличие от точной записи этот метод не требует от фай ловой системы упорядочения операций вывода для предотвращения нарушения целостности. Основное преимущество файловых систем с точной записью в том, что в случае сбоя дисковый том остается целостным и его можно использовать дальше — немедленный запуск утилиты исправления тома не обязателен. Такая утилита нужна для исправления предсказуемых, неразрушительных нарушений целостности диска, которые возникли в результате сбоя, но ее можно запустить в удобное время, обычно при перезагрузке системы. Файловые системы с отложенной записью Файловая система с точной записью жертвует производительностью ради надежности. Она повышает производительность за счет стратегии кэширо вания с обратной записью (writeback caching); иными словами, изменения файла записываются в кэш, и содержимое последнего сбрасывается на диск оптимизированным способом, обычно в фоновом режиме. Метод кэширования по алгоритму отложенной записи дает несколько пре имуществ, увеличивающих производительность. Вопервых, уменьшается об щее число операций записи на диск. Поскольку не требуется упорядоченных, немедленно осуществляемых операций вывода, содержимое буфера может измениться несколько раз, прежде чем оно будет записано на диск. Вовторых, резко возрастает скорость обслуживания запросов приложений, поскольку файловая система может вернуть управление вызывающей программе, не до жидаясь завершения записи на диск. Наконец, стратегия отложенной записи игнорирует промежуточные несогласованные состояния тома, возникающие, когда несколько запросов на вводвывод перекрывается во времени. Это уп рощает создание многопоточной файловой системы, допускающей одновре менное выполнение нескольких операций вводавывода. Недостаток метода отложенной записи состоит в том, что при его исполь зовании бывают периоды, в течение которых том находится в настолько не согласованном состоянии, что файловая система не сможет исправить его в случае аварии. Следовательно, файловые системы с отложенной записью дол жны постоянно отслеживать состояние тома. В общем случае отложенная за пись дает выигрыш в производительности по сравнению с точной запи сью — за счет большего риска и неудобств для пользователя при сбое системы. Восстанавливаемые файловые системы Восстанавливаемая файловая система типа NTFS превосходит по надежно сти файловые системы с точной записью и при этом достигает уровня про изводительности файловых систем с отложенной записью. Восстанавлива емая файловая система гарантирует сохранение целостности тома; с этой целью используется журнал изменений, изначально созданный для обработ
808 ГЛ А В А 12 БЕЗОПАСНОСТЬ ки транзакций. В случае аварии операционной системы такая файловая сис тема восстанавливает целостность, выполняя процедуру восстановления на основе информации из файла журнала. Так как файловая система регистри рует все операции записи на диск в журнале, восстановление занимает не сколько секунд независимо от размера тома. Процедура восстановления в восстанавливаемой файловой системе явля ется точной и гарантирует возвращение тома в согласованное состояние. Неадекватные результаты восстановления, характерные для файловых сис тем с отложенной записью, в NTFS исключены. За высокую надежность восстанавливаемой файловой системы приходит ся расплачиваться. При каждой транзакции, изменяющей структуру тома, в файл журнала требуется заносить по одной записи на каждую подоперацию транзакции. Файловая система уменьшает издержки протоколирования за счет объединения записей файла журнала в пакеты: за одну операцию вво давывода в журнал добавляется сразу несколько записей. Кроме того, вос станавливаемая файловая система может применять алгоритмы оптимиза ции, используемые файловыми системами с отложенной записью. Она мо жет даже увеличить интервалы между сбросами кэша на диск, так как фай ловую систему можно восстановить, если авария произошла до того, как из менения переписаны из кэша на диск. Такой рост в производительности кэша компенсирует и часто даже перевешивает издержки, вызванные про токолированием транзакций. Ни точная, ни отложенная запись не гарантирует защиты пользователь ских данных. Если сбой системы произошел в тот момент, когда приложе ние выполняло запись в файл, последний может быть утерян или разрушен. Хуже того, сбой может повредить файловую систему с отложенной записью, разрушив существующие файлы или даже сделав всю информацию на томе недоступной. Восстанавливаемая файловая система NTFS использует стратегию, повы шающую ее надежность по сравнению с традиционными файловыми систе мами. Вопервых, восстанавливаемость NTFS гарантирует, что структура тома не будет разрушена, так что в случае сбоя системы все файлы останут ся доступными. Вовторых, хотя NTFS не гарантирует сохранности пользовательских дан ных в случае сбоя системы (некоторые изменения в кэше могут быть потеря ны), приложения могут использовать преимущества сквозной записи и сброса кэша NTFS для гарантии того, что изменения файлов будут записываться на диск в должное время. Как сквозная запись (принудительная немедленная за пись на диск), так и сброс кэша (принудительная запись на диск содержимого кэша) — операции вполне эффективные. NTFS не требуется дополнительно го вводавывода для сброса на диск изменений нескольких различных струк тур данных файловой системы, так как изменения в этих структурах регист рируются в файле журнала (в ходе единственной операции записи); если про изошел сбой и содержимое кэша потеряно, изменения файловой системы могут быть восстановлены по информации из журнала. Более того, NTFS в
ГЛАВА 9 Файловые системы 809 отличие от FAT гарантирует, что сразу после операции сквозной записи или сброса кэша пользовательские данные останутся целостными и будут доступ ны, даже если вслед за этим произойдет сбой системы. Протоколирование Восстанавливаемость NTFS обеспечивается методикой обработки транзак ций, называемой протоколированием (logging). Прежде чем выполнить над содержимым диска подоперации какойлибо транзакции, изменяющей важ ные структуры данных файловой системы, NTFS регистрирует ее в файле журнала. Таким образом, в случае сбоя системы незавершенные транзакции можно повторить или отменить после перезагрузки компьютера. В техно логии обработки транзакций эта методика называется опережающим про токолированием (writeahead logging). В NTFS транзакции, к которым отно сятся, в частности, запись на диск или удаление файла, могут состоять из нескольких подопераций. Сервис файла журнала Сервис файла журнала (log file service, LFS) — это набор процедур режима ядра, локализованных в драйвере NTFS, который она использует для досту па к файлу журнала. Хотя LFS изначально был разработан для того, чтобы предоставлять средства протоколирования и восстановления более чем од ному клиенту, он используется только NTFS. Вызывающая программа, в дан ном случае NTFS, передает LFS указатель на открытый объект «файл», кото рый определяет файл, выступающий в роли журнала. LFS либо инициализи рует новый журнал, либо вызывает диспетчер кэша для доступа к существу ющему журналу через кэш, как показано на рис. 1246. Рис. 12-46. Сервис файла журнала (LFS)
810 ГЛ А В А 12 БЕЗОПАСНОСТЬ LFS делит файл журнала на две части: область перезапуска (restart area) и «безразмерную» область протоколирования (logging area) (рис. 1247). Рис. 12-47. Области файла журнала NTFS вызывает LFS для чтения и записи области перезапуска. В этой об ласти NTFS хранит информацию о контексте, например позицию в облас ти протоколирования, откуда начнется чтение при восстановлении после сбоя системы. На тот случай, если область перезапуска будет разрушена или по какимлибо причинам станет недоступной, LFS создает ее копию. Осталь ная часть журнала транзакций — это область протоколирования, в которой находятся записи транзакций, обеспечивающие восстановление тома пос ле сбоя. LFS создает иллюзию бесконечности журнала транзакций за счет его циклического повторного использования (в то же время не перезаписывая нужную информацию). Для идентификации записей, помещенных в журнал, LFS использует номера логической последовательности (logical sequence number, LSN). Циклически используя журнал, LFS увеличивает значения LSN. NTFS представляет LSN в виде 64битных чисел, поэтому число возможных LSN настолько велико, что практически может считаться бесконечным. NTFS никогда не выполняет чтение/запись транзакций в журнал напря мую. LFS предоставляет сервисы, которые NTFS вызывает для открытия файла журнала, помещения в него записей, чтения записей из журнала в прямом и обратном порядке, сброса записей журнала до заданного LSN или установ ки логического начала журнала на больший LSN. В процессе восстановления NTFS вызывает LFS для чтения записей журнала в прямом направлении, что бы повторить все транзакции, которые запротоколированы в журнале, но не записаны на диск в момент сбоя. NTFS также обращается к LFS для чтения записей в обратном направлении, чтобы отменить (или откатить) все тран закции, не полностью запротоколированные перед аварией системы, и ус тановить начало файла журнала на запись с бóльшим LSN после того, как ста рые записи журнала стали не нужны. Вот как система обеспечивает восстановление тома. 1. Сначала NTFS вызывает LFS для записи в кэшируемый файл журнала лю бых транзакций, модифицирующих структуру тома. 2. NTFS модифицирует том (также в кэше). 3. Диспетчер кэша сообщает LFS сбросить файл журнала на диск. (Этот сброс реализуется LFS путем обратного вызова диспетчера кэша с указа нием страниц памяти, подлежащих выводу на диск; см. рис. 1246.)
ГЛАВА 9 Файловые системы 811 4. Сбросив на диск журнал транзакций, диспетчер кэша записывает на диск изменения тома (результаты операций над метаданными). Эта последовательность действий гарантирует: если завершить измене ние файловой системы не удастся, соответствующие транзакции можно бу дет считать из журнала и либо повторить, либо отменить в процессе восста новления файловой системы. Восстановление файловой системы начинается автоматически при пер вом обращении к дисковому тому после перезагрузки. NTFS проверяет, при менялись ли к тому транзакции, запротоколированные в журнале до сбоя, и, если нет, повторяет их. NTFS гарантирует и отмену транзакций, не полнос тью запротоколированных до сбоя, так что вызываемые ими изменения не появятся на томе. Типы записей журнала LFS позволяет своим клиентам помещать в журналы транзакций записи лю бого типа. NTFS использует несколько типов записей, два из которых — записи модификации (update records) и записи контрольной точки (check point records) — будут рассмотрены в этом разделе. Записи модификации К ним относится большинство записей, кото рые NTFS помещает в журнал транзакций. Каждая такая запись содержит два вида информации. 쐽 Информация для повтора (redo information) Описывает, как вновь применить к дисковому тому одну подоперацию полностью запротоко лированной транзакции, если сбой системы произошел до того, как тран закция была переписана из кэша на диск. 쐽 Информация для отмены (undo information) Описывает, как обра тить изменения, вызванные одной подоперацией транзакции, которая в момент сбоя была запротоколирована лишь частично. На рис. 1248 показаны три записи модификации в файле журнала. Каж дая запись представляет одну подоперацию транзакции, создающей новый файл. Информация для повтора в каждой записи модификации сообщает NTFS, как повторно применить данную подоперацию к дисковому тому, а информация для отмены — как откатить (отменить) эту подоперацию. Рис. 12-48. Записи модификации в файле журнала
812 ГЛ А В А 12 БЕЗОПАСНОСТЬ После протоколирования транзакции (в данном примере — вызовом LFS до помещения трех записей модификации в файл журнала) NTFS выполня ет в кэше подоперации этой транзакции, изменяющие том. Закончив обнов ление кэша, NTFS помещает в журнал еще одну запись, которая помечает всю транзакцию как завершенную. Эта подоперация известна как фиксация транзакции (committing transaction). После фиксации транзакции NTFS га рантирует, что все вызванные ею модификации будут отражены на томе, даже если после фиксации произойдет сбой операционной системы. При восстановлении после сбоя системы NTFS просматривает журнал и повторяет все зафиксированные транзакции. Даже если NTFS и завершила транзакцию до момента сбоя системы, ей неизвестно, были ли изменения тома своевременно переписаны на диск диспетчером кэша. Модификации, выполненные в кэше, могли быть потеряны при сбое. Следовательно, NTFS выполняет зафиксированную транзакцию снова, чтобы гарантировать акту альность состояния диска. После повтора всех зафиксированных транзакций NTFS отыскивает в журнале такие, которые не были зафиксированы к моменту сбоя, и откаты вает каждую запротоколированную подоперацию. В случае, представленном на рис. 1248, NTFS вначале должна была бы отменить подоперацию Т1c, после чего перейти по указателям назад и отменить T1b. Переход по указа телям в обратном направлении и отмена подопераций продолжались бы до тех пор, пока NTFS не достигла бы первой подоперации транзакции. Следуя указателям, NTFS определяет, сколько и какие записи модификации нужно отменить для того, чтобы откатить транзакцию. Информация для повтора и отмены может быть выражена либо физичес ки, либо логически. Физическое описание задает модификации тома как диапазоны байтов на диске, которые следует изменить, переместить и т. д., а логическое — представляет модификации в терминах операций, например «удалить файл A.dat». Как самый низкий уровень программного обеспечения, поддерживающего структуру файловой системы, NTFS использует записи модификации с физическими описаниями. Однако для программного обес печения обработки транзакций и других приложений записи модификации в логическом виде могут быть удобнее, поскольку логическое представление обновлений тома компактнее физических. Логическое описание требует участия NTFS в выполнении действий, связанных с такими операциями, как удаление файла. NTFS генерирует записи модификации (обычно несколько) для каждой из следующих транзакций: 쐽 создание файла; 쐽 удаление файла; 쐽 расширение файла; 쐽 урезание файла; 쐽 установка файловой информации;
ГЛАВА 9 Файловые системы 813 쐽 переименование файла; 쐽 изменение прав доступа к файлу. Информация для повтора и отмены в записи модификации должна быть очень точной, иначе при отмене транзакции, восстановлении после сбоя системы или даже в ходе нормальной работы NTFS может попытаться повто рить транзакцию, которая уже выполнена, или, наоборот, отменить транзак цию, которая никогда не выполнялась либо уже отменена. Аналогичным образом NTFS может попытаться повторить или отменить транзакцию, включающую нескольких записей модификации, которые не все были при менены к диску. Формат записей модификации должен гарантировать, что лишние операции повтора или отмены будут идемпотентными (idempo tent), т. е. дадут нейтральный эффект. Например, установка уже установлен ного бита, не оказывает никакого действия, но изменение на противополож ное значения бита, которое уже изменено, — оказывает. Файловая система также должна корректно обрабатывать переходные состояния тома. Записи контрольной точки Помимо записей модификации NTFS пе риодически помещает в файл журнала запись контрольной точки, как пока зано на рис. 1249. Рис. 12-49. Запись контрольной точки в файле журнала Запись контрольной точки помогает NTFS определить, какая обработка нужна для восстановления тома, если сбой произошел сразу после добавле ния этой записи в журнал. Благодаря записи контрольной точки NTFS, напри мер, знает, как далеко назад ей нужно пройти по журналу, чтобы начать вос становление. Добавив новую запись контрольной точки, NTFS записывает ее LSN в область перезапуска, так что, начиная восстановление после сбоя сис темы, она быстро находит самую последнюю запись контрольной точки. Хотя LFS представляет NTFS, будто журнал транзакций безразмерен, на са мом деле он не бесконечен. Значительный размер журнала транзакций и частая вставка записей контрольной точки (операция, обычно освобожда ющая место в файле журнала) делают вероятность его переполнения доста точно малой. Тем не менее LFS учитывает такую возможность, отслеживая не сколько значений: 쐽 размер свободного пространства в журнале; 쐽 размер пространства, необходимого для добавления в журнал следующей записи и для отмены этого действия (если это вдруг потребуется);
814 ГЛ А В А 12 БЕЗОПАСНОСТЬ 쐽 размер пространства, нужного для отката всех активных (не зафиксиро ванных) транзакций (если это вдруг потребуется). Если в журнале не хватает места для суммы последних двух значений из списка, LFS сообщает об ошибке переполнения файла журнала, и NTFS ге нерирует исключение. Обработчик исключений NTFS откатывает текущую транзакцию и помещает ее в очередь для последующего перезапуска. Чтобы освободить пространство в журнале транзакций, NTFS должна вре менно приостановить вводвывод в системе. Для этого она блокирует созда ние и удаление файлов, после чего запрашивает монопольный доступ ко всем системным файлам и разделяемый доступ ко всем пользовательским файлам. Постепенно активные транзакции либо завершаются успешно, либо вызывают исключение переполнения файла журнала. В последнем случае NTFS откатывает их, а затем помещает в очередь. Заблокировав вышеописанным способом выполнение транзакций при операциях над файлами, NTFS вызывает диспетчер кэша для сброса на диск еще не записанных туда данных, в том числе данных файла журнала. После того как все успешно записано на диск, данные в журнале NTFS становятся ненужными. NTFS устанавливает начало журнала на текущую позицию, что делает журнал «пустым». Затем NTFS перезапускает транзакции, поставлен ные ранее в очередь. Так что за исключением короткой паузы в обработке вводавывода ошибка переполнения файла журнала не оказывает влияния на выполняемые программы. Описанный сценарий — один из примеров того, как NTFS использует файл журнала не только для восстановления файловой системы, но и для исправления ошибок при нормальной работе. Восстановление NTFS автоматически выполняет восстановление диска при первом обраще нии к нему какойлибо программы после загрузки системы. (Если восстанов ление не требуется, весь процесс тривиален.) При восстановлении исполь зуются две таблицы, которые NTFS поддерживает в памяти. 쐽 Таблица транзакций (transaction table) — предназначена для отслежи вания начатых, но еще не зафиксированных транзакций. В процессе вос становления результаты подопераций этих транзакций должны быть уда лены с диска. 쐽 Таблица измененных страниц (dirty page table) — в нее записывается информация о том, какие страницы кэша содержат изменения структу ры файловой системы, еще не записанные на диск. Эти данные в процессе восстановления должны быть сброшены на диск. Каждые 5 секунд NTFS добавляет в файл журнала транзакций запись конт рольной точки. Непосредственно перед этим она обращается к LFS для со хранения в журнале текущей копии таблицы транзакций и таблицы изменен ных страниц. Затем NTFS запоминает в записи контрольной точки LSN запи сей журнала, содержащих копии таблиц. В начале процесса восстановления
ГЛАВА 9 Файловые системы 815 после сбоя NTFS обращается к LFS для поиска записей журнала транзакций, содержащих самую последнюю запись контрольной точки и самые последние копии упомянутых выше таблиц. Затем NTFS копирует эти таблицы в память. Обычно за последней записью контрольной точки в журнале транзакций находится еще несколько записей модификации. Эти записи соответствуют обновлениям тома, произошедшим после того, как запись контрольной точ ки была помещена в журнал. NTFS должна обновить таблицу транзакций и таблицу измененных страниц, включив в них информацию из этих допол нительных записей. После обновления таблиц NTFS использует их, а также содержимое журнала транзакций для обновления собственно тома. При восстановлении тома NTFS выполняет три прохода по журналу тран закций, загружая его в память на первом проходе, чтобы минимизировать объем дискового вводавывода. Каждый проход имеет свое назначение: 쐽 анализ; 쐽 повтор транзакций; 쐽 отмена транзакций. Проход анализа При проходе анализа (analysis pass) NTFS просматривает журнал транзакций в прямом направлении, начиная с последней операции контрольной точки, чтобы найти записи модификации и обновить скопированные ранее в память таблицы транзакций и измененных страниц. Обратите внимание, что опера ция контрольной точки помещает в журнал транзакций три записи, между которыми могут оказаться записи модификации (рис. 1250). NTFS должна приступить к сканированию с начала операции контрольной точки. Рис. 12-50. Проход анализа Большинство записей модификации, расположенных в журнале после начала операции контрольной точки, представляет собой изменение либо таблицы транзакций, либо таблицы измененных страниц. Например, если запись модификации относится к фиксации транзакции, то транзакция, ко торую представляет данная запись, должна быть удалена из таблицы тран закций. Аналогично, если запись модификации относится к обновлению страницы, изменяющему структуру данных файловой системы, нужно вне сти соответствующую поправку в таблицу измененных страниц. После того как таблицы в памяти приведены в актуальное состояние, NTFS просматривает их, чтобы определить LSN самой старой записи моди
816 ГЛ А В А 12 БЕЗОПАСНОСТЬ фикации, которая регистрирует операцию, не выполненную над диском. Таблица транзакций содержит LSN незафиксированных (незавершенных) транзакций, а таблица измененных страниц — LSN записей, соответствую щих модификациям кэша, не отраженным на диске. LSN самой старой запи си, найденной NTFS в этих двух таблицах, определяет, откуда начнется про ход повтора. Однако, если последняя запись контрольной точки окажется более ранней, NTFS начнет проход повтора именно с нее. Проход повтора На проходе повтора (redo pass) NTFS сканирует журнал транзакций в пря мом направлении, начиная с LSN самой старой записи, которая была обна ружена на проходе анализа (рис. 1251). Она ищет записи модификации, относящиеся к обновлению страницы и содержащие модификации тома, которые были запротоколированы до сбоя системы, но не сброшены из кэша на диск. NTFS повторяет эти обновления в кэше. Рис. 12-51. Проход повтора Когда NTFS достигает конца журнала транзакций, она уже обновила кэш необходимыми модификациями тома, и подсистема отложенной записи, принадлежащая диспетчеру кэша, может начать переписывать содержимое кэша на диск в фоновом режиме. Проход отмены Завершив проход повтора, NTFS начинает проход отмены (undo pass), откаты вая транзакции, не зафиксированные к моменту сбоя системы. На рис. 1252 показаны две транзакции в журнале: транзакция 1 зафиксирована до сбоя системы, а транзакция 2 — нет. NTFS должна отменить транзакцию 2. Рис. 12-52. Проход отмены
ГЛАВА 9 Файловые системы 817 Допустим, в ходе транзакции 2 создавался файл. Эта операция состоит из трех подопераций (каждая со своей записью модификации). Записи моди фикации, относящиеся к одной транзакции, связываются в журнале обрат ными указателями, поскольку эти записи обычно не располагаются одна за другой. В таблице транзакций NTFS для каждой незавершенной транзакции хра нится LSN записи модификации, помещенной в журнал последней. В данном примере таблица транзакций сообщает, что для транзакции 2 это запись с LSN 4049. NTFS выполняет откат транзакции 2, как показано на рис. 1253 (справа налево). Рис. 12-53. Отмена транзакции Найдя LSN 4049, NTFS извлекает информацию для отмены и выполняет отмену, сбрасывая биты 3–9 в своей битовой карте. Затем NTFS следует по обратному указателю к LSN 4048, который указывает ей удалить новое имя файла из индекса имен файлов. Наконец, NTFS переходит по последнему обратному указателю и освобождает запись MFT, зарезервированную для данного файла, в соответствии с информацией из записи модификации с LSN 4046. На этом откат транзакции 2 закончен. Если имеются другие неза вершенные транзакции, NTFS повторяет ту же процедуру для их отката. По скольку отмена транзакций изменяет структуру файловой системы на томе, NTFS должна протоколировать операцию отмены в журнале транзакций. В конце концов, при восстановлении может снова произойти сбой питания, и NTFS придется выполнить повтор операций отмены! Когда проход отмены завершен, том возвращается в согласованное состо яние. В этот момент NTFS сбрасывает на диск изменения кэша, чтобы гаран тировать правильность содержимого тома. Далее NTFS записывает «пустую» область перезапуска, указывающую, что том находится в согласованном со стоянии и что, если система сразу потерпит еще одну аварию, никакого вос становления не потребуется. На этом восстановление заканчивается. NTFS гарантирует, что восстановление вернет том в некое существовавшее ранее целостное состояние, но не обязательно в непосредственно предше ствовавшее сбою. NTFS не может дать такой гарантии, поскольку для большей производительности она использует алгоритм отложенной фиксации (lazy commit), а значит, сброс журнала транзакций из кэша на диск не выполняет ся немедленно всякий раз, когда добавляется запись «транзакция зафиксиро
818 ГЛ А В А 12 БЕЗОПАСНОСТЬ вана». Вместо этого несколько записей фиксации транзакций объединяются в пакет и записываются совместно — либо когда диспетчер кэша вызывает LFS для сброса журнала на диск, либо когда LFS помещает в журнал новую запись контрольной точки (каждые 5 секунд). Другая причина, по которой том не всегда возвращается к самому последнему состоянию, — в момент сбоя сис темы могли быть активны несколько параллельных транзакций, и одни запи си фиксации этих транзакций были перенесены на диск, а другие — нет. Со гласованное состояние тома, полученное в результате восстановления, отра жает только те транзакции, чьи записи фиксации успели попасть на диск. NTFS применяет журнал транзакций не только для восстановления тома, но и для других целей, реализация которых становится возможной за счет протоколирования транзакций. Файловые системы обязательно включают большой объем кода для обработки ошибок, возникающих в процессе обыч ного файлового вводавывода. Поскольку NTFS протоколирует каждую тран закцию, модифицирующую структуру тома, она может использовать журнал транзакций для восстановления после ошибок файловой системы и таким образом существенно упростить код обработки ошибок. Ошибка перепол нения журнала транзакций, описанная ранее, — один из примеров исполь зования протоколирования транзакций для обработки ошибок. Большинство ошибок вводавывода, получаемых программой, не являет ся ошибками файловой системы, и поэтому NTFS не может исправить их самостоятельно. Например, получив запрос на создание файла, NTFS может начать с создания записи в MFT, после чего ввести имя файла в индекс ката лога. Однако при попытке выделить по своей битовой карте пространство для нового файла она может обнаружить, что диск заполнен, и запрос на создание файла удовлетворить не удастся. Тогда NTFS использует информа цию из журнала транзакций для отмены уже выполненной части операции и освобождения структур данных, зарезервированных ею для файла. Затем ошибка «диск заполнен» возвращается вызывающей программе, которая и должна предпринять соответствующие действия. Восстановление плохих кластеров в NTFS Диспетчеры томов Windows — FtDisk (для базовых дисков) и LDM (для дина мических) — могут восстанавливать данные из плохого (аварийного) секто ра на отказоустойчивом томе, но, если жесткий диск не является SCSIдиском или если на нем больше нет резервных секторов, они не в состоянии заме нить плохой сектор новым (подробнее о диспетчерах томов см. главу 10). В таком случае, когда файловая система считывает данные из плохого сек тора, диспетчер томов восстанавливает информацию и возвращает ее вме сте с соответствующим предупреждением. Файловая система FAT никак не обрабатывает это предупреждение. Более того, ни эта файловая система, ни диспетчеры томов не ведут учет плохих секторов, поэтому, чтобы диспетчер томов не повторял все время восстанов ление данных из плохого сектора, пользователь должен запустить утилиту Chkdsk или Format. Обе эти утилиты далеко не идеальны в исключении пло
ГЛАВА 9 Файловые системы 819 хого сектора из дальнейшего использования. Chkdsk требует много време ни для поиска и удаления плохих секторов, a Format уничтожает все данные в форматируемом разделе. NTFSэквивалент механизма замены секторов динамически заменяет кла стер, содержащий плохой сектор, и ведет учет плохих кластеров, чтобы пре дотвратить их дальнейшее использование. (Вспомните, что NTFS адресует ся к логическим кластерам, а не к физическим секторам.) Эта функциональ ность NTFS активизируется, если диспетчер томов не может заменить пло хой сектор. Когда FtDisk возвращает предупреждение о плохом секторе или когда драйвер диска сообщает об ошибке, связанной с плохим сектором, NTFS выделяет новый кластер для замены того, который содержит плохой сектор. NTFS копирует данные, восстановленные диспетчером томов, в но вый кластер, чтобы снова добиться избыточности данных. На рис. 1254 показана запись MFT для пользовательского файла, в одном из групп которого имеется плохой сектор. Когда NTFS получает ошибку, свя занную с плохим сектором, она присоединяет содержащий его кластер к сво ему файлу плохих кластеров. Это предотвращает повторное выделение дан ного кластера другому файлу. Затем NTFS выделяет новый кластер и изменя ет сопоставление VCNLCN для файла так, чтобы оно указывало на этот клас тер. Данная процедура, известная как переназначение плохого кластера (bad cluster remapping), иллюстрируется на рис. 1255. Кластер номер 1357, содер жащий плохой сектор, заменяется новым кластером с номером 1049. Рис. 12-54. Запись MFT для пользовательского файла с плохим кластером Появление плохих секторов нежелательно, но когда они все же появля ются, лучшее решение предлагается NTFS в сочетании с диспетчером томов. Если плохой сектор находится на томе с избыточностью данных, диспетчер томов восстанавливает данные и замещает сектор, если это возможно. Если сектор заменить нельзя, диспетчер томов возвращает предупреждение NTFS, которая заменяет кластер с плохим сектором. Если том не сконфигурирован как отказоустойчивый, данные из плохого сектора восстановить нельзя. Когда том отформатирован для FAT и диспетчер томов не может восстановить данные, чтение из плохого сектора дает непред
820 ГЛ А В А 12 БЕЗОПАСНОСТЬ сказуемые результаты. Если в плохом секторе располагались какиелибо уп равляющие структуры файловой системы, может быть потерян целый файл или группа файлов (а иногда и весь диск). В лучшем случае будет потеряна часть данных файла (как правило, все файловые данные, расположенные в данном секторе и за ним). Более того, FAT скорее всего повторно выделит пло хой сектор под другой файл, в результате чего проблема возникнет снова. Рис. 12-55. Переназначение плохих кластеров Как и другие файловые системы, NTFS не может восстановить данные из плохого сектора без помощи диспетчера томов. Однако она значительно сокращает ущерб, который наносится появлением плохого сектора. Если NTFS обнаруживает плохой сектор в ходе операции чтения, она переназна чает кластер, как показано на рис. 1255. Если том не сконфигурирован для избыточного хранения информации, NTFS возвращает ошибку чтения вы зывающей программе. Хотя данные, находившиеся в этом кластере, теряют ся, остаток файла и сама файловая система сохраняются, вызывающая про грамма может соответствующим образом отреагировать на потерю данных, а плохой кластер больше не будет использоваться при распределении про странства на томе. Если NTFS обнаруживает плохой кластер во время запи
ГЛАВА 9 Файловые системы 821 си, а не чтения, она переназначает его до выполнения операции записи и тем самым вообще избегает потери данных. Та же процедура восстановления используется, когда в аварийном секто ре хранятся данные файловой системы. Если он находится на томе с избы точностью данных, NTFS динамически заменяет соответствующий кластер, используя данные, восстановленные диспетчером томов. Если том не избы точный, восстановить данные нельзя, и NTFS устанавливает в файле тома бит, указывающий, что том поврежден. При перезагрузке системы NTFSутилита Chkdsk проверяет этот бит и, если он установлен, исправляет повреждение файловой системы, реконструируя метаданные NTFS. Крайне редко повреждение файловой системы может произойти даже на отказоустойчивом томе: двойная ошибка способна разрушить и данные фай ловой системы, и информацию для их восстановления. Если авария систе мы происходит в тот момент, когда NTFS сохраняет, например, зеркальную копию записи MFT, индекса имен файлов или журнала транзакций, то зер кальная копия этих данных файловой системы обновляется не полностью. Если после перезагрузки системы ошибка, связанная с плохим сектором, возникает в том же месте основного диска, где находится частично записан ная зеркальная копия, NTFS не может восстановить информацию с зеркаль ного диска. Для детекции таких повреждений системных данных в NTFS ре ализована специальная схема. Если обнаружено нарушение целостности, в файле тома устанавливается бит повреждения, в результате чего при следу ющей загрузке системы метаданные NTFS будут реконструированы Chkdsk. Так как в отказоустойчивой дисковой конфигурации повреждение данных файловой системы маловероятно, потребность в Chkdsk возникает редко. Эта утилита позиционируется как дополнительная мера предосторожности, а не как основное средство восстановления информации. Использование Chkdsk в NTFS существенно отличается от ее использова ния в FAT. Перед записью на диск FAT устанавливает бит изменения тома, который сбрасывается по завершении модификации тома. Если сбой систе мы происходит при выполнении операции вывода, бит остается установлен ным, и после перезагрузки машины запускается Chkdsk. В NTFS утилита Chkdsk запускается, только когда обнаруживаются неожиданные или нечи таемые данные файловой системы и NTFS не может восстановить их с из быточного тома или из избыточных структур данных файловой системы на обычном томе. (Система дублирует загрузочный сектор, равно как и части MFT, необходимые для загрузки системы и выполнения процедуры восста новления NTFS. Эта избыточность гарантирует, что NTFS всегда сможет за грузиться и восстановить сама себя.) В таблицу 126 сведены данные о том, что происходит при появлении пло хого сектора на дисковом томе (отформатированном для одной из файловых систем Windows ) в различных ситуациях, описанных в данном разделе.
822 ГЛ А В А 12 Таблица 12-6. БЕЗОПАСНОСТЬ Сценарии восстановления данных NTFS Сценарий При наличии SCSI-диска, имеющего резервные секторы При наличии диска, отличного от SCSI, или SCSI-диска без резервных секторов1 Отказоустойчивый том2 1. Диспетчер томов восстанавливает данные 1. Диспетчер томов восстанавливает данные 2. Диспетчер томов выпол няет замену сектора (заме няет плохой сектор) 2. Диспетчер томов возвращает файловой системе данные и ошибку «плохой сектор» 3. Файловой системе не сообщается об ошибке 3. NTFS переназначает кластер Обычный том 1. Диспетчер томов не может 1. Диспетчер томов не может восстановить данные восстановить данные 2. Диспетчер томов возвра щает файловой системе ошибку «плохой сектор» 2. Диспетчер томов возвращает файловой системе ошибку «плохой сектор» 3. NTFS переназначает кластер; данные теряются3 3. NTFS переназначает кластер; данные теряются3 1 Диспетчер томов не может заменять секторы ни в одном из следующих случаев: 1) жесткие диски, отличные от SCSI, не поддерживают стандартный интерфейс для замены секторов; 2) некоторые жесткие диски не имеют аппаратной поддержки за мены секторов, a SCSIдиски, у которых она есть, могут со временем исчерпать весь резерв секторов. 2 Отказоустойчивым является том одного из следующих типов: зеркальный или RAID5. 3 При записи данные не теряются: NTFS переназначает кластер до выполнения записи. Если том, на котором появился плохой сектор, сконфигурирован как от казоустойчивый, а жесткий диск поддерживает замену секторов и его запас резервных секторов еще не исчерпан, то тип файловой системы (FAT или NTFS) не имеет значения. Диспетчер томов заменяет плохой сектор, не тре буя вмешательства со стороны пользователя или файловой системы. Если плохой сектор появился на жестком диске, не поддерживающем за мену секторов, то за переназначение плохого сектора или, как в случае NTFS, кластера, в котором находится плохой сектор, отвечает файловая система. FAT не умеет переназначать секторы или кластеры. Механизм EFS EFS (Encrypting File System) использует средства поддержки шифрования. При первом шифровании файла EFS назначает учетной записи пользователя, шиф рующего этот файл, криптографическую пару — закрытый и открытый клю чи. Пользователи могут шифровать файлы с помощью Windows Explorer; для этого нужно открыть диалоговое окно Properties (Свойства) применительно к нужному файлу, щелкнуть кнопку Advanced (Другие) и установить флажок
ГЛАВА 9 Файловые системы 823 Encrypt Contents To Secure Data (Шифровать содержимое для защиты данных), как показано на рис. 1256. Пользователи также могут шифровать файлы с помощью утилиты командной строки cipher. Windows автоматически шифру ет файлы в каталогах, помеченных зашифрованными. При шифровании фай ла EFS генерирует случайное число, называемое шифровальным ключом фай ла (file encryption key, FEK). EFS использует FEK для шифрования содержимо го файла по более стойкому варианту DES (Data Encryption Standard) — DESX (в Windows 2000), а также по DESX, 3DES (TripleDES) или AES (Advanced En cryption Standard) в Windows XP (Service Pack 1 и выше) и Windows Server 2003. EFS сохраняет FEK вместе с самим файлом, но FEK шифруется по алгоритму RSAшифрования на основе открытого ключа. После выполнения EFS этих действий файл защищен: другие пользователи не смогут расшифровать дан ные без расшифрованного FEK файла, а FEK они не смогут расшифровать без закрытого ключа пользователя — владельца файла. Стойкость алгоритмов шифрования FEK По умолчанию FEK шифруется в Windows 2000 и Windows XP по ал горитму DESX, а в Windows XP с Service Pack 1 (или выше) и Windows Server 2003 — по алгоритму AES. В версиях Windows, разрешенных к экспорту за пределы США, драйвер EFS реализует 56битный ключ шифрования DESX, тогда как в версии, подлежащей использованию только в США, и в версиях с пакетом для 128битного шифрования длина ключа DESX равна 128 битам. Алгоритм AES в Windows исполь зует 256битные ключи. Применение 3DES разрешает доступ к более длинным ключам, поэтому, если вам требуется более высокая стой кость FEK, вы можете включить шифрование 3DES одним из двух спо собов: как алгоритм шифрования для всех криптографических серви сов в системе или только для EFS. Чтобы 3DES стал алгоритмом шифрования для всех системных криптографических сервисов, запустите редактор локальной полити ки безопасности, введя secpol.msc в диалоговом окне Run (Запуск программы), и откройте узел Security Options (Параметры безопасно сти) под Local Policies (Локальные политики). Найдите параметр Sys tem Cryptography: Use FIPS Compliant Algorithms For Encryption, Hashing And Signing (Системная криптография: использовать FIPSсовмести мые алгоритмы для шифрования, хеширования и подписывания) и включите его. Чтобы активизировать 3DES только для EFS, создайте DWORDпа раметр HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\EFS\ AlgorithmID, присвойте ему значение 0x6603 и перезагрузите систему.
824 ГЛ А В А 12 БЕЗОПАСНОСТЬ Рис. 12-56. Шифрование файлов через пользовательский интерфейс Windows Explorer Для шифрования FEK используется алгоритм криптографической пары, а для шифрования файловых данных — DESX, AES или 3DES (все это алго ритмы симметричного шифрования, в которых применяется один и тот же ключ для шифрования и дешифрования). Как правило, алгоритмы симмет ричного шифрования работают очень быстро, что делает их подходящими для шифрования больших объемов данных, в частности файловых. Однако у алгоритмов симметричного шифрования есть одна слабая сторона: зашиф рованный ими файл можно вскрыть, получив ключ. Если несколько человек собирается пользоваться одним файлом, защищенным только DESX, AES или 3DES, каждому из них понадобится доступ к FEK файла. Очевидно, что неза шифрованный FEK — серьезная угроза безопасности. Но шифрование FEK все равно не решает проблему, поскольку в этом случае нескольким людям приходится пользоваться одним и тем же ключом расшифровки FEK. Защита FEK — сложная проблема, для решения которой EFS использует ту часть своей криптографической архитектуры, которая опирается на техноло гии шифрования с открытым ключом. Шифрование FEK на индивидуальной основе позволяет нескольким лицам совместно использовать зашифрован ный файл. EFS может зашифровать FEK файла с помощью открытого ключа каждого пользователя и хранить их FEK вместе с файлом. Каждый может по лучить доступ к открытому ключу пользователя, но никто не сможет расшиф ровать с его помощью данные, зашифрованные по этому ключу. Единствен ный способ расшифровки файла заключается в использовании операцион ной системой закрытого ключа. Закрытый ключ помогает расшифровать нуж ный зашифрованный экземпляр FEK файла. Алгоритмы на основе открытого ключа обычно довольно медленные, поэтому они используются EFS только для шифрования FEK. Разделение ключей на открытый и закрытый немного упрощает управление ключами по сравнению с таковым в алгоритмах сим метричного шифрования и решает дилемму, связанную с защитой FEK. Windows хранит закрытые ключи в подкаталоге Application Data\Micro soft\Crypto\RSA каталога профиля пользователя. Для защиты закрытых клю
ГЛАВА 9 Файловые системы 825 чей Windows шифрует все файлы в папке RSA на основе симметричного клю ча, генерируемого случайным образом; такой ключ называется мастерклю чом пользователя. Мастерключ имеет длину в 64 байта и создается стойким генератором случайных чисел. Мастерключ также хранится в профиле пользователя в каталоге Application Data\Microsoft\Protect и зашифровыва ется по алгоритму 3DES с помощью ключа, который отчасти основан на па роле пользователя. Когда пользователь меняет свой пароль, мастерключи автоматически расшифровываются, а затем заново зашифровываются с уче том нового пароля. Функциональность EFS опирается на несколько компонентов, как видно на схеме архитектуры EFS (рис. 1257). В Windows 2000 EFS реализована в виде драйвера устройства, работающего в режиме ядра и тесно связанного с драйвером файловой системы NTFS, но в Windows XP и Windows Server 2003 поддержка EFS включена в драйвер NTFS. Всякий раз, когда NTFS встре чает шифрованный файл, она вызывает функции EFS, зарегистрированные кодом EFS режима ядра в NTFS при инициализации этого кода. Функции EFS осуществляют шифрование и расшифровку файловых данных по мере об ращения приложений к шифрованным файлам. Хотя EFS хранит FEK вмес те с данными файла, FEK шифруется с помощью открытого ключа индиви дуального пользователя. Для шифрования или расшифровки файловых дан ных EFS должна расшифровать FEK файла, обращаясь к криптографическим сервисам пользовательского режима. Рис. 12-57. Архитектура EFS
826 ГЛ А В А 12 БЕЗОПАСНОСТЬ Подсистема локальной аутентификации (Local Security Authentication Subsystem, LSASS) (\Windows\System32\Lsass.exe) не только управляет сеан сами регистрации, но и выполняет все рутинные операции, связанные с уп равлением ключами EFS. Например, когда драйверу EFS требуется расшиф ровать FEK для расшифровки данных файла, к которому обращается пользо ватель, драйвер EFS посылает запрос LSASS через LPC. Драйвер устройства KSecDD (\Windows\System32\Drivers\Ksecdd.sys) экспортирует функции, не обходимые драйверам для посылки LPCсообщений LSASS. Компонент LSASS, сервер локальной аутентификации (Local Security Authentication Server, Lsasrv) (\Windows\System32\Lsasrv.dll), ожидает запросы на расшифровку FEK через RPC; расшифровка выполняется соответствующей функцией EFS, ко торая также находится в Lsasrv. Для расшифровки FEK, передаваемого LSASS драйвером EFS в зашифрованном виде, Lsasrv использует функции Microsoft CryptoAPI (CAPI). CryptoAPI состоит из DLL провайдеров криптографических сервисов (cryptographic service providers, CSP), которые обеспечивают приложениям доступ к различным криптографическим сервисам (шифрованию, дешиф рованию и хэшированию). Например, эти DLL управляют получением от крытого и закрытого ключей пользователя, что позволяет Lsasrv не заботить ся о деталях защиты ключей и даже об особенностях работы алгоритмов шифрования. EFS опирается на алгоритмы шифрования RSA, предоставляе мые провайдером Microsoft Enhanced Cryptographic Provider (\Windows\ System32\Rsaenh.dll). Расшифровав FEK, Lsasrv возвращает его драйверу EFS в ответном LPCсообщении. Получив расшифрованный FEK, EFS с помощью DESX расшифровывает данные файла для NTFS. Подробнее о том, как EFS взаимодействует с NTFS и как Lsasrv управляет ключами через CryptoAPI, мы поговорим в следующих разделах. Первое шифрование файла Обнаружив шифрованный файл, драйвер NTFS вызывает функции EFS. О состоянии шифрования файла сообщают его атрибуты — так же, как и о со стоянии сжатия в случае сжатых файлов. NTFS и EFS имеют специальные интерфейсы для преобразования файла из незашифрованной в зашифро ванную форму, но этот процесс протекает в основном под управлением ком понентов пользовательского режима. Как уже говорилось, Windows позво ляет шифровать файлы двумя способами: утилитой командной строки cipher или установкой флажка Encrypt Contents To Secure Data на вкладке Advanced Attributes окна свойств файла в Windows Explorer. Windows Explorer и cipher используют Windowsфункцию EncryptFile, экспортируемую Advapi32.dll (Advanced Windows API DLL). Чтобы получить доступ к API, который нужен для LPCвызова интерфейсов EFS в Lsasrv, Advapi32 загружает другую DLL, Feclient.dll (File Encryption Client DLL). Получив RPCсообщение с запросом на шифрование файла от Feclient, Lsasrv использует механизм олицетворения Windows для подмены собой пользователя, запустившего программу, шифрующую файл (cipher или Win
ГЛАВА 9 Файловые системы 827 dows Explorer). Это заставляет Windows воспринимать файловые операции, выполняемые Lsasrv, как операции, выполняемые пользователем, желающим зашифровать файл. Lsasrv обычно работает под учетной записью System (об этой учетной записи см. главу 8). Если бы Lsasrv не олицетворял пользова теля, то не получил бы прав на доступ к шифруемому файлу. Далее Lsasrv создает файл журнала в каталоге System Volume Information, где регистрирует ход процесса шифрования. Имя файла журнала — обыч но Efs0.log, но, если шифруется несколько файлов, 0 заменяется числом, ко торое последовательно увеличивается на 1 до тех пор, пока не будет полу чено уникальное имя журнала для текущего шифруемого файла. CryptoAPI полагается на информацию пользовательского профиля, хра нящуюся в реестре, поэтому, если профиль еще не загружен, следующий шаг Lsasrv — загрузка в реестр профиля олицетворяемого пользователя вызовом функции LoadUserProfile из Userenv.dll (User Environment DLL). Обычно про филь пользователя к этому моменту уже загружен, поскольку Winlogon за гружает его при входе пользователя в систему. Но если пользователь регис трируется под другой учетной записью с помощью команды RunAs, то при попытке обращения к зашифрованному файлу под этой учетной записью соответствующий профиль может быть не загружен. После этого Lsasrv генерирует для файла FEK, обращаясь к средствам шифрования RSA, реализованным в Microsoft Base Cryptographic Provider 1.0. Создание связок ключей К этому моменту Lsasrv уже получил FEK и может сгенерировать информа цию EFS, сохраняемую вместе с файлом, включая зашифрованную версию FEK. Lsasrv считывает из параметра реестра HKCU\Software\Microsoft\Win dows NT\CurrentVersion\EFS\CurrentKeys\CertificateHash значение, присвоен ное пользователю, который затребовал операцию шифрования, и получает сигнатуру открытого ключа этого пользователя. (Заметьте, что этот раздел не появляется в реестре, если ни один файл или каталог не зашифрован.) Lsasrv использует эту сигнатуру для доступа к открытому ключу пользовате ля и для шифрования FEK. Теперь Lsasrv может создать информацию, которую EFS сохранит вместе с файлом. EFS хранит в шифрованном файле только один блок информации, в котором содержатся записи для всех пользователей этого файла. Данные записи называются элементами ключей (key entries); они хранятся в облас ти сопоставленных с файлом данных EFS, которая называется Data Decryp tion Field (DDF). Совокупность нескольких элементов ключей называется связкой ключей (key ring), поскольку, как уже говорилось, EFS позволяет не скольким лицам совместно использовать шифрованный файл. Формат данных EFS, сопоставленных с файлом, и формат элемента клю ча показан на рис. 1258. В первой части элемента ключа EFS хранит инфор мацию, достаточную для точного описания открытого ключа пользователя. В нее входит SID пользователя (его наличие не гарантируется), имя контей нера, в котором хранится ключ, имя провайдера криптографических серви
828 ГЛ А В А 12 БЕЗОПАСНОСТЬ сов и хэш сертификата криптографической пары (при расшифровке ис пользуется только этот хэш). Во второй части элемента ключа содержится шифрованная версия FEK. Lsasrv шифрует FEK через CryptoAPI по алгорит му RSA с применением открытого ключа данного пользователя. Рис. 12-58. Формат информации EFS и элемента ключа Далее Lsasrv создает еще одну связку ключей, содержащую элементы клю чей восстановления (recovery key entries). EFS хранит информацию об этих элементах в поле DRF файла (см. рис. 1258). Формат элементов DRF иден тичен формату DDF. DRF служит для расшифровки пользовательских данных по определенным учетным записям (агентов восстановления) в тех случаях, когда администратору нужен доступ к пользовательским данным. Допустим, сотрудник компании забыл свой пароль для входа в систему. В этом случае администратор может сбросить пароль этого сотрудника, но без агентов восстановления никто не сумеет восстановить его зашифрованные данные. Агенты восстановления (Recovery Agents) определяются в политике безо пасности Encrypted Data Recovery Agents (Агенты восстановления шифрован ных данных) на локальном компьютере или в домене. Эта политика доступ на через оснастку Group Policy (Групповая политика) консоли MMC. Запус тите Recovery Agent Wizard (Мастер добавления агента восстановления), щелкнув правой кнопкой мыши строку Encrypted Data Recovery Agents (рис. 1259) и последовательно выбрав команды New (Создать) и Encrypted Recovery Agent (Агент восстановления шифрованных данных). Вы можете добавить агенты восстановления и указать, какие криптографические пары (обозначенные их сертификатами) могут использовать эти агенты для вос становления шифрованных данных. Lsasrv интерпретирует политику восста новления в процессе своей инициализации или при получении уведомления об изменении политики восстановления. EFS создает DRFэлементы ключей для каждого агента восстановления, используя провайдер криптографичес ких сервисов, зарегистрированный для EFSвосстановления. Провайдером по умолчанию служит Base Cryptographic Provider 1.0.
ГЛАВА 9 Файловые системы 829 Рис. 12-59. Групповая политика Encrypted Data Recovery Agents (Агенты восстановления шифрованных данных) На завершающем этапе создания информации EFS для файла Lsasrv вы числяет контрольную сумму для DDF и DRF по механизму хэширования MD5 из Base Cryptographic Provider 1.0. Lsasrv хранит вычисленную контрольную сумму в заголовке данных EFS. EFS ссылается на эту сумму при расшифров ке, чтобы убедиться в том, что сопоставленные с файлом данные EFS не по вреждены и не взломаны. Шифрование файловых данных Ход процесса шифрования показан на рис. 1260. После создания всех дан ных, необходимых для шифруемого пользователем файла, Lsasrv приступа ет к шифрованию файла и создает его резервную копию, Efs0.tmp (если есть другие резервные копии, Lsasrv просто увеличивает номер в имени резерв ного файла). Резервная копия помещается в тот каталог, где находится шиф руемый файл. Lsasrv применяет к резервной копии ограничивающий де скриптор защиты, так что доступ к этому файлу можно получить только по учетной записи System. Далее Lsasrv инициализирует файл журнала, создан ный им на первом этапе процесса шифрования и регистрирует в нем факт создания резервного файла. Lsasrv шифрует исходный файл только после его резервирования. Наконец, Lsasrv посылает через NTFS коду EFS режима ядра команду на добавление к исходному файлу созданной информации EFS. В Windows 2000 NTFS получает эту команду, но поскольку она не понимает команд EFS, то просто вызывает драйвер EFS. Код EFS режима ядра принимает посланные Lsasrv данные EFS и применяет их к файлу через функции, экспортируемые NTFS. Эти функции позволяют EFS добавлять к NTFSфайлам атрибут $EFS. После этого управление возвращается к Lsasrv, который копирует содержи мое шифруемого файла в резервный. Закончив создание резервной копии (в том числе скопировав все дополнительные потоки данных), Lsasrv отме чает в файле журнала, что резервный файл находится в актуальном состоя нии. Затем Lsasrv посылает NTFS другую команду, требуя зашифровать содер жимое исходного файла.
830 ГЛ А В А 12 Рис. 12-60. БЕЗОПАСНОСТЬ Схема работы EFS Получив от EFS команду на шифрование файла, NTFS удаляет содержимое исходного файла и копирует в него данные резервного. По мере копирова ния каждого раздела файла NTFS сбрасывает данные раздела из кэша фай ловой системы, и они записываются на диск. Поскольку файл помечен как шифрованный, NTFS вызывает EFS для шифрования раздела данных перед записью на диск. EFS использует незашифрованный FEK, переданный NTFS, чтобы шифровать файловые данные по алгоритму DESX, AES или 3DES пор циями, равными по размеру одному сектору (512 байтов). После того как файл зашифрован, Lsasrv регистрирует в файле журнала, что шифрование успешно завершено, и удаляет резервную копию файла. В заключение Lsasrv удаляет файл журнала и возвращает управление приложе нию, запросившему шифрование файла. Сводная схема процесса шифрования Ниже приведен сводный список этапов шифрования файла через EFS. 1. Загружается профиль пользователя, если это необходимо. 2. В каталоге System Volume Information создается файл журнала с именем Efsx.log, где x — уникальное целое число от 0. По мере выполнения сле дующих этапов в журнал заносятся записи, позволяющие восстановить файл после сбоя системы в процессе шифрования. 3. Base Cryptographic Provider 1.0 генерирует для файла случайное 128бит ное число, используемое в качестве FEK. 4. Генерируется или считывается криптографическая пара ключей пользо вателя. Она идентифицируется в HKCU\Software\Microsoft\Windows NT\ CurrentVersion\EFS\CurrentKeys\CertificateHash.
ГЛАВА 9 Файловые системы 831 5. Для файла создается связка ключей DDF с элементом для данного пользо вателя. Этот элемент содержит копию FEK, зашифрованную с помощью открытого EFSключа пользователя. 6. Для файла создается связка ключей DRF. В нем есть элементы для каждого агента восстановления в системе, и при этом в каждом элементе содержит ся копия FEK, зашифрованная с помощью открытого EFSключа агента. 7. Создается резервный файл с именем вида Efs0.tmp в том каталоге, где находится и шифруемый файл. 8. Связки ключей DDF и DRF добавляются к заголовку и сопоставляются с файлом как атрибут EFS. 9. Резервный файл помечается как шифрованный, и в него копируется со держимое исходного файла. 10. Содержимое исходного файла уничтожается, в него копируется содержи мое резервного. В результате этой операции данные исходного файла шифруются, так как теперь файл помечен как шифрованный. 11. Удаляется резервный файл. 12. Удаляется файл журнала. 13. Выгружается профиль пользователя (загруженный на этапе 1). При сбое системы во время шифрования согласованные данные непремен но сохранятся в одном из файлов — исходном или резервном. Когда Lsasrv инициализируется после сбоя системы, он ищет файлы журнала в каталоге System Volume Information на каждом NTFSтоме в системе. Если Lsasrv нахо дит один или несколько файлов журнала, он изучает их содержимое и опре деляет порядок восстановления. Если исходный файл не был модифицирован на момент аварии, Lsasrv удаляет файл журнала и соответствующий резервный файл; в ином случае он копирует резервный файл поверх исходного (частич но шифрованного) файла, после чего удаляет журнал и резервную копию. После того как Lsasrv обработает файлы журналов, файловая система возвра щается в целостное состояние без потери пользовательских данных. Процесс расшифровки Процесс расшифровки начинается, когда пользователь открывает шифро ванный файл. При открытии файла NTFS анализирует его атрибуты и выпол няет функцию обратного вызова в драйвере EFS. Драйвер EFS считывает ат рибут $EFS, сопоставленный с шифрованным файлом. Чтобы прочитать этот атрибут, драйвер вызывает функции поддержки EFS, которые NTFS экспор тирует для EFS. NTFS выполняет все необходимые действия, чтобы открыть файл. Драйвер EFS проверяет наличие у пользователя, открывающего файл, прав доступа к данным шифрованного файла (т. е. зашифрованный FEK в связке ключей DDF или DRF должен соответствовать криптографической паре ключей, сопоставленной с пользователем). После такой проверки EFS получает расшифрованный FEK файла, применяемый для обработки данных в операциях, которые пользователь может выполнять над файлом.
832 ГЛ А В А 12 БЕЗОПАСНОСТЬ EFS не может расшифровать FEK самостоятельно и полагается в этом на Lsasrv (который может использовать CryptoAPI). С помощью драйвера Kse cdd.sys EFS посылает LPCсообщение Lsasrv, чтобы тот извлек из атрибута $EFS (т. е. из данных EFS) FEK пользователя, открывающего файл, и расшиф ровал его. Получив LPCсообщение, Lsasrv вызывает функцию LoadUserProfile из Use renv.dll для загрузки в реестр профиля пользователя, если он еще не загружен. Lsasrv перебирает все поля ключей в данных EFS, пробуя расшифровать каж дый FEK на основе закрытого ключа пользователя; с этой целью Lsasrv пыта ется расшифровать FEK в DDF или DRFэлементе ключа. Если хэш сертифи ката в поле ключа не подходит к ключу пользователя, Lsasrv переходит к сле дующему полю ключа. Если Lsasrv не удастся расшифровать ни одного FEK в DDF или DRF, пользователь не получит FEK файла, и EFS запретит доступ к файлу приложению, которое пыталось открыть этот файл. А если Lsasrv най дет какойнибудь хэш, который соответствует ключу пользователя, он рас шифрует FEK по закрытому ключу пользователя через CryptoAPI. Lsasrv, обрабатывая при расшифровке FEK связки ключей DDF и DRF, ав томатически выполняет операции восстановления файла. Если к файлу пы тается получить доступ агент восстановления, не зарегистрированный на доступ к шифрованному файлу (т. е. у него нет соответствующего поля в связ ке ключей DDF), EFS позволит ему обратиться к файлу, потому что агент имеет доступ к паре ключей для поля ключа в связке ключей DRF. Кэширование расшифрованного FEK Путь от драйвера EFS до Lsasrv и обратно требует довольно много времени — в процессе расшифровки FEK в типичной системе CryptoAPI использует ре зультаты более 2000 вызовов APIфункций реестра и 400 обращений к файловой системе. Чтобы сократить издержки от всех этих вызовов, драй вер EFS использует кэш в паре с NTFS. Расшифровка файловых данных Открыв шифрованный файл, приложение может читать и записывать его данные. Для расшифровки файловых данных NTFS вызывает драйвер EFS по мере чтения этих данных с диска — до того, как помещает их в кэш файло вой системы. Аналогичным образом, когда приложение записывает данные в файл, они остаются незашифрованными в кэше файловой системы, пока приложение или диспетчер кэша не сбросит данные обратно на диск с по мощью NTFS. При записи данных шифрованного файла из кэша на диск NTFS вызывает драйвер EFS, чтобы зашифровать их. Как уже говорилось, драйвер EFS выполняет шифрование и расшифровку данных порциями по 512 байтов. Такой размер оптимален для драйвера, пото му что объем данных при операциях чтения и записи кратен размеру сектора.
ГЛАВА 9 Файловые системы 833 Резервное копирование шифрованных файлов Важный аспект разработки любого механизма шифрования файлов заклю чается в том, что приложения не могут получить доступ к расшифрованным данным иначе, чем через механизмы шифрования. Это ограничение особен но важно для утилит резервного копирования, с помощью которых файлы сохраняются на архивных носителях. EFS решает эту проблему, предостав ляя утилитам резервного копирования механизм, с помощью которого они могут создавать резервные копии файлов и восстанавливать их в шифрован ном виде. Таким образом, утилитам резервного копирования не обязатель но шифровывать или расшифровывать данные файлов в процессе резерв ного копирования. Для доступа к шифрованному содержимому файлов утилиты резервного копирования в Windows используют новый EFS API: функции OpenEncrypted FileRaw, ReadEncryptedFileRaw, WriteEncryptedFileRaw и CloseEncryptedFileRaw. Эти функции, предоставляемые Advapi32.dll, вызывают соответствующие функции Lsasrv по механизму LPC. Например, после того как утилита резерв ного копирования открывает файл, она вызывает ReadEncryptedFileRaw, что бы получить данные. Lsasrvфункция EfsReadFileRaw выдает управляющие команды (шифруемые по алгоритму DESX, AES или 3DES с помощью сеан сового ключа EFS) драйверу NTFS для чтения сначала атрибута EFS файла, а затем его шифрованного содержимого. EfsReadFileRaw может понадобиться несколько операций чтения, чтобы считать большой файл. По мере того как EfsReadFileRaw считывает очеред ную порцию файла, Lsasrv посылает Advapi32.dll RPCсообщение, в резуль тате которого выполняется функция обратного вызова, указанная програм мой резервного копирования при вызове ReadEncryptedFileRaw. Функция EfsReadFileRaw передает считанные шифрованные данные функции обрат ного вызова, которая записывает их на архивный носитель. Восстанавлива ются шифрованные файлы аналогичным образом. Программа резервного копирования вызывает APIфункцию WriteEncryptedFileRaw, которая активи зирует функцию обратного вызова программы резервного копирования для получения нешифрованных данных с архивного носителя, в то время как Lsasrvфункция EfsWriteFileRaw восстанавливает содержимое файла. ЭКСПЕРИМЕНТ: просмотр информации EFS EFS поддерживает массу других APIфункций, с помощью которых приложения могут манипулировать шифрованными файлами. Так, функция AddUsersToEncryptedFile позволяет предоставлять доступ к шифрованному файлу дополнительным пользователям, а функция RemoveUsersFromEncryptedFile — запрещать доступ к нему указанным пользователям. Функция QueryUsersOnEncryptedFile сообщает о сопо ставленных с файлом полях ключей DDF и DRF. Она возвращает SID, хэш сертификата и содержимое каждого поля ключа DDF и DRF. Ниже приведен образец вывода утилиты EFSDump (www.sysinternals.com). см. след. стр.
834 ГЛ А В А 12 БЕЗОПАСНОСТЬ В качестве параметра ее командной строки указано имя шифрованно го файла. C:\>efsdump test.txt EFS Information Dumper v1.02 Copyright (C) 1999 Mark Russinovich Systems Internals – http://www.sysinternals.com test.txt: DDF Entry: DARYL\Mark: CN=Mark,L=EFS,OU=EFS File Encryption Certificate DRF Entry: DARYL\Administrator OU=EFS File Encryption Certificate, L=EFS, CN=Administrator Как видите, в файле test.txt имеется один элемент DDF, соответству ющий пользователю Mark, и один элемент DRF, соответствующий Ad ministrator, который является единственным агентом восстановления, зарегистрированным в системе на данный момент. Чтобы убедиться в наличии атрибута $EFS в зашифрованном фай ле, используйте утилиту Nfi из OEM Support Tools: C:\>nfi test.txt NTFS File Sector Information Utility.Copyright (C) Microsoft Corporation 1999. All rights reserved. \Temp\README.TXT $STANDARD_INFORMATION (resident) $FILE_NAME (resident) $DATA (nonresident) logical sectors 27281242728135 (0x29a0bc0x29a0c7) Attribute Type 0x100 $EFS (nonresident) logical sectors 21569842156987 (0x20e9b80x20e9bb) Резюме Windows поддерживает широкий спектр форматов файловых систем, до ступных как локальной системе, так и удаленным клиентам. Архитектура драйвера фильтра файловой системы позволяет корректно расширять и до полнять средства доступа к файловой системе, а NTFS является надежным, безопасным и масштабируемым форматом файловой системы. В следующей главе мы рассмотрим поддержку сетей в Windows.
Г Л А В А 1 3 Поддержка сетей Windows создавалась с учетом необходимости работы в сети, поэтому в опе рационную систему включена всесторонняя поддержка сетей, интегриро ванная с подсистемой вводавывода и Windows API. К четырем базовым ти пам сетевого программного обеспечения относятся сервисы, API, протоко лы и драйверы устройств сетевых адаптеров. Все они располагаются один над другим, образуя сетевой стек. Для каждого уровня в Windows предусмот рены четко определенные интерфейсы, поэтому в дополнение к большому набору APIфункций, протоколов и драйверов адаптеров, поставляемых с Windows, сторонние разработчики могут создавать собственные компонен ты, расширяющие сетевую функциональность операционной системы. В этой главе будет рассмотрен весь сетевой стек Windows — снизу довер ху. Сначала мы поговорим о том, как сетевые компоненты Windows соотно сятся с уровнями эталонной модели OSI (Open Systems Interconnection). Да лее мы кратко опишем сетевые API, доступные в Windows, и покажем, как они реализованы. Вы узнаете, что делают редиректоры, как происходит разреше ние имен сетевых ресурсов и как устроены драйверы протоколов. Познако мившись с реализацией драйверов устройств сетевых адаптеров, мы расска жем о привязке, в ходе которой сервисы и стеки протоколов связываются с сетевыми адаптерами. Сетевая архитектура Windows Задача сетевого программного обеспечения состоит в приеме запроса (обычно на вводвывод) от приложения на одной машине, передаче его на другую, выполнении запроса на удаленной машине и возврате результата на первую машину. В ходе этих операций запрос неоднократно трансформи руется. Высокоуровневый запрос вроде «считать х байтов из файла у на ма шине z» требует, чтобы программное обеспечение определило, как достичь машины z и какой коммуникационный протокол она понимает. Затем за прос должен быть преобразован для передачи по сети — например, разбит на короткие пакеты данных. Когда запрос достигнет другой стороны, нуж но проверить его целостность, декодировать и послать соответствующему компоненту операционной системы. По окончании обработки запрос дол жен быть закодирован для обратной передачи по сети.
836 ГЛ А В А 13 БЕЗОПАСНОСТЬ Эталонная модель OSI Чтобы помочь поставщикам в стандартизации и интеграции их сетевого программного обеспечения, международная организация по стандарти зации (ISO) определила программную модель пересылки сообщений между компьютерами. Эта модель получила название эталонной модели OSI (Open Systems Interconnection). В ней определено семь уровней программного обеспечения (рис. 131). Рис. 13-1. Эталонная модель OSI Эталонная модель OSI — идеал, точно реализованный лишь в очень не многих системах, но часто используемый при объяснении основных прин ципов работы сети. Каждый уровень на одной из машин считает, что он вза имодействует с тем же уровнем на другой машине. На данном уровне обе машины «разговаривают» на одном языке, или протоколе. Но в действитель ности сетевой запрос должен сначала пройти до самого нижнего уровня на первой машине, затем он передается по несущей среде и уже на второй ма шине вновь поднимается до уровня, который его поймет и обработает. Задача каждого уровня в том, чтобы предоставлять сервисы более высо ким уровням и скрывать от них конкретную реализацию этих сервисов. Подробное обсуждение каждого сетевого уровня выходит за рамки нашей книги, но мы все же дадим их краткое описание. 쐽 Прикладной уровень (application layer) Обрабатывает передачу данных между двумя сетевыми приложениями, включая проверку прав доступа, идентификацию взаимодействующих машин и инициацию об мена данными. 쐽 Презентационный уровень (presentation layer) Отвечает за форма тирование данных, в том числе решает, должны ли строки заканчиваться па рой символов «возврат каретки/перевод строки» (CR/LF) или только симво лом «возврат каретки» (CR), надо ли сжимать данные, кодировать и т. д. 쐽 Сеансовый уровень (session layer) Управляет соединением взаимо действующих приложений, включая высокоуровневую синхронизацию и контроль за тем, какое из них «говорит», а какое «слушает». 쐽 Транспортный уровень (transport layer) На передающей стороне разбивает сообщения на пакеты и присваивает им порядковые номера, га
ГЛАВА 9 Поддержка сетей 837 рантирующие прием пакетов в должном порядке. Кроме того, изолирует сеансовый уровень от влияния изменений в составе оборудования. 쐽 Сетевой уровень (network layer) Создает заголовки пакетов, отвеча ет за маршрутизацию, контроль трафика и взаимодействие с межсетевой средой. Это самый высокий из уровней, который понимает топологию се тей, т. е. физическую конфигурацию машин в них, ограничения пропуск ной способности этих сетей и т. д. 쐽 Канальный уровень (datalink layer) Пересылает низкоуровневые кадры данных, ждет подтверждений об их приеме и повторяет передачу кадров, потерянных в ненадежных линиях связи. 쐽 Физический уровень (physical layer) Передает биты по сетевому ка белю или другой физической несущей среде. Как уже говорилось, каждый сетевой уровень считает, что он взаимодей ствует с эквивалентным уровнем на другой машине, который использует тот же протокол. Набор протоколов, передающих запросы по сетевым уровням, называется стеком протоколов. Сетевые компоненты Windows На рис. 132 представлена общая схема сетевых компонентов Windows, их соответствие уровням модели OSI, а также протоколы, используемые раз личными уровнями. Как видите, между уровнями OSI и реальными сетевы ми компонентами нет точного соответствия. Некоторые компоненты охва тывают несколько уровней. Ниже приводится список сетевых компонентов с кратким описанием. 쐽 Сетевые API Обеспечивают независимое от протоколов взаимодействие приложений через сеть. Сетевые API реализуются либо в режиме ядра и пользовательском режиме, либо только в пользовательском режиме. Неко торые сетевые API являются оболочками других API и реализуют специфи ческую модель программирования или предоставляют дополнительные сервисы. (Термином «сетевые API» обозначаются любые программные ин терфейсы, предоставляемые сетевым программным обеспечением.) 쐽 Клиенты TDI (Transport Driver Interface) Драйверы устройств ре жима ядра, обычно реализующие ту часть сетевого API, которая работает в режиме ядра. Клиенты TDI называются так изза того, что пакеты зап росов вводавывода (IRP), которые они посылают драйверам протоколов, форматируются по стандарту Transport Driver Interface (документирован ному в DDK). Этот стандарт определяет общий интерфейс программиро вания драйверов устройств режима ядра. (Об IRP см. главу 9.) 쐽 Транспорты TDI Представляют собой драйверы протоколов режима ядра и часто называются транспортами, NDISдрайверами протоколов или драйверами протоколов. Они принимают IRP от клиентов TDI и об рабатывают запросы, представленные этими IRP. Обработка запросов может потребовать взаимодействия через сеть с другим равноправным
838 ГЛ А В А 13 БЕЗОПАСНОСТЬ компьютером; в таком случае транспорт TDI добавляет к данным IRP за головки, специфичные для конкретного протокола (TCP, UDP, IPX), и вза имодействует с драйверами адаптеров через функции NDIS (также доку ментированные в DDK). В общем, транспорты TDI связывают приложе ния через сеть, выполняя такие операции, как сегментация сообщений, их восстановление, упорядочение, подтверждение и повторная передача. 쐽 Библиотека NDIS (Ndis.sys) Инкапсулирует функциональность для драйверов адаптеров, скрывая от них специфику среды Windows, рабо тающей в режиме ядра. Библиотека NDIS экспортирует функции для транспортов TDI, а также функции поддержки для драйверов адаптеров. Рис. 13-2. Модель OSI и сетевые компоненты Windows 쐽 Минипортдрайверы NDIS Драйверы режима ядра, отвечающие за организацию интерфейсов между транспортами TDI и конкретными се тевыми адаптерами. Минипортдрайверы NDIS пишутся так, чтобы они были заключены в оболочку библиотеки NDIS. Такая инкапсуляция обес печивает межплатформенную совместимость с потребительскими вер сиями Microsoft Windows. Минипортдрайверы NDIS не обрабатывают IRP, а регистрируют интерфейс таблицы вызовов библиотеки NDIS, которая
ГЛАВА 9 Поддержка сетей 839 содержит указатели на функции, соответствующие функциям, экспорти руемым библиотекой NDIS для транспортов TDI. Минипортдрайверы NDIS взаимодействуют с сетевыми адаптерами, используя функции биб лиотеки NDIS, которые вызывают соответствующие функции HAL. Фактически четыре нижних сетевых уровня часто обозначают собиратель ным термином «транспорт», а компоненты, расположенные на трех верхних уровнях, — термином «пользователи транспорта». Далее мы подробно рассмотрим сетевые компоненты, показанные на рис. 132 (равно как и не показанные на нем), обсудим их взаимосвязи и то место, которое они занимают в Windows. Сетевые API Для поддержки унаследованных приложений и для совместимости с про мышленными стандартами в Windows реализован целый набор сетевых API. В этом разделе мы расскажем о сетевых API и поясним, как они используются приложениями. Важно иметь в виду, что выбор API для приложения опреде ляется характеристиками API: поверх каких протоколов он может работать, поддерживает ли он надежную и двустороннюю связь, а также переносим ли он на другие Windowsплатформы, на которых может работать данное при ложение. Мы обсудим следующие сетевые API: 쐽 Windows Sockets (Winsock); 쐽 Remote Procedure Call (RPC); 쐽 API доступа к Web; 쐽 именованные каналы (named pipes) и почтовые ящики (mailslots); 쐽 NetBIOS: 쐽 прочие сетевые API. Windows Sockets Изначально Windows Sockets (Winsock) версии 1.0 был Microsoftреализаци ей BSD (Berkeley Software Distribution) Sockets, программного интерфейса, с 80х годов прошлого века ставшего стандартом, на основе которого UNIX системы взаимодействовали через Интернет. Поддержка сокетов в Win dows существенно упрощает перенос сетевых приложений из UNIX в Win dows. Современные версии Winsock включают большую часть функциональ ности BSD Sockets, а также содержат специфические расширения от Micro soft, развитие которых продолжается. Winsock поддерживает как надежные коммуникации, ориентированные на логические соединения, так и ненадеж ные коммуникации, не требующие логических соединений. Windows предо ставляет Winsock 2.2 — для устаревших версий Windows он доступен в виде надстройки. Функциональность Winsock 2.2 выходит далеко за рамки специ фикации BSD Sockets, и, в частности, он поддерживает функции, использу ющие средства асинхронного вводавывода в Windows, что обеспечивает
840 ГЛ А В А 13 БЕЗОПАСНОСТЬ гораздо более высокую производительность и масштабируемость, чем ис ходный BSD Sockets. Winsock обеспечивает: 쐽 вводвывод по механизму «scatter/gather» и асинхронный вводвывод; 쐽 поддержку Quality of Service (QoS) — если нижележащая сеть поддержи вает QoS, приложения могут согласовывать между собой максимальные задержки и полосы пропускания; 쐽 расширяемость — Winsock можно использовать не только с протокола ми, которые он поддерживает в Windows, но и с другими; 쐽 поддержку интегрированных пространств имен, отличных от определен ных протоколом, который используется приложением вместе с Winsock. Например, сервер может опубликовать свое имя в Active Directory, а кли ент, используя расширения пространств имен, — найти адрес сервера в Active Directory; 쐽 поддержку многоадресных сообщений, передаваемых из одного источ ника сразу нескольким адресатам. Далее мы рассмотрим принципы работы Winsock и опишем способы его расширения. Функционирование Winsock на клиентской стороне Первый шаг Winsockприложения — инициализация Winsock API вызовом инициализирующей функции. В Windows 2000 такое приложение должно затем создать сокет, представляющий конечную точку коммуникационного соединения. Приложение получает адрес сервера, к которому ему нужно подключиться, вызовом gethostbyname. Winsock не зависит от конкретного протокола, поэтому адрес может быть указан по любому установленному в системе протоколу, поверх которого работает Winsock (TCP/IP, TCP/IP с IP версии 6, IPX). Получив адрес сервера, клиент, ориентированный на логичес кие соединения (connectionoriented client), пытается подключиться к это му серверу, вызывая функцию connect и передавая ей адрес сервера. В Windows XP и Windows Server 2003 приложение должно получить ад рес сервера через getaddrinfo, а не gethostbyname. Функция getaddrinfo возвра щает список адресов, назначенных серверу, и клиент пытается поочередно подключиться по каждому из них до тех пор, пока ему не удастся установить соединение. Это гарантирует, что клиент, поддерживающий, например, толь ко IP версии 4 (IPv4), соединится с сервером, которому могли быть назна чены как IPv4, так и IPv6адреса, по соответствующему IPv4адресу. Установив соединение, клиент может посылать и принимать данные че рез свой сокет, используя, например, recv и send. Клиент, не ориентирован ный на логические соединения (connectionless client), указывает удаленный адрес через эквивалентные функции API, не ориентированного на логичес кие соединения; в данном случае — через sendto и recvfrom соответственно.
ГЛАВА 9 Поддержка сетей 841 Функционирование Winsock на серверной стороне Последовательность операций серверного приложения отличается от тако вой для клиентского. После инициализации Winsock API сервер создает со кет и выполняет его привязку к локальному адресу через bind. Как и в слу чае клиентского приложения, тип адреса (по TCP/IP, TCP/IP с IP версии 6 или какомуто другому протоколу) выбирается серверным приложением. Если сервер ориентирован на логические соединения, он выполняет на сокете операцию listen, указывая число соединений, которое он может под держивать на этом сокете. Далее он выполняет операцию accept, чтобы кли ент мог подключиться к сокету. При наличии ждущего запроса на соедине ние вызов accept завершается немедленно. В ином случае он завершается лишь после поступления запроса на соединение. После того как соединение установлено, функция accept возвращает новый сокет, представляющий сер верную сторону соединения. Сервер может выполнять операции приема и передачи данных с помощью таких функций, как, например, recv и send. Рис. 133 иллюстрирует коммуникационную связь между клиентом и серве ром Winsock, ориентированными на логические соединения. Рис. 13-3. Так работает Winsock при использовании логических соединений После привязки к адресу сервер, не требующий логических соединений, ничем не отличается от аналогичного клиента: он посылает и получает дан ные через сокет, просто указывая удаленный адрес для каждой операции. Большинство протоколов, не ориентированных на логические соединения, ненадежны и, как правило, не позволяют определить, получил ли адресат отправленные ему пакеты данных — дейтаграммы (datagrams). Такие про токолы идеальны для передачи коротких сообщений, когда надежность до ставки не играет определяющей роли (впрочем, приложение может само ре ализовать соответствующие средства поверх протокола). Расширения Winsock С точки зрения программирования для Windows, сильной стороной Winsock API является его интеграция с механизмом Windowsсообщений. Winsock приложение может использовать преимущества такой интеграции для вы полнения асинхронных операций с сокетом и приема уведомления о завер шении операции через стандартное Windowsсообщение или функцию об ратного вызова. Это упрощает разработку Windowsприложений, посколь
842 ГЛ А В А 13 БЕЗОПАСНОСТЬ ку позволяет отказаться от многопоточности и синхронизирующих объек тов для поддержки сетевого вводавывода и реакции на пользовательский ввод или запросы диспетчера окон на обновление окон приложения. Кроме вспомогательных функций, прямо соответствующих функциям, реализованным в BSD Sockets, Microsoft добавила несколько функций, не входящих в стандарт Winsock. Две из них, AcceptEx и TransmitFile, стоят того, чтобы привести здесь их описание, так как благодаря им многие Webсер веры под управлением Windows достигают высокой производительности. AcceptEx является версией функции accept, которая в процессе установления соединения с клиентом возвращает адрес и первое сообщение клиента. Ac ceptEx дает возможность серверному приложению подготовиться к серии операций accept для последующей обработки множества входящих соедине ний. А это позволяет Webсерверу избежать выполнения сразу нескольких Winsockфункций. Установив соединение с клиентом, Webсервер обычно посылает ему файл, например Webстраницу. Реализация функции TransmitFile интегриро вана с диспетчером кэша, что позволяет серверу посылать файл непосред ственно из кэша файловой системы. Такая пересылка данных называется нулевым копированием (zerocopy), поскольку в этом случае серверу не при ходится обращаться к файловым данным: он просто указывает описатель файла и диапазон пересылаемых байтов. Кроме того, функция TransmitFile позволяет серверу присоединять к началу или концу файла дополнительные данные. Это дает ему возможность посылать заголовочную информацию, например имя Webсервера и поле, в котором указывается размер посылае мого сообщения. Internet Information Services (IIS), входящая в комплект по ставки Windows, использует как AcceptEx, так и TransmitFile. В Windows XP и Windows Server 2003 добавлен целый набор других, много функциональных APIфункций, в том числе ConnectEx, DisconnectEx и Trans mitPackets. ConnectEx устанавливает соединение и посылает первое сообще ние по этому соединению. DisconnectEx закрывает соединение и разрешает повторное использование описателя сокета, представляющего данное соеди нение, в вызове AcceptEx или ConnectEx. Наконец, TransmitPackets — полный аналог TransmitFile с тем исключением, что позволяет передавать не только файловые данные, но и данные, находящиеся в памяти. Принципы расширения Winsock Winsock является расширяемым API, поскольку сторонние разработчики могут добавлять провайдеры транспортных сервисов (transport service pro viders, TSP), организующие интерфейсы между Winsock и другими протоко лами или уровнями поверх существующих протоколов (это позволяет реа лизовать такую функциональность, как поддержка прокси). Сторонние раз работчики также могут добавлять провайдеры пространств имен (name space service providers), дополняющие механизмы разрешения имен в Win sock. Такие компоненты подключаются к Winsock через его интерфейс про вайдеров сервисов (service provider interface, SPI). Если какойто TSP регист
ГЛАВА 9 Поддержка сетей 843 рируется в Winsock, последний реализует на его основе функции сокета (вроде connect и accept) для тех типов адресов, которые указаны этим про вайдером как поддерживаемые. Никаких ограничений на то, как TSP реали зует функции, не налагается, но такая реализация обычно требует взаимо действия с драйвером транспорта в режиме ядра. Требование к любому клиентсерверному приложению, использующему Winsock, заключается в следующем: сервер должен сделать свой адрес дос тупным клиентам, чтобы они могли подключаться к серверу. Для стандарт ных сервисов, выполняемых в TCP/IP, с этой целью используются так назы ваемые общеизвестные адреса. Если браузер знает имя компьютера, на ко тором работает Webсервер, он может подключиться к нему, указав общеиз вестный адрес Webсервера (к IPадресу сервера добавляется строка «:80» — номер HTTPпорта). Провайдеры пространств имен позволяют серверам регистрировать свое присутствие и другими способами. Например, провай дер пространства имен мог бы на серверной стороне регистрировать адрес сервера в Active Directory, а на клиентской — искать его в Active Directory. Провайдеры пространств имен обеспечивают эту функциональность Win sock, реализуя такие стандартные Winsockфункции разрешения имен, как getaddrinfo (заменяет gethostbyname) и getnameinfo. ЭКСПЕРИМЕНТ: просмотр провайдеров сервисов Winsock Утилита Windows Sockets Configuration (Sporder.exe), входящая в Plat form SDK, показывает зарегистрированные в Winsock провайдеры транспортных сервисов и пространств имен и позволяет изменять порядок перечисления TSP. Например, если в системе имеется два про вайдера транспортных сервисов TCP/IP, то первым в списке идет TSP по умолчанию для Winsockприложений, использующих протокол TCP/IP. На иллюстрации показано окно Sporder, в котором перечисле ны зарегистрированные TSP.
844 ГЛ А В А 13 БЕЗОПАСНОСТЬ Реализация Winsock Реализация Winsock представлена на рис. 134. Его программный интерфейс поддерживается библиотекой Ws2_32.dll (\Windows\System32\Ws2_32.dll), которая обеспечивает приложениям доступ к функциям Winsock. Для опе раций над именами и сообщениями Ws2_32.dll вызывает сервисы TSP и про вайдеров пространств имен. Библиотека Mswsock.dll выступает в роли TSP для протоколов, поддерживаемых Microsoft в Winsock. Она взаимодейству ет с драйверами протоколов режима ядра с помощью вспомогательных биб лиотек Winsock (Winsock Helpers), специфичных для конкретного протоко ла. Например, Wshtcpip.dll — вспомогательная библиотека TCP/IP. В Msw sock.dll (\Windows\System32\Mswsock.dll) реализованы такие расширения Winsock, как функции TransmitFile, AcceptEx и WSARecvEx. Windows поставля ется со вспомогательными библиотеками для TCP/IP, TCP/IP с IPv6, AppleTalk, IPX/SPX, ATM и IrDA (Infrared Data Association), а также с провайдерами про странств имен для DNS (TCP/IP), Active Directory и IPX/SPX. Рис. 13-4. Реализация Winsock Подобно API именованных каналов и почтовых ящиков Winsock интегри руется с Windowsмоделью вводавывода и использует для представления со кетов описатели файлов. Для этого нужна помощь со стороны драйвера фай ловой системы режима ядра, поэтому, реализуя функции на основе сокетов, Msafd.dll использует сервисы AFD (Ancillary Function Driver) (\Windows\Sys tem32\Drivers\Afd.sys). AFD является клиентом TDI и выполняет сетевые опе рации с использованием сокетов, например посылает и принимает сообще ния, отправляя TDI IRPпакеты драйверам протокола. AFD не запрограммиро ван на использование определенных драйверов протоколов — вместо этого
ГЛАВА 9 Поддержка сетей 845 Msafd.dll уведомляет AFD о протоколе, используемом для сокета, и в результа те AFD может открыть объект «устройство», представляющий этот протокол. Windows Sockets Direct Windows Sockets Direct (WSD) — это интерфейс, позволяющий в Winsock приложениях без всякой модификации использовать преимущества сетей устройств хранения данных (System Area Networks, SAN). Высокопроизводи тельные SAN идеальны для самых разнообразных применений — от распре деленных вычислений до трехуровневых архитектур электронной коммер ции вроде показанной на рис. 135. В данной системе сети SAN соединяют Webсерверы (презентационный Webуровень) с серверами бизнеслогики и с серверами базы данных, что обеспечивает высокоскоростную передачу данных между различными уровнями обработки информации. Поддержка WSD имеется в Windows 2003 и Windows 2000 Data Center Server, а также в Windows 2000 Advanced Server с Service Pack (SP) 2 и выше. Рис. 13-5. Применение SAN в трехуровневой архитектуре электронной коммерции SANсоединения Высокая производительность SAN обычно достигает ся за счет специализированных сетевых соединений и коммутационного оборудования. К наиболее распространенным типам SANсоединений отно сятся InfiniBand, Gigabit Ethernet, FiberChannel и различные фирменные (зак рытые) решения. Физическая память, разделяемая двумя компьютерами, тоже может служить SANсоединением. Коммутационное оборудование SAN реализует немаршрутизируемый протокол, предоставляющий TCPэквивалентные гарантии, в частности на дежную доставку сообщений в правильном порядке. Эти аппаратные сред ства также поддерживают механизм SAN, называемый удаленным прямым доступом к памяти (Remote Direct Memory Access, RDMA); этот механизм
846 ГЛ А В А 13 БЕЗОПАСНОСТЬ позволяет напрямую передавать сообщения из физической памяти компью тераисточника в физическую память компьютераполучателя без промежу точной операции копирования, которая обычно выполняется на стороне, принимающей сообщения. Благодаря этому RDMA освобождает процессор и шину памяти от лишней нагрузки, связанной с операцией копирования. Реализации SAN также позволяют обходиться без обращений к компонен там режима ядра, посылая и принимая данные напрямую между пользова тельскими приложениями. Это сокращает число системных вызовов, иници ируемых приложениями, и соответственно уменьшает время, затрачиваемое на выполнение системного кода поддержки сетей. Архитектура WSD Большинство реализаций SAN требуют модифика ции приложений для взаимодействия с сетевыми протоколами SAN и ис пользования преимуществ аппаратнореализованных протоколов и меха низмов SAN вроде RDMA, но WSD позволяет любому Winsockприложению, работающему по протоколу TCP, задействовать возможности SAN без такой модификации. Само название WSD подчеркивает, что он обеспечивает при ложениям прямой доступ к оборудованию SAN, в обход стека TCP/IP. А со кращение пути передачи данных повышает производительность приложе ний в 2–2,5 раза. Рис. 13-6. Традиционная модель Winsock и модель WSD Такое сокращение достигается за счет использования программного ком мутатора, размещаемого на уровень ниже Winsock DLL, как показано на рис. 136. Этот коммутатор переадресует сетевые операции SAN провайдеру сервисов Winsock (Winsock service provider, WSP), который предоставляется производителем SAN. WSP служит эквивалентом NDISдрайвера, работаю
ГЛАВА 9 Поддержка сетей 847 щим в пользовательском режиме, и может проецировать аппаратные реги стры SAN на память пользовательского режима, а затем манипулировать обо рудованием без участия компонентов режима ядра. Однако некоторые опе рации все же требуют поддержки со стороны таких компонентов, например для проецирования содержимого аппаратных регистров на память пользо вательского режима; эта поддержка тоже предоставляется производителем оборудования SAN. Наконец, производитель SAN предоставляет минипорт драйвер NDIS, выступающий в роли интерфейса между стеком TCP/IP и обо рудованием SAN для приложений, которые используют сетевые средства Winsock, не поддерживаемых SAN на аппаратном уровне. Remote Procedure Call (RPC) RPC — стандарт сетевого программирования, разработанный в начале 80х. Организация Open Software Foundation (теперь — The Open Group) сделала RPC частью стандарта OSF DCE (Distributed Computing Environment). Несмот ря на наличие второго стандарта RPC, SunRPC, реализация RPC от Microsoft совместима со стандартом OSF DCE. RPC, опираясь на другие сетевые API (именованные каналы или Winsock), предоставляет альтернативную модель программирования, в какойто мере скрывающую детали сетевого програм мирования от разработчика приложений. Функционирование RPC Механизм RPC позволяет создавать приложения, состоящие из произволь ного числа процедур, часть которых выполняется локально, а часть — на удаленных компьютерах (через сеть). RPC предоставляет модель работы с сетью, ориентированную на процедуры, а не на транспорты, что упрощает разработку распределенных приложений. Сетевое программное обеспечение традиционно базируется на модели обработки вводавывода. В Windows, например, сетевая операция начинает ся с того, что приложение выдает запрос на удаленный вводвывод. Опера ционная система обрабатывает запрос, передавая его редиректору, который действует в качестве удаленной файловой системы, обеспечивая прозрачное взаимодействие клиента с удаленной файловой системой. Редиректор пере дает запрос удаленной файловой системе, а после того как удаленная сис тема выполнит запрос и вернет результаты, локальная сетевая плата генери рует прерывание. Ядро обрабатывает это прерывание, и исходная операция вводавывода завершается, возвращая результаты вызывающей программе. RPC использует совершенно другой подход. Приложения RPC похожи на другие структурированные приложения: у них есть основная программа, ко торая для выполнения специфических задач вызывает процедуры или биб лиотеки процедур. Отличие приложений RPC от обычных программ в том, что некоторые библиотеки процедур в приложениях RPC выполняются на удаленных компьютерах, а некоторые — на локальном (рис. 137).
848 ГЛ А В А 13 БЕЗОПАСНОСТЬ Рис. 13-7. Так работает RPC Для приложения RPC все процедуры кажутся локальными. Иначе говоря, вместо того чтобы заставлять программиста писать код для передачи запро сов на вычисления или вводвывод по сети, работы с сетевыми протокола ми, обработки сетевых ошибок, ожидания результатов и т. д., программное обеспечение RPC выполняет все эти задачи автоматически. Кроме того, ме ханизм RPC в Windows работает с любыми транспортами, которые имеют ся в системе. Создавая приложение RPC, программист решает, какие процедуры будут выполняться локально, а какие — удаленно. Допустим, обычная рабочая стан ция подключена по сети к суперкомпьютеру Cray или к специализирован ной машине, предназначенной для быстрого выполнения векторных вычис лений. Если программист пишет программу, работающую с большими мат рицами, то с точки зрения производительности имело бы смысл переложить математические вычисления на удаленный компьютер, написав программу в виде приложения RPC. Функционирует приложение RPC следующим образом. В процессе своей работы оно вызывает как локальные процедуры, так и процедуры, отсут ствующие на локальной машине. Для обработки последнего случая прило жение связывается с локальной DLL, которая содержит интерфейсные про цедуры (stub procedures) для всех удаленных процедур. В простой програм ме интерфейсные процедуры статически связываются с приложением, но в компоненте большего размера они включаются в отдельные DLL. В DCOM обычно применяется последний метод. Интерфейсная процедура имеет то же имя и тот же интерфейс, что и удаленная процедура, но вместо выпол нения соответствующей операции она просто преобразует переданные ей параметры для передачи по сети — такой процесс называется маршалингом (marshaling). Маршалинг заключается в упорядочении параметров и их упа ковке в определенном формате. Далее интерфейсная процедура вызывает процедуры библиотеки RPC периода выполнения, и они находят компьютер, на котором расположены удаленные процедуры, определяют используемые этим компьютером меха низмы транспорта и посылают запрос при помощи локального програм много обеспечения сетевого транспорта. Когда удаленный сервер получает запрос RPC, он выполняет обратное преобразование параметров (unmar
ГЛАВА 9 Поддержка сетей 849 shaling), реконструирует исходный вызов процедуры и вызывает ее. Закон чив обработку, сервер выполняет обратную последовательность действий для возврата результатов вызывающей программе. Кроме интерфейса, основанного на описанном здесь синхронном вызо ве процедур, RPC в Windows также поддерживает асинхронный RPC (asyn chronous RPC). Он позволяет приложению RPC вызывать функцию и, не до жидаясь ее выполнения, продолжать свою работу. На это время приложение может перейти к выполнению другого кода. Когда от сервера придет ответ, библиотека RPC периода выполнения уведомит клиент о завершении опера ции. При этом используется механизм уведомления, запрошенный клиентом. Если клиент выбрал для уведомления синхронизирующий объект «событие», он ждет его перехода в свободное состояние, вызвав функцию WaitForSingle Object или WaitForMultipleObject. Если клиент предоставляет APC (Asynchro nous Procedure Call), библиотека RPC периода выполнения ставит APC в оче редь потока, выполняющего RPCфункцию. Если же клиент использует в ка честве механизма уведомления порт завершения вводавывода, он должен вызвать GetQueuedCompletionStatus, чтобы узнать об окончании работы этой функции. Наконец, клиент может опрашивать библиотеку RPC периода вы полнения о ходе выполнения операции, вызывая RcpAsyncGetCallStatus. Помимо библиотеки периода выполнения в Microsoft RPC входит компи лятор MIDL (Microsoft Interface Definition Language). Этот компилятор упро щает создание приложений RPC. Программист пишет набор обычных про тотипов функций (предполагается, что он использует язык С или C++), опи сывающих удаленные процедуры, а затем помещает их в какойлибо файл. Далее он добавляет к этим прототипам нужную дополнительную информа цию, например уникальный для сети идентификатор пакета процедур, но мер версии и атрибуты, указывающие, являются ли параметры входными, выходными или и теми, и другими одновременно. В конечном счете про граммист получает файл на языке IDL (Interface Definition Language). Подготовленный IDLфайл транслируется компилятором MIDL, который создает интерфейсные процедуры для клиентской и серверной сторон, а также заголовочные файлы, включаемые в приложение. Когда клиентское приложение связывается с файлом интерфейсных процедур, компоновщик разрешает все ссылки на удаленные процедуры. Аналогичным образом уда ленные процедуры устанавливаются на серверной машине. Программист, который намерен вызывать существующее приложение RPC, должен напи сать только клиентскую часть программы и скомпоновать ее с локальной библиотекой RPC периода выполнения. Библиотека RPC периода выполнения использует для взаимодействия с транспортным протоколом универсальный интерфейс провайдеров транс порта RPC (RPC transport provider interface). Этот интерфейс служит тонкой прослойкой между механизмом RPC и транспортом, которая увязывает опе рации RPC с функциями, предоставляемыми транспортом. RPC в Win dows реализует DLLмодули провайдеров транспорта для именованных ка налов, NetBIOS, SPX, TPC/IP и UDP. В Windows Server 2003 провайдер транс
850 ГЛ А В А 13 БЕЗОПАСНОСТЬ порта NetBIOS изъят, но добавлен провайдер для HTTP. Аналогичным обра зом RPC поддерживает работу с различными средствами сетевой защиты. ПРИМЕЧАНИЕ В Windows 2000 можно написать новые DLLмодули провайдеров для поддержки дополнительных транспортов, но, начи ная с Windows XP, встраивание дополнительных DLL провайдеров не поддерживается. Большинство сетевых служб Windows является приложениями RPC, а это значит, что они могут вызываться как локальными процессами, так и про цессами на удаленных машинах. Таким образом, удаленный клиентский компьютер может обращаться к службам сервера для просмотра списка об щих ресурсов, открытия файлов, записи данных в очереди печати или до бавления пользователей на этом сервере, либо он может вызывать Messenger Service (Службу сообщений) для посылки сообщений (конечно, при наличии соответствующих прав доступа). Сервер может регистрировать свое имя по адресу, который будет досту пен клиенту при поиске. Эта возможность, называемая публикацией имени сервера, реализована в RPC и интегрирована с Active Directory. Если Active Directory не установлена, служба локатора имен возвращается к широкове щательной рассылке с использованием NetBIOS. Это позволяет взаимодей ствовать с системами под управлением Windows NT 4 и дает возможность RPC функционировать на автономных серверах и рабочих станциях. Защита в RPC RPC интегрирован с компонентами поддержки защиты (security support pro viders, SSP), что позволяет клиентам и серверам RPC использовать аутенти фикацию и шифрование при коммуникационной связи. Когда серверу RPC требуется защищенное соединение, он сообщает библиотеке RPC периода выполнения, какую службу аутентификации следует добавить в список дос тупных служб аутентификации. А когда клиенту нужно использовать защи щенное соединение, он выполняет привязку к серверу. Во время привязки к серверу клиент должен указать библиотеке RPC службу аутентификации и нужный уровень аутентификации. Различные уровни аутентификации обеспечивают подключение к серверу только авторизованных клиентов, проверку каждого сообщения, получаемого сервером (на предмет того, по слано ли оно авторизованным клиентом), контроль за целостностью RPC сообщений и даже шифрование данных RPCсообщений. Чем выше уровень аутентификации, тем больше требуется обработки. Клиент также может ука зывать имя участника безопасности (principal name) для сервера. Участник безопасности (principal) — это сущность, распознаваемая системой защи ты RPC. Сервер должен зарегистрироваться в SSP под именем участника бе зопасности, специфичным для SSP. SSP берет на себя все, что связано с аутентификацией и шифрованием при коммуникационной связи, не только для RPC, но и для Winsock. В Win dows несколько встроенных SSP, в том числе Kerberos SSP, реализующий
ГЛАВА 9 Поддержка сетей 851 аутентификацию Kerberos v5, SChannel (Secure Channel), реализующий Secure Sockets Layer (SSL), и протоколы TLS (Transport Layer Security). Если SSP не указан, программное обеспечение RPC использует встроенные средства за щиты нижележащего транспорта. Одни транспорты, в частности именован ные каналы и локальный RPC, имеют такие средства защиты, а другие, напри мер TCP, — нет. В последнем случае RPC при отсутствии указанного SSP вы дает небезопасные вызовы. Еще одна функция защиты RPC позволяет серверу подменять клиент через функцию RpcImpersonateClient. Когда сервер заканчивает выполнение операций, потребовавших подмены клиента собой, он возвращается к использованию сво их идентификационных данных защиты вызовом функции RpcRevertToSelf или RpcRevertToSelfEx (подробнее о подмене, или олицетворении, см. главу 8). Реализация RPC Реализация RPC изображена на рис. 138, где показано, что приложение на основе RPC связано с библиотекой RPC периода выполнения (\Windows\Sys tem32\Rpcrt4.dll). Последняя предоставляет для интерфейсных RPCфункций приложений функции маршалинга, а также функции для приема и передачи упакованных данных. Библиотека RPC периода выполнения включает проце дуры поддержки RPCвзаимодействия через сеть и разновидность RPC под названием локальный RPC. Локальный RPC позволяет двум процессам взаимо действовать в одной системе, при этом библиотека RPC в качестве сетевого API использует LPC в режиме ядра (об LPC см. главу 3). Когда RPCвзаимодей ствие осуществляется между удаленными системами, библиотека RPC исполь зует APIфункции Winsock, именованного канала или Message Queuing. ПРИМЕЧАНИЕ Message Queuing в Windows Server 2003 не поддержи вается в качестве транспорта. Рис. 13-8. Реализация RPC
852 ГЛ А В А 13 БЕЗОПАСНОСТЬ Подсистема RPC (RPCSS) (\Windows\System32\Rpcss.dll) реализована в виде Windowsсервиса. RPCSS сама является приложением RPC, которое вза имодействует со своими экземплярами на других системах для поиска имен, регистрации и динамического подключения конечной точки (dynamic end point mapping). (Для упрощения на рис. 138 не показана связь RPCSS с биб лиотекой RPC периода выполнения.) API-интерфейсы доступа к Web Чтобы упростить разработку Интернетприложений, в Windows предусмот рены клиентские и серверные APIинтерфейсы доступа к Интернету. С по мощью этих API приложения могут предоставлять и использовать сервисы Gopher, FTP и HTTP, не зная внутреннего устройства соответствующих про токолов. Клиентские API включают Windows Internet, также называемый WinInet (позволяет приложениям взаимодействовать с протоколами Gopher, FTP и HTTP), и WinHTTP (дает возможность приложениям взаимодейство вать с протоколом HTTP). В определенных ситуациях WinHTTP удобнее WinInet. HTTP — это серверный API, введенный в Windows Server 2003 для поддержки разработки серверных Webприложений. WinInet WinInet поддерживает протоколы Gopher, FTP и HTTP версий 1.0 и 1.1. Этот API делится на наборы подAPI, специфичные для каждого протокола. Ис пользуя APIфункции FTP вроде InternetConnect для подключения к FTPсер веру, FtpFindFirstFile и FtpFindNextFile для перечисления содержимого FTP каталога, а также FtpGetFile и FtpPutFile для приема и передачи файлов, раз работчик приложения может не задумываться о деталях, связанных с уста новлением соединения и форматированием TCP/IPсообщений для прото кола FTP. APIфункции Gopher и HTTP обеспечивают аналогичный уровень абстракции. WinInet применяется базовыми компонентами Windows, напри мер Windows Explorer и Internet Explorer. WinHTTP Текущая версия WinHTTP API — 5.1; она доступна в Windows 2000 с Service Pack 3, в Windows XP и Windows Server 2003. Этот API обеспечивает абстрак цию протокола HTTP 1.1 для клиентских HTTPприложений по аналогии с HTTP API в WinInet. Однако, если WinInet HTTP API предназначен для интер активных клиентских приложений, то WinHTTP API — для серверных при ложений, взаимодействующих с HTTPсерверами. Серверные приложения часто реализуются как Windowsслужбы без UI, поэтому им не нужны диа логовые окна, которые позволяют выводить APIфункции WinInet. Кроме того, WinHTTP API лучше масштабируется и предоставляет средства защиты вроде подмены потоков, недоступные в WinInet API.
ГЛАВА 9 Поддержка сетей 853 HTTP С помощью HTTP API, реализованного в Windows Server 2003, серверные приложения могут регистрироваться на прием HTTPзапросов с определен ных URL, принимать такие запросы и передавать HTTPответы. HTTP API включает поддержку SSL (Secure Sockets Layer), чтобы приложения могли обмениваться данными по защищенным HTTPсоединениям. Этот API под держивает кэширование на серверной стороне, модели синхронного и асин хронного вводавывода, а также адресацию по IPv4 и IPv6. HTTP API исполь зуется IIS версии 6 (поставляется с Windows Server 2003). HTTP API, к которому приложения обращаются через библиотеку Httpapi.dll, опирается на драйвер Http.sys режима ядра. Http.sys запускается по требованию при первом вызове HttpInitialize любым приложением. Функ ция HttpCreateHttpHandle позволяет создавать закрытую очередь запросов, а функция HttpAddUrl — указывать URLадреса, по которым приложение соби рается принимать запросы для обработки. Используя очереди запросов и их зарегистрированные URL, Http.sys дает возможность обслуживать HTTPзап росы на одном порту, например 80, более чем одному приложению. HttpReceiveHttpRequest принимает входящие запросы, направленные по зарегистрированным URL, а HttpSendHttpResponse передает HTTPответы. Обе функции работают в асинхронном режиме, так что приложение может оп ределять, закончена ли какаято операция, используя GetOverlappedResult или порты завершения вводавывода. Приложения могут использовать Http.sys для кэширования данных в непод качиваемой физической памяти, вызывая HttpAddToFragmentCache и сопостав ляя имя фрагмента с кэшируемыми данными. Для выделения неспроецирован ных страниц физической памяти Http.sys запускает функцию MmAllocate PagesForMdl, принадлежащую диспетчеру памяти. Когда Http.sys требуется со поставление виртуального адреса с физической памятью, описываемой эле ментом кэша (например, если Http.sys копирует данные в кэш или передает их из кэша), он вызывает MmMapLockedPagesSpecifyCache, а по окончании опе раций — MmUnmapLockedPages. Http.sys хранит кэшируемые данные до тех пор, пока приложение не объявит их недействительными или пока не исте чет срок их актуальности, заданный приложением. Http.sys также усекает кэ шируемые данные при пробуждении рабочего потока изза перехода в сво бодное состояние события, уведомляющего о малом объеме памяти (инфор мацию об этом событии см. в главе 7). Если при вызове HttpSendHttpResponse приложение указывает одно или несколько имен фрагментов, Http.sys пере дает указатель на данные, кэшируемые в физической памяти, драйверу TCP/ IP и тем самым исключает лишнюю операцию копирования. Именованные каналы и почтовые ящики Именованные каналы и почтовые ящики — это API, изначально разработан ные Microsoft для OS/2 LAN Manager и впоследствии перенесенные в Windows NT. Именованные каналы обеспечивают надежную двустороннюю связь, тог
854 ГЛ А В А 13 БЕЗОПАСНОСТЬ да как почтовые ящики — ненадежную одностороннюю передачу данных. Преимущество почтовых ящиков — в поддержке широковещательной пере дачи. Оба API используют систему защиты Windows, что позволяет серверам контролировать, какие клиенты могут подключаться к ним. Серверы назначают именованным каналами и их клиентам имена в со ответствии с универсальными правилами именования (Universal Naming Convention, UNC), которые обеспечивают независимый от протоколов спо соб идентификации ресурсов в Windowsсетях. О реализации UNCимен мы расскажем позже. Функционирование именованных каналов Коммуникационная связь по именованному каналу включает сервер имено ванного канала и клиент именованного канала. Сервером именованного ка нала является приложение, создающее именованный канал, к которому под ключаются клиенты. Формат имени канала выглядит так: \\Сервер\Pipe\ ИмяКанала. Элемент Сервер указывает компьютер, на котором работает сер вер именованного канала. Элемент Pipe должен быть строкой «Pipe», а Имя Канала — уникальное имя, назначенное именованному каналу. Уникальная часть имени канала может включать подкаталоги. Пример такого UNCиме ни канала — \\MyComputer\Pipe\MyServerApp\ConnectionPipe. Для создания именованного канала сервер использует Windowsфункцию CreateNamedPipe. Одним из входных параметров этой функции является ука затель на имя канала в форме \\.\Pipe\ИмяКанала, где «\\.\» — псевдоним локального компьютера, определенный в Windows. Функция также прини мает необязательный дескриптор защиты, запрещающий несанкциониро ванный доступ к именованному каналу, флаг, указывающий, должен ли канал быть двусторонним или односторонним, параметр, определяющий макси мальное число одновременных соединений по данному каналу, и флаг ре жима работы канала (побайтовой передачи или передачи сообщений). Большинство сетевых APIфункций работают только в режиме побайто вой передачи. Это означает, что переданное сообщение может быть приня то адресатом в виде нескольких фрагментов, из которых воссоздается пол ное сообщение. Именованные каналы, работающие в режиме передачи со общений, упрощают реализацию приемника, поскольку в этом случае чис ло передач и приемов одинаково, а приемник, разом получая целое сообще ние, не должен заботиться об отслеживании фрагментов сообщений. При первом вызове CreateNamedPipe с указанием какоголибо имени соз дается первый экземпляр именованного канала с этим именем и задается поведение всех последующих экземпляров этого канала. Повторно вызывая CreateNamedPipe, сервер может создавать дополнительные экземпляры име нованного канала, максимальное число которых указывается при первом вызове CreateNamedPipe. Создав минимум один экземпляр именованного канала, сервер выполняет Windowsфункцию ConnectNamedPipe, после чего именованный канал позволяет устанавливать соединения с клиентами. Функ
ГЛАВА 9 Поддержка сетей 855 ция ConnectNamedPipe может выполняться как синхронно, так и асинхрон но, и она не завершится, пока клиент не установит соединение через данный экземпляр именованного канала (или не возникнет ошибка). Для подключения к серверу клиенты именованного канала используют Windowsфункцию CreateFile или CallNamedPipe, указывая при вызове имя созданного сервером канала. Если сервер вызывает функцию ConnectNamed Pipe, профиль защиты клиента и запрошенные им права доступа к каналу (для чтения или записи) сравниваются с дескриптором защиты канала (под робнее об алгоритмах проверки прав доступа см. главу 8). Если клиенту раз решен доступ к именованному каналу, он получает описатель, представляю щий клиентскую сторону именованного канала, и функция ConnectNamed Pipe, вызванная сервером, завершается. После того как соединение по именованному каналу установлено, клиент и сервер могут использовать его для чтения и записи данных через Windows функции ReadFile и WriteFile. Именованные каналы поддерживают как син хронную, так и асинхронную передачу сообщений. Взаимодействие клиен та и сервера через именованный канал показано на рис. 139. Рис. 13-9. Связь через именованный канал Уникальная особенность API именованного канала заключается в том, что он позволяет серверу олицетворять клиент с помощью функции Imperso nateNamedPipeClient. О том, как используется олицетворение в клиентсер верных приложениях, см. раздел «Олицетворение» главы 8. Функционирование почтового ящика Почтовые ящики предоставляют механизм ненадежного одностороннего широковещания. Одним из примеров приложений, использующих этот тип коммуникационной связи, является сервис синхронизации времени, который каждые несколько секунд широковещательно рассылает в пределах домена сообщение с эталонным временем. Такие сообщения не критичны для рабо ты компьютеров в сети, поэтому они рассылаются через почтовые ящики. Как и именованные каналы, почтовые ящики интегрированы с Windows API. Сервер почтового ящика создает почтовый ящик вызовом CreateMailslot. Входным параметром этой функции является имя в форме «\\.\Mailslot\Имя ПочтовогоЯщика». Сервер может создавать почтовые ящики только на той машине, на которой он работает, а назначаемые им имена почтовых ящи ков могут включать подкаталоги. CreateMailslot также принимает необяза тельный дескриптор защиты, контролирующий доступ клиента к почтово му ящику. Описатели, возвращаемые CreateMailslot, являются перекрытыми.
856 ГЛ А В А 13 БЕЗОПАСНОСТЬ Это означает, что операции с использованием таких описателей (например, рассылка и получение сообщений) выполняются асинхронно. Поскольку почтовые ящики поддерживают одностороннюю ненадежную передачу, число параметров CreateMailslot меньше, чем у CreateNamedPipe. После создания почтового ящика сервер просто отслеживает поступающие клиентские сообщения, вызывая функцию ReadFile и указывая описатель, представляющий почтовый ящик. Клиенты почтового ящика используют формат именования, аналогичный применяемому клиентами именованных каналов, за исключением вариаций, необходимых для широковещательной передачи сообщений всем почтовым ящикам с данным именем в домене клиента или в другом указанном домене. Чтобы послать сообщение в определенный экземпляр почтового ящика, кли ент вызывает функцию CreateFile, указывая имя, специфичное для компьюте ра, например «\\Сервер\Mailslot\ИмяПочтовогоЯщика». (Для представления локального компьютера клиент задает «\\.\».) Если клиент хочет получить описатель, представляющий все почтовые ящики с заданным именем в доме не, членом которого он является, он указывает имя в формате «\\*\Mailslot\ ИмяПочтовогоЯщика». Для широковещательной передачи во все почтовые ящики с заданным именем в другом домене используется имя в формате «\\ИмяДомена\Mailslot\ИмяПочтовогоЯщика». Получив описатель, представляющий клиентскую сторону почтового ящи ка, клиент посылает сообщения через функцию WriteFile. Реализация почто вых ящиков допускает широковещательную передачу сообщений длиной не более 425 байтов. Если длина сообщения превышает 425 байтов, почтовый ящик использует механизм надежной коммуникационной связи, требующий соединения клиента с сервером по типу «один к одному», что исключает воз можность широковещательной передачи. Другая (довольно странная) особен ность почтовых ящиков — урезание сообщений с исходной длиной в 425 или 426 байтов до 424 байтов. Таким образом, почтовые ящики непригодны для рассылки сообщений, длина которых превышает 424 байта. На рис. 1310 по казан пример широковещательной передачи клиентского сообщения на не сколько серверов почтовых ящиков в пределах домена. Рис. 13-10. Широковещательная передача с помощью почтовых ящиков
ГЛАВА 9 Поддержка сетей 857 Реализация именованных каналов и почтовых ящиков О тесной интеграции функций именованных каналов и почтовых ящиков с Windows свидетельствует тот факт, что все они реализованы в Kernel32.dll. ReadFile и WriteFile, используемые приложениями для обмена сообщениями через именованные каналы и почтовые ящики, являются основными Win dowsфункциями вводавывода. CreateFile, с помощью которой клиент от крывает именованный канал или почтовый ящик, также является стандарт ной Windowsфункцией вводавывода. Однако имена, указываемые приложе ниями при использовании именованных каналов и почтовых ящиков, отно сятся к пространству имен под управлением драйверов файловых систем именованных каналов (\Windows\System32\Drivers\Npfs.sys) и почтовых ящиков (\Windows\System32\Drivers\Msfs.sys), как показано на рис. 1311. Драйвер файловой системы именованных каналов создает объект «устрой ство» \Device\NamedPipe и символьную ссылку на этот объект с именем \Global??\Pipe (\??\Pipe в Windows 2000), а драйвер файловой системы почто вых ящиков создает объект «устройство» \Device\Mailslot и символьную ссылку \Global??\Mailslot (\??\Mailslot в Windows 2000), которая указывает на этот объект. (О каталоге \Global?? диспетчера объектов см. главу 3.) Префикс «\\.\» в именах «\\.\Pipe\…» и «\\.\Mailslot\…», передаваемых CreateFile, транс лируется в «\Global??\», чтобы эти имена разрешались через символьную ссылку на объект «устройство». Специальные функции CreateNamedPipe и CreateMailslot используют соответствующие функции ядра NtCreateNamed PipeFile и NtCreateMailslotFile. Рис. 13-11. Реализация именованного канала и почтового ящика Позже мы обсудим, как драйвер файловой системы участвует в поиске удаленной системы по имени, которое задает удаленный именованный ка нал или почтовый ящик. Однако, когда именованный канал либо почтовый ящик создается сервером или открывается клиентом, в конечном счете вы зывается соответствующий драйвер файловой системы (FSD) на той маши не, где находится именованный канал или почтовый ящик. Именованные каналы и почтовые ящики реализованы в виде FSD режима ядра по несколь ким причинам. Основной из них является интеграция с пространством имен
858 ГЛ А В А 13 БЕЗОПАСНОСТЬ диспетчера объектов, что позволяет использовать объекты «файл» для пред ставления открытых именованных каналов и почтовых ящиков. Подобная интеграция дает следующие преимущества. 쐽 Используя функции защиты режима ядра, FSD реализуют для именован ных каналов и почтовых ящиков стандартную защиту Windows. 쐽 Поскольку FSD интегрированы с пространством имен диспетчера объек тов, приложения могут открывать именованный канал или почтовый ящик вызовом функции CreateFile. 쐽 Приложения могут взаимодействовать с именованными каналами и по чтовыми ящиками через Windowsфункции вроде ReadFile и WriteFile. 쐽 FSD полагаются на диспетчер объектов в поддержке счетчиков описате лей и ссылок для объектов «файл», представляющих именованные кана лы и почтовые ящики. 쐽 FSD могут реализовать собственные пространства имен каналов и почто вых ящиков, допускающие указание подкаталогов. Так как взаимодействие через сеть при разрешении имен именованных каналов и почтовых ящиков осуществляется через редиректор, FSD при этом неявно используют протокол CIFS (Common Internet File System). Поскольку CIFS способен работать с TCP/IP, TCP/IP с IPv6 и IPX, именованные каналы и почтовые ящики доступны приложениям, выполняемым в системах, где уста новлен хотя бы один общий такой протокол. (Сведения о CIFS см. в главе 12.) ЭКСПЕРИМЕНТ: просмотр пространства имен именованных каналов и наблюдение за активностью таких каналов Открыть корневой каталог FSD именованных каналов и перечислить его содержимое с помощью Windows API нельзя — для этого нужно вос пользоваться сервисами встроенного API. Утилита PipeList (www.sys internals.com) перечисляет именованные каналы, определенные на компьютере, число созданных экземпляров канала с данным именем и максимальное число каналов, заданное сервером при вызове Create NamedPipe. Вот пример вывода PipeList. C:\>pipelist PipeList v1.01 by Mark Russinovich http://www.sysinternals.com Pipe Name  TerminalServer\AutoReconnect InitShutdown lsass protected_storage ntsvcs Instances  1 2 4 2 58 Max Instances  1 1 1 1 1
ГЛАВА 9 scerpc net\NtControlPipe1 net\NtControlPipe2 ExtEventPipe_Service net\NtControlPipe3 Winsock2\CatalogChangeListener37c0 net\NtControlPipe4 net\NtControlPipe0 DhcpClient ProfMapApi winlogonrpc net\NtControlPipe5 SfcApi net\NtControlPipe6 Winsock2\CatalogChangeListener4c40 atsvc epmapper net\NtControlPipe7 spoolss wkssvc DAV RPC SERVICE net\NtControlPipe8 keysvc net\NtControlPipe9 PCHHangRepExecPipe PCHFaultRepExecPipe net\NtControlPipe10 000000ac.000 Winsock2\CatalogChangeListenerac0 net\NtControlPipe11 net\NtControlPipe12 winreg SECLOGON srvsvc ipsec trkwks Winsock2\CatalogChangeListenerac1 net\NtControlPipe13 vmwareauthdpipe W32TIME net\NtControlPipe14 net\NtControlPipe15 Winsock2\CatalogChangeListenere80 INETINFO SMTPSVC browser net\NtControlPipe16 Ctx_WinStation_API_service 2 1 1 1 1 1 1 1 1 2 2 1 2 1 1 2 2 1 2 3 2 1 2 1 1 1 1 2 1 1 1 2 2 3 2 2 1 1 1 2 1 1 1 2 2 3 1 2 Поддержка сетей 859 1 1 1 30 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 8 8 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 см. след. стр.
860 ГЛ А В А 13 БЕЗОПАСНОСТЬ ExtEventPipe_s0 1 ExtEventPipe_s0_poller 1 net\NtControlPipe17 1 interbas\server\gds_db 1 ROUTER 8 PIPE_EVENTROOT\CIMV2SCM EVENT PROVIDER 2 net\NtControlPipe20 1 30 30 1 1 1 1 1 Из этого листинга ясно, что некоторые системные компоненты используют именованные каналы как механизм связи. Например, ка нал InitShutdown создан Winlogon для приема удаленных команд на завершение работы, а канал SecLogon — сервисом SecLogon для выпол нения операций входа в интересах утилиты Runas. Определить, каким из процессов открыт каждый из этих каналов, можно с помощью ути литы Process Explorer (www.sysinternals.com). Заметьте, что значение Max Instances, равное –1, означает, что на число экземпляров канала с данным именем не накладывается никаких ограничений. Драйвер фильтра файловой системы Filemon (www.sysinternals.com) способен подключаться к драйверу файловой системы Npfs.sys или Msfs.sys, что позволяет ему наблюдать за активностью всех именован ных каналов или почтовых ящиков в системе. Для подключения File mon к соответствующему драйверу выберите из меню Drives команду Named Pipes или Mail Slots. На иллюстрации ниже показано окно File mon, в котором сообщается об активности именованных каналов, вы зываемой двойным щелчком значка My Network Places (Мое сетевое окружение) на рабочем столе. Заметьте, что сообщения передаются через именованные каналы LSASS и службы рабочей станции.
ГЛАВА 9 Поддержка сетей 861 NetBIOS До начала 90х годов NetBIOS (Network Basic Input/Output System) API был самым популярным интерфейсом программирования для персональных компьютеров. NetBIOS поддерживал связь как надежную, ориентированную на логические соединения, так и ненадежную, не требующую логических соединений. Windows поддерживает NetBIOS для совместимости с унаследо ванными приложениями. Microsoft не рекомендует разработчикам приложе ний использовать NetBIOS, поскольку существуют куда более гибкие и пере носимые API, например именованные каналы и Winsock. NetBIOS в Windows поддерживается протоколами TCP/IP и IPX/SPX. NetBIOS-имена NetBIOS использует правила именования, согласно которым компьютерам и сетевым службам назначаются 16байтовые имена, называемые NetBIOS именами; 16й байт в NetBIOSимени интерпретируется как модификатор, который указывает, является ли имя уникальным или групповым.* Уникаль ное NetBIOSимя может быть назначено только одному компьютеру или службе в сети, а групповое имя — нескольким компьютерам или службам. Адресуя сообщение на групповое имя, клиент может вести широковещатель ную рассылку. Windows — для поддержки взаимодействия с системами под управлени ем Windows NT 4 и потребительских версий Windows — автоматически оп ределяет NetBIOSимя для домена как первые 15 байтов DNSимени (Domain Name System), назначенного домену администратором. Например, домен mspress.microsoft.com получает NetBIOSимя mspress. Аналогичным образом Windows требует, чтобы во время установки администратор назначил каж дому компьютеру NetBIOSимя. Еще одна концепция, используемая в NetBIOS, — номера адаптеров LAN (LANA). Номер LANA присваивается каждому NetBIOSсовместимому прото колу, расположенному на более высоком уровне, чем сетевой адаптер. Так, если в компьютере установлено два сетевых адаптера, доступных для TCP/ IP и NWLink, то в результате будет назначено четыре номера LANA. Номера LANA важны, поскольку приложения NetBIOS должны явно закреплять име на своих сервисов за каждым LANA, через который они готовы принимать клиентские соединения. Если приложение ждет соединений с клиентами по определенному имени, клиенты получат доступ к приложению только через протоколы, для которых зарегистрировано это имя. Разрешение NetBIOSимен в IPадреса описывается в разделе «Windows Internet Name Service» далее в этой главе. * Здесь авторы допускают неточность. 16й байт NetBIOSимени прежде всего явля ется идентификатором типа ресурса. Он указывает сетевой компонент или службу, которая назначила это NetBIOSимя компьютеру, пользователю или домену. Ну и, кроме того, NetBIOSимя может быть зарегистрировано как уникальное (принад лежащее одному владельцу) или как групповое (принадлежащее нескольким вла дельцам). — Прим. перев.
862 ГЛ А В А 13 БЕЗОПАСНОСТЬ Функционирование NetBIOS Серверное приложение NetBIOS использует NetBIOS API для перечисления LANA, имеющихся в системе, и назначения каждому из них NetBIOSимени, представляющего сервис приложения. Если сервер требует логических соеди нений, он выполняет NetBIOSкоманду listen для ожидания попыток подклю чения клиентов. После того как соединение с клиентом установлено, сервер выполняет функции NetBIOS для передачи и приема данных. Аналогичным образом осуществляется и связь, не требующая логических соединений, но сервер просто принимает сообщения, не устанавливая соединение. Клиент, ориентированный на логические соединения, устанавливает со единение с сервером NetBIOS, а затем с помощью функций NetBIOS передает и принимает данные. Установленное NetBIOSсоединение также называет ся сеансом (session). Если клиент хочет посылать сообщения без установле ния логического соединения, он просто указывает NetBIOSимя сервера при вызове функции передачи данных. NetBIOS состоит из набора функций, но все они действуют через один и тот же интерфейс — Netbios. Это наследие тех времен, когда NetBIOS реали зовали в виде прерывания MSDOS. Приложение NetBIOS выполняло преры вание MSDOS и передавало NetBIOS структуру данных, где задавались все параметры нужной команды. В итоге функция Netbios в Windows принима ет единственный параметр, который представляет собой структуру данных с параметрами, специфичными для запрошенного приложением сервиса. ЭКСПЕРИМЕНТ: просмотр NetBIOS-имен через Nbtstat Для вывода списка активных сеансов в системе, кэшируемых сопостав лений NetBIOSимен и IPадресов, а также NetBIOSимен, определен ных на компьютере, можно использовать встроенную в Windows ко манду Nbtstat. Ниже приведен пример вывода этой команды с парамет ром –n, при указании которого выводится список NetBIOSимен, оп ределенных на компьютере. C:\>nbtstat n Local Area Connection: Node IpAddress: [10.1.23.147] Scope Id: [] NetBIOS Local Name Table Name Type Status —————————————————————— MARKLAP <00> UNIQUE Registered WORKGROUP <00> GROUP Registered MARKLAP <20> UNIQUE Registered WORKGROUP <00> GROUP Registered WORKGROUP <1E> GROUP Registered WORKGROUP <1D> UNIQUE Registered ..__MSBROWSE__.<01> GROUP Registered
ГЛАВА 9 Поддержка сетей 863 Wireless Network Connection: Node IpAddress: [0.0.0.0] Scope Id: [] No names in cache Реализация NetBIOS API Компоненты, реализующие NetBIOS API, показаны на рис. 1312. Функция Netbios экспортируется приложениям из \Windows\System32\Netapi32.dll. Netapi32.dll открывает описатель драйвера режима ядра под названием эму лятор NetBIOS (\Windows\System32\Drivers\Netbios.sys) и выдает Windows команды DeviceIoControlFile от имени приложения. Эмулятор NetBIOS транс лирует команды NetBIOS в команды TDI, посылаемые драйверам протоколов. Рис. 13-12. Реализация NetBIOS API Если приложение требует использовать NetBIOS поверх TCP/IP, то эмуля тору NetBIOS нужен драйвер NetBT (\Windows\System32\Drivers\Netbt.sys). NetBT отвечает за поддержку семантики NetBIOS, присущей не TCP/IP, а NetBEUI (NetBIOS Extended User Interface), который включался в предыдущие версии Windows. Например, NetBIOS полагается на NetBEUIподдержку ре жима передачи данных в виде сообщений и на средства разрешения имен, поэтому драйвер NetBT реализует их поверх протокола TCP/IP. Аналогичным образом драйвер NwLinkNB реализует семантику NetBIOS поверх IPX/SPX.
864 ГЛ А В А 13 БЕЗОПАСНОСТЬ Другие сетевые API В Windows входит еще несколько сетевых API, которые используются реже и расположены на более высоком уровне, чем уже рассмотренные API. Изу чение всех этих API выходит за рамки книги, но четыре из них — RTC (Real Time Communications), DCOM (Distributed Component Object Model), Message Queuing и UPnP (Universal Plug and Play) — достаточно важны для функцио нирования Windows и многих приложений и поэтому заслуживают кратко го описания. RTC RTC Client API, доступный в Windows XP и Windows Server 2003, позволяет раз работчикам создавать приложения, способные устанавливать многорежим ные коммуникационные соединения и превращать персональный компьютер (ПК) в центр домашних или деловых коммуникаций. Голосовая и видеосвязь, мгновенный обмен сообщениями (Instant Messaging, IM), поддержка совмес тной работы — все это становится доступным в одном сеансе коммуника ционной связи. Помимо сеансов связи между ПК, этот API позволяет устанав ливать сеансы связи «ПКтелефон», «телефонтелефон» или только текстово го IM. В сеансах связи между ПК также доступны совместное использование приложений (application sharing) и общая электронная доска (whiteboard). RTC поддерживает информацию о присутствии (presence information), на основе которой клиенты могут связываться с контактами через серверре гистратор (registrar server), хранящий информацию о текущих адресах кон тактов. Адресом контакта может быть ПК или телефон, а в будущем и мобиль ный телефон, пейджер или другое карманное устройство. Например, если приложение пытается связаться с контактом по его рабочему адресу и ин формация о присутствии указывает на то, что данный контакт доступен че рез домашний ПК, RTC автоматически перенаправит соединение на этот адрес. RTC API также обеспечивает невмешательство в частную жизнь, позво ляя блокировать определенные вызовы. DCOM Microsoft COM API позволяет составлять приложения из компонентов, и каж дый компонент представляет собой заменяемый самодостаточный модуль. Любой COMобъект экспортирует объектноориентированный интерфейс для манипулирования своими данными. Поскольку COMобъекты предостав ляют четко определенные интерфейсы, разработчики могут реализовать новые объекты для расширения существующих интерфейсов и динамичес кого добавления новой функциональности в приложения. DCOM — это расширение COM, которое дает возможность размещать компоненты приложения на разных компьютерах, при этом приложению безразлично, что один COMобъект находится на локальном компьютере, а другой — на какомто компьютере в локальной сети. Таким образом, DCOM упрощает разработку распределенных приложений. DCOM не является ав тономным API — в своей работе он опирается на RPC.
ГЛАВА 9 Поддержка сетей 865 Message Queuing Message Queuing представляет собой универсальную платформу для разработ ки распределенных приложений, использующих преимущества свободно свя занного обмена сообщениями (loosely coupled messaging). Поэтому Message Queuing является также APIинтерфейсом и инфраструктурой передачи сооб щений. Гибкость Message Queuing определяется тем, что его очереди служат репозитариями сообщений, в которые отправители помещают сообщения для посылки получателям и из которых получатели извлекают адресованные им сообщения. Отправителям и получателям не требуется ни устанавливать со единения, ни работать в одно и то же время. А это позволяет асинхронно об мениваться сообщениями, не устанавливая прямых соединений. Примечательная особенность Message Queuing — его интеграция с MTS (Microsoft Transaction Server) и SQL Server, что дает возможность Message Queuing участвовать в транзакциях, координируемых MS DTC (Microsoft Distributed Transaction Coordinator). Используя MS DTC с Message Queuing, можно разрабатывать для трехуровневых приложений надежные компонен ты, отвечающие за обработку транзакций. UPnP Universal Plug and Play (UPnP) — это распределенная, открытая сетевая ар хитектура для поддержки соединений с интеллектуальными устройствами и точками управления (control points), подключенными к домашним сетям, интрасетям или напрямую к Интернету. Она построена на принятых стан дартах и опирается на существующие технологии TCP/IP и Web. UPnP не требует конфигурирования и поддерживает автоматическое распознавание широкого спектра устройств. Она позволяет устройству динамически под ключаться к сети, получать IPадрес и сообщать о своих возможностях, ког да поступает соответствующий запрос. Точки управления могут применять Control Point API в сочетании с технологией UPnP для определения присут ствия и возможностей остальных устройств в сети. Устройство может авто матически выходить из сети, если оно больше не используется. Поддержка нескольких редиректоров У приложений есть два способа просмотра удаленных ресурсов или досту па к ним. Один из них заключается в использовании стандарта UNC и пря мой адресации к удаленным ресурсам через Windowsфункции, а второй — в применении Windows Networking (WNet) API для перечисления компью теров и экспортируемых ими ресурсов. Оба подхода опираются на возмож ности редиректора. Для доступа клиентов к CIFSсерверам Microsoft постав ляет редиректор CIFS, у которого есть компонент режима ядра (FSD редирек тора) и компонент пользовательского режима (служба рабочей станции). Microsoft также предоставляет редиректор, способный обращаться к ресур сам серверов Novell NetWare, а сторонние разработчики могут добавлять в
866 ГЛ А В А 13 БЕЗОПАСНОСТЬ Windows собственные редиректоры. В этом разделе мы расскажем о про граммном обеспечении, которое решает, какой редиректор следует вызвать для обработки запроса на удаленный вводвывод. За это отвечают следую щие компоненты. 쐽 Маршрутизатор многосетевого доступа (multiple provider router, MPR) Это DLL (\Windows\System32\Mpr.dll), определяющая, к какой сети следует обратиться, когда приложение использует Windows WNet API для просмотра удаленной файловой системы. 쐽 Многосетевой UNCпровайдер (multiple UNC provider, MUP) Драйвер (\Windows\System32\Drivers\Mup.sys), определяющий, к какой сети следует обратиться, когда приложение использует Windows API вво давывода для открытия удаленных файлов. Маршрутизатор многосетевого доступа Windowsфункции WNet позволяют приложениям (включая Windows Explo rer и My Network Places) подключаться к сетевым ресурсам (файлам и прин терам), а также просматривать содержимое удаленных файловых систем любого типа. Так как этот API предназначен для работы с различными сетя ми и по разным протоколам, необходимо специальное программное обес печение, способное посылать запросы по сети и правильно интерпретиро вать результаты, получаемые от удаленных серверов. Это программное обес печение показано на рис. 1313. Рис. 13-13. Компоненты MPR
ГЛАВА 9 Поддержка сетей 867 Провайдер (provider) — это программный компонент, позволяющий Win dows выступать в качестве клиента какоголибо удаленного сервера. В чис ло операций, выполняемых провайдером WNet, входят установление и раз рыв сетевых соединений, удаленная печать и передача данных. Встроенный провайдер WNet включает DLL, службу рабочей станции и редиректор. По ставщики других сетей должны предоставлять только DLL и редиректор. Когда приложение вызывает некую функцию WNet, этот вызов передается непосредственно MPR DLL. MPR принимает вызов и определяет, какой из про вайдеров WNet распознает запрошенный ресурс. Все DLL провайдеров, распо ложенные ниже MPR, предоставляют набор стандартных функций, в совокуп ности называемых интерфейсом сетевого доступа (network provider interface). Этот интерфейс позволяет MPR определить, к какой сети пытается обратиться приложение, и направить вызов соответствующему провайдеру WNet. Провай дером службы рабочей станции является \Windows\System32\Ntlanman.dll, что указывается в параметре ProviderPath в разделе реестра HKLM\SYSTEM\Cur rentControlSet\Services\LanManWorkstation\NetworkProvider. Рис. 13-14. Редактор порядка провайдеров (служб доступа к сети) Когда MPR вызывается для подключения к удаленному сетевому ресурсу APIфункцией WNetAddConnection, он просматривает в реестре параметр HKLM\SYSTEM\CurrentControlSet\Control\NetworkProvider\HwOrder\Provider Order, чтобы определить, какие провайдеры сетей загружены. Далее он опра шивает их в том порядке, в каком они перечислены в реестре, и делает это до тех пор, пока один из них не распознает сетевой ресурс или пока все они не будут опрошены. Параметр ProviderOrder можно изменить через диалоговое окно Advanced Settings (Дополнительные параметры), показанное на рис. 1314. (В системе, в которой был сделан этот экранный снимок, установлен только
868 ГЛ А В А 13 БЕЗОПАСНОСТЬ один провайдер.) В Windows 2000 или при настройке меню Start (Пуск) в тра диционном стиле это диалоговое окно вызывается из меню Advanced (Допол нительно) апплета Network Connections (Сетевые подключения), который за пускается несколькими способами. Вы можете, например, щелкнуть правой кнопкой мыши значок My Network Places (Мое сетевое окружение) на рабо чем столе и выбрать из контекстного меню команду Properties (Свойства), либо открыть меню Start (Пуск), затем подменю Settings (Настройка) и вы брать команду Network Connections (Сетевые подключения). Функция WNetAddConnection может также назначить удаленному ресурсу букву диска или имя устройства. В этом случае она направляет вызов соот ветствующему компоненту сетевого доступа. Тот в свою очередь создает объект «символьная ссылка» в пространстве имен диспетчера объектов, и этот объект увязывает данную букву диска с редиректором нужной сети (т. е. с удаленным FSD). На рис. 1315 показан каталог \?? в системе Windows 2000, в котором вы заметите несколько букв диска, представляющих соединения с удаленными файловыми ресурсами. Как видите, редиректор создает объект «устройство» с именем \Device\LanmanRedirector, а дополнительный текст, который вхо дит в значение символьной ссылки, сообщает редиректору, какому удален ному ресурсу соответствует буква диска. Когда пользователь открывает X:\ Book\Chap13.doc, редиректору передается неразобранная часть пути, кото рая разрешается через символьную ссылку как «;X:0\dual\e\Book\ Chap13.doc». Редиректор отмечает, что данный ресурс расположен на общем диске Е сервера dual. Рис. 13-15. Разрешение имени сетевого ресурса Как и встроенный редиректор, другие редиректоры тоже создают объект «устройство» в пространстве имен диспетчера объектов в процессе своей загрузки и инициализации. После этого, когда WNet или другой API обраща ется к диспетчеру объектов для открытия ресурса, расположенного в другой
ГЛАВА 9 Поддержка сетей 869 сети, диспетчер использует данный объект «устройство» как точку входа в удаленную файловую систему. Он вызывает метод разбора, принадлежащий диспетчеру вводавывода и сопоставленный с объектом, для поиска FSD ре директора, способного обработать данный запрос (о драйверах файловых систем см. главу 12). Многосетевой UNC-провайдер Многосетевой UNCпровайдер (Multiple UNC Provider, MUP) — сетевой ком понент, сходный с MPR. Он обрабатывает запросы вводавывода (адресован ные к файлам или устройствам) с UNCименами (именами, которые начи наются с символов \\, указывающих, что данный ресурс находится в сети). MUP, как и MPR, определяет, какой локальный редиректор распознает удален ный ресурс. Но MUP в отличие от MPR является драйвером устройства (за гружаемым при загрузке системы), который выдает запросы на вводвывод драйверам более низкого уровня, в данном случае — редиректорам, как по казано на рис. 1316. Mup.sys также содержит клиентскую реализацию Distri buted File System (DFS). Клиент DFS включен по умолчанию, и его можно от ключить, присвоив DWORDпараметру реестра HKLM\System\CurrentCont rolSet\Services\Mup\DisableDfs значение 1. Рис. 13-16. Многосетевой UNC-провайдер (MUP) При загрузке MUP создает объект «устройство» с именем \Device\Mup. Когда сетевой редиректор вроде CIFS загружает редиректор, тот создает именованный объект «устройство» (скажем, \Device\LanmanRedirector) и регистрируется в MUP как UNCпровайдер вызовом функции FsRtlRegister
870 ГЛ А В А 13 БЕЗОПАСНОСТЬ UncProvider. Если этот редиректор — первый из зарегистрированных и если поддержка DFSклиента в MUP отключена, то FsRtlRegisterUncProvider созда ет символьную ссылку \??\UNC, которая указывает на объект «устройство» редиректора; в ином случае MUP настраивает символьную ссылку \Global??\ UNC (\??\UNC в Windows 2000) так, чтобы она указывала на его объект «уст ройство», \Device\MUP. Драйвер MUP активизируется, когда приложение впервые пытается от крыть удаленный файл или устройство по UNCимени (а не по букве сете вого диска). Получив запрос на вводвывод с UNCпутем, Kernel32.dll (экс портирующая APIфункции файлового вводавывода) на клиентской сторо не добавляет переданный в запросе UNCпуть к строке \Global??\UNC, пос ле чего вызывает системный сервис NtCreateFile для открытия файла. Если зарегистрирован только один провайдер сети, то \Global??\UNC раз решается в объект «устройство», представляющий драйвер, и запрос обраба тывается этим драйвером. При наличии нескольких зарегистрированных провайдеров \Global??\UNC разрешается в \Device\MUP, и MUP должен оп ределить, какой провайдер будет обрабатывать данный запрос. Когда драйвер MUP принимает запрос вводавывода и клиент DFS вклю чен, MUP сначала определяет, соответствует ли указанный путь DFSпути (DFSпути тоже форматируются по стандарту UNC), и, если да, сам обраба тывает запрос. Если клиент DFS отключен или путь не соответствует DFS пути, MUP считывает параметр реестра HKLM\SYSTEM\CurrentControlSet\ Control\NetworkProvider\Order\ProviderOrder, чтобы определить приоритет провайдеров сетей, зарегистрированных через FsRtlRegisterUncProvider. Затем MUP поочередно опрашивает провайдеры в том порядке, в каком они пере числены в данном параметре реестра, до тех пор, пока один из них не со общит, что он распознал данный путь, или пока не будут опрошены все име ющиеся провайдеры. MUP игнорирует те редиректоры, которые указаны в параметре ProviderOrder, но не зарегистрированы. Когда один из редирек торов распознает путь, он сообщает, какая часть пути уникальна именно для него. Например, если путем является строка «\\WIN2K3SERVER\PUBLIC\Win dowsinternals\Chap13.doc», редиректор может распознать и объявить своей подстроку «\\WIN2K3SERVER\PUBLIC». Драйвер MUP кэширует эту информа цию и впоследствии пересылает запросы, начинающиеся с данной подстро ки, непосредственно этому редиректору, пропуская стадию опроса. Кэш драйвера MUP хранит данные в течение определенного периода, поэтому через некоторое время сопоставление подстроки с данным редиректором становится недействительным. Разрешение имен Разрешение имен (name resolution) — это процесс, в ходе которого символь ное имя вроде Mycomputer или www.microsoft.com транслируется в числовой адрес типа 192.168.1.1, распознаваемый стеком протоколов. В этом разделе описываются два TCP/IPпротокола разрешения имен, предоставляемые Win dows, — DNS (Domain Name System) и WINS (Windows Internet Name Service).
ГЛАВА 9 Поддержка сетей 871 DNS DNS (Domain Name System) — стандарт трансляции имен в Интернете (напри мер, www.microsoft.com) в соответствующие IPадреса. Сетевое приложение, которому требуется разрешить DNSимя в IPадрес, использует TCP/IP для пе редачи серверу запроса на поиск DNSимени. DNSсерверы реализуют распре деленную базу данных сопоставлений имен и IPадресов, используемых при разрешении. Каждый сервер обслуживает разрешение имен для определенной зоны. Подробное описание DNS не входит в задачи этой книги, но DNS пред ставляет собой основной протокол разрешения имен в Windows. DNSсервер реализован в виде Windowsсервиса (\Windows\System32\ Dns.exe), который входит в состав серверных версий Windows. DNSсервер в стандартной реализации использует в качестве базы данных текстовый файл, но DNSсервер в Windows может быть сконфигурирован на хранение зонной информации в Active Directory. WINS Сетевая служба WINS (Windows Internet Name Service) хранит и поддержи вает сопоставления между NetBIOSименами и IPадресами, используемые TCP/IPприложениями на основе NetBIOS. Если WINS не установлена, Net BIOS разрешает имена, рассылая широковещательные сообщения в локаль ной подсети. Заметьте, что NetBIOSимена вторичны по отношению к DNS именам в случае приложений Windows Sockets: имена компьютеров регист рируются и разрешаются сначала через DNS. Windows возвращается к Net BIOSименам, только если разрешение имени через DNS заканчивается не удачно. Драйверы протоколов Драйверы сетевых API должны принимать запросы, адресованные к API, и транслировать их в низкоуровневые запросы сетевых протоколов для пере дачи по сети. Драйверы API выполняют реальную трансляцию с помощью драйверов транспортных протоколов в режиме ядра. Отделение API от ниже лежащих протоколов придает сетевой архитектуре гибкость, позволяющую каждому API использовать множество различных протоколов. В Windows вхо дят следующие драйверы протоколов: TCP/IP, TCP/IP с IPv6, NWLink и Apple Talk. Ниже дается краткое описание каждого из этих протоколов. 쐽 Взрывное развитие Интернета и популярность TCP/IP обусловили статус этих протоколов как основных в Windows. TCP/IP был разработан DARPA (Defense Advanced Research Projects Agency) в 1969 году как фундамент Интернета, поэтому характеристики TCP/IP (поддержка маршрутизации и хорошая производительность в WAN) благоприятствуют его использо ванию в глобальных сетях. TCP/IP — основной стек протоколов в Win dows. Он устанавливается по умолчанию, и его нельзя удалить.
872 ГЛ А В А 13 БЕЗОПАСНОСТЬ 쐽 4байтовые сетевые адреса, используемые протоколом IPv4 в стандартном стеке протоколов TCP/IP, ограничивают число общедоступных IPадресов примерно до 4 миллиардов. И это становится серьезной проблемой, по скольку в Интернете появляется все больше и больше устройств, таких как сотовые телефоны и КПК. По этой причине начинается внедрение про токола IPv6, в котором каждый адрес имеет 16 байтов. В Windows XP (Service Pack 1 и выше) и Windows Server 2003 включен стек TCP/IP, \Win dows\System32\Drivers\Tcpip6.sys, реализующий IPv6. Windowsреализа ция IPv6 совместима с сетями на основе IPv4 за счет туннелирования. 쐽 NWLink состоит из протоколов Novell IPX и SPX. NWLink включен в Win dows для взаимодействия с серверами Novell NetWare. 쐽 Протокол AppleTalk используется в сетях Apple Macintosh; его поддержка позволяет Windows взаимодействовать со службами доступа к файлам и принтерам в сетях на основе AppleTalk. В Windows транспорты TDI в общем случае реализуют все протоколы, сопоставленные с основным стеком протоколов. Например, драйвер TCP/IP IPv4 (\Windows\System32\Drivers\Tcpip.sys) реализует протоколы TCP, UDP, IP, ARP, ICMP и IGMP. Для представления конкретных протоколов транспорт TDI обычно создает объекты «устройство», что позволяет клиентам получать объект «файл», представляющий нужный протокол, и выдавать ему запросы на сетевой вводвывод с использованием IRP. Драйвер TCP/IP создает не сколько объектов «устройство» для представления различных протоколов, доступных клиентам TDI: \Device\Tcp, \Device\Udp и \Device\Ip, а также (в Windows XP и Windows Server 2003) \Device\Rawip и \Device\Ipmulticast. ЭКСПЕРИМЕНТ: просмотр объектов «устройство», принадлежащих TCP/IP С помощью отладчика ядра можно изучить эти объекты в работающей системе. Команда !drvobj позволяет узнать адрес каждого объекта «ус тройство» драйвера, а !devobj — просмотреть имя и другие сведения о конкретном объекте. lkd> !drvobj tcpip Driver object (8a01ada0) is for: \Driver\Tcpip Driver Extension List: (id , addr) Device Object list: 8a0dbc88 8a0dc958 8a0dcd80 8a0eff18 8a0f32a0 lkd> !devobj 8a0dbc88 Device object (8a0dbc88) is for: RawIp \Driver\Tcpip DriverObject 8a01ada0 Current Irp 00000000 RefCount 3 Type 00000012 Flags 00000050 Dacl e100d19c DevExt 00000000 DevObjExt 8a0dbd40
ГЛАВА 9 Поддержка сетей 873 ExtensionFlags (0000000000) Device queue is not busy. lkd> !devobj 8a0dc958 Device object (8a0dc958) is for: Udp \Driver\Tcpip DriverObject 8a01ada0 Current Irp 00000000 RefCount 41 Type 00000012 Flags 00000050 Dacl e100d19c DevExt 00000000 DevObjExt 8a0dca10 ExtensionFlags (0000000000) Device queue is not busy. lkd> !devobj 8a0dcd80 Device object (8a0dcd80) is for: Tcp \Driver\Tcpip DriverObject 8a01ada0 Current Irp 00000000 RefCount 302 Type 00000012 Flags 00000050 Dacl e1c3a1ac DevExt 00000000 DevObjExt 8a0dce38 ExtensionFlags (0000000000) Device queue is not busy. lkd> !devobj 8a0eff18 Device object (8a0eff18) is for: IPMULTICAST \Driver\Tcpip DriverObject 8a01ada0 Current Irp 00000000 RefCount 0 Type 00000012 Flags 00000040 Dacl e100d19c DevExt 00000000 DevObjExt 8a0effd0 ExtensionFlags (0000000000) Device queue is not busy. lkd> !devobj 8a0f32a0 Device object (8a0f32a0) is for: Ip \Driver\Tcpip DriverObject 8a01ada0 Current Irp 00000000 RefCount 48 Type 00000012 Flags 00000050 Dacl e1c3a1ac DevExt 00000000 DevObjExt 8a0f3358 ExtensionFlags (0000000000) Device queue is not busy. Microsoft определила стандарт TDI (Transport Driver Interface), чтобы драйверам сетевых API не приходилось использовать отдельные интерфей сы для каждого необходимого им транспортного протокола. Как уже гово рилось, интерфейс TDI фактически представляет собой правила формати рования сетевых запросов в IRP, а также выделения сетевых адресов и ком муникационных соединений. Транспортные протоколы, отвечающие стан дарту TDI, экспортируют интерфейс TDI своим клиентам, в число которых входят драйверы сетевых API, например AFD и редиректор. Транспортный протокол, реализованный в виде драйвера устройства Windows, называется транспортом TDI. Поскольку транспорты TDI являются драйверами уст ройств, они преобразуют получаемые от клиентов запросы в формат IRP. Интерфейс TDI образуют функции поддержки из библиотеки \Windows\ System32\Drivers\Tdi.sys вместе с определениями, включаемыми разработчи
874 ГЛ А В А 13 БЕЗОПАСНОСТЬ ками в свои драйверы. Модель программирования TDI очень напоминает таковую в Winsock. Устанавливая соединение с удаленным сервером, клиент TDI выполняет следующие действия. 1. Чтобы выделить адрес, клиент создает и форматирует TDI IRPпакет ad dress open. Транспорт TDI возвращает объект «файл», который представ ляет адрес и называется объектом адреса (address object). Эта операция эквивалентна вызову Winsockфункции bind. 2. Далее клиент создает и форматирует TDI IRPпакет connection open, а транспорт TDI возвращает объект «файл», который представляет соеди нение и называется объектом соединения (connection object). Эта опера ция эквивалентна вызову Winsockфункции socket. 3. Клиент сопоставляет объект соединения с объектом адреса с помощью TDI IRPпакета associate address (для этой операции эквивалентных функ ций Winsock нет). 4. Клиент TDI, соглашающийся установить удаленное соединение, выдает TDI IRPпакет listen, указывая для объекта соединения максимальное чис ло подключений. После этого он выдает TDI IRPпакет accept, обработка которого заканчивается либо установлением соединения с удаленной системой, либо ошибкой. Эти операции эквивалентны вызову Winsock функций listen и accept. 5. Клиент TDI, которому нужно установить соединение с удаленным серве ром, выдает TDI IRPпакет connect, указывая объект соединения, выполня емый транспортом TDI после установления соединения или появления ошибки. Выдача TDI IRPпакета connect эквивалентна вызову Winsock функции connect. TDI также поддерживает коммуникационную связь, не требующую логи ческих соединений, для протоколов соответствующего типа, например для UDP. Кроме того, TDI предоставляет клиенту TDI средства для регистрации в транспортах TDI своих функций обратного вызова по событиям (event callbacks) (т. е. функций, вызываемых напрямую). Например, при получении данных через сеть транспорт TDI может вызвать зарегистрированную кли ентом функцию обратного вызова для приема данных. Поддержка функций обратного вызова на основе событий позволяет транспорту TDI уведомлять своих клиентов о сетевых событиях, а клиенты, использующие такие функ ции, могут не выделять ресурсы для приема данных из сети, поскольку им доступно содержимое буферов, предоставляемых драйвером протокола TDI. ЭКСПЕРИМЕНТ: наблюдаем активность, связанную с TDI Утилита TDImon (www.sysinternals.com) является разновидностью драй вера фильтра, который подключается к объектам «устройство» \Device\Tcp и \Device\Udp, создаваемым драйвером TCP/IP. После под ключения TDImon может наблюдать за каждым IRP, выдаваемым кли ентами TDI своим протоколам. TDImon также может отслеживать функ
ГЛАВА 9 Поддержка сетей 875 ции обратного вызова по событиям, перехватывая запросы на их ре гистрацию от клиентов TDI. Драйвер TDImon посылает информацию об активности TDI своему графическому пользовательскому интер фейсу, который и отображает эти сведения (время операции, тип ак тивности TDI, локальный и удаленный адреса TCPсоединения или локальный адрес конечной точки UDP, код статуса IRP и др.). Ниже приведен экранный снимок окна TDImon, в котором ведется монито ринг активности TDI при просмотре Webстраницы в Internet Explorer. Как доказательство «врожденной» асинхронности операций TDI, в колонке Result выводятся сообщения «PENDING». Это говорит о том, что операция инициирована, но обработка IRP, вызвавшего ее выпол нение, еще не завершена. Чтобы было видно, в каком порядке одни операции завершаются относительно начала других, факт выдачи каж дого IRP или обращения к функции обратного вызова отмечается сво им порядковым номером. Если до завершения обработки данного IRP генерируются или завершаются другие IRP, эти факты также отмеча ются соответствующими порядковыми номерами, которые показыва ются в колонке Result. Например, на нашей иллюстрации IRP 1278 за вершился после генерации IRP 1279, поэтому в колонке Result для IRP 1278 выводится число 1280. Расширения TCP/IP Ряд сетевых сервисов Windows расширяет базовые сетевые возможности драйвера TCP/IP за счет применения драйверовнадстроек, интегрируемых с драйвером TCP/IP через закрытые интерфейсы. К числу таких сервисов относятся трансляция сетевых адресов (NAT), IPфильтрация, подключение IPловушек (IPhooking) и IPбезопасность (IPSec). На рис. 1317 показано, как эти расширения связаны с драйвером TCP/IP.
876 ГЛ А В А 13 Рис. 13-17. БЕЗОПАСНОСТЬ Архитектура расширений TCP/IP Трансляция сетевых адресов Трансляция сетевых адресов (network address translation, NAT) представляет собой сервис маршрутизации, позволяющий отображать несколько закры тых IPадресов на один общий IPадрес, видимый в Интернете. Без NAT для коммуникационной связи с Интернетом каждому компьютеру в локальной сети (LAN) пришлось бы назначать свой IPадрес, видимый в Интернете. NAT дает возможность назначить такой IPадрес только одному из компьютеров в локальной сети и подключать остальные компьютеры к Интернету через него. NAT по мере необходимости транслирует LANадреса в общий IPадрес, перенаправляя пакеты из Интернета на соответствующий компьютер в ло кальной сети. Компоненты NAT в Windows — драйвер устройства NAT (\Windows\Sys tem32\Drivers\Ipnat.sys), взаимодействующий со стеком TCP/IP, а также ре дакторы, с помощью которых возможна дополнительная обработка пакетов (помимо трансляции адресов и портов). NAT может быть установлен как маршрутизирующий протокол через оснастку Routing And Remote Access (Маршрутизация и удаленный доступ) консоли MMC или настройкой Интер нетсоединения на общее использование через апплет Network Connections (Сетевые подключения). (Более широкие возможности в настройке NAT пре доставляет оснастка Routing And Remote Access.) IP-фильтрация В Windows 2000, Windows XP и Windows Server 2003 есть минимальные ба зовые средства IPфильтрации, позволяющие пропускать пакеты только по определенным портам или IPпротоколам. Хотя эти средства в какойто мере защищают компьютер от несанкционированного доступа из сети, их недо
ГЛАВА 9 Поддержка сетей 877 статок в том, что они статичны и не предусматривают возможность автома тического создания новых фильтров для трафика, инициируемого работа ющими на компьютере приложениями. В Windows XP введен персональный брандмауэр — Windows Firewall, воз можности которого шире, чем у базовых средств фильтрации. Windows Fire wall реализует брандмауэр с поддержкой состояний (stateful firewall), кото рый отслеживает и различает трафик, генерируемый TCP/IP, и трафик, по ступающий из LAN и Интернета. Когда вы включаете Windows Firewall для какоголибо сетевого интерфейса, весь незатребованный входящий трафик по умолчанию отбрасывается. Приложение или пользователь может опреде лить исключения, чтобы сервисы, работающие на данном компьютере (вро де службы доступа к общим файлам и принтерам), были доступны с других компьютеров. Сервис Windows Firewall/ICS (Internet Connection Sharing), выполняемый в процессе Svchost, передает правила исключения, определенные через поль зовательский интерфейс Windows Firewall, драйверу IPNat. В режиме ядра Windows Firewall реализован в том же драйвере (\Windows\System32\Dri vers\Ipnat.Sys), который реализует трансляцию сетевых адресов (NAT). Драй вер NAT регистрируется в драйвере TCP/IP как драйвер ловушки брандмауэ ра (firewall hook). Драйвер TCP/IP выполняет функции обратного вызова каж дой зарегистрированной ловушки брандмауэра в ходе обработки входящих и исходящих IPпакетов. Функция обратного вызова может выступать в роли NAT, модифицируя адреса источника и получателя в пакете, или в роли бранд мауэра, возвращая код состояния, указывающий TCP/IP отбросить пакет. Хотя Ipnat реализует Windows Firewall с применением интерфейса лову шек брандмауэра TCP/IP, Microsoft рекомендует сторонним разработчикам реализовать поддержку фильтрации пакетов в виде промежуточного драй вера NDIS (о нем мы еще расскажем в этой главе). IP-фильтр и ловушка фильтра В Windows XP и Windows Server 2003 включен API фильтрации пакетов поль зовательского режима, а также драйвер фильтра IP, \Windows\System32\ Drivers\Ipfltrdrv.sys, которые позволяют приложениям управлять входящими и исходящими пакетами. Кроме того, драйвер фильтра IP дает возможность максимум одному драйверу регистрироваться в качестве драйвера ловушки фильтра (filter hook). TCP/IP — по аналогии с тем, как он взаимодействует с драйверами ловушек брандмауэра, — выполняет функцию, которую указы вает драйвер фильтра IP, а это позволяет IPфильтру отбрасывать или моди фицировать пакеты. В свою очередь IPфильтр обращается к функции обрат ного вызова, заданной драйвером ловушки фильтра, и тем самым передает изменения или запрос на отклонение пакета драйверу TCP/IP. Функциональность ловушки фильтра, предоставляемая системой, дает возможность сторонним разработчикам добавлять новые средства трансля ции, брандмауэра, протоколирования и т. д.
878 ГЛ А В А 13 БЕЗОПАСНОСТЬ IP-безопасность IPбезопасность (Internet Protocol Security, IPSec) интегрирована со стеком TCP/IP и защищает одноадресные (unicast) IPданные от перехвата и несанк ционированной модификации, подмены IPадресов и атак через посредни ка (maninthemiddle attacks). IPSec обеспечивает глубоко эшелонированную оборону от сетевых атак с недоверяемых компьютеров, от атак, которые могут привести к отказу в обслуживании, от повреждения данных, кражи информации и учетных данных пользователей, а также от попыток захва тить административный контроль над серверами, другими компьютерами и сетью. Эти цели реализуются за счет сервисов защиты на основе шифрова ния, протоколов безопасности и динамического управления ключами. При обмене одноадресными IPпакетами между доверяемыми хостами IPSec под держивает следующую функциональность: 쐽 аутентификацию источника данных — проверку источника IPпакета и запрет несанкционированного доступа к данным; 쐽 целостность данных — защиту IPпакета от модификации в процессе до ставки и распознавание любых изменений; 쐽 конфиденциальность — содержимое IPпакетов зашифровывается перед отправкой, благодаря чему их содержимое может быть расшифровано только указанным адресатом; 쐽 защиту от повторений пакетов (antireplay, или replay protection) — гаран тирует уникальность каждого IPпакета и невозможность его повторно го использования. Злоумышленник, даже если он сумеет перехватить IP пакеты, не сможет повторно использовать их для установления сеанса связи или неавторизованного доступа к информации. Для защиты от сетевых атак вы можете настроить IPSec на фильтрацию пакетов хостом (hostbased packet filtering) и разрешать соединения только с доверяемыми компьютерами. После настройки на фильтрацию пакетов хостом IPSec может разрешать или блокировать определенные виды одно адресного IPтрафика, исходя из адресов источника и получателя, заданных протоколов и портов. Поскольку IPSec интегрирован с IPуровнем (уровнем 3) стека TCP/IP и действует на все приложения, вам не понадобится настраи вать параметры безопасности индивидуально для каждого приложения, ра ботающего с TCP/IP. В среде Active Directory групповая политика позволяет настраивать доме ны, сайты и организационные единицы (organizational units, OU), а полити ки IPSec можно закреплять за нужными объектами групповой политики (Group Policy Objects, GPO). В качестве альтернативы можно конфигуриро вать и применять локальные политики IPSec. Политики IPSec хранятся в Active Directory, а копия параметров текущей политики поддерживается в кэше в локальном реестре. Локальные политики IPSec хранятся в реестре ло кальной системы. Для установления доверяемого соединения IPSec использует взаимную аутентификацию (mutual authentication), при этом поддерживаются следу
ГЛАВА 9 Поддержка сетей 879 ющие методы аутентификации: Kerberos версии 5, сертификат открытого ключа X.509 версии 3 или на основе общего ключа (preshared key). Windowsреализация IPSec основана на RFC, относящихся к IPSec. Архи тектура Windows IPSec включает IPSec Policy Agent (Агент политики IPбезо пасности), протокол Internet Key Exchange (IKE) и драйвер IPSec. 쐽 Агент политики IPбезопасности Выполняется как сервис в процес се LSASS (о LSASS см. главу 8). В MMCоснастке Services (Службы) в списке служб он отображается как IPSEC Services (Службы IPSEC). Агент полити ки IPбезопасности получает политику IPSec из домена Active Directory или из локального реестра и передает фильтры IPадресов драйверу IPSec, а параметры аутентификации и безопасности — IKE. 쐽 IKE Ожидает от драйвера IPSec запросы на согласование сопоставле ний безопасности (security associations, SA), согласовывает SA, а потом воз вращает параметры SA драйверу IPSec. SA — это набор взаимно согласо ванных параметров политики IPSec и ключей, определяющий службы и механизмы защиты, которые будут использоваться при защищенной ком муникационной связи между двумя равноправными хостами с IPSec. Каж дое SA является односторонним, или симплексным, соединением, кото рое защищает передаваемый по нему трафик. IKE согласует SA основно го и быстрого режимов, когда от драйвера IPSec поступает соответству ющий запрос. SA основного режима IKE (или ISAKMP) защищает процесс согласования, выполняемый IKE, а SA быстрого режима (или IPSec) — тра фик приложений. 쐽 Драйвер IPSec Это драйвер устройства (\Windows\System32\Drivers\ Ipsec.sys), который привязывается к драйверу TCP/IP и который обраба тывает пакеты, передаваемые через драйвер TCP/IP. Драйвер IPSec отсле живает и защищает исходящий одноадресный IPтрафик, а также отсле живает, расшифровывает и проверяет входящие одноадресные IPпакеты. Этот драйвер принимает фильтры от агента политики IPбезопасности, а затем пропускает, блокирует или защищает пакеты в соответствии с критериями фильтров. Для защиты трафика драйвер IPSec использует параметры активного SA либо запрашивает создание новых SA. MMCоснастка IP Security Policy Management (Управление политикой безо пасности IP) позволяет создавать политику IPSec и управлять ею. С помощью этой оснастки можно создавать, изменять и сохранять локальные политики IPSec или политики IPSec на основе Active Directory, а также модифицировать политику IPSec на удаленных компьютерах. В Windows XP и Windows Server 2003, после того как защищенное IPSecсоединение установлено, вы можете отслеживать информацию IPSec для локального и удаленных компьютеров через MMCоснастку IP Security Monitor (Монитор IPбезопасности). Драйверы NDIS Когда драйверу протокола требуется получить или отправить сообщение в формате своего протокола, он должен сделать это с помощью сетевого адап
880 ГЛ А В А 13 БЕЗОПАСНОСТЬ тера. Поскольку ожидать от драйверов протоколов понимания нюансов рабо ты каждого сетевого адаптера нереально (на рынке предлагается несколько тысяч моделей сетевых адаптеров с закрытой спецификацией), производите ли сетевых адаптеров предоставляют драйверы устройств, которые принима ют сетевые сообщения и передают их через свои устройства. В 1989 году ком пании Microsoft и 3Com совместно разработали спецификацию Network Dri ver Interface Specification (NDIS), которая определяет аппаратнонезависимое взаимодействие драйверов протоколов с драйверами сетевых адаптеров. Драйверы сетевых адаптеров, соответствующие NDIS, называются драйвера ми NDIS или минипортдрайверами NDIS. С Windows 2000 поставляется NDIS версии 5, а с Windows XP и Windows Server 2003 — версии 5.1. Библиотека NDIS (\Windows\System32\Drivers\Ndis.sys) реализует погра ничный уровень между транспортами TDI (в типичном случае) и драйвера ми NDIS. Как и Tdi.sys, библиотека NDIS является вспомогательной и исполь зуется клиентами драйверов NDIS для форматирования команд, посылаемых этим драйверам. Драйверы NDIS взаимодействуют с библиотекой, чтобы получать запросы и отвечать на них. Взаимосвязи между компонентами, имеющими отношение к NDIS, показаны на рис. 1318. Рис. 13-18. Компоненты NDIS Одна из целей Microsoft при разработке сетевой архитектуры состояла в том, чтобы производителям сетевых адаптеров было легче разрабатывать драйверы NDIS и переносить их код между потребительскими версиями Windows и Windows 2000. Таким образом, библиотека NDIS предоставляет драйверам не просто вспомогательные пограничные процедуры NDIS, а це лую среду выполнения драйверов NDIS. Последние не являются истинными драйверами Windows, поскольку не могут функционировать без инкапсули
ГЛАВА 9 Поддержка сетей 881 рующей их библиотеки NDIS. Этот инкапсулирующий уровень является на столько плотной оболочкой драйверов NDIS, что они не принимают и не обрабатывают IRP. Вместо этого драйверы протоколов TDI вызывают функ цию NdisAllocatePacket в библиотеке NDIS и передают пакеты минипорту NDIS, вызывая соответствующую NDISфункцию, например NdisSend. По умолчанию драйверам NDIS также не приходится заботиться о реентера бельности, когда библиотека NDIS вызывает драйвер с новым запросом до того, как он успел обработать предыдущий запрос. Освобождение от поддерж ки реентерабельности кода означает, что создатели драйверов NDIS могут не думать о сложных проблемах синхронизации, которые еще больше услож няются в многопроцессорных системах. ПРИМЕЧАНИЕ Библиотека NDIS использует для представления запро сов вводавывода NDISпакеты, а не IRP. Транспорты TDI создают NDIS пакет вызовом NdisAllocatePacket, после чего пакет передается мини порту NDIS вызовом одной из функций библиотеки NDIS (например, NdisSend). Хотя сериализация обращений к драйверам NDIS, осуществляемая биб лиотекой NDIS, упрощает разработку, она может помешать масштабирова нию многопроцессорных систем. Некоторые операции стандартных драй веров NDIS 4 (версия библиотеки NDIS 4 из Windows NT 4) плохо масшта бируются в многопроцессорных системах. В NDIS 5 разработчики получи ли возможность отказаться от такой сериализации. Драйвер NDIS 5 может сообщить библиотеке NDIS, что сериализация ему не нужна, и тогда библио тека NDIS переправляет драйверу запросы по мере получения соответству ющих IRP. В этом случае ответственность за управление параллельными зап росами ложится на драйвер NDIS, но отказ от сериализации окупается по вышением производительности в многопроцессорных системах. NDIS 5 также обеспечивает следующие преимущества. 쐽 Драйверы NDIS могут сообщать, активна ли несущая сетевая среда, что позволяет Windows выводить на панель задач значок, показывающий, подключен ли компьютер к сети. Эта функция также позволяет протоко лам и другим приложениям быть в курсе этого состояния и соответству ющим образом реагировать. Например, транспорт TCP/IP будет исполь зовать эту информацию, чтобы определять, когда нужно заново оцени вать информацию об адресах, получаемую им от DHCP. 쐽 Аппаратное ускорение TCP/IPопераций (TCP/IP task offload) позволяет ми нипорту пользоваться аппаратными функциями сетевого адаптера для вы полнения таких операций, как расчет контрольных сумм пакетов и все вы числения, связанные с IPбезопасностью (IPSec). Аппаратное ускорение этих операций средствами сетевого адаптера повышает производительность сис темы, освобождая центральный процессор от выполнения этих задач. 쐽 Функция WakeOnLAN дает возможность сетевому адаптеру с соответ ствующей поддержкой выводить систему Windows из состояния с низким
882 ГЛ А В А 13 БЕЗОПАСНОСТЬ энергопотреблением при какихлибо событиях в сети. Сигнал пробужде ния может быть инициирован сетевым адаптером при одном из следую щих событий: подключении к несущей среде (например, подключении сетевого кабеля к адаптеру) и приеме специфичных для протокола пос ледовательностей байтов (в случае адаптеров Ethernet — при получении волшебного пакета, т. е. сетевого пакета с 16 копиями Ethernetадреса адаптера подряд). 쐽 NDIS, ориентированная на логические соединения, позволяет драйверам NDIS управлять несущей средой, требующей логических соединений, на пример устройствами ATM (Asynchronous Transfer Mode). Интерфейсы, предоставляемые библиотекой NDIS драйверам NDIS для взаимодействия с сетевыми адаптерами, доступны через функции, вызовы которых транслируются непосредственно в вызовы соответствующих HAL функций. ЭКСПЕРИМЕНТ: перечисление загруженных минипортов NDIS Библиотека расширения отладчика ядра Ndiskd поддерживает коман ды !miniports и !miniport, которые позволяют с помощью отладчика ядра перечислять загруженные минипортдрайверы (минипорты) и получать детальную информацию о какомлибо минипорте по задан ному адресу блока минипорта (структуры данных, применяемой Win dows для отслеживания минипортов). Ниже приведен пример исполь зования команд !miniports и !miniport для вывода списка всех мини портдрайверов, а также для исследования специфики минипорта, от вечающего за взаимодействие системы с PCIадаптером Ethernet (за метьте, что WANминипорты работают с соединениями удаленного доступа). kd> .load ndiskd Loaded ndiskd extension DLL kd> !miniports Driver verifier level: 0 Failed allocations: 0 Miniport Driver Block: 817aa610 Miniport: 817b1130 RAS Async Adapter Miniport Driver Block: 81a1ef30 Miniport: 81a1ea70 Direct Parallel Miniport Driver Block: 81a21cd0 Miniport: 81a217f0 WAN Miniport (PPTP) Miniport Driver Block: 81a23290 Miniport: 81a22130 WAN Miniport (L2TP) Miniport Driver Block: 81a275f0 Miniport: 81a25130 Intel 8255xbased PCI Ethernet Adapter (10/100) kd> !miniport 81a25130 Miniport 81a25130 : Intel 8255xbased PCI Ethernet Adapter (10/100)
ГЛАВА 9 Поддержка сетей 883 Flags : 20413208 BUS_MASTER, INDICATES_PACKETS, IGNORE_REQUEST_QUEUE IGNORE_TOKEN_RING_ERRORS, NDIS_5_0, RESOURCES_AVAILABLE, DESERIALIZED, MEDIA_CONNECTED, NOT_SUPPORTS_MEDIA_SENSE, PnPFlags : 00010021 PM_SUPPORTED, DEVICE_POWER_ENABLED, RECEIVED_START CheckforHang interval: 2 seconds CurrentTick : 0001 IntervalTicks : 0001 InternalResetCount : 0000 MiniportResetCount : 0000 References: 3 UserModeOpenReferences: 0 PnPDeviceState : PNP_DEVICE_STARTED CurrentDevicePowerState : PowerDeviceD0 Bus PM capabilities DeviceD1: 1 DeviceD2: 1 WakeFromD0: 0 WakeFromD1: 1 WakeFromD2: 0 WakeFromD3: 0 SystemState PowerSystemUnspecified S0 S1 S2 S3 S4 S5 SystemWake: S1 DeviceWake: D1 DeviceState PowerDeviceUnspecified D0 D1 PowerDeviceUnspecified PowerDeviceUnspecified D3 D3 WakeupMethodes Enabled 6: WAKE_UP_PATTERN_MATCH WAKE_UP_LINK_CHANGE WakeUpCapabilities of the miniport MinMagicPacketWakeUp: 4 MinPatternWakeUp: 4 MinLinkChangeWakeUp: 4 Current PnP and PM Settings: : 00000030 DISABLE_WAKE_UP, DISABLE_WAKE_ON_RECONNECT, см. след. стр.
884 ГЛ А В А 13 БЕЗОПАСНОСТЬ Allocated Resources: Memory: f4100000, Length: 1000 IO Port: 1440, Length: 40 Memory: f4000000, Length: 100000 Interrupt Level: 9, Vector: 9 Translated Allocated Resources: Memory: f4100000, Length: 1000 IO Port: 1440, Length: 40 Memory: f4000000, Length: 100000 Interrupt Level: 12, Vector: 39 MediaType : 802.3 DeviceObject : 81a25030, PhysDO : 81a93cd0 Next DO: 81a63030 MapRegisters : 819fc000 FirstPendingPkt: 0 SingleWorkItems: [0]: 81a254e8 [1]: 81a254f4 [2]: 81a25500 [3]: 81a2550c [4]: 81a25518 [5]: 81a25524 DriverVerifyFlags : 00000000 Miniport Open Block Queue: 8164b888: Protocol 816524a8 = NBF, ProtocolContext 81649030 8191f628: Protocol 81928d88 = TCPIP, ProtocolContext 8191f728 Miniport Interrupt 81a00970 Поле Flags исследуемого минипорта показывает, что он поддержи вает несериализованные операции (DESERIALIZED), что несущая сре да в данный момент активна (MEDIA_CONNECTED) и что он является минипортом NDIS 5 (NDIS_5_0). Кроме того, выводится информация, отражающая сопоставления состояний электропитания устройства и системы, а также список ресурсов шины, назначенных адаптеру дис петчером Plug and Play. (Подробнее о соответствии состояний элект ропитания устройств и системы см. раздел «Диспетчер электропита ния» главы 9.) Разновидности минипорт-драйверов NDIS Модель NDIS также поддерживает гибридные NDISдрайверы транспорта TDI, называемые промежуточными драйверами NDIS (NDIS intermediate drivers). Они размещаются между транспортами TDI и драйверами NDIS. Драйверу NDIS промежуточный драйвер кажется транспортом TDI, а транс порту TDI — драйвером NDIS. Промежуточные драйверы NDIS видят весь сетевой трафик в системе, поскольку они расположены между драйверами протоколов и сетевыми драйверами. Программное обеспечение, предостав ляющее сетевым адаптерам поддержку отказоустойчивости и балансировки нагрузки, например Microsoft Network Load Balancing Provider, основано на использовании промежуточных драйверов NDIS.
ГЛАВА 9 Поддержка сетей 885 NDIS, ориентированная на логические соединения Поддержка сетевого оборудования, ориентированного на логические соеди нения (например, ATM) в Windows является встроенной, и соответствующие стандарты учтены в сетевой архитектуре Windows. Драйверы NDIS, ориен тированные на логические соединения, используют многие API, применяе мые и стандартными драйверами NDIS, но посылают пакеты через установ ленные сетевые соединения, а не просто помещают их в сетевую среду. Кроме поддержки минипортдрайверов для сетевых сред, ориентирован ных на логические соединения, в NDIS 5 включены определения для драй веров, поддерживающих такие минипортдрайверы. 쐽 Диспетчеры вызовов (call managers) являются драйверами NDIS, которые предоставляют сервисы настройки и завершения вызовов для клиентов, ориентированных на логические соединения (см. ниже). Диспетчер вы зовов использует ориентированный на логические соединения мини порт, чтобы обмениваться сигнальными сообщениями с другими сетевы ми компонентами (аппаратными или программными), например с ком мутаторами или другими диспетчерами вызовов. Диспетчер вызовов под держивает один или несколько сигнальных протоколов вроде ATM User Network Interface (UNI) 3.1. 쐽 Интегрированный Miniport Call Manager (MCM) представляет собой ми нипортдрайвер, ориентированный на логические соединения, который также предоставляет клиентам, требующим логических соединений, сер висы диспетчера вызовов. В сущности, MCM — это минипортдрайвер NDIS со встроенным диспетчером вызовов. 쐽 Ориентированный на логические соединения клиент использует серви сы настройки и завершения вызовов, предоставляемые диспетчером вы зовов или MCM, а также передает и принимает обращения к сервисам минипортдрайвера NDIS, ориентированного на логические соединения. Такой клиент может предоставлять собственные сервисы протокола бо лее высоким уровням сетевого стека или реализовать уровень эмуляции для взаимодействия с унаследованными протоколами, не требующими логических соединений, и соответствующей несущей средой. Пример уровня эмуляции, реализуемой ориентированным на логические соеди нения клиентом, — LAN Emulation (LANE), которая скрывает от вышеле жащих протоколов особенности ориентированной на логические соеди нения ATM и эмулирует для них несущую среду, не требующую соедине ний (например, Ethernet). Взаимосвязи между этими компонентами показаны на рис. 1319.
886 ГЛ А В А 13 Рис. 13-19. БЕЗОПАСНОСТЬ Драйверы NDIS, ориентированные на логические соединения ЭКСПЕРИМЕНТ: захват сетевых пакетов с помощью сетевого монитора Windows Server поставляется с программой Network Monitor (Сетевой монитор), которая позволяет перехватывать пакеты, проходящие че рез один или несколько минипортдрайверов NDIS, за счет установки промежуточного драйвера NDIS. Для использования Network Monitor нужно сначала установить Network Monitor Tools (Средства сетевого монитора). Для этого откройте апплет Add/Remove Programs (Установ ка и удаление программ) в Control Panel (Панель управления) и выбе рите Add/Remove Windows Components (Добавление и удаление ком понентов Windows). Укажите строку Management And Monitoring Tools (Средства управления и наблюдения), щелкните кнопку Details (Со став), установите флажок в строке Network Monitor Tools (Средства сетевого монитора) и щелкните кнопку OK. После установки Network Monitor (Сетевой монитор) можно запустить, выбрав одноименную команду из меню Administrative Tools (Администрирование). Network Monitor может спросить, за каким сетевым соединением вы хотите наблюдать. Выбрав нужное соединение, можно начать мо ниторинг, щелкнув на панели инструментов кнопку Start Capture (На чать запись данных). Выполните несколько операций, генерирующих сетевую активность в отслеживаемом соединении. Увидев, что Network Monitor захватил пакеты, остановите мониторинг, щелкнув кнопку Stop And View Capture (Закончить запись и отобразить данные). В ре зультате Network Monitor покажет захваченные данные.
ГЛАВА 9 Поддержка сетей 887 На этой иллюстрации показаны пакеты SMB (CIFS), захваченные Network Monitor при обращении системы к удаленным файлам. Если вы дважды щелкнете какуюнибудь строку, Network Monitor переклю чится в режим отображения пакетов, в котором показывается содер жимое различных заголовков в пакетах. Network Monitor поддерживает и другие возможности, например захват триггеров и фильтров, что делает его мощным диагностическим инструментом, помогающим выявлять и устранять неполадки в сети.
888 ГЛ А В А 13 БЕЗОПАСНОСТЬ Remote NDIS До разработки Remote NDIS производитель, например, сетевого USBустрой ства должен был предоставлять драйвер, который создавал интерфейс с NDIS (в качестве минипортдрайвера) и с WDMдрайвером шины USB (рис. 1320). Если производитель оборудования поддерживал другие шины, скажем, IEEE 1394, он должен был реализовать драйверы, создающие интерфейсы с каж дым типом шины. Рис. 13-20. Минипорт-драйвер NDIS для сетевого USB-устройства Remote NDIS — спецификация для сетевых устройств на PnPшинах вво давывода, допускающих динамическое подключение устройств, например USB, IEEE 1394 и Infiniband. Эта спецификация вообще избавляет произво дителя оборудования от необходимости писать минипортдрайвер NDIS, так как в ней определены сообщения, независимые от конкретной шины, и ме ханизм, с помощью которого сообщения передаются по различным шинам. В Remote NDIS включены сообщения для инициализации и сброса состоя ния устройства, передачи и приема пакетов, установки и опроса параметров устройства, а также для уведомления о состоянии канала передачи данных. Архитектура Remote NDIS (рис. 1321) построена на минипортдрайвере NDIS от Microsoft, \Windows\System32\Drivers\Rndismp.sys, который трансли рует NDISкоманды и передает их драйверу транспорта для шины, к которой подключено устройство. Эта архитектура позволяет использовать один ми нипортдрайвер NDIS для всех драйверов Remote NDIS и один драйвер транспорта для каждой поддерживаемой шины. В настоящее время Remote NDIS для USBустройств поддерживается в Windows XP и Windows Server 2003; кроме того, соответствующие компонен ты можно скачать с сайта Microsoft и установить в Windows 2000. Хотя Re mote NDIS для устройств IEEE 1394 полностью определен, он пока не под держивается в Windows.
ГЛАВА 9 Рис. 13-21. Поддержка сетей 889 Архитектура Remote NDIS для сетевых USB-устройств QoS Без специальных мер IPтрафик в сети доставляется по принципу «первым пришел — первым обслужен». Приложения не могут контролировать при оритет своих сообщений, и их данные передаются неравномерно: иногда они получают широкую полосу пропускания и малые задержки, а в осталь ное время — узкую полосу пропускания и длительные задержки. Хотя такой уровень обслуживания в большинстве ситуаций вполне приемлем, все боль шее число сетевых приложений требует гарантированных уровней обслужи вания, или гарантий качества обслуживания (Quality of Service, QoS). При мерами приложений, требующих хорошей сетевой производительности, могут служить видеоконференции, потоковая передача мультимедийной информации и программное обеспечение для планирования ресурсов пред приятия (enterprise resource planning, ERP). QoS позволяет приложениям ука зывать минимальную ширину полосы пропускания и максимальные задерж ки, которые могут быть удовлетворены только в том случае, если все сетевое программноаппаратное обеспечение на пути между отправителем и полу чателем поддерживает стандарты QoS, например IEEE 802.1p — промышлен ный стандарт, который определяет формат пакетов QoS и реакцию на их получение устройств второго сетевого уровня (коммутаторов и сетевых адаптеров). Поддержка QoS в Windows основана на наборе Winsockфункций, опре деленных Microsoft и позволяющих приложениям запрашивать QoS для тра фика через свои сокеты Winsock, а также на API управления трафиком (TC API), который позволяет административным приложениям более точно кон тролировать трафик через сети. Центральное место в реализации QoS в Windows занимает протокол RSVP (Resource Reservation Setup Protocol), представляющий собой Windowsсервис (\Windows\System32\Rsvp.exe), как показано на рис. 1322. Провайдер служ бы RSVP (\Windows\System32\Rsvpsp.dll) передает QoSзапросы приложений
890 ГЛ А В А 13 БЕЗОПАСНОСТЬ через RPC службе RSVP. Та в свою очередь контролирует сетевой трафик с помощью TC API. TC API, реализованный в \Windows\System32\Traffic.dll, по сылает команды управления вводомвыводом драйверу GPC (Generic Packet Classifier) (\Windows\System32\Drivers\Msgpc.sys). Драйвер GPC — в тесном вза имодействии с планировщиком пакетов QoS (промежуточным драйвером NDIS) (\Windows\System32\Drivers\Psched.sys) — контролирует поток пакетов с компьютера в сеть, гарантируя уровни QoS, обещанные конкретным прило жениям. При этом он вставляет в пакеты соответствующие заголовки QoS. ПРИМЕЧАНИЕ В Windows XP и Windows Server 2003 служба RSVP по прежнему работает, но действует лишь как посредник между приложе ниями и компонентами, управляющими трафиком. Рис. 13-22. Архитектура QoS Привязка Последний фрагмент головоломки под названием «сетевая архитектура Win dows» — способ, посредством которого сетевые компоненты, расположен ные на различных уровнях (сетевых API, драйверов транспортов TDI, драй веров NDIS), находят друг друга. Процесс соединения уровней называется привязкой (binding). Вы сами были свидетелем привязки, если хоть раз из меняли конфигурацию сети, добавляя или удаляя компоненты в окне свойств сетевого соединения. Устанавливая сетевой компонент, вы должны предоставить его INFфайл (INFфайлы описаны в главе 9). Этот файл содержит инструкции, которым должны следовать APIфункции установки, чтобы установить и сконфигури ровать компонент, учитывая его зависимости от других компонентов. Раз
ГЛАВА 9 Поддержка сетей 891 работчик может указать зависимости для своего компонента, что позволит SCM загружать его в корректной очередности и только тогда, когда все ком поненты, от которых он зависит, уже присутствуют в системе (о SCM см. гла ву 4). Привязки определяются механизмом привязки (bind engine) на осно ве информации из INFфайла компонента, что позволяют соединить его с другими компонентами, расположенными на различных уровнях. Эти соеди нения указывают, какие компоненты нижележащего уровня могут быть ис пользованы сетевым компонентом данного уровня. Так, служба рабочей станции (редиректор) автоматически привязывает ся к протоколам TCP/IP и NWLink. Порядок привязки, который можно уви деть на вкладке Adapters And Bindings (Адаптеры и привязки) диалогового окна Advanced Settings (Дополнительные параметры) (рис. 1323), определя ет приоритет привязки. (О том, как открыть это диалоговое окно, см. раздел «Поддержка нескольких редиректоров» ранее в этой главе.) Получив запрос на доступ к удаленному файлу, редиректор выдает запрос обоим драйверам протоколов. После того как редиректору приходит ответ, он дополнитель но ждет ответы от любых драйверов протоколов с более высоким приори тетом. И только тогда редиректор возвращает результат вызывающей про грамме. Поэтому, присвоив высокий приоритет привязкам, которые дают максимальную производительность или применимы к большинству компь ютеров в сети, можно добиться определенного выигрыша. Рис. 13-23. Редактирование привязок в диалоговом окне Advanced Settings Информация о привязках компонента содержится в параметре Bind под раздела Linkage того раздела реестра, в котором хранится конфигурация данного сетевого компонента. Например, информацию о привязках службы
892 ГЛ А В А 13 БЕЗОПАСНОСТЬ рабочей станции можно найти в HKLM\SYSTEM\CurrentControlSet\Services\ LanmanWorkstation\Linkage\Bind. Многоуровневые сетевые сервисы Windows включает сетевые сервисы, построенные на основе API и компо нентов, представленных в этой главе. Описание возможностей и внутренних деталей их реализации выходит за рамки этой книги, но мы приведем здесь краткий обзор по удаленному доступу, службе каталогов Active Directory, Network Load Balancing, службе репликации файлов (File Replication Service, FRS) и распределенной файловой системе (Distributed File System, DFS). Удаленный доступ Windows Server с установленной службой Routing and Remote Access Service (Служба маршрутизации и удаленного доступа) позволяет клиентам удален ного доступа подключаться к серверам удаленного доступа и обращаться к таким сетевым ресурсам, как файлы, принтеры и службы, создавая иллюзию физического подключения к серверу удаленного доступа через локальную сеть. Windows поддерживает два типа удаленного доступа. 쐽 Удаленный доступ через телефонную линию (dialup remote ac cess) Используется клиентом при подключении к серверу удаленного доступа через телефонную линию или иную телекоммуникационную инфраструктуру. Телекоммуникационная несущая среда используется для создания временного физического или виртуального соединения между клиентом и сервером. 쐽 Удаленный доступ через виртуальную частную сеть (virtual pri vate network, VPN) Позволяет клиентам VPN устанавливать с сервером виртуальное соединение типа «точкаточка» через IPсеть, например Ин тернет. Удаленный доступ отличается от удаленного управления, поскольку про граммное обеспечение удаленного доступа выступает в роли проксисоеди нения с сетью Windows, тогда как программное обеспечение для удаленно го управления выполняет приложения на сервере, предоставляя клиенту пользовательский интерфейс. Active Directory Active Directory — реализация службы каталогов LDAP (Lightweight Directory Access Protocol) в Windows. Active Directory основана на базе данных, в ко торой хранятся объекты, представляющие ресурсы, определенные приложе ниями в сети Windows. Например, в Active Directory хранится структура и список членов домена Windows, включая информацию об учетных записях и паролях пользователей.
ГЛАВА 9 Поддержка сетей 893 Классы объектов и атрибуты, определяющие свойства объектов, задают ся схемой (schema). Иерархическая организация объектов в схеме Active Directory напоминает логическую организацию реестра, где объектыкон тейнеры могут хранить другие объекты, включая контейнеры. Active Directory поддерживает несколько API, используемых клиентами для обращения к объектам в базе данных Active Directory. 쐽 LDAP C API Предназначен для программ на C/C++ и использует сетевой протокол LDAP. Приложения, написанные на С/C++, могут работать с этим API напрямую, а приложения, написанные на других языках, — че рез транслирующие уровни. 쐽 ADSI (Active Directory Service Interfaces) COMинтерфейс Active Directory, реализованный поверх LDAP и абстрагирующий от деталей про граммирования для LDAP. ADSI поддерживает несколько языков, в том числе Microsoft Visual Basic, C и Microsoft Visual C++. ADSI также доступен приложениям Windows Script Host (Сервер сценариев Windows). 쐽 MAPI (Messaging API) Поддерживается для совместимости с клиентами Microsoft Exchange и клиентскими приложениями Outlook Address Book. 쐽 Security Account Manager (SAM) API Базируется на сервисах Active Directory и предоставляет интерфейс пакетам аутентификации MSV1_0 (\Windows\System32\Msv1_0.dll) и Kerberos (\Windows\System32\Kdcsvc.dll). 쐽 Сетевые API Windows NT 4 (Net API) Используются клиентами Win dows NT 4 для доступа к Active Directory через SAM. 쐽 NTDS API Применяется для просмотра SID и GUID в Active Directory (в основном через DsCrackNames), а также для управления каталогом и его репликацией. Несколько сторонних разработчиков написали приложе ния, позволяющие вести мониторинг Active Directory через этот API. Active Directory реализована в виде файла базы данных (по умолчанию — в \Windows\Ntds\Ntds.dit), реплицируемой между контроллерами домена. Этой базой данных управляет служба каталогов Active Directory, которая яв ляется Windowsсервисом, выполняемым в процессе LSASS; при этом она использует DLL, реализующие структуру базы данных на диске и предостав ляющие механизмы обновления на основе транзакций для поддержания целостности базы данных. В Windows 2000 хранилище базы данных Active Directory реализовано на основе ядра Extensible Storage Engine (ESE), приме няемого в Microsoft Exchange Server 5.5, а в Windows 2003 Server — на осно ве ядра ESE, используемого в Microsoft Exchange Server 2000. Архитектура Active Directory показана на рис. 1324.
894 ГЛ А В А 13 Рис. 13-24. БЕЗОПАСНОСТЬ Архитектура Active Directory Network Load Balancing Как мы уже говорили в этой главе, в основе компонента Network Load Balan cing (Балансировка нагрузки сети), который входит в Windows Advanced Server, лежит технология промежуточных драйверов NDIS. Network Load Balancing допускает создание кластера, включающего до 32 компьютеров, которые в терминологии Network Load Balancing называются узлами клас тера (cluster hosts). Кластер поддерживает единый виртуальный IPадрес, публикуемый клиентам, и клиентские запросы поступают ко всем компью терам кластера. Однако на запрос отвечает только один узел кластера. Драй веры NDIS компонента Network Load Balancing эффективно разделяют кли ентское пространство между доступными узлами кластера по аналогии с распределенной обработкой. При таком подходе каждый узел обрабаты вает свою порцию клиентских запросов, причем каждый клиентский запрос обрабатывается одним — и только одним — узлом. Если входящий в состав кластера узел определяет, что именно он должен обработать клиентский запрос, то этот узел позволяет запросу пройти до уровня драйвера TCP/IP и в конце концов достичь серверного приложения. Если на узле кластера про
ГЛАВА 9 Поддержка сетей 895 исходит авария, остальные узлы кластера распознают, что этот узел больше не способен обрабатывать запросы, и перераспределяют поступающие кли ентские запросы между собой; при этом клиентские запросы отключенно му узлу больше не посылаются. К кластеру можно подключить новый узел на замену потерпевшему аварию, и он автоматически примет участие в обра ботке клиентских запросов. Network Load Balancing не является универсальным кластерным решени ем, поскольку серверные приложения, с которыми взаимодействуют клиен ты, должны обладать определенными характеристиками. Вопервых, они должны поддерживать TCP/IP, а во вторых, уметь обрабатывать клиентские запросы на любой системе в кластере Network Load Balancing. Второе тре бование, как правило, означает, что приложения, у которых для обслужива ния клиентских запросов должен быть доступ к общему состоянию (shared state), обязаны сами управлять этим состоянием. В Network Load Balancing не входят сервисы автоматического распределения общего состояния меж ду узлами кластера. Приложения, идеально подходящие для Network Load Balancing, — Webсервер со статичным информационным наполнением (контентом), Windows Media Server и Terminal Services (Службы терминалов). Пример работы Network Load Balancing показан на рис. 1325. Рис. 13-25. Так работает Network Load Balancing Служба репликации файлов Служба репликации файлов (File Replication Service, FRS) входит в системы Windows Server. Она предназначена в основном для репликации содержимо го каталога \SYSVOL контроллера домена (в этом месте контроллеры доме
896 ГЛ А В А 13 БЕЗОПАСНОСТЬ нов Windows хранят сценарии регистрации и групповые политики). Кроме того, FRS позволяет реплицировать общие ресурсы DFS (Distributed File Sys tem) между системами. FRS поддерживает распределенную репликацию с несколькими хозяевами (distributed multimaster replication), благодаря чему репликацию может проводить любой сервер. Когда реплицируемый файл или каталог изменяется, эти изменения распространяются на другие кон троллеры домена. Фундаментальное понятие в FRS — набор репликации (replica set), пред ставляющий собой дерево каталогов, которое реплицируется между двумя или более системами по определенной топологии и расписанию, заданно му администратором. Реплицированы могут быть только каталоги на томах NTFS, поскольку FRS использует журнал изменений NTFS для определения модификаций в файлах и каталогах, включенных в набор репликации. По скольку FRS обеспечивает репликацию с несколькими хозяевами, теорети чески она может поддерживать сотни и даже тысячи систем в наборе реп ликации, а топология соединения соответствующих компьютеров может быть совершенно произвольной (кольцо, звезда, сетка и др.). Кроме того, компьютеры могут участвовать в нескольких наборах репликации. FRS реализована в виде Windowsсервиса (\Windows\System32\Ntfrs.exe), который использует аутентифицируемый RPC для взаимодействия со свои ми экземплярами, работающими на других компьютерах. Кроме того, по скольку Active Directory располагает собственными средствами репликации, FRS использует APIфункции Active Directory для выборки конфигурацион ной информации из домена Active Directory. DFS DFS (Distributed File System) — сервис поверх службы рабочей станции, со единяющий отдельные файловые ресурсы в единое пространство имен. DFS обеспечивает клиентам прозрачный доступ к файловым ресурсам независи мо от того, где находятся эти ресурсы — на локальном или удаленных ком пьютерах. Корнем пространства имен DFS должен быть файловый ресурс, определенный на компьютере с Windows Server. В дополнение к унифицированному пространству имен сетевых ресур сов DFS дает и другие преимущества при использовании наборов реплика ции DFS. Администратор может создать набор репликации DFS минимум из двух сетевых ресурсов и использовать механизм репликации вроде FRS для копирования данных между ресурсами, входящими в набор репликации, и тем самым обеспечить синхронизацию их содержимого. DFS поддерживает несколько видов балансировки нагрузки, упорядочивая и/или выбирая сете вые ресурсы, входящие в набор репликации, при обращении клиента к дан ным из этого набора. DFS также обеспечивает высокую доступность данных, перенаправляя запросы на другие сетевые ресурсы из набора репликации, если какойто из сетевых ресурсов временно недоступен.
ГЛАВА 9 Поддержка сетей 897 Компоненты, образующие архитектуру DFS, показаны на рис. 1326. Реа лизация DFS на серверной стороне включает Windowsсервис (\Windows\ System32\Dfssvc.exe) и драйвер устройства (\Windows\System32\Drivers\ Dfs.sys). Служба DFS отвечает за экспорт интерфейсов управления топологи ей DFS и поддержку топологии DFS либо в реестре (в отсутствие Active Di rectory), либо в Active Directory. Драйвер DFS принимает клиентский запрос и переадресует его системе, на которой находится запрошенный файл. Рис. 13-26. Компоненты DFS На клиентской стороне поддержка DFS реализована в драйвере MUP (о нем мы уже рассказывали) и использует редиректор CIFS для взаимодействия с серверами DFS на внутреннем уровне. Провайдер клиента DFS реализован в \Windows\System32\Ntlanman.dll. Когда клиент выдает запрос на вводвы вод для файла в пространстве имен DFS, драйвер MUP на клиентской сторо не взаимодействует с сервером, на котором находится этот файл, через под ходящий редиректор. Резюме Сетевая архитектура Windows предоставляет гибкую инфраструктуру сете вым API, драйверам протоколов и сетевых адаптеров. Эта архитектура ис пользует преимущества многоуровневого вводавывода, обеспечивая расши ряемость сетевой поддержки по мере развития компьютерных сетей. При появлении нового протокола разработчики смогут создать транспорт TDI, реализующий этот протокол в Windows. Аналогичным образом новые API смогут взаимодействовать с существующими драйверами протоколов Win dows. Наконец, набор сетевых API, реализованных в Windows, позволяет раз работчикам сетевых приложений выбирать подходящие им реализации, поддерживающие разные модели программирования и протоколы.
Г Л А В А 1 4 Анализ аварийного дампа Почти каждый пользователь Windows слышал о так называемом «синем эк ране смерти» (blue screen of death, BSOD) или даже видел его. Этим зловещим термином называют экран с синим фоном, показываемый при крахе или остановке Windows изза катастрофического сбоя или внутренней ситуации, изза которой стала невозможной дальнейшая работа системы. В этой главе мы рассмотрим основные причины краха Windows, опишем информацию, выводимую на «синем экране» и расскажем о различных па раметрах конфигурации, управляющих созданием аварийного дампа (crash dump) — копии системной памяти на момент краха, которая может помочь определить, какой именно компонент вызвал крах. В цели данного раздела не входит детальное рассмотрение способов выявления и устранения про блем с помощью анализа аварийного дампа Windows. Тем не менее в этом разделе показывается, как, проанализировав аварийный дамп, идентифици ровать некорректно работающий драйвер или компонент. Для базового ана лиза аварийного дампа требуется минимум усилий и несколько минут вре мени. Анализ дампа стоит проводить, даже если проблемный драйвер удается выявить только с пятой или десятой попытки: успешно выполненный ана лиз позволит избежать потерь данных и простоя системы. Почему происходит крах Windows? Крах Windows (остановка системы и вывод «синего экрана») может быть вызван следующими причинами: 쐽 необработанным исключением, вызванным драйвером устройства или системной функцией режима ядра, например изза нарушения доступа к памяти (при попытке записи на страницу с атрибутом «только для чте ния» или чтения по еще не спроецированному и, следовательно, недопу стимому адресу); 쐽 вызовом процедуры ядра, результатом которой является перераспределе ние процессорного времени изза, например, ожидания на занятом объекте диспетчера ядра при IRQL уровня «DPC/dispatch» или выше (об IRQL см. главу 3); 쐽 обращением к данным на выгруженной из памяти странице при IRQL уровня «DPC/dispatch» или выше (что требует от диспетчера памяти ждать
ГЛАВА 9 Анализ аварийного дампа 899 операции вводавывода, а это, как уже говорилось, невозможно на таких уровнях IRQL, поскольку требует перераспределения процессорного вре мени); 쐽 явным вызовом краха системы драйвером устройства или системной функцией (через функцию KeBugCheckEx) при обнаружении поврежден ных внутренних данных или в ситуации, когда продолжение работы сис темы грозит таким повреждением; 쐽 аппаратной ошибкой, например ошибкой аппаратного контроля или появлением немаскируемого прерывания (NonMaskable Interrupt, NMI). В Microsoft проанализировали аварийные дампы, отправляемые пользо вателями Windows XP на сайт Microsoft Online Crash Analysis (OCA) (о нем еще пойдет речь в этой главе), и обнаружили, что причины краха систем распределяются, как показано на диаграмме на рис. 141 (по состоянию на апрель 2004 года). Рис. 14-1. Причины краха систем по данным OCA Когда драйвер устройства или компонент режима ядра вызывает необра батываемое исключение, перед Windows встает трудная дилемма. Какаято часть операционной системы, имеющая право доступа к любым аппаратным устройствам и любому участку памяти, сделала нечто такое, чего делать нельзя. Но почему при этом обязательно должен произойти крах Windows? По чему бы не проигнорировать это исключение и не позволить драйверам работать дальше, как ни в чем не бывало? Ведь не исключено, что ошибка носила локальный характер и соответствующий компонент какнибудь су меет после нее восстановиться. Но гораздо вероятнее, что обнаруженное исключение связано с более серьезными проблемами, например с повреж дением памяти или со сбоями в работе оборудования. Тогда дальнейшее функционирование системы скорее всего приведет к еще большему числу исключений и порче данных на дисках и других периферийных устрой ствах, а это слишком рискованно.
900 ГЛ А В А 14 БЕЗОПАСНОСТЬ «Синий экран» Независимо от причины реальный крах системы вызывается функцией Ke BugCheckEx (документирована в Windows DDK). Она принимает так называ емый стопкод (stop code), или контрольный код ошибки (bug check code), и четыре параметра, интерпретируемые с учетом стопкода. KeBugCheckEx маскирует все прерывания на всех процессорах системы, а затем переклю чает видеоадаптер в графический режим VGA с низким разрешением (под держиваемый всеми видеокартами, совместимыми с Windows) и выводит на синем фоне значение стопкода и несколько строк текста с рекомендация ми относительно дальнейших действий. Наконец, KeBugCheckEx вызывает все зарегистрированные (с помощью функции KeRegisterBugCheckCallback) функции обратного вызова драйверов устройств при ошибке (device driver bug check callbacks), чтобы они могли остановить свои устройства. (Систем ные структуры данных могут быть настолько серьезно повреждены, что «си ний экран» может и не появиться.) Образец «синего экрана» Windows XP показан на рис. 142. ПРИМЕЧАНИЕ В Windows XP Service Pack 1 (или выше) и в Windows Server 2003 введена функция KeRegisterBugCheckReasonCallback, позво ляющая драйверам устройств добавить данные в аварийный дамп или вывести информацию аварийного дампа на альтернативное устройство. Рис. 14-2. Пример «синего экрана» В Windows 2000 KeBugCheckEx выводит текстовое представление стоп кода, его числовое значение и четыре параметра вверху «синего экрана», но в Windows XP и Windows Server 2003 числовое значение и параметры пока зываются внизу «синего экрана». В первой строке выводится стопкод и значения четырех дополнитель ных параметров, переданных в KeBugCheckEx. Строка вверху экрана пред
ГЛАВА 9 Анализ аварийного дампа 901 ставляет собой текстовый эквивалент числового идентификатора стопкода. В примере на рис. 142 стопкод 0х000000D1 соответствует IRQL_NOT_ LESS_OR_ EQUAL. Если параметр содержит адрес части операционной сис темы или кода драйвера устройства (как на рис. 142), Windows выводит ба зовый адрес соответствующего модуля, дату и имя файла драйвера. Одной этой информации может оказаться достаточно для идентификации сбойно го компонента. Хотя стопкодов более сотни, большинство из них очень редко или во обще никогда не встречается в рабочих системах. Причины краха Windows могут быть представлены довольно небольшой группой стопкодов. Кроме того, не забывайте, что смысл дополнительных параметров зависит от кон кретного стопкода (но не для всех стопкодов предусматривается расши ренная информация, передаваемая через эти параметры). Тем не менее, ана лиз стопкода и значений параметров (если таковые есть) может, по край ней мере, помочь в выявлении сбойного компонента (или аппаратного уст ройства, вызывающего крах). Информацию, необходимую для интерпретации стопкодов, можно най ти в разделе «Bug Checks (Blue Screens)» справочного файла Windows Debug ging Tools. (Сведения о Windows Debugging Tools см. в главе 1.) Кроме того, можно поискать стопкод и имя проблемного устройства или приложения в Microsoft Knowledge Base (http://support.microsoft.com). В ней можно найти информацию о способах исправления ошибки, об обновлениях или сервис ных пакетах, решающих проблему, с которой вы столкнулись. Файл Bug codes.h в Windows DDK содержит полный список из примерно 150 стопко дов с детальным описанием некоторых из них. «Синие экраны» часто возникают после установки нового программно го обеспечения или оборудования. Если вы видите «синий экран» сразу после установки нового драйвера на раннем этапе перезагрузки, то можете вернуть прежнюю конфигурацию системы, нажав клавишу F8 и выбрав из дополни тельного загрузочного меню команду Last Known Good Configuration (Пос ледняя удачная конфигурация). Тогда Windows использует копию раздела реестра, где были зарегистрированы драйверы устройств (HKLM\SYSTEM\ CurrentControlSet\Services) при последней успешной загрузке (до установки нового драйвера). Последней удачной конфигурацией считается последняя конфигурация, в которой успешно завершилась загрузка всех сервисов и драйверов и был выполнен минимум один успешный вход в систему. (О пос ледней удачной конфигурации более подробно рассказывается в главе 5.) Если это не помогает и вы попрежнему видите «синие экраны», то самый очевидный подход — удалить компоненты, установленные перед появлени ем первого «синего экрана». Если после установки уже прошло некоторое время или вы одновременно добавили несколько устройств либо драйверов, обратите внимание на имена драйверов, указываемые в какихлибо парамет рах на «синем экране». Если там есть ссылка на недавно установленные ком поненты (например, Scsiport.sys в случае установки нового SCSIдиска), при чина сбоя скорее всего связана именно с ними.
902 ГЛ А В А 14 БЕЗОПАСНОСТЬ Имена многих драйверов весьма загадочны, но вы можете выяснить, ка кие устройства или программные компоненты соответствуют данному име ни. Для этого просмотрите раздел реестра HKLM\SYSTEM\CurrentControlSet\ Services, где Windows хранит регистрационную информацию для каждого драйвера в системе, и попробуйте найти имя сервиса и сопоставленный с ним драйвер устройства. Описание найденного драйвера содержится в па раметрах DisplayName и Description, здесь также описывается предназначе ние некоторых драйверов. Так, строка «Virus Scanner», обнаруженная в Dis playName, говорит о том, что драйвер является частью антивирусной про граммы. Список драйверов также можно вывести с помощью утилиты System Information (Сведения о системе): раскройте в ней узел Software Environment (Программная среда) и выберите System Drivers (Системные драйверы). Однако чаще всего информации, сообщаемой стопкодом и сопоставлен ными с ним параметрами, недостаточно для устранения сбоя, приводящего к краху системы. Так, чтобы выяснить точное имя драйвера или системного компонента, вызывающего крах, может понадобиться анализ стека вызовов режима ядра. Поскольку в Windows после краха системы по умолчанию сле дует перезагрузка и у вас вряд ли будет время для изучения информации, представленной на «синем экране», Windows пытается записывать инфор мацию о крахе системы на диск для последующего анализа. Эта информа ция помещается в файлы аварийного дампа. Файлы аварийного дампа По умолчанию все Windowsсистемы настраиваются на запись информации о состоянии системы на момент краха. Соответствующие настройки можно уви деть так: откройте System (Система) в Control Panel (Панель управления), в окне свойств системы перейдите на вкладку Advanced (Дополнительно) и щелкните кнопку Startup And Recovery (Загрузка и восстановление). На рис. 143 показа ны настройки по умолчанию для системы Windows XP Professional. Рис. 14-3. Параметры аварийного дампа
ГЛАВА 9 Анализ аварийного дампа 903 При крахе системы может быть зарегистрировано три уровня информации. 쐽 Complete memory dump (Полный дамп памяти) Полный дамп па мяти представляет собой все содержимое физической памяти на момент краха. Для такого дампа нужно, чтобы размер страничного файла был ра вен, как минимум, объему физической памяти плюс 1 Мб (для заголовка). Этот параметр используется реже всего, так как в системах с большим объемом памяти страничный файл будет слишком велик. Windows NT 4 поддерживает только этот тип файлов аварийного дампа. Кроме того, этот параметр используется по умолчанию в системах Windows Server. 쐽 Kernel memory dump (Дамп памяти ядра) Этот вариант дампа вклю чает лишь страницы (как для чтения, так и для записи) режима ядра, нахо дящиеся в физической памяти на момент краха. Страницы, принадлежа щие пользовательским процессам, не включаются. Поскольку только код режима ядра может напрямую вызывать крах Windows, содержимое стра ниц пользовательских процессов обычно ничего не дает для понимания причин краха. Кроме того, все структуры данных, используемые при ана лизе аварийного дампа, — список выполняемых процессов, стек текущего потока и список загруженных драйверов — хранятся в неподкачиваемой памяти, содержимое которой запоминается в дампе памяти ядра. Заранее предсказать объем дампа памяти ядра нельзя, поскольку он зависит от объема памяти ядра, выделенной операционной системой и драйверами. 쐽 Small memory dump (Малый дамп памяти) Размер этого дампа (ва риант по умолчанию в системах Windows Professional) составляет 64 Кб (128 Кб в 64битных системах). Такой дамп еще называют минидампом (mini dump) или минимальным дампом (triage dump). Он включает в себя стопкод с параметрами, список загруженных драйверов устройств, структуры данных, описывающие текущие процесс и поток (EPROCESS и ETHREAD, которые рас сматриваются в главе 6), а также стек ядра для вызвавшего крах потока. Полный дамп памяти является надмножеством двух других дампов, но у него есть недостаток: его размер зависит от объема физической памяти сис темы и, следовательно, он может оказаться слишком большим. Мощные сер верные системы, оснащенные несколькими гигабайтами памяти, — не такая уж редкость. Записываемые на них файлы полного аварийного дампа будут слишком велики для закачивания на FTPсервер или прожигания на CD. По скольку в большинстве случаев код и данные пользовательского режима не используются при анализе аварийных дампов (ведь причиной краха являют ся проблемы, связанные с памятью ядра, системные структуры данных так же содержатся в памяти ядра), большая часть данных, сохраненных в пол ном дампе памяти, не нужна для анализа и впустую увеличивает размер фай ла дампа. Наконец, еще один недостаток в том, что размер страничного фай ла на загрузочном томе (содержащем каталог \Windows) должен быть равен объему физической памяти системы плюс 1 Mб. Поскольку необходимость в страничном файле, как правило, уменьшается с ростом объема физичес кой памяти, это требование означает, что страничный файл будет неоправ
904 ГЛ А В А 14 БЕЗОПАСНОСТЬ данно большим. Поэтому приходится признать, что лучше использовать малый дамп памяти или дамп памяти ядра. Преимущество минидампа — его небольшой размер, благодаря которо му, например, удобно передавать дамп по электронной почте. При каждом крахе в каталог \Windows\Minidump записывается файл с уникальным име нем, начинающимся со строки «Mini», за которой идут дата и порядковый номер (например, Mini08260401.dmp). Недостаток минидампов в том, что для их анализа нужны именно те образы, которые использовались системой, сгенерировавшей дамп. (Даже для самого простого анализа, как минимум, необходима копия соответствующего Ntoskrnl.exe.) Это может стать пробле мой, если вы анализируете дамп не на той системе, где он был создан. Од нако на сервере символов Microsoft есть образы (и символы) для систем Windows XP и более поздних версий, поэтому можно задать в отладчике путь к образу, указывающий на сервер символов, и отладчик автоматически ска чает нужные образы. (Конечно, на сервере символов Microsoft нет образов устанавливаемых вами драйверов сторонних производителей.) Более существенный недостаток — такой дамп содержит ограниченное количество данных, что может помешать эффективному анализу. С минидам пами можно работать, даже если вы настроили систему на генерацию дам па памяти ядра или полного дампа, — просто откройте более объемный дамп в Windbg и извлеките минидамп командой .dump /m. Заметьте: в Windows XP и Windows Server 2003 минидамп автоматически создается, даже если сис тема настроена на генерацию полного дампа памяти или дампа памяти ядра. ПРИМЕЧАНИЕ Выполнив команду .dump в Livekd, можно сгенериро вать образ памяти работающей системы, чтобы, не останавливая сис тему, получить дамп для анализа в автономном режиме. Такой подход полезен, когда в системе проявляются какието проблемы, но она про должает обслуживать клиентов и вы хотели бы устранить проблемы, не прерывая обслуживание. Полученный в результате дамп не обяза тельно будет полностью корректным, так как содержимое различных областей памяти извлекается в разные моменты времени, но может со держать информацию, полезную для анализа. Золотой серединой является дамп памяти ядра. Он содержит всю физи ческую память режима ядра, и, следовательно, позволяет вести анализ на том же уровне, что и полный дамп памяти, но не содержит код и данные пользо вательского режима, обычно не относящиеся к проблеме, и поэтому имеет значительно меньший размер. Так, в системе с 256 Мб памяти под управле нием Windows XP дамп памяти ядра занимает 34 Мб, а в системе с Windows XP и 1,5 Гб памяти этот дамп требует 72 Мб. Когда вы настраиваете параметры дампа памяти ядра, система проверяет, достаточен ли размер страничного файла (в соответствии с таблицей 141), но это всего лишь оценочные размеры, поскольку предсказать размер дам па памяти ядра невозможно. Причина, по которой невозможно заранее оп ределить размер дампа памяти ядра, состоит в том, что этот размер зави
ГЛАВА 9 Анализ аварийного дампа 905 сит от количества памяти режима ядра, используемой операционной систе мой и драйверами, выполнявшимися на компьютере в момент краха. Таблица 14-1. Минимальные размеры страничного файла для дампов ядра Объем системной памяти Минимальный размер страничного файла для генерации дампов ядра (Мб) < 128 Мб 50 < 4 Гб 200 < 8 Гб 400 >= 8 Гб 800 Таким образом, может оказаться, что в момент краха системы странич ный файл будет слишком мал для того, чтобы вместить дамп ядра. Если вы хотите узнать размер дампа ядра для своей системы, вызовите крах систе мы вручную: сконфигурируйте систему так, чтобы можно было вручную вызывать ее крах с консоли, или воспользуйтесь программой Notmyfault. (В этой главе описаны оба подхода.) После перезагрузки вы сможете прове рить, сгенерирован ли дамп памяти ядра, и по его размеру оценить, каким должен быть размер страничного файла для вашего загрузочного тома. Для единообразия можно задавать для 32разрядных систем размер странично го файла 2 Гб плюс 1 Мб, поскольку 2 Гб — максимальный размер адресно го пространства режима ядра. Наконец, даже если система в случае краха успешно записывает аварий ный дамп в страничный файл, нужно, чтобы на диске хватало места для из влечения файла дампа. Если места не хватит, аварийный дамп пропадет, по скольку используемое им пространство страничного файла высвободится и будет перезаписано, когда система начнет использовать страничный файл. Если на загрузочном томе недостаточно места для сохранения файла me mory.dmp, можно задать путь на другом жестком диске в диалоговом окне, показанном на рис. 143. Генерация аварийного дампа При загрузке система получает параметры аварийного дампа из раздела ре естра HKLM\System\CurrentControlSet\Control\CrashControl. Если задана ге нерация дампа, система создает копию минипортдрайвера диска (disk mini port driver), используемую для записи загрузочного тома в память и присва ивает ей то же имя, что и у минипорта, но с префиксом «dump_». Кроме того, система подсчитывает и сохраняет контрольную сумму для компонентов, используемых при записи аварийного дампа: скопированного минипорт драйвера диска, функций диспетчера вводавывода, записывающих дамп, и карты области, в которой располагается страничный файл на загрузочном томе. Когда вызывается функция KeBugCheckEx, она заново пересчитывает контрольную сумму и сравнивает новую контрольную сумму с полученной при загрузке. Если они не совпадают, функция не записывает аварийный дамп, так как это может привести к сбою диска или повреждению данных на
906 ГЛ А В А 14 БЕЗОПАСНОСТЬ диске. Если контрольные суммы совпали, KeBugCheckEx записывает инфор мацию дампа прямо в секторы диска, занимаемые страничным файлом, ми нуя драйвер файловой системы (который, возможно, поврежден или даже является причиной краха). Когда SMSS в процессе загрузки активизирует постраничную подкачку, система проверяет, не содержится ли в страничном файле на загрузочном томе аварийный дамп, и защищает ту часть страничного файла, которая от ведена под дамп. В результате на раннем этапе загрузки часть страничного файла или весь этот файл выводится из использования, что может вызвать системные уведомления о нехватке виртуальной памяти, однако это лишь временное явление. При дальнейшей загрузке Winlogon определяет, содер жится ли дамп в страничном файле, вызывая недокументированную APIфунк цию NtQuerySystemInformation. Если дамп есть, запускается процесс Savedump (\Windows\System32\Savedump.exe), который извлекает аварийный дамп из страничного файла и записывает его в заданное место. Эти операции пока заны на рис. 144. Рис. 14-4. Генерация файла аварийного дампа Windows Error Reporting Как уже говорилось в главе 3, в Windows XP и Windows Server 2003 имеется механизм Windows Error Reporting, позволяющий автоматически передавать данные о сбоях процессов и системы на анализ в Microsoft (или на внутрен ний сервер отчетов об ошибках). По умолчанию этот механизм включен. На его работу можно повлиять, изменив поведение процесса Savedump, кото рый выполняет следующую дополнительную операцию: при перезагрузке после краха проверяет, настроена ли система на отправку аварийного дам па на анализ в Microsoft (или на закрытый сервер). На рис. 145 показано диалоговое окно Error Reporting (Отчет об ошибках), которое можно от крыть с вкладки Advanced (Дополнительно) апплета System (Система) пане ли управления. В этом диалоговом окне можно настроить параметры сис темных отчетов об ошибках, хранящиеся в разделе реестра HKLM\Software\ Microsoft\PCHealth\ErrorReporting.
ГЛАВА 9 Рис. 14-5. Анализ аварийного дампа 907 Диалоговое окно настройки Error Reporting После перезагрузки, вызванной крахом, Savedump проверяет несколько параметров, содержащихся в разделе ErrorReporting: Showui, DoReport и IncludeKernelFaults. Если все они имеют значение true, Savedump выполняет следующие операции по подготовке отчета о крахе системы к отправке на сайт Microsoft Online Crash Analysis (OCA) (или на внутренний сервер отче тов об ошибках, если это задано в настройках). 1. Если сгенерированный дамп не является минидампом, извлекает из файла дампа минидамп и записывает его в каталог по умолчанию — \Windows\ Minidumps. 2. Записывает имя файла минидампа в HKLM\Software\Microsoft\PCHealth\ ErrorReporting\KernelFaults. 3. Добавляет команду запуска утилиты Dumprep (\Windows\System32\Dump rep.exe) в раздел HKLM\Software\Microsoft\Windows\CurrentVersion\Run, чтобы Dumprep запустилась при первом входе пользователя в систему. Анализ аварийных дампов через Интернет Когда запускается утилита Dumprep (в результате того, что Savedump доба вила в реестр соответствующее значение), эта утилита проверяет те же три параметра, что и Savedump, чтобы определить, должна ли система отправить отчет об ошибке после перезагрузки, вызванной крахом. Если должна, Dump rep генерирует XMLфайл, содержащий базовое описание системы, в том числе версию операционной системы, список драйверов, установленных на компьютере, и список драйверов Plug and Play, загруженных в момент кра ха. Затем Dumprep выводит диалоговое окно, показанное на рис. 146, за прашивая у пользователя, нужно ли отправить в Microsoft отчет об ошибке. Если пользователь указал, что нужно, и это не противоречит групповым по литикам, Dumprep отправляет XMLфайл и минидамп на сайт http://wat son.microsoft.com, который пересылает данные на серверную ферму, где от четы автоматически анализируются (об этом см. следующий раздел). Через групповые политики администраторы могут настроить свои системы так, чтобы данные об ошибках направлялись во внутренний сетевой каталог,
908 ГЛ А В А 14 БЕЗОПАСНОСТЬ предназначенный для сбора данных об ошибках. В дальнейшем эти данные можно обрабатывать с помощью Microsoft Corporate Error Reporting (CER) Toolkit, доступного только избранным клиентам Microsoft Software Assurance (информацию см. по ссылке http://www.microsoft.com/resources/satech/cer). Рис. 14-6. Диалоговое окно, предлагающее отправить отчет об ошибке Ферма серверов автоматического анализа использует тот же механизм, что и разработанные Microsoft отладчики ядра, в которые вы можете загру зить аварийный дамп (вскоре мы о них расскажем). При анализе генериру ется так называемый идентификатор типа (bucket ID) — сигнатура, иден тифицирующая определенный тип краха. Ферма серверов выполняет запрос к базе данных, пытаясь по идентификатору типа найти решение проблемы, вызвавшей крах, и отправляет утилите Dumprep URL со ссылкой на сайт OCA (http://oca.microsoft.com). Dumprep запускает Webбраузер, чтобы открыть страницу сайта OCA с предварительными результатами анализа дампа. Если решение проблемы найдено, на странице выводятся инструкции о том, где получить критическое исправление, сервисный пакет или обновление сто роннего драйвера; в ином случае предоставляется возможность получать информацию о ходе анализе дампа по электронной почте. Если у организации нет доступа к Интернету или она не собирается ав томатически отправлять аварийные дампы в Microsoft, то через групповые политики можно указать, что данные об ошибках должны храниться во внут реннем сетевом каталоге; в дальнейшем их можно будет обрабатывать с по мощью Microsoft CER Toolkit, упоминавшегося выше. Базовый анализ аварийных дампов Если при анализе, выполненном OCA, не удалось найти решение проблемы или если вы не сумели отправить аварийный дамп на сайт OCA (например, если этот дамп сгенерирован Windows 2000, не поддерживающей OCA), то вы мо жете самостоятельно проанализировать дамп. Как уже говорилось, когда вы загружаете аварийный дамп в Windbg или Kd, эти отладчики ядра применяют тот же механизм анализа, что и OCA. Иногда даже базового анализа достаточ но для выявления проблемы. Таким образом, если вам повезет, вы найдете ре шение проблемы путем автоматического анализа аварийного дампа. Но даже если и не повезет, существуют простые методики выявления причин краха.
ГЛАВА 9 Анализ аварийного дампа 909 В этом разделе поясняется, как выполнить базовый анализ аварийного дампа, затем даются рекомендации, как с помощью Driver Verifier (с которым вы познакомились в главе 7) перехватывать операции некорректно написан ных драйверов, приводящие к повреждению системы, и получать аварийные дампы, анализ которых может выявить проблему. Notmyfault Различные виды краха системы, рассматриваемые здесь, можно вызвать с помощью утилиты Notmyfault (www.sysinternals.com/windowsinternals). Not myfault состоит из исполняемого файла Notmyfault.exe и драйвера Myfault.sys. Когда вы запускаете исполняемый файл Notmyfault, он загружает драйвер и выводит диалоговое окно, показанное на рис. 147. В этом окне вы можете выбрать различные варианты краха системы или указать, что драйвер дол жен вызвать утечку памяти из пула подкачиваемой памяти. Доступны наибо лее распространенные (по статистике Microsoft Product Support Services) виды краха системы. После того как вы выбрали параметр и щелкнули кноп ку Do Bug, исполняемый файл через APIфункцию DeviceIoControl обращает ся к драйверу и указывает ему, ошибка какого типа должна произойти. За метьте: лучше экспериментировать, вызывая крах системы через Notmyfault, на тестовой или виртуальной системе, так как полностью исключить веро ятность того, что поврежденная память не будет записана на диск, нельзя. Рис. 14-7. Notmyfault
910 ГЛ А В А 14 БЕЗОПАСНОСТЬ ПРИМЕЧАНИЕ Имена исполняемого файла и драйвера Notmyfault («не моя вина») отражают тот факт, что приложение, выполняемое в пользовательском режиме, не может напрямую вызвать крах системы. Исполняемый файл Notmyfault способен вызвать крах системы, толь ко загрузив драйвер, который выполнит запрещенную операцию в режиме ядра. Базовый анализ Самый простой для отладки крах вызывается при выборе переключателя High IRQL Fault (Kernelmode) и нажатии кнопки Do Bug. Тогда драйвер вы делит страницу в пуле подкачиваемой памяти, освободит страницу, подни мет уровень IRQL выше «DPC/dispatch», а затем обратится к освобожденной странице. (Об IRQL см. главу 3.) Если это не приведет к краху, система про должит считывать память после конца страницы до тех пор, пока не про изойдет крах изза обращения к недействительной странице. Таким образом, драйвер выполняет несколько недопустимых операций. 1. Ссылается на память, которая ему не принадлежит. 2. Обращается к пулу подкачиваемой памяти при IRQL уровня «DPC/dis patch» или выше, что недопустимо, так как при таких IRQL ошибки стра ниц не разрешены. 3. Выходит за конец выделенной области памяти и пытается обратиться к памяти, которая потенциально может быть недействительной. Первое обращение к странице не обязательно должно вызвать крах, если страница, освобожденная драйвером, остается в системном рабочем набо ре. (О системном рабочем наборе см. главу 7.) Загрузив в Kd аварийный дамп, сгенерированный при таком крахе, вы увидите следующие результаты: Microsoft (R) Windows Debugger Version 6.3.0011.2 Copyright (c) Microsoft Corporation. All rights reserved. Loading Dump File [c:\windows\memory.dmp] Kernel Summary Dump File: Only kernel address space is available Symbol search path is: srv*c:\symbols*http://msdl.microsoft.com/ download/symbols Executable search path is: Windows 2000 Kernel Version 2195 UP Free x86 compatible Product: LanManNt, suite: Enterprise TerminalServer Kernel base = 0x80400000 PsLoadedModuleList = 0x8046a4c0 Debug session time: Mon Apr 05 18:28:44 2004 System Uptime: 0 days 0:09:20.105 Loading Kernel Symbols
ГЛАВА 9 Анализ аварийного дампа 911 .............................................................................................. Loading unloaded module list No unloaded module list present Loading User Symbols .......... ********************************************************************* * * * Bugcheck Analysis * * * ********************************************************************* Use !analyze v to get detailed debugging information. BugCheck D1, {bead1800, 1c, 0, ec1fb357} *** ERROR: Module load completed but symbols could not be loaded for myfault.sys *** WARNING: Unable to verify checksum for NotMyfault.exe *** ERROR: Module load completed but symbols could not be loaded for NotMyfault.exe Probably caused by : myfault.sys ( myfault+357 ) Followup: MachineOwner ———— kd> Прежде всего следует заметить, что Kd сообщает об ошибках при загруз ке символов для Myfault.sys и Notmyfault.exe. Этого можно было ожидать, поскольку файлы символов для них нельзя обнаружить по пути поиска фай лов символов (который указывает на сервер символов Microsoft). Вы будете получать аналогичные ошибки для драйверов сторонних производителей и исполняемых файлов, не входящих в операционную систему. Текст, содержащий результаты анализа, достаточно краток: показаны чис ловой стопкод и контрольные параметры, далее идет строка «probably cau sed by». В ней указан драйвер, который, с точки зрения механизма анализа, является наиболее вероятной причиной ошибки. В данном случае наш драй вер попал на заметку, и эта строка указывает прямо на Myfault.sys, поэтому проводить анализ вручную нет нужды. Строка «Followup», как правило, не несет полезной информации — эти данные используются в Microsoft, когда отладчик ищет имя модуля в файле Triage.ini, содержащемся в подкаталоге Triage установочного каталога Debug ging Tools for Windows. В версии этого файла, используемой внутри Microsoft, перечислены разработчики или группы, которые должны анализировать крах системы, вызываемый тем или иным драйвером, и, если удалось найти разработчика или группу, соответствующее имя выводится в строке Followup.
912 ГЛ А В А 14 БЕЗОПАСНОСТЬ Детальный анализ Во всех случаях, даже когда удалось выявить сбойный драйвер с помощью базового анализа аварийного дампа Notmyfault, нужно проводить детальный анализ командой: !analyze –v Первое очевидное отличие детального анализа и анализа по умолчанию состоит в том, что в первом случае выводится описание стопкода и его па раметров. Ниже приведен вывод этой команды для того же дампа: DRIVER_IRQL_NOT_LESS_OR_EQUAL (d1) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high. This is usually caused by drivers using improper addresses. If kernel debugger is available get stack backtrace. Arguments: Arg1: bead1800, memory referenced Arg2: 0000001c, IRQL Arg3: 00000000, value 0 = read operation, 1 = write operation Arg4: ec1fb357, address which referenced memory Таким образом, вам не придется открывать справочный файл, чтобы по лучить ту же информацию. Иногда выводимый текст содержит рекоменда ции по устранению неполадок — вы увидите такой пример в следующем разделе, где рассматривается углубленный анализ дампов. Другая потенциально полезная информация, выводимая при детальном анализе — трассировочные данные стека потока, выполнявшегося в момент краха. Вот как она выглядит для того же дампа: STACK_TEXT: WARNING: Stack unwind information not available. Following frames may be wrong. b7e6dc34 804ac5de ff7c4040 beb4bf68 ff80a9c8 myfault+0x357 b7e6dd00 804a8f1e 00000070 00000000 00000000 nt!IopXxxControlFile+0x5e4 b7e6dd34 80461691 00000070 00000000 00000000 nt!NtDeviceIoControlFile+0x28 b7e6dd34 77f96be2 00000070 00000000 00000000 nt!KiSystemService+0xc4 0012f4a0 77e84c9b 00000070 00000000 00000000 ntdll!ZwDeviceIoControlFile+0xb 0012f504 004017c3 00000070 83360018 00000000 KERNEL32!DeviceIoControl+0x100 000200ac 00000000 00000000 00000000 00000000 NotMyfault+0x17c3 Приведенный выше стек показывает, что образ исполняемого файла Not myfaul, показанный внизу, вызывал функцию DeviceIoControl в Kernel32.dll,
ГЛАВА 9 Анализ аварийного дампа 913 которая в свою очередь вызвала ZwDeviceIoControlFile в Ntdl.dll, и т. д., пока система, наконец, не рухнула при выполнении инструкции в образе Myfault. Стеки вызовов, подобные этому, могут оказаться полезными, поскольку иног да причиной краха системы является то, что один драйвер передал другому неправильно отформатированные, поврежденные или недопустимые пара метры. Драйвер, передавший некорректные данные, способные вызвать крах системы, можно выявить при анализе, просмотрев стек вызовов, из которо го видно, что было обращение к другому драйверу. В данном простом при мере в стеке вызовов показан только драйвер myfault. (Модуль «nt» — это Ntoskrnl.) Если вам не известен драйвер, выявленный при анализе, выполните ко манду lm (аббревиатура от «list modules»), чтобы посмотреть информацию о версии драйвера. Укажите параметры k (kernel modules), v (verbose), m (match), а затем имя драйвера и символ подстановки: kd> lm kv m myfault* start end module name f224d000 f224dbe0 myfault (deferred) Image path: \??\C:\WINNT\system32\drivers\myfault.sys Timestamp: Thu Apr 29 14:53:12 2004 (40915D28) Checksum: 00010090 ImageSize : 00000BE0 File version: 2.0.0.0 Product version: 2.0.0.0 File flags: 0 (Mask 3F) File OS: 40004 NT Win32 File type: 3.7 Driver File date: 00000000.00000000 Translations: 0409.04b0 CompanyName: Sysinternals ProductName: Sysinternals Myfault InternalName: myfault.sys OriginalFilename: myfault.sys ProductVersion: 2.0 FileVersion: 2.0 FileDescription: Crash Test Driver LegalCopyright: Copyright (C) M. Russinovich 20022004 Вы можете идентифицировать назначение драйвера по описанию, а так же выяснить по версии файла и продукта, установлена ли у вас самая послед няя версия. (Это можно определить, например, посетив сайт разработчика драйвера.) Если информация о версии отсутствует, например в момент кра ха соответствующая страница была выгружена из физической памяти, вы получите ее из свойств файла образа драйвера: просмотрите их с помощью Windows Explorer.
914 ГЛ А В А 14 БЕЗОПАСНОСТЬ Средства анализа проблем, вызывающих крах В предыдущем разделе, когда мы вызвали крах системы, выбрав параметр High IRQL Fault (Kernelmode) в Notmyfault, автоматический анализ дампа в отладчике не составил труда. Увы, в большинстве случаев исследовать крах системы с помощью отладчика сложно, а зачастую и невозможно. Существу ет несколько уровней верификации (с нарастающей степенью сложности и пропорциональным падением производительности системы), которые по зволяют добиться того, чтобы вместо дампа, непригодного для анализа, ге нерировался дамп, пригодный для анализа. Если после настройки системы в соответствии с требованиями одного уровня и перезагрузки, вам не уда лось выявить причину краха, попробуйте перейти на следующий уровень. 1. Если вы считаете, что крах системы может вызывать один или несколько драйверов, поскольку они были установлены в систему относительно недавно или их недавно обновили, или это следует из обстоятельств, при которых система терпит крах, то включите верификацию этих драйверов в Driver Verifier и выберите все режимы верификации, кроме имитации нехватки ресурсов. 2. Задайте тот же уровень верификации, но для всех неподписанных драй веров в системе. Или, если вы работаете с Windows 2000, в которой Driver Verifier не делает различий между подписанными и неподписанными драйверами, включите верификацию всех драйверов, поставляемых не Microsoft, а другими компаниями. 3. Задайте тот же уровень верификации, но для всех драйверов системы. Чтобы сохранить приемлемую производительность, можно разбить драй веры на группы и в промежутках между перезагрузками активизировать Driver Verifier для какойто одной группы драйверов. Очевидно, прежде чем тратить время и силы на изменение конфигурации системы и анализ аварийных дампов, стоит убедиться в том, что использу ются последние версии компонентов ядра и драйверов сторонних постав щиков, и при необходимости обновить их через Windows Update или напря мую через сайты производителей устройств. ПРИМЕЧАНИЕ Если загрузка вашей системы стала невозможной из за того, что Driver Verifier обнаруживает ошибку драйвера и вызывает крах системы, загрузите систему в безопасном режиме (в котором ве рификация отключена), запустите Driver Verifier и отключите парамет ры проверки. В следующих разделах показывается, как с помощью Driver Verifier сделать так, чтобы вместо дампов, непригодных для отладки, создавались дампы, позволяющие решить проблему. Кроме того, почитайте справочный файл Debugging Tools, где есть руководства по методикам углубленной отладки.
ГЛАВА 9 Анализ аварийного дампа 915 Переполнение буфера и особый пул Несомненно, что чаще всего причиной краха Windows является поврежде ние пула. Обычно оно вызывается ошибкой драйвера, в результате которой данные записываются до начала или за концом буфера, выделенного в пуле подкачиваемой или неподкачиваемой памяти. Структуры управления пула ми (pool tracking structures) исполнительной системы располагаются с каж дой стороны буфера и отделяют их друг от друга. Таким образом, подобные ошибки приводят к повреждению структур управления пулами, поврежде нию буферов других драйверов или и к тому, и к другому. Крах, вызванный повреждением пулов, практически невозможно исследовать с помощью от ладчика, поскольку крах системы происходит при обращении к поврежден ным данным, а не в момент их повреждения. ПРИМЕЧАНИЕ Чтобы облегчить выявление этих трудноуловимых по вреждений, в Windows XP Service Pack 2 (или выше) всегда выполня ется проверка выхода за границы блока в пуле (poolblock tail che cking). Поэтому переполнение буфера скорее всего тут же приведет к краху BAD_POOL_HEADER. Вы можете вызвать крах, связанный с переполнением буфера, запустив Notmyfault и выбрав переключатель Buffer Overflow. В этом случае Myfault выделит память под буфер и перезапишет 40 байтов, идущих после буфера. Между щелчком кнопки Do Bug и крахом системы может пройти довольно много времени, возможно, вам даже придется задействовать пул, запустив какиелибо приложения. Это еще раз подчеркивает, что повреждение может не скоро привести к последствиям, влияющим на стабильность системы. Анализ аварийного дампа, полученного при такой ошибке, почти всегда показывает, что проблема связана с Ntoskrnl или какимлибо другим драй вером. И это демонстрирует бесполезность детального анализа при таком описании стопкода: DRIVER_CORRUPTED_EXPOOL (c5) An attempt was made to access a pageable (or completely invalid) address at an interrupt request level (IRQL) that is too high. This is caused by drivers that have corrupted the system pool. Run the driver verifier against any new (or suspect) drivers, and if that doesn’t turn up the culprit, then use gflags to enable special pool. Arguments: Arg1: 4f4f4f53, memory referenced Arg2: 00000002, IRQL Arg3: 00000001, value 0 = read operation, 1 = write operation Arg4: 80467139, address which referenced memory В описании стопкода рекомендуется запустить Driver Verifier для каждо го нового или подозрительного драйвера или активизировать особый пул с помощью Gflags. В обоих случаях преследуется одна и та же цель: выявить потенциальное повреждение в момент, когда оно происходит, и вызвать
916 ГЛ А В А 14 БЕЗОПАСНОСТЬ крах системы так, чтобы при автоматическом анализе удалось обнаружить драйвер, вызвавший повреждение. Если в Driver Verifier включен режим особого пула, проверяемые драйве ры используют специальный пул вместо пула подкачиваемой или неподка чиваемой памяти во всех случаях, когда выделяется память для буферов раз мера, немного меньшего размера страницы. Буфер, память под который вы деляется из особого пула, заключен между двумя недействительными стра ницами и по умолчанию выравнивается по верхней границе страницы. Кро ме того, подпрограммы управления особым пулом заполняют неиспользуе мое пространство страницы, содержащей буфер, по случайному шаблону. На рис. 148 показано, как выделяется память из особого пула. Рис. 14-8. Выделение памяти из особого пула Система обнаруживает любые переполнения буфера, содержащегося в странице, поскольку они приводят к ошибке страницы: происходит обраще ние к недействительной странице, которая идет за буфером. Сигнатура нуж на, чтобы перехватывать выход за конец буфера в момент, когда драйвер освобождает буфер: при выходе за конец будет нарушена целостность шаб лона, помещенного в эту область при выделении памяти под буфер. Чтобы посмотреть, как с помощью особого пула вызвать крах системы, который легко диагностировать с помощью механизма автоматического ана лиза, запустите Driver Verifier Manager (Диспетчер проверки драйверов). В Win dows 2000 перейдите на вкладку Settings (Параметры), введите myfault.sys в текстовое поле внизу страницы, предназначенное для задания дополнитель ных драйверов, установите флажок особого пула, сохраните изменения, вый дите из Driver Verifier Manager и перезагрузитесь. В Windows XP и Windows Server 2003 выберите Create Custom Settings (For Code Developers) [Создать не стандартные параметры (для кода программ)] на первой странице мастера, на второй — Select Individual Settings From A Full List (Выбрать параметры из списка), на третьей — Special Pool (Особый пул). Далее выберите Select Drivers From A List (Выберите имя драйвера из списка), а на странице, где перечис лены типы драйверов, введите myfault.sys в диалоговом окне, открываемом после нажатия кнопки добавления незагруженных драйверов. (Не ищите в
ГЛАВА 9 Анализ аварийного дампа 917 этом диалоговом окне файл myfault.sys — просто введите его имя.) Затем от метьте драйвер myfault.sys, выйдите из мастера и перезагрузитесь. Когда вы запустите Notmyfault и вызовете переполнение буфера, сразу же произойдет крах системы, а анализ дампа даст следующий результат: Probably caused by : myfault.sys ( myfault+3f1 ) При детальном анализе вы получите следующее описание стопкода: DRIVER_PAGE_FAULT_BEYOND_END_OF_ALLOCATION (d6) N bytes of memory was allocated and more than N bytes are being referenced. This cannot be protected by tryexcept. When possible, the guilty driver’s name (Unicode string) is printed on the bugcheck screen and saved in KiBugCheckDriver. Arguments: Arg1: beb50000, memory referenced Arg2: 00000001, value 0 = read operation, 1 = write operation Arg3: ec3473f1, if nonzero, the address which referenced memory. Arg4: 00000000, (reserved) Благодаря особому пулу трудноуловимая ошибка немедленно проявила себя, и анализ стал тривиальным. Перезапись кода и защита системного кода от записи Драйвер, в котором изза «бага» происходит повреждение или неправильная интерпретация его собственных структур данных, может обращаться к не принадлежащей ему памяти, воспринимая поврежденные данные как указа тель на область памяти. Такой некорректный указатель может указывать на что угодно в адресном пространстве, в том числе на данные, принадлежащие другим драйверам, недействительные страницы памяти или на код других драйверов или ядра. Как и при переполнении буфера, драйвер, вызвавший повреждение данных, обычно не удается идентифицировать в момент, ког да повреждение обнаруживается и происходит крах системы. Использова ние особого пула увеличивает вероятность выявления «багов», связанных с некорректными указателями, но не выявляет повреждение кода. Если вы запустите Notmyfault и выберете переключатель Code Overwrite, драйвер Myfault повредит точку входа функции NtReadFile. Далее возможны два варианта. Если ваша система работает под управлением Windows 2000 и оснащена не более чем 127 Мб физической памяти или работает под управ лением Windows XP или Windows Server 2003 и оснащена не более чем 255 Мб физической памяти, произойдет крах и анализ дампа укажет на Myfault.sys. В описании стопкода, выводимом при детальном анализе, говорится, что драйвер Myfault попытался записать данные в память, доступную только для чтения: ATTEMPTED_WRITE_TO_READONLY_MEMORY (be) An attempt was made to write to readonly memory. The guilty driver is on the stack trace (and is typically the current instruction pointer). When possible, the guilty driver’s name (Unicode string) is printed on the bugcheck screen and saved in KiBugCheckDriver.
918 ГЛ А В А 14 Arguments: Arg1: 804bb7fd, Arg2: 004bb121, Arg3: b804db60, Arg4: 0000000b, БЕЗОПАСНОСТЬ Virtual address for the attempted write. PTE contents. (reserved) (reserved) Однако, если у вас Windows 2000 и более 127 Мб памяти либо Windows XP или Windows Server 2003 и более 255 Мб памяти, произойдет крах дру гого типа, так как повреждение памяти сразу не проявится. Поскольку NtReadFile — широко используемая системная функция, к которой подсис тема Windows обращается при считывании ввода с клавиатуры или от мыши, крах системы произойдет почти сразу же, как только какойлибо поток по пытается выполнить поврежденный код. Возникнет ошибка изза выполне ния недопустимой инструкции. Анализ аварийного дампа, выполняемый в этом случае, может давать разные результаты, но они обязательно будут не правильными. Обычно механизм анализа приходит к выводу, что наиболее вероятными источниками ошибки являются Windows.sys или Ntoskrnl.exe. При таком крахе выводится следующее описание стопкода: KMODE_EXCEPTION_NOT_HANDLED (1e) This is a very common bugcheck. Usually the exception address pinpoints the driver/function that caused the problem. Always note this address as well as the link date of the driver/image that contains this address. Arguments: Arg1: c0000005, The exception code that was not handled Arg2: 80461885, The address that the exception occurred at Arg3: 00000000, Parameter 0 of the exception Arg4: 00000000, Parameter 1 of the exception Разные конфигурации ведут себя поразному в связи с тем, что в Windows 2000 введен механизм защиты системного кода от записи (system code write protection). В таблице 142 показано, в каких конфигурациях защита системного кода от записи не используется по умолчанию. Таблица 14-2. Конфигурации, в которых отключена защита системного кода от записи Защита системного кода от записи отключена Windows 2000 Windows XP и Windows Server 2003 RAM > 127 Мб RAM > 255 Мб Если защита системного кода от записи включена, диспетчер памяти про ецирует Ntoskrnl.exe, HAL и загрузочные драйверы как стандартные физичес кие страницы (4 Кб для x86 и x64, 8 Кб для IA64). Поскольку при проециро вании образов обеспечивается детализация с точностью до размера стандарт ной страницы, диспетчер памяти может защитить страницы, содержащие код, от записи и генерировать ошибку доступа при попытке их модифика ции (что вы и видели при первом крахе). Но когда защита системного кода от записи отключена, диспетчер памяти использует при проецировании Ntoskrnl.exe большие страницы (4 Мб для x86 или 16 Мб для IA64 и x64). Та
ГЛАВА 9 Анализ аварийного дампа 919 кой режим по умолчанию действует в Windows 2000 при наличии более чем 127 Мб памяти, а в Windows XP или Windows Server 2003 — при наличии более чем 255 Мб памяти. Диспетчер памяти не может защитить код, по скольку код и данные могут находиться на одной странице. Если защита системного кода от записи отключена и при анализе аварий ного дампа сообщается о маловероятных причинах краха или если вы по дозреваете, что произошло повреждение кода, следует включить защиту. Для этого проще всего включить проверку хотя бы одного драйвера с помощью Driver Verifier. Кроме того, можно включить защиту вручную, добавив два параметра в раздел реестра HKLM\System\CurrentControlSet\Control\Session Manager\Memory Management. Сначала укажите максимально возможное значение для объема памяти, начиная с которого диспетчер памяти исполь зует при проецировании Ntoskrnl.exe большие страницы вместо стандарт ных. Создайте параметр LargePageMinimum типа DWORD, присвойте ему значение 0xFFFFFFFF. Добавьте еще один параметр типа DWORD — Enforce WriteProtection — и присвойте ему значение 1. Чтобы изменения вступили в силу, перезагрузите компьютер. ПРИМЕЧАНИЕ Когда отладчик имеет доступ к файлам образов, вклю ченным в аварийный дамп, при анализе на внутреннем уровне выпол няется команда отладчика !chkimg, которая проверяет, совпадает ли ко пия образа в аварийном дампе с образом на диске, и сообщает о раз личиях. Заметьте: если вы активизируете Driver Verifier, chkimg обяза тельно обнаружит различия при сравнении с файлом Ntoskrnl.exe. Углубленный анализ аварийных дампов В предыдущем разделе рассказывалось о том, как с помощью Driver Verifier получать аварийные дампы, автоматический анализ которых может решить проблему. Тем не менее, возможны случаи, когда невозможно добиться, что бы система сгенерировала дамп, который легко проанализировать. В таких случаях нужен анализ вручную, чтобы попытаться определить, в чем заклю чается проблема. 쐽 С помощью команды отладчика !process 0 0 посмотрите, какие процессы выполняются, и убедитесь, что вам понятно назначение каждого из них. Попробуйте завершить или удалить приложения и сервисы, без которых можно обойтись. 쐽 С помощью команды lm с параметром kv выведите список загруженных драйверов режима ядра. Убедитесь, что вам понятно назначение каждо го из драйверов сторонних поставщиков и что вы используете самые последние версии. 쐽 С помощью команды !vm проверьте, не исчерпаны ли виртуальная память системы, пул подкачиваемой памяти и пул неподкачиваемой памяти. Если исчерпана виртуальная память, объем переданных страниц будет близок
920 ГЛ А В А 14 БЕЗОПАСНОСТЬ к пределу. В этом случае попытайтесь выявить потенциальную утечку па мяти: просмотрите список процессов и выберите те из них, которым пе редано много памяти. Если исчерпан пул подкачиваемой или неподкачи ваемой памяти (т. е. объем занятой памяти близок к максимуму), см. экс перимент «Анализ утечки памяти в пуле» в главе 7. Существуют и другие отладочные команды, которые могут оказаться по лезными, но для их применения нужны более глубокие знания. Одной из таких команд является !irp. В следующем разделе показано, как с ее помощью идентифицировать подозрительные драйверы. Засорение стека Переполнение или засорение стека (stack trashing) вызывается ошибками, связанными с выходом за конец или начало буфера. Однако в таких случа ях буфер находится не в пуле, а в стеке потока, выполняющего ошибочный код. Ошибки этого типа также трудны в отладке, поскольку стек играет важ ную роль при любом анализе аварийного дампа. Когда вы запускаете Notmyfault и выбираете Stack Trash, драйвер Myfault переполняет буфер, память под который выделена в стеке потока, где выпол няется код драйвера. Myfault пытается вернуть управление вызвавшей его функции Ntoskrnl и считывает из стека адрес возврата, с которого должно продолжиться выполнение. Однако этот адрес поврежден при переполне нии буфера стека, поэтому поток продолжает выполнение с какогото дру гого адреса, может быть, даже не содержащего код. Когда поток попытается выполнить недопустимую инструкцию процессора или обратится к недопу стимой области памяти, будет сгенерировано исключение и произойдет крах системы. В различных случаях краха анализ аварийного дампа, проводимый при переполнении стека, будет указывать на разные драйверы, но стопкод все гда будет одним и тем же — KMODE_EXCEPTION_NOT_HANDLED. Если вы выполните детальный (verbose) анализ, трассировочная информация для стека будет выглядеть так: STACK_TEXT: b7b0ebd4 00000000 00000000 00000000 00000000 0x0 Это объясняется тем, что мы перезаписываем стек нулями. К сожалению, такие механизмы, как особый пул и защита системного кода от записи, не позволяют выявлять «баги» этого типа. Придется выполнять анализ вручную, по косвенным признакам определяя, какой драйвер выполнялся в момент повреждения стека. Один из возможных вариантов — исследовать IRPпаке ты, с которыми работает поток, выполняемый в момент засорения стека. Когда поток передает запрос вводавывода, диспетчер вводавывода записы вает указатель на соответствующий IRP в список Irp, хранящийся в структу ре ETHREAD потока. Команда отладчика !thread выводит дамп этого списка для заданного потока. (Если адрес объекта «поток» не указан, команда !thread
ГЛАВА 9 Анализ аварийного дампа 921 выводит дамп для текущего потока, выполняемого процессором.) Затем IRP можно изучить с помощью команды !irp: kd> !thread THREAD ff740020 Cid 8f8.420 Teb: 7ffde000 Win32Thread: a20cdbe8 RUNNING IRP List: bc5a7f68: (0006,0094) Flags: 00000000 Mdl: 00000000 Not impersonating Owning Process ff75f120 ... kd> !irp bc5a7f68 Irp is active with 1 stacks 1 is current (= 0xbc5a7fd8) No Mdl Thread ff740020: Irp stack trace. cmd flg cl Device File CompletionContext >[ e, 0] 0 0 ff79e4c0 ff7ac028 0000000000000000 \Driver\MYFAULT Args: 00000000 00000000 83360010 00000000 Вывод показывает, что текущий и единственный фрагмент стека для IRP (обозначенный префиксом «>») принадлежит драйверу Myfault. Если бы это было на практике, далее следовало бы убедиться, что установлена последняя версия драйвера, и, если это не так, установить новую версию. Если это не помогло, нужно было бы активизировать Driver Verifier для данного драйве ра (включив все режимы, кроме имитации нехватки памяти). Зависание или отсутствие отклика системы Если система перестает отвечать (т. е. не реагирует на ввод с клавиатуры или мыши, курсор мыши не перемещается или вы можете перемещать курсор, но система не реагирует на щелчки), говорят, что система зависла. Существует несколько возможных причин зависания системы: 쐽 при обращении к драйверу устройства ISR (interrupt service routine) или DPC не вернула управление; 쐽 поток с высоким приоритетом (выполняемый в режиме реального вре мени) вытеснил потоки ввода данных в подсистему управления окнами (windowing system); 쐽 произошла взаимная блокировка при выполнении кода в режиме ядра (два потока или процессора удерживают ресурсы, нужные друг другу, при чем ни один из них не освобождает свой ресурс). Если вы работаете с Windows XP или Windows Server 2003, то можете вы являть взаимные блокировки, используя одну из функций Driver Verifier — обнаружение взаимных блокировок (deadlock detection). При обнаружении взаимных блокировок ведется наблюдение за спинблокировками (spin locks), быстрыми и обычными мьютексами и выявляются закономерности, которые могут приводить к взаимной блокировке. (Информацию об этих и других синхронизирующих примитивах см. в главе 3.) Если обнаружена такая ситу
922 ГЛ А В А 14 БЕЗОПАСНОСТЬ ация, Driver Verifier вызывает крах системы, указывая, какой драйвер является причиной взаимной блокировки. Простейшая форма взаимной блокировки — каждый из двух потоков удерживает некий ресурс, нужный другому пото ку, при этом ни один из них не освобождает свой ресурс и ждет освобожде ния другого ресурса. Если вы используете Windows XP или Windows Server 2003, первое, что нужно сделать для устранения зависаний системы, — вклю чить обнаружение взаимных блокировок для подозрительных драйверов, за тем для неподписанных драйверов, а затем для всех драйверов. В этом режи ме следует работать до тех пор, пока не произойдет крах системы, который позволит выявить драйвер, вызывающий взаимную блокировку. Если вы используете Windows 2000 или если вы проверили все драйве ры, а система продолжает зависать, то должны либо вручную вызвать крах зависшей системы и проанализировать полученный в результате дамп, либо исследовать систему с помощью отладчика ядра. Итак, есть два подхода к исследованию зависающей системы, позволяю щие выявить драйвер или компонент, который вызывает зависания. Пер вый — вызвать крах зависшей системы и надеяться, что будет получен дамп, который удастся проанализировать. Второй — исследовать систему с помо щью отладчика ядра и проанализировать работу системы. И при том, и при другом подходе необходимы предварительная настройка и перезагрузка. Чтобы выявить и устранить причину зависания, в обоих случаях выполня ется одно и то же исследование состояния системы. Чтобы вручную вызвать крах зависшей системы, сначала добавьте в ре естр параметр HKLM\System\CurrentControlSet\Services\i8042prt\Parameters\ CrashOnCtrlScroll типа DWORD со значением 1. После перезагрузки порт драйвер i8042, который является драйвером порта ввода с PS/2клавиатуры, будет наблюдать за нажатиями клавиш в своей ISR (об ISR подробно расска зывается в главе 3) и отслеживать двукратное нажатие клавиши Scroll Lock при нажатой правой клавише Ctrl. Обнаружив такую последовательность нажатий, драйвер вызывает функцию KeBugCheckEx со стопкодом MANU ALLY_INITIATED_CRASH (0xE2), указывающим, что крах инициирован поль зователем вручную. Когда система перезагрузится, откройте аварийный дамп и с помощью методик, описанных выше, попробуйте установить, почему система зависла (например, определите, какой поток выполнялся, когда сис тема зависла, попытайтесь понять, что произошло, проанализировав стек ядра и т. д.). Заметьте: этот подход работает в большинстве случаев зависа ния систем, но не годится, когда ISR портдрайвера i8042 не выполняется. (Эта ISR не выполняется, если все процессоры зависли изза того, что их IRQL выше, чем IRQL у ISR, или если повреждение системных структур дан ных затронуло код либо данные, используемые при обработке прерываний.) ПРИМЕЧАНИЕ Вызов краха зависшей системы вручную на основе функциональности портдрайвера i8042 невозможен при использова нии USBклавиатур. Этот подход работает только в случае PS/2кла виатур.
ГЛАВА 9 Анализ аварийного дампа 923 Еще один способ вручную вызвать крах системы — использовать встро енную кнопку «crash». (Она имеется на некоторых серверах класса «high end».) Тогда, чтобы инициировать крах, материнская плата системы генери рует NMI (немаскируемое прерывание). Чтобы активизировать эту функцию, задайте значение 1 для содержащегося в реестре DWORDпараметра HKLM\ System\CurrentControlSet\Control\CrashControl\NMICrashDump. В этом слу чае при нажатии кнопки «crash» в системе будет генерироваться NMI, и об работчик NMIпрерываний ядра вызовет KeBugCheckEx. Такой подход более универсален, чем применение портдрайвера i8042, поскольку IRQL у NMI всегда выше, чем у прерывания портдрайвера i8042. Дополнительные све дения см. по ссылке http://www.microsoft.com/hwdev/platform/proc/dmpsw.asp. Если сгенерировать аварийный дамп вручную нельзя, попытайтесь иссле довать зависшую систему. Прежде всего загрузите систему в отладочном ре жиме. Это можно сделать двумя способами. Нажмите клавишу F8 во время загрузки и выберите Debugging Mode (Режим отладки) или добавьте запись, задающую загрузку в отладочном режиме, в файл Boot.ini: скопируйте запись, которая уже имеется в файле Boot.ini системы, и добавьте ключ /DEBUG. При нажатии F8 система будет использовать соединение по умолчанию (после довательный порт COM2 и скорость 19200 бод). При использовании режи ма /DEBUG вы должны будете настроить механизм соединения между хост системой, на которой выполняется отладчик ядра, и целевой системой, заг ружаемой в отладочном режиме, и задать ключи /Debugport и /Baudrate, со ответствующие типу соединения. Доступно два типа соединения: нульмо демный кабель, соединяющий последовательные порты, или (в системах Windows XP и Windows Server 2003) кабель IEEE 1394 (Firewire), подключен ный к порту 1394 каждой системы. Подробности настройки хостсистемы и целевой системы для отладки ядра см. в справочном файле Windows De bugging Tools. При загрузке в отладочном режиме система загружает отладчик ядра и готовит его к соединению с отладчиком ядра, выполняемом на другом ком пьютере, подключенном по нульмодемному кабелю или по IEEE 1394. За метьте: присутствие отладчика ядра не влияет на производительность. Ког да система зависнет, запустите отладчик Windbg или Kd на подключенной системе, установите соединение между отладчиками ядра и выполните от ладку кода зависшей системы. Такой подход не сработает, если прерывания отключены или если поврежден код отладчика ядра. ПРИМЕЧАНИЕ Загрузка системы в отладочном режиме не влияет на производительность, если эта система не соединена с другой. Однако этого нельзя сказать о системе, настроенной на автоматическую пере загрузку после краха: если при загрузке системы включена отладка ядра, то после краха системы отладчик ядра будет ожидать соедине ния с другой системой. При выполнении анализа можно не оставлять систему в остановленном состоянии, а с помощью команды отладчика .dump создать файл аварийного
924 ГЛ А В А 14 БЕЗОПАСНОСТЬ дампа на хосткомпьютере отладки. Затем перезагрузить зависшую систему и проанализировать аварийный дамп в автономном режиме (или отправить его в Microsoft). Заметьте: это может занять много времени, если вы исполь зуете нульмодемный кабель (по сравнению с более скоростным соединени ем 1394), поэтому можно получить только минидамп командой .dump /m. Если целевой компьютер способен записать аварийный дамп, можно заста вить его сделать это, введя в отладчике команду .crash. Тогда целевой компь ютер создаст дамп на своем локальном жестком диске, и вы сможете посмот реть дамп после перезагрузки системы. Зависание можно вызвать, запустив Notmyfault и выбрав параметр Hang. Тогда драйвер Myfault поставит в очередь DPC, выполняющую бесконечный цикл для каждого процессора системы. Поскольку при выполнении DPCфунк ций IRQL процессора имеет уровень «DPC/dispatch», ISR клавиатуры будет ре агировать на последовательность нажатий клавиш, вызывающую крах. Когда вы приступили к отладке зависшей системы или загрузили в отлад чик дамп, который вручную сгенерировали для зависшей системы, следует выполнить команду !analyze с параметром –hang. Тогда отладчик проанали зирует блокировки системы и попытается определить, не произошла ли вза имная блокировка, и, если да, то какой драйвер или драйверы в ней участву ют. Однако, если зависание аналогично вызванному программой Notmyfault, команда !analyze не сообщит ничего полезного. Если команда !analyze не помогла решить проблему, выполните команды !thread и !process в каждом из контекстов процессоров для дампа. (Для пере ключения между контекстами процессоров используйте команду ~, напри мер ~1 переключает в контекст процессора 1.) Если поток, вызвавший зави сание системы, выполняет бесконечный цикл на уровне IRQL «DPC/dispatch» или выше, вы увидите модуль драйвера, в котором это происходит, в трас сировочной информации стека, выводимой командой !thread. Если зависа ние системы вызвано программой Notmyfault, трассировочная информация стека, получаемая по аварийному дампу системы, выглядит так: STACK_TEXT: f9e66ed8 f9b0d681 000000e2 00000000 00000000 nt!KeBugCheckEx+0x19 f9e66ef4 f9b0cefb 0069b0d8 010000c6 00000000 i8042prt!I8xProcessCrashDump+0x235 f9e66f3c 804ebb04 81797d98 8169b020 00010009 i8042prt!I8042KeyboardInterruptService+0x21c f9e66f3c fa12e34a 81797d98 8169b020 00010009 nt!KiInterruptDispatch+0x3d WARNING: Stack unwind information not available. Following frames may be wrong. ffdff980 8169b288 f9e67000 0000210f 00000004 myfault+0x34a 8054ace4 ffdff980 804ebf58 00000000 0000319c 0x8169b288 8054ace4 ffdff980 804ebf58 00000000 0000319c 0xffdff980 8169ae9c 8054ace4 f9b12b0f 8169ac88 00000000 0xffdff980 ...
ГЛАВА 9 Анализ аварийного дампа 925 Первые несколько строк трассировочной информации стека относятся к подпрограммам, вызванным, когда вы нажали клавиши, по которым порт драйвер i8042 вызывает крах системы. Присутствие драйвера Myfault озна чает, что зависание системы могло произойти изза него. Еще одна команда, которая может оказаться полезной, — !locks; она вы водит состояние всех блокировок ресурсов исполнительной системы. По умолчанию команда показывает только спорные ресурсы, т. е. ресурсы, на владение которыми претендуют минимум два потока. Исследуйте стеки по токов, владеющих такими ресурсами, с помощью команды !thread, и посмот рите, какому драйверу они могут принадлежать. Если аварийного дампа нет В этом разделе мы рассмотрим, как устранять неполадки в системах, кото рые по какимлибо причинам не записывают аварийный дамп. Аварийный дамп может не записываться изза того, что размер страничного файла на загрузочном томе слишком мал, чтобы вместить дамп, или изза того, что на диске недостаточно места, чтобы извлечь дамп после перезагрузки. Эти две причины легко устранить, увеличив размер страничного файла или задав при настройке, что дамп сохраняется на томе, где достаточно места. Третьей причиной, по которой аварийный дамп не записывается, может быть то, что код ядра и структуры данных, необходимые для записи аварий ного дампа, повреждены при крахе. Как уже говорилось, для этих данных под считывается контрольная сумма, и, если при крахе обнаружено несовпадение контрольных сумм, система даже не пытается сохранить аварийный дамп (чтобы не рисковать данными на диске). Поэтому в таком случае нужно от слеживать момент краха системы и пытаться определить причину краха. Наконец, еще одна причина в том, что дисковая подсистема не может обрабатывать запросы записи на диск (ситуация, которая сама по себе мо жет вызвать сбой системы). Такая ситуация возникает, если произошел ап паратный сбой контроллера дисков или поврежден кабель жесткого диска. Одно из простых решений — отключить параметр Automatically Restart (Выполнить автоматическую перезагрузку) в параметрах Startup And Reco very (Загрузка и восстановление), чтобы можно было изучать «синий экран» с консоли. Однако текст «синего экрана» позволяет выявить причины краха системы только в самых простых случаях. Для более глубокого анализа необходимо с помощью отладчика ядра ис следовать поведение системы в момент краха. Для этого загрузите систему в отладочном режиме, о котором рассказывалось в предыдущем разделе. Когда происходит крах системы, загруженной в отладочном режиме, она не выводит «синий экран» и не пытается записать дамп, а ожидает соединения с отладчиком ядра, выполняемым на хостсистеме. Поэтому можно увидеть, что вызвало причину краха, и, вполне вероятно, провести некий базовый анализ с помощью команд отладчика ядра, описанных ранее. Как говорилось в предыдущем разделе, команда отладчика позволяет сохранить копию па
926 ГЛ А В А 14 БЕЗОПАСНОСТЬ мяти системы, потерпевшей крах, для дальнейшей отладки, что даст возмож ность перезагрузить эту систему и вести отладку в автономном режиме. ЭКСПЕРИМЕНТ: экранная заставка Blue Screen Отличный способ вспомнить, как выглядит «синий экран», или подшу тить над своими друзьями и коллегами — запустить экранную застав ку Sysinternals Blue Screen, которую можно скачать с сайта www.sysinter nals.com. Она точно имитирует «синий экран» для той версии Windows, в которой вы работаете, и выводит системную информацию (напри мер, список загруженных драйверов), соответствующую действитель ности. Кроме того, она имитирует автоматическую перезагрузку, по казывая экран запуска Windows. Заметьте: в отличие от других экран ных заставок, исчезающих при перемещении мыши, Blue Screen тре бует нажатия клавиши. С помощью утилиты Psexec с сайта Sysinternals вы даже можете за пустить экранную заставку на другой системе, выполнив команду: psexec \\computername –i –d “c:\sysinternals bluescreen.scr” –s Для этого у вас должны быть административные привилегии на уда ленной системе. (С помощью ключей –u и –p утилиты Psexec можно задать другие удостоверения защиты.) Проверьте, есть ли у ваших кол лег чувство юмора!
Словарь терминов A accesscontrol list (ACL) — список управления доступом (ACL) ~ часть дескриптора защиты, в которой перечисляется, кто имеет доступ к объекту и какой. Владелец объекта может изменять ACL этого объекта, разрешая или запрещая доступ к нему другим пользо! вателям. ACL состоит из заголовка и произвольного числа элементов ACL (ACE). ACL без ACE называется пустым (null ACL) и указывает, что доступ к объекту не разрешен ни одному поль! зователю. access token — маркер доступа ~ структура данных, определяющая характеристики за! щиты процесса или потока и включающая идентификатор защиты (security ID, SID), спи! сок групп, в которые входит пользователь, и список привилегий. У каждого процесса име! ется основной маркер доступа (primary access token), по умолчанию наследуемый от роди! тельского процесса. adddevice routine — процедура добавления устройства ~ процедура, реализуемая драйверами, которые поддерживают Plug and Play. Через эту процедуру диспетчер Plug and Play уведомляет драйвер при обнаружении соответствующего устройства. В этой процеду! ре драйвер, как правило, создает объект «устройство», представляющий обнаруженное уст! ройство. Address Windowing Extensions (AWE) ~ механизм Windows, позволяющий 32!разрядно! му приложению выделять до 128 Гб физической памяти и проецировать ее представления, или окна, на свое 2!гигабайтное виртуальное адресное пространство. Применение AWE ус! ложняет программирование, но решает проблему прямого доступа к дополнительной фи! зической памяти. affinity mask — маска привязки (к процессорам) ~ битовая маска, определяющая, на каких процессорах разрешено выполнение данного потока. Начальная маска привязки пото! ка к процессорам наследуется от его процесса. alertable wait state — состояние «тревожного» ожидания ~ состояние потока, при ко! тором он либо переходит к ожиданию на объекте и указывает, что это ожидание должно быть «тревожным» (вызовом Windows!функции WaitForMultipleObjectsEx), либо напрямую проверяет появление APC в своей очереди (используя SleepEx). В любом случае, если в оче! реди потока появляется APC пользовательского режима, ядро прерывает поток, передает уп! равление APC!процедуре, а по завершении APC!процедуры возобновляет его выполнение. APC пользовательского режима доставляются потоку, только когда он находится в состоя! нии «тревожного» ожидания. allocation granularity — гранулярность выделения памяти ~ дискретность выделения виртуальной памяти. Windows выравнивает каждый регион зарезервированного адресно! го пространства процесса так, чтобы он начинался с границы, кратной гранулярности вы! деления памяти. Последнее значение можно получить через Windows!функцию GetSys temInfo. В настоящее время оно составляет 64 Кб. Такое значение было выбрано с учетом возможности поддержки будущими процессорами страниц большого размера (например, до 64 Кб). (Код Windows режима ядра может резервировать память с гранулярностью в одну страницу памяти.) APC queue — APCочередь ~ очередь, в которую помещаются APC. Такие очереди (одна — для пользовательского режима, другая — для режима ядра) индивидуальны для каждого по! тока. (Заметьте, что DPC!очередь индивидуальна для каждого процессора.) asymmetric multiprocessing (ASMP) — асимметричная мультипроцессорная обра ботка ~ схема обработки, при которой один процессор обычно выделяется коду операци! онной системы, а остальные процессоры выполняют только пользовательский код.
928 Словарь терминов БЕЗОПАСНОСТЬ asynchronous I/O — асинхронный вводвывод ~ модель ввода!вывода, которая позво! ляет приложению выдать запрос на ввод!вывод и перейти к выполнению других задач на то время, пока запрос обрабатывается. asynchronous procedure call (APC) ~ функция, которая позволяет пользовательским про! граммам и системе выполнять код в контексте конкретного пользовательского потока (т. е. в адресном пространстве конкретного процесса). APC могут быть либо пользовательского режима, либо режима ядра. Последние (в отличие от первых) не требуют «разрешения» це! левого потока на выполнение в его контексте. asynchronous readahead with history — асинхронное опережающее чтение с хро нологией ~ метод, используемый диспетчером кэша для сохранения хронологии последних двух запросов на чтение в закрытой карте кэша применительно к описателю файла, к кото! рому происходит обращение. atomic transaction — атомарная транзакция ~ метод внесения изменений в базу данных, не влияющий на корректность информации или целостность базы данных в случае сбоя си! стемы. В основе атомарных транзакций лежит принцип «все или ничего»: если хотя бы одна из операций с базой данных заканчивается неудачно, отменяются все операции текущей ато! марной транзакции. Если транзакция прерывается из!за сбоя системы, изменения, уже вне! сенные в ходе этой транзакции, подлежат отмене, или откату. Операция отката возвращает базу данных в предыдущее согласованное состояние. См. также transaction. attribute list — список атрибутов ~ особый тип атрибута файла в заголовке NTFS!фай! ла, который содержит дополнительные атрибуты. Список атрибутов создается в том случае, если у файла слишком много атрибутов и они не умещаются в записи главной таблицы файлов (MFT). Атрибут «список атрибутов» содержит имя и код типа всех атрибутов фай! ла, а также файловые ссылки на записи MFT, в которых хранятся эти атрибуты. authentication packages — пакеты аутентификации ~ DLL!модули, которые выполня! ются в контексте LSASS и реализуют политику аутентификации. DLL аутентификации отве! чает за проверку имени и пароля пользователя и, если они верны, за передачу LSASS деталь! ной информации об удостоверениях защиты данного пользователя. В Windows включено два пакета аутентификации: Kerberos и MSV1_0. automatic working set trimming — автоматическое усечение рабочих наборов ~ метод, применяемый диспетчером памяти для увеличения объема свободной памяти в си! стеме при нехватке физической памяти. B badcluster file — файл плохих кластеров ~ системный файл (с именем $BadClus), в ко! тором регистрируются аварийные (плохие) участки дискового пространства на томе. balance set manager — диспетчер настройки баланса ~ системный поток, который пробуждается раз в секунду для проверки и при необходимости для инициации различных событий, связанных с планированием потоков и управлением памяти. basic disk — базовый диск ~ диск, разбитый на разделы в стиле MS!DOS. См. также dynamic disk. bitmap file — файл битовой карты ~ системный файл (с именем $Bitmap), в котором NTFS регистрирует занятые и свободные кластеры на томе. Атрибут данных этого файла содержит битовую карту, каждый бит которой представляет один из кластеров тома и со! общает, свободен этот кластер или выделен какому!то файлу. boot code — загрузочный (стартовый) код ~ команды, выполняемые при загрузке сис! темы. boot device drivers — загрузочные драйверы устройств (используемые на этапе загрузки системы) ~ драйверы устройств, необходимые для загрузки системы. boot file — загрузочный файл ~ системный файл (с именем $Boot), в котором хранится код начальной загрузки Windows. boot partition — загрузочный раздел ~ раздел, в котором хранятся основные файлы операционной системы. Загрузочный раздел идентифицируется системой при запуске. Код,
ГЛАВА 9 Словарь терминов 929 содержащийся в главной загрузочной записи (MBR), сканирует таблицу главных разделов и находит раздел с флагом, который сообщает, что данный раздел является загрузочным. Как только MBR находит хотя бы один такой флаг, она считывает первый сектор соответ! ствующего раздела в память и передает управление коду из этого сектора. boot sector — загрузочный сектор ~ первый сектор раздела, помеченного как активный. Из этого сектора загружается MBR (главная загрузочная запись). За!грузочный сектор со! держит информацию, идентифицирующую формат и структуру файловой системы в дан! ном разделе. boot volume — загрузочный том ~ том, где содержатся операционная система Windows и ее вспомогательные файлы. Загрузочный том может совпадать с системным томом. bus driver — драйвер шины ~ драйвер, обслуживающий контроллер шины, адаптер, мост и любое устройство, у которого имеются дочерние устройства. Такие драйверы обязатель! ны, они обычно поставляются Microsoft; для каждой шины, например PCI, PCMCIA и USB, в системе должен быть один драйвер шины. C cache manager — диспетчер кэша ~ компонент исполнительной системы Windows, ко! торый предоставляет общесистемные сервисы кэширования для NTFS и других файловых систем, в том числе сетевых. careful write — точная запись ~ метод поддержки файлового ввода!вывода и кэширова! ния в системе. См. также write!through. change journal — журнал изменений ~ внутренний файл, в котором NTFS регистриру! ет информацию, позволяющую приложениям вести эффективный мониторинг изменений в файлах и каталогах. Журнал изменений достаточно велик, чтобы приложения успевали обрабатывать все изменения. checked build — проверочная версия ~ специальная отладочная версия Windows, дос! тупная только при подписке на MSDN уровня Professional или Universal. Проверочная вер! сия создается компиляцией исходного кода Windows с флагом DEBUG периода компиля! ции, установленным в TRUE. checkpoint record — запись контрольной точки ~ запись, помогающая NTFS опреде! лять, какая обработка понадобится для восстановления тома, если система рухнет в данный момент. Эта запись также включает информацию для повтора и отмены. class driver — драйвер класса ~ тип драйвера устройства режима ядра, реализующий об! работку ввода!вывода для конкретного класса устройств, например для дисков, ленточных накопителей или приводов CD!ROM. clock interrupt handler — обработчик прерываний от системного таймера ~ сис! темная процедура, обновляющая системное время, а затем уменьшающая на 1 значение счетчика, который используется для отслеживания того, сколько времени выполняется те! кущий поток. cluster factor — кластерный множитель ~ размер кластеров тома, устанавливаемый при форматировании конкретного тома командой format или с помощью оснастки Disk Mana! gement (Управление дисками) в Microsoft Management Console (MMC) (Консоль управления Microsoft). cluster remapping — переназначение кластеров ~ процесс, в ходе которого NTFS ди! намически извлекает сохранившиеся данные из кластера с плохим сектором, выделяет но! вый кластер и копирует в него эти данные. cluster — кластер ~ единица выделения дискового пространства на томе. Каждый кластер нумеруется 16!битным числом. collided page fault — конфликт ошибок страницы ~ ситуация, когда другой поток или процесс вызывает ошибку той страницы, которая в данный момент загружается в память с диска. commitment — передача ~ выделение физической памяти зарезервированному региону виртуальной памяти.
930 Словарь терминов БЕЗОПАСНОСТЬ common model — общая модель ~ набор классов в Common Information Model (CIM), которые представляют объекты, специфичные для областей управления в системе, но не! зависимые от конкретной реализации. Эти классы считаются расширением базовой моде! ли CIM. См. также core model. complete memory dump — полный дамп памяти ~ дамп памяти, включающий содер! жимое всей физической памяти на момент краха системы. Этот тип дампа требует, чтобы страничный файл был по крайней мере того же размера, что и физическая память. Windows NT 4 поддерживала только этот тип файлов аварийных дампов. completion port — порт завершения ~ механизм уведомления потоков о завершении ввода!вывода. Как только файл сопоставляется с портом завершения, по окончании любой операции асинхронного ввода!вывода над этим файлом в очередь порта завершения ста! вится пакет завершения. Поток узнает о выполнении каких!либо операций ввода!вывода, просто проверяя наличие пакета завершения в очереди порта. Благодаря такому механиз! му число потоков, активно обслуживающих клиентские запросы, контролируется самой системой. configuration manager — диспетчер конфигурации ~ один из основных компонентов исполнительной системы, отвечающих за реализацию системного реестра и управление им. container object — объектконтейнер ~ объект пространства имен, способный хранить другие объекты, в том числе другие контейнеры. Примеры контейнеров — каталоги в про! странстве имен файловой системы и разделы в пространстве имен реестра. context switch — переключение контекста ~ процедура сохранения переменного со! стояния машины, связанного с выполняемым потоком, загрузки переменного состояния другого потока и начала выполнения этого потока. control objects — управляющие объекты ~ набор объектов ядра, определяющих семан! тику управления различной функциональностью операционной системы. В этот набор вхо! дят объекты «процесс», APC! и DPC!объекты, а также несколько объектов, используемых подсистемой ввода!вывода, например объект прерывания. core model — базовая модель ~ набор классов в Common Information Model (CIM), явля! ющийся частью стандарта WBEM. Эти классы образуют базовый язык CIM и представляют объекты, применимые ко всем областям управления. См. также common model. crash dump — аварийный дамп ~ запись содержимого системной памяти на момент краха, которая может помочь выяснить, какие компоненты вызвали крах. critical section — критическая секция ~ взаимоисключающий синхронизирующий при! митив, используемый для синхронизации доступа потоков внутри процесса к какому!либо общему ресурсу. D deferred procedure call (DPC) ~ процедура, выполняющая основную часть работы по обработке прерывания от устройства после выполнения процедуры обслуживания преры! вания (interrupt service routine, ISR). DPC!процедура работает при уровне IRQL ниже того, на котором выполняется ISR, чтобы свести к минимуму блокирование других прерываний. DPC!процедура инициирует завершение ввода!вывода и начинает новую операцию ввода! вывода, ждущую в очереди устройства. deferred procedure call (DPC) object — DPCобъект ~ управляющий объект ядра, кото! рый описывает запрос и позволяет отложить обработку прерывания до момента повыше! ния IRQL до уровня «DPC/dispatch». Этот объект невидим программам пользовательского режима — он доступен только драйверам устройств и другому системному коду. Самая важ! ная часть информации в DPC!объекте — адрес системной функции, которая будет вызвана ядром для обработки прерывания DPC. deferred ready — состояние «готов, отложен» ~ состояние, используемое для потоков, выбранных для выполнения на конкретном процессоре, но пока не за!планированных к вы! полнению. Это новое состояние, введенное в Windows Server 2003, позволяет ядру свести к минимуму время, в течение которого удерживается общесистемная блокировка базы данных планировщика.
ГЛАВА 9 Словарь терминов 931 device drivers — драйверы устройств ~ загружаемые модули режима ядра (обычно SYS! файлы), образующие интерфейс между подсистемой ввода!вывода и соответствующим обо! рудованием. Драйверы устройств в Windows не работают с аппаратными устройствами на! прямую, а вызывают функции HAL (уровня абстрагирования от оборудования). device ID — идентификатор устройства ~ идентификатор, сообщаемый диспетчеру Plug and Play. Такие идентификаторы специфичны для конкретной шины; в случае шины USB он состоит из идентификатора изготовителя (vendor ID, VID) и идентификатора продукта (product ID, PID), назначенного изготовителем данному устройству. device instance ID (DIID) — идентификатор экземпляра устройства (DIID) ~ иденти! фикатор, который состоит из идентификатора устройства и идентификатора экземпляра и используется диспетчером Plug and Play для поиска раздела данного устройства в ветви рее! стра HKLM\SYSTEM\CurrentControlSet\Enum. device object — объект «устройство» ~ структура данных, которая представляет физичес! кое, логическое или виртуальное устройство в системе и описывает его характеристики. device tree — дерево устройств ~ внутренняя структура данных, формируемая диспетчером Plug and Play и отражающая взаимосвязи между устройствами в системе. См. также devnode. devnode — узел устройств ~ узел дерева устройств. Содержит информацию об объектах «устройство», которые представляют однотипные устройства и хранят информацию, специ! фическую для диспетчера Plug and Play. См. также device tree. dirty page threshold — пороговое число измененных страниц ~ число страниц сис! темного кэша в памяти, по достижении которого пробуждается поток подсистемы отложен! ной записи, принадлежащий диспетчеру кэша и вы!гружающий страницы кэша на диск. Это значение вычисляется при инициализации системы и зависит от объема физической па! мяти и параметра LargeSystemCache в разделе реестра HKLM\SYSTEM\CurrentControlSet\ Control\Session Manager\Memory Management. discretionary access control — управление избирательным доступом ~ позволяет вла! дельцу ресурса определять, кто может обращаться к данному ресурсу и что с ним можно делать. Владелец выдает права, разрешающие те или иные виды доступа, пользователю либо группе. disk group — дисковая группа ~ динамические диски с общей базой данных. Windows поддерживает дисковые группы, но диспетчер логических дисков (Logical Disk Manager, LDM), реализованный в Windows, позволяет создать только одну дисковую группу. dispatch code — код диспетчеризации, диспетчерский код ~ ассемблерный код, за! писываемый в объект прерывания при его инициализации. Этот код выполняется, когда возникает какое!нибудь прерывание. dispatch routines — процедуры диспетчеризации, диспетчерские процедуры ~ ос! новные функции, предоставляемые драйвером устройства (для открытия и закрытия уст! ройства, чтения и записи данных, а также для поддержки любых других возможностей уст! ройства, файловой системы или сети). Когда поступает запрос на операцию ввода!вывода, диспетчер ввода!вывода генерирует соответствующий IRP и вызывает нужный драйвер че! рез одну из диспетчерских процедур этого драйвера. dispatcher — диспетчер ядра ~ набор функций ядра, реализующих планирование в Win! dows . Единого модуля планировщика в Windows нет — соответствующий код распределен по всему ядру. dispatcher database — база данных диспетчера ядра ~ набор структур данных, поддержи! ваемых ядром для принятия решений по планированию потоков. Эта база данных предназна! чена для учета того, какие потоки выполняются и на каких процессорах, а какие потоки ждут выполнения. См. также dispatcher ready queue. dispatcher header — заголовок диспетчера ~ структура данных, содержащая тип объек! та, его состояние (свободен/занят) и список потоков, ждущих на этом объекте. dispatcher objects — объекты диспетчера ядра ~ набор объектов ядра, включающих сред! ства синхронизации и способных влиять на планирование потоков. В число этих объектов входят мьютекс (его внутреннее название — мутант), событие, пара событий ядра, семафор, таймер и ожидаемый таймер.
932 Словарь терминов БЕЗОПАСНОСТЬ dispatcher ready queue — очередь готовых (к выполнению) потоков, принадлежа щая диспетчеру ядра ~ самая важная структура в базе данных диспетчера ядра (хранит! ся в KiDispatcherReadyListHead). Эта очередь на самом деле представляет собой группу оче! редей — по одной для каждого уровня приоритета. Очереди содержат потоки, готовые к выполнению и ожидающие подключения к процессору. display driver — драйвер видеоадаптера ~ драйвер, транслирующий аппаратно!незави! симые запросы на операции с графикой в запросы, специфичные для конкретного устрой! ства. Далее запросы направляются соответствующему минипорт!драйверу режима ядра. Драй! вер видеоадаптера отвечает за реализацию операций рисования, либо напрямую записывая данные в буфер кадров, либо взаимодействуя с чипом ускорителя графики на видеоплате. driver object — объект «драйвер» ~ структура данных, которая представляет индивиду! альный драйвер в системе и в которой регистрируется адрес каждой диспетчерской про! цедуры (входной точки) драйвера. driver support routines — процедуры поддержки драйверов ~ процедуры, вызывае! мые драйверами устройств при выполнении запросов на ввод!вывод. dynamic disk — динамический диск ~ диск, который поддерживает составные тома и более гибкую схему разбиения на разделы, чем у базовых дисков. См. также basic disk. dynamiclink library (DLL) — динамически подключаемая библиотека (DLL) ~ на! бор функций, связанных в двоичный образ, который приложения могут динамически заг! ружать при необходимости. E environment subsystems — подсистемы окружения ~ пользовательские процессы и DLL, которые предоставляют сервисы, встроенные в операционную систему, пользователь! ским приложениям, и тем самым формируют определенное окружение. Windows поддер! живает две подсистемы окружения: Windows и POSIX. Windows NT 4.0 поддерживала и OS/ 2 1.2. Windows XP и более поздние версии поставляются только с подсистемой Windows, но вы можете бесплатно скачать продукт Microsoft Services for Unix, в состав которого вхо! дит расширенная версия подсистемы POSIX. event — событие ~ объект, способный находиться в одном из двух состояний — свобод! ном (signaled) или занятом (nonsignaled); применяется для синхронизации потоков. Собы! тием также называется то, что заставляет систему выполнить определенное действие. exception dispatcher — диспетчер исключений ~ модуль ядра, обслуживающий все исключения, кроме тех, которые могут быть разрешены обработчиком ловушки. Задача диспетчера исключений — найти обработчик исключений, способный «устранить» данное исключение. executive — исполнительная система ~ верхний уровень Ntoskrnl.exe (ядро находится на более низком уровне). Исполнительная система предоставляет базовые сервисы опера! ционной системы, например диспетчер процессов и потоков, диспетчер виртуальной па! мяти, диспетчер памяти, монитор состояния защиты, подсистему ввода!вывода и диспет! чер кэша. См. также kernel. executive objects — объекты исполнительной системы ~ объекты, реализуемые раз! личными компонентами исполнительной системы (диспетчером процессов, диспетчером памяти, подсистемой ввода!вывода и т. д.). Эти объекты и их сервисы служат примитивами, из которых подсистемы окружения конструируют собственные версии объектов и другие ресурсы. Поскольку объекты исполнительной системы обычно создаются либо подсисте! мой окружения в интересах пользовательской программы, либо компонентами операци! онной системы, многие из них содержат (инкапсулируют) один или несколько объектов ядра. См. также kernel objects. executive resources — ресурсы исполнительной системы ~ объекты, которые обеспе! чивают как монопольный доступ (например, мьютекс), так и разделяемый доступ для чте! ния (несколько потоков могут одновременно считывать данные из одной структуры). Эти объекты доступны только коду режима ядра — к ним нельзя обратиться через Windows API.
ГЛАВА 9 Словарь терминов 933 extended partition — дополнительный раздел ~ раздел особого типа, который содер! жит главную загрузочную запись (MBR) и свою таблицу разделов. Применение таких раз! делов позволяет операционным системам Microsoft создавать на диске более четырех раз! делов. См. также partition. F fast I/O — быстрый вводвывод ~ метод чтения и записи кэшируемого файла без гене! рации пакета запроса ввода!вывода (I/O request packet, IRP). fast LPC — быстрый LPC ~ особый механизм межпроцессной связи, обеспечивающий обмен сообщениями между потоками. file mapping object — объект «проекция файла» ~ объект Windows API, позволяющий использовать разделяемую память (его внутреннее название — объект!раздел). См. также section object. file reference — файловая ссылка ~ 64!битное значение, которое идентифицирует файл на NTFS!томе. Файловая ссылка состоит из номера файла и номера последовательности. Первый номер соответствует позиции записи о данном файле в главной таблице файлов (MFT) за вычетом единицы (или позиции базовой записи о данном файле за вычетом еди! ницы, если файл требует более одной записи в MFT). file system driver (FSD) — драйвер файловой системы (FSD) ~ тип драйвера устрой! ства режима ядра, который принимает запросы на ввод!вывод, обращенные к файлам, и на их основе выдает свои, более сложные запросы, адресуя их драйверам физических уст! ройств. См. также local file system driver (FSD), network file system driver (FSD). file system filter driver — драйвер фильтра файловой системы ~ тип драйвера уст! ройства режима ядра, который перехватывает запросы ввода!вывода, дополнительно обра! батывает их и передает драйверам более низкого уровня. file system format — формат файловой системы ~ определяет способ хранения фай! ловых данных на носителях и характеристики файловой системы. Например, формат, не предусматривающий сопоставление прав доступа с файлами и каталогами, не позволяет файловой системе поддерживать защиту. Кроме того, формат файловой системы может накладывать ограничения на размеры файлов и емкости устройств внешней памяти. filter driver — драйвер фильтра ~ см. file system filter driver. foreground application — активное приложение ~ процесс, которому принадлежит поток, владеющий активным окном (находящимся в фокусе ввода). free build — свободная (от отладочного кода) версия ~ версия Windows, которая мо! жет быть приобретена в системе розничной торговли. При ее сборке включаются все па! раметры оптимизации, поддерживаемые компилятором, и, кроме того, из всех образов уда! ляется информация о таблицах внутренних символов. См. также checked build. function driver — функциональный драйвер ~ основной драйвер устройства, который предоставляет рабочий интерфейс к своему устройству. Обязателен, если только ввод!вывод на устройстве не выполняется драйвером шины и каким!либо драйвером фильтра шины, как в случае SCSI PassThru. Функциональный драйвер обычно является единственным, кто обра! щается к регистрам устройства. G granted access rights — предоставленные права доступа ~ права доступа, выданные потоку монитором состояния защиты в результате успешного открытия объекта. Graphical Identification and Authentication (GINA) ~ DLL пользовательского режима, выполняемая в процессе Winlogon и применяемая Winlogon для получения имени и пароля пользователя или PIN!кода смарт!карты. Стандартная GINA — \Windows\System32\Msgina.dll. H handle — описатель ~ идентификатор объекта. Процесс получает описатель объекта при создании или открытии объекта по имени. Ссылка на объект по описателю действует быс!
934 Словарь терминов БЕЗОПАСНОСТЬ трее, чем ссылка по имени, так как в первом случае диспетчеру объектов не приходится просматривать свое пространство имен. handle table — таблица описателей ~ таблица, содержащая указатели на все объекты, описатели которых открыты процессом. Таблица описателей реализуется по трехуровне! вой схеме — по аналогии с тем, как аппаратный блок управления памятью в x86!системах реализует трансляцию виртуальных адресов в физические. hardware abstraction layer (HAL) — уровень абстрагирования от оборудования (HAL) ~ загружаемый модуль режима ядра (Hal.dll), предоставляющий низкоуровневый ин! терфейс для аппаратной платформы, на которой работает Windows. HAL скрывает от опера! ционной системы все, что связано с аппаратной реализацией функциональности, специфич! ной для архитектуры и конкретного оборудования, в том числе интерфейсы ввода!вывода, контроллеры прерываний и механизмы взаимодействия между процессорами. hash — хэш ~ статистически уникальное значение, генерируемое из блока данных (напри! мер, из файла) с использованием алгоритмов шифрования. Поскольку разные данные дают разные хэши, их можно использовать для распознавания изменений в данных в процессе передачи (скажем, попыток взлома или умышленной модификации информации). Хэши используются механизмом поддержки цифровых подписей драйверов Windows. heap — куча (динамически распределяемая память) ~ область, которая состоит из одной или нескольких страниц памяти и из которой функции диспетчера куч позволяют выделять блоки памяти меньшего размера. heap manager — диспетчер куч ~ набор функций, позволяющих выделять и освобождать блоки памяти различного размера (который может быть меньше размера страниц памяти). Эти функции находятся в двух местах — в Ntdll.dll и Ntoskrnl.exe. API подсистемы окруже! ния используют функции диспетчера куч, размещенные в Ntdll, а компоненты исполнитель! ной системы и драйверы устройств — функции, содержащиеся в Ntoskrnl. hive — куст ~ один из нескольких файлов на диске, содержащих информацию реестра. Каждый куст хранит дерево реестра, где один из разделов выступает в роли корня данного дерева. hyperspace — гиперпространство ~ особый регион, на который проецируется список ра! бочего набора процесса. Кроме того, он используется для временного проецирования фи! зических страниц при таких операциях, как обнуление страницы из списка свободных стра! ниц (когда список обнуленных страниц пуст и возникает потребность в обнуленной стра! нице), объявление недействительными PTE в других таблицах страниц (когда страница уда! ляется из списка простаивающих страниц) и создание адресного пространства дочернего процесса. I I/O completion routine — процедура завершения вводавывода ~ процедура, реали! зуемая для уведомления драйвера более высокого уровня о том, что драйвер более низкого уровня закончил обработку IRP (пакета запроса ввода!вывода). Например, диспетчер вво! да!вывода вызывает такую процедуру драйвера файловой системы после того, как драйвер устройства завершает передачу данных в файл или из файла. Процедура завершения уве! домляет драйвер файловой системы об успехе, неудаче или отмене операции и позволяет ему выполнить соответствующие действия. I/O request packet (IRP) — пакет запроса вводавывода (IRP) ~ структура данных, кон! тролирующая обработку операции ввода!вывода на каждом этапе. Большинство запросов на ввод!вывод представляется IRP, которые передаются от одного компонента подсистемы ввода!вывода другому. I/O system — подсистема вводавывода ~ компонент исполнительной системы, который принимает запросы на ввод!вывод (поступающие от потоков как пользовательского режи! ма, так и режима ядра) и, преобразовав в нужный формат, доставляет их соответствующим устройствам ввода!вывода. ideal processor — идеальный процессор ~ предпочтительный процессор для определен! ного потока.
ГЛАВА 9 Словарь терминов 935 idle summary — сводка простоя ~ битовая маска (KiIdleSummary), в которой каждый ус! тановленный бит представляет простаивающий процессор. impersonation — олицетворение, подмена ~ функциональность, позволяющая закреп! лять за потоками маркеры доступа, отличные от тех, которые назначены процессу. initialization routine — процедура инициализации ~ процедура драйвера, выполняемая диспетчером ввода!вывода при загрузке драйвера в операционную систему. Эта процедура создает системные объекты, используемые диспетчером ввода!вывода для распознавания драйвера и обращения к нему. inpaging I/O — вводвывод, связанный с подкачкой страниц в память ~ ввод!вывод, вызываемый ошибкой страницы и требующий операции чтения из файла (страничного или проецируемого) для загрузки соответствующей страницы в память. Такой ввод!вывод явля! ется синхронным (поток ждет его окончания на каком!либо событии) и не может быть прерван доставкой APC. instancing — создание экземпляра ~ здесь: термин, относящийся к созданию отдельных копий одних и тех же частей пространства имен. Создание экземпляров \DosDevices позво! ляет каждому пользователю присваивать одним и тем же дискам разные буквы и получать свой набор Windows!объектов вроде последовательных портов. intelligent file readahead — интеллектуальное опережающее чтение файловых данных ~ метод предсказания того, какие данные будут скорее всего считаны вызывающим потоком в следующий раз. interprocessor interrupt (IPI) — межпроцессорное прерывание ~ прерывание, ини! циируемое ядром, чтобы запросить выполнение какой!либо операции другим процессором, например подключение определенного потока к этому процессору или обновление его TLB!кэша. interrupt — прерывание ~ асинхронное событие (которое может произойти в любой момент), не связанное с текущим кодом, выполняемым процессором. Прерывания генери! руются в основном устройствами ввода!вывода и системными таймерами. interrupt dispatch table (IDT) — таблица диспетчеризации прерываний (IDT) ~ струк! тура данных, используемая Windows для поиска процедуры, способной обработать конкрет! ное прерывание. Уровень запроса прерывания (IRQL) источника прерывания используется как индекс таблицы, а соответствующий элемент в таблице указывает на искомую процеду! ру обработки прерывания. interrupt dispatcher — диспетчер прерываний ~ часть обработчика ловушек, которая реагирует на прерывания. interrupt object — объект прерывания ~ управляющий объект ядра, который позволяет драйверам устройств регистрировать процедуры обслуживания прерываний (ISR) для своих устройств. Объект прерывания содержит всю информацию, необходимую ядру для того, что! бы сопоставить ISR устройства с конкретным уровнем прерывания. В эту информацию вклю! чается адрес ISR, IRQL, при котором возникает прерывание от устройства, и элемент в таб! лице диспетчеризации прерываний, с которым следует связать эту ISR. interrupt request (IRQ) — запрос прерывания (IRQ) ~ значение, идентифицирующее прерывание. В x86!системах внешние прерывания ввода!вывода поступают по одной из линий контроллеру прерываний. Контроллер в свою очередь прерывает работу процессо! ра (по единственной линии). Как только процессор прерывается, он запрашивает контрол! лер получить IRQ. Контроллер прерываний преобразует IRQ в номер прерывания, который используется как индекс в таблице диспетчеризации прерываний (IDT), и передает управ! ление соответствующей процедуре. При загрузке системы Windows заполняет IDT указате! лями на все процедуры ядра, обрабатывающие прерывания и исключения. interrupt request level (IRQL) — уровень запроса прерывания (IRQL) ~ схема приори! тетов прерываний в Windows. Ядро нумерует уровни IRQL от 0 до 31 (или от 0 до 15 в 64! разрядной Windows), причем бóльшие числа соответствуют более высоким приоритетам. Хотя ядро определяет стандартный набор IRQL для программных прерываний, HAL также увязывает номера аппаратных прерываний с уровнями IRQL.
936 Словарь терминов БЕЗОПАСНОСТЬ interrupt service routine (ISR) — процедура обслуживания прерываний (ISR) ~ про! цедура драйвера устройства, которой диспетчер прерываний, принадлежащий ядру, пере! дает управление при прерывании от устройства. В модели ввода!вывода Windows ISR рабо! тают при высоком уровне IRQL, поэтому они выполняют минимум команд, чтобы избежать излишней блокировки прерываний более низкого уровня. ISR ставит в очередь DPC, кото! рая выполняется при более низком IRQL и отвечает за основную часть обработки преры! вания. ISR могут быть только у драйверов устройств. J job object — объект «задание» ~ это именуемый, защищаемый и разделяемый объект ядра, обеспечивающий управление одним или несколькими процессами как группой. Объект «за! дание» также регистрирует базовую учетную информацию всех включенных в него процес! сов, в том числе уже завершившихся. journaling — ведение журнала ~ метод протоколирования, изначально разработанный для обработки транзакций. Используется восстанавливаемыми файловыми системами вроде NTFS для поддержания целостного состояния тома. K kernel — ядро ~ самый нижний уровень в Ntoskrnl.exe. Ядро, компонент исполнительной системы, определяет, как операционная система использует процессор или процессоры, и гарантирует, что они используются эффективно. Ядро отвечает за планирование и диспет! черизацию потоков, обработку ловушек и диспетчеризацию исключений, обработку и дис! петчеризацию прерываний, а также за синхронизацию процессоров в многопроцессорных системах. См. также executive. kernel debugger — отладчик ядра ~ инструмент, применяемый для отладки драйверов, выявления причины краха операционной системы и анализа аварийных дампов. Также по! лезен как инструмент для исследования внутреннего устройства Windows, поскольку он сообщает системную информацию, недоступную стандартным утилитам. kernel handle table — таблица описателей, принадлежащая ядру ~ таблица (с внут! ренним именем ObpKernelHandleTable), описатели в которой доступны только в режиме ядра в контексте любого процесса. Функции режима ядра могут ссылаться на описатели в этой таблице из контекста любого процесса без отрицательных последствий для общей производительности системы. kernel memory dump — дамп памяти ядра ~ тип дампа памяти (в системах Windows Server предлагается по умолчанию), который включает лишь страницы (как для чтения, так и для записи) режима ядра, находящиеся в физической памяти на момент краха. Страни! цы, принадлежащие пользовательским процессам, не включаются. Поскольку только код режима ядра может напрямую вызывать крах Windows, содержимое страниц пользователь! ских процессов обычно ничего не дает для понимания причин краха. Заранее предсказать объем дампа памяти ядра нельзя, так как он зависит от объема памяти ядра, выделенной опе! рационной системой и драйверами. kernel mode — режим ядра ~ привилегированный режим выполнения кода, при котором доступна вся память и можно выполнять любые команды процессора. В этом режиме ра! ботает код операционной системы. См. также user mode. kernel objects — объекты ядра ~ набор примитивных объектов, реализуемых ядром Windows. Эти объекты невидимы коду пользовательского режима — они создаются и исполь! зуются только внутри исполнительной системы. Объекты ядра предоставляют базовую фун! кциональность вроде синхронизации, на которую опираются объекты исполнительной си! стемы. См. также executive objects. kernel streaming filter drivers — драйверы потоковых фильтров ядра ~ драйверы ре! жима ядра, соединенные в цепочку для обработки потоковых данных, например при записи или воспроизведении аудио! и видеоинформации. kernelmode device driver — драйвер устройства режима ядра ~ единственный тип драйверов, способных напрямую обращаться к аппаратным устройствам и управлять ими.
ГЛАВА 9 Словарь терминов 937 kernelmode graphics driver — графический драйвер режима ядра ~ драйвер видео! адаптера или принтера подсистемы Windows, который преобразует аппаратно!независи! мые GDI!запросы в запросы, специфичные для конкретных устройств. key — раздел ~ механизм ссылок на данные в реестре. С объектом «раздел реестра» сопос! тавляется произвольное количество параметров, содержащих собственно данные. key control block — блок управления разделом ~ структура, в которой хранится пол! ное имя раздела реестра, индекс ячейки раздела, на которую ссылается данный блок управ! ления, и флаг, указывающий, надо ли диспетчеру конфигурации удалять ячейку раздела (на которую ссылается данный блок) при за!крытии последнего описателя этого раздела. В Windows все блоки управления разделами помещаются в двоичное дерево с сортировкой по алфавиту, что позволяет быстро находить нужный блок по имени. key object — объект «раздел реестра» ~ тип объекта, определяемый диспетчером конфигу! рации для интеграции пространства имен реестра с универсальным пространством имен ядра. keyed event — событие с ключом ~ синхронизирующий объект, введенный в Windows XP. L last known good control set — набор параметров последней удачной конфигура ции ~ копия критически важной для загрузки системы информации в разделе реестра HKLM\SYSTEM\CurrentControlSet, создаваемая после успешного входа пользователя в сис! тему. Этот набор параметров можно выбрать в стартовом меню, если какие!то изменения в конфигурации не дают возможности загрузить систему. lazy writer — подсистема отложенной записи ~ набор системных потоков, вызываю! щих диспетчер памяти для сброса содержимого кэша на диск в фоновом режиме (асинх! ронная запись на диск). Благодаря этой подсистеме диспетчер кэша оптимизирует диско! вый ввод!вывод. legacy drivers — унаследованные драйверы ~ драйверы устройств, написанные для Microsoft Windows NT, но загружаемые в Windows без всяких изменений в исходном коде. Такие драйверы не поддерживают управление электропитанием и не взаимодействуют с диспетчером Plug and Play. local file system driver (FSD) — локальный драйвер файловой системы ~ драйвер, управ! ляющий локальными томами компьютера. См. также file system driver. local kernel debugging — локальная отладка ядра ~ возможность подключения отлад! чика ядра к локальной работающей системе для просмотра ее внутреннего состояния (в противоположность подключению к целевой системе, загруженной в отладочном режиме, с использованием нуль!модемного кабеля или кабеля 1394). local procedure call (LPC) ~ механизм межпроцессной связи для высокоскоростного обмена сообщениями. Этот внутренний механизм не доступен через Windows API — к нему могут обращаться только компоненты операционной системы Windows. LPC обычно использует! ся для взаимодействия серверного процесса с одним или несколькими клиентскими процес! сами. LPC!соединение может быть установлено между двумя процессами пользовательского режима или между процессом пользовательского режима и компонентом режима ядра. Local Security Authentication Subsystem (LSASS) — подсистема локальной аутентифи кации (LSASS) ~ системный процесс пользовательского режима, отвечающий за аутентифи! кацию учетных записей, по которым пользователи или приложения пытаются обратиться к данному компьютеру. Local System account — учетная запись локальной системы ~ предопределенная ло! кальная учетная запись, используемая для запуска службы и формирования контекста за! щиты для этой службы. Эта учетная запись называется NT AUTHORITY\System. В ней не ис! пользуется пароль, и любой заданный вами пароль будет проигнорирован. Эта запись пре! доставляет полный доступ к системе. Поскольку учетная запись локальной системы действу! ет как компьютер в сети, она получает доступ к сетевым ресурсам. log file — файл журнала ~ файл метаданных (с именем $LogFile), используемый NTFS для регистрации всех операций, влияющих на структуру NTFS!тома. Этот файл применяется для восстановления NTFS!тома после аварии системы.
938 Словарь терминов БЕЗОПАСНОСТЬ log hive — регистрационный куст ~ куст, используемый диспетчером конфигурации для поддержки восстановления неизменяемого куста реестра (связанного с дисковым файлом). С каждым неизменяемым кустом сопоставлен свой регистрационный куст — скрытый файл с тем же базовым именем, но с расширением LOG. См. также hive. logging — протоколирование ~ метод обработки транзакций, применяемый NTFS для поддержания целостности файловой системы на случай каких!либо сбоев. При этом подо! перации любой транзакции, меняющей важные структуры данных файловой системы, ре! гистрируются в файле журнала еще до их выполнения, поэтому после сбоя частично вы! полненную транзакцию можно повторить или отменить. logical cluster numbers (LCN) — логические номера кластеров (LCN) ~ номера класте! ров от начала тома и до конца; по ним NTFS ссылается на физические участки диска. Для пре! образования LCN в физический адрес на диске NTFS умножает LCN на кластерный множитель (cluster factor), получая физическое смещение на диске в байтах, как того требует интерфейс драйвера диска. logical prefetcher — средство логической предвыборки ~ компонент ядра, который отслеживает обращения к файлам при загрузке системы и приложений и считывает соот! ветствующие данные для ускорения последующих процессов загрузки. logical sequence numbers (LSNs) — номера логической последовательности (LSN) ~ номера, используемые NTFS для идентификации записей, вносимых в файл журнала. logon process — процесс входа ~ процесс пользовательского режима, выполняющий Winlogon.exe — сервис, который отвечает за прием имени и пароля пользователя, передачу этой информации серверу локальной аутентификации для проверки и за создание начального про! цесса в сеансе пользователя. lookaside list — ассоциативный список ~ высокоскоростной механизм выделения па! мяти блоками фиксированного размера. Ассоциативные списки могут быть подкачиваемы! ми или неподкачиваемыми — в зависимости от того, в каком пуле они создаются. M mapped file I/O — вводвывод в проецируемые файлы ~ ввод!вывод в дисковый файл, являющийся частью виртуальной памяти процесса. Программа может обращаться к тако! му файлу как к большому массиву без буферизации данных или выполнения дискового вво! да!вывода. Все операции, связанные с вводом!выводом, берет на себя диспетчер памяти, который использует для этого механизм подкачки. master file table (MFT) — главная таблица файлов (MFT) ~ центральное звено струк! туры NTFS!тома. MFT реализуется как массив записей о файлах. Размер каждой записи фик! сирован и составляет 1 Кб независимо от размера кластеров. memory manager — диспетчер памяти ~ компонент исполнительной системы, который реализует виртуальную память с подкачкой по требованию и создает иллюзию того, что у каждого процесса имеется свое большое виртуальное адресное пространство (на физичес! кую память проецируется лишь некое подмножество этого пространства). metadata — метаданные ~ данные, описывающие файлы на диске; также называются дан! ными о структуре тома. metadata files — файлы метаданных ~ набор файлов на каждом NTFS!томе, которые хранят информацию, используемую для реализации структуры файловой системы. MFT mirror — зеркальная копия MFT ~ файл метаданных NTFS (с именем $MFTMirr), размещаемый в середине диска и содержащий первые несколько строк из главной табли! цы файлов. miniport driver — минипортдрайвер ~ разновидность драйвера устройства режима ядра; преобразует универсальный запрос ввода!вывода в специфический для конкретного типа адаптеров, например SCSI!адаптеров. mirrored volume — зеркальный том ~ том, содержимое которого дублируется на рав! ном разделе другого диска. Зеркальные тома иногда называются RAID уровня 1 (RAID!1).
ГЛАВА 9 Словарь терминов 939 modified page writer — подсистема записи модифицированных страниц ~ два си! стемных потока в диспетчере виртуальной памяти, отвечающие за ограничение размера списка модифицированных страниц. При чрезмерном увеличении этого списка страницы записываются в соответствующие места — в страничный файл (поток MiModifiedPageWriter) или проецируемые файлы (поток MiMappedPageWriter). mount — монтирование ~ метод, применяемый NTFS при первом обращении к тому; в этом контексте монтирование подразумевает подготовку тома к использованию. Чтобы смонтировать том, NTFS просматривает загрузочный файл и ищет физический адрес (на диске) главной таблицы файлов. mount points — точки монтирования ~ механизм, позволяющий связывать тома через каталоги на NTFS!томах, что позволяет обращаться к томам, которым не назначена буква диска. Точки монтирования поддерживаются точками повторного разбора. MSDN ~ Microsoft Developer Network, программа Microsoft для поддержки разработчиков. MSDN предлагает три уровня подписки: MSDN Library, Professional и Universal. Более подроб! ную информацию см. на msdn.microsoft.com. multipartition volume — составной том ~ объект, который представляет несколько раз! делов и позволяет файловой системе управлять этими разделами как единым целым. Состав! ные тома обеспечивают такие уровни производительности, надежности и масштабирова! нии, которые невозможны при использовании простых томов. mutant — мутант ~ внутреннее название мьютекса. mutex — мьютекс ~ синхронизирующий механизм, используемый для упорядочения до! ступа к общему ресурсу. N native application — встроенное приложение ~ приложение, использующее только системные сервисы Ntdll и не являющееся клиентом подсистемы Windows. Пример такого приложения — Smss (Session Manager). network file system driver (FSD) — сетевой драйвер файловой системы ~ драйвер, который дает возможность пользователям обращаться к данным на томах удаленных ком! пьютеров. См. также file system driver. network logon service — служба сетевого входа ~ сервис пользовательского режима в процессе Services.exe, реагирующий на запросы сетевого входа. Аутентификация обрабатывает! ся как при локальном входе, и соответствующая информация передается LSASS для проверки. network redirector and server — сетевые редиректор и сервер ~ драйверы файловой системы, первый из которых передает запросы удаленного ввода!вывода соответствующей машине в сети, а второй — принимает такие запросы. nonpaged pool — пул неподкачиваемой памяти ~ пул памяти, состоящий из диапазо! нов системных виртуальных адресов, которые всегда находятся в физической памяти и поэтому доступны из любого адресного пространства без обращения к механизму подкач! ки. Такой пул создается при инициализации системы и используется компонентами режи! ма ядра для выделения системной памяти. Ntdll.dll ~ особая библиотека системной поддержки, которая используется в основном DLL! модулями подсистем и которая содержит диспетчерские интерфейсы к системным серви! сам исполнительной системы и внутренним функциям поддержки. Ntkrnlmp.exe ~ исполнительная система и ядро для многопроцессорных систем. Ntoskrnl.exe ~ исполнительная система и ядро для однопроцессорных систем. O object — объект ~ в исполнительной системе Windows: единственный экземпляр периода выполнения (run!time instance) статически определенного типа объекта. object attribute — атрибут объекта ~ поле данных в объекте, которое частично опреде! ляет состояние этого объекта.
940 Словарь терминов БЕЗОПАСНОСТЬ object directory — каталог объектов ~ контейнер других объектов. Каталог объектов позволяет реализовать иерархическое пространство имен, внутри которого хранятся объек! ты других типов. object handle — описатель объекта ~ индекс в таблице описателей, специфичный для кон! кретного процесса; на эту таблицу указывает блок EPROCESS. object manager — диспетчер объектов ~ компонент исполнительной системы, отвеча! ющий за создание, удаление, защиту и учет объектов. Диспетчер объектов обеспечивает централизованное управление ресурсами. object methods — методы объекта ~ средства манипулирования объектами — обычно для чтения или изменения их атрибутов. Например, в случае процесса метод open принимает идентификатор процесса и возвращает указатель на объект «процесс». object reuse protection — защита от повторного использования объектов ~ средства, предотвращающие доступ пользователей к данным, удаленным другим пользователем, или к освобожденной им памяти. Такая защита ликвидирует потенциальные бреши в защите, инициализируя все объекты, файлы и области памяти перед выделением их какому!либо пользователю. object type — тип объекта ~ тип данных, определенных в системе и включающий серви! сы, которые оперируют с экземплярами этого типа данных, и набор атрибутов объекта; иногда называется классом объекта. P page directory — каталог страниц ~ страница, создаваемая диспетчером памяти для хра! нения адресов всех таблиц страниц процесса. В каждом процессе имеется один каталог страниц. page directory entry (PDE) — элемент каталога страниц (PDE) ~ каталог страниц со! стоит из PDE (размером по 4 байта), которые описывают состояние и адреса всех таблиц страниц, возможных для процесса. page fault — ошибка страницы ~ попытка обращения к недействительной странице (от! сутствующей в физической памяти). Обработчик ловушек, принадлежащий ядру, пересылает такие ошибки соответствующему обработчику диспетчера памяти (функции MmAccessFault). page file backed section — раздел, поддерживаемый страничным файлом ~ объект «раздел», проецируемый на переданную память. page frame database — база данных фреймов страниц ~ база данных, описывающая состо! яние каждой страницы физической памяти. Страницы могут находиться в одном из восьми со! стояний: активная (или действительная), в переходном состоянии, простаивающая, модифици! рованная, модифицированная, но не записываемая, свободная, обнуленная или аварийная. page frame number (PFN) database — база данных номеров фреймов страниц (PFN) ~ см. page frame database. page table — таблица страниц ~ страница с информацией о проецировании (состоит из массива PTE). Операционная система создает такую таблицу для описания адресов вирту! альных страниц в адресном пространстве процесса. Поскольку адресные пространства яв! ляются закрытыми, у каждого процесса имеется свой набор таблиц страниц. Таблицы стра! ниц, описывающие системное пространство, являются общими для всех процессов. page table entry (PTE) — элемент таблицы страниц (PTE) ~ элемент в таблице стра! ниц, содержащий адрес, на который проецируется виртуальный адрес. Эта таблица может находиться как в физической памяти, так и в страничном файле на диске. paged pool — пул подкачиваемой памяти ~ регион виртуальной памяти в системном пространстве, который может подгружаться в рабочий набор системного процесса и выг! ружаться из него. Пул подкачиваемой памяти создается при инициализации системы и ис! пользуется компонентами режима ядра для выделения системной памяти. В однопроцес! сорных системах таких пулов два, а в многопроцессорных — четыре. paging — подкачка ~ перемещение содержимого памяти на диск с целью освобождения физической памяти для использования другими процессами или самой системой, а также загрузка страниц с диска в физическую память.
ГЛАВА 9 Словарь терминов 941 partition — раздел (дисковый) ~ область жесткого диска в операционных системах Microsoft. Файловые системы (вроде FAT и NTFS) форматируют каждый раздел как том. На жестком диске может быть до четырех главных разделов. См. также extended partition. partition table — таблица разделов ~ часть главной загрузочной записи (MBR), состоя! щая из четырех элементов, каждый из которых определяет местонахождение одного из четырех главных разделов на диске. В таблицу разделов также записывается тип раздела; последний определяет файловую систему на этом разделе. Physical Address Extension (PAE) ~ режим проецирования памяти, поддерживаемый все! ми процессорами типа Intel x86, начиная с Pentium Pro. При наличии соответствующего чипсета режим PAE позволяет адресоваться к 64 Гб физической памяти. Когда процессор работает в режиме PAE, блок управления памятью (MMU) разбивает виртуальные адреса на четыре поля. Plug and Play (PnP) manager — диспетчер Plug and Play (PnP) ~ один из основных компонентов исполнительной системы, который определяет и загружает драйверы, нужные для поддержки конкретного устройства. Диспетчер PnP выясняет требования каждого уст! ройства к аппаратным ресурсам в процессе перечисления. Исходя из требований к ресур! сам, диспетчер PnP выделяет каждому устройству соответствующие аппаратные ресурсы — порты ввода!вывода, IRQ!линии, DMA!каналы и диапазоны памяти. Он также отвечает за рассылку уведомлений о любых изменениях в аппаратной конфигурации системы. port driver — портдрайвер ~ разновидность драйвера устройства режима ядра. Реали! зует обработку запроса на ввод!вывод, специфичного для конкретного типа порта ввода! вывода, например для SCSI. power manager — диспетчер электропитания ~ один из основных компонентов испол! нительной системы, который координирует события, связанные с управлением электропи! танием, и генерирует соответствующие уведомления для драйверов устройств. Когда сис! тема простаивает, диспетчер электропитания может переводить ее в состояние понижен! ного энергопотребления. Изменения в уровне энергопотребления реализуются драйвера! ми конкретных устройств, но координируются диспетчером электропитания. printer driver — драйвер принтера ~ драйвер, транслирующий аппаратно!независимые запросы на графические операции в команды, специфичные для принтера. Эти команды обыч! но пересылаются порт!драйверу режима ядра — драйверу параллельного порта (Parport.sys) или USB!порта принтера (Usbprint.sys). private cache map — закрытая карта кэша ~ структура, хранящая последние два адреса, по которым считывались данные. Эта информация помогает диспетчеру кэша выполнять интеллектуальное опережающее чтение данных. process — процесс ~ виртуальное адресное пространство и управляющая информация, необходимая для выполнения набора объектов!потоков. process ID — идентификатор процесса ~ уникальный идентификатор процесса (его внутреннее название — идентификатор клиента). process working set — рабочий набор процесса ~ подмножество виртуального адрес! ного пространства процесса, резидентное в физической памяти и принадлежащее выпол! няемому процессу. См. также system working set. processor affinity — привязка к процессорам ~ набор процессоров, на которых может выполняться данный поток. processor control register (PCR) ~ структура данных и ее расширение — PRCB (processor control block) — содержат информацию о состоянии каждого процессора в системе, в том числе текущий IRQL, указатель на аппаратную IDT, сведения о текущем потоке и потоке, ко! торый будет выполняться следующим. Ядро и HAL используют эту информацию для выпол! нения операций, специфичных для данной машины и ее архитектуры. Отдельные части структур PCR и PRCB документированы и определены в заголовочном файле Ntddk.h (в Windows DDK). program — программа ~ статическая последовательность инструкций. protectedmode — защищенный режим ~ состояние на одном из этапов за!грузки сис! темы, при котором трансляция виртуальных адресов в физические еще не поддерживает!
942 Словарь терминов БЕЗОПАСНОСТЬ ся, но становится доступной 32!разрядная адресация к памяти. После того как система пе! реходит в защищенный режим, Ntldr может обращаться ко всей физической памяти. protocol driver — драйвер протокола ~ драйвер, реализующий сетевой протокол. prototype page table entry (prototype PTE) — прототипный элемент таблицы стра ниц (PTE) ~ программная структура, используемая диспетчером памяти для проецирова! ния потенциально разделяемых страниц. Массив прототипных PTE создается при первом создании объекта «раздел». Q Quality of Service (QoS) ~ сетевая технология, гарантирующая выделение согласованных полос пропускания и поддержку ряда других параметров. quantum — квант ~ отрезок времени, в течение которого поток может работать до того, как Windows прервет его выполнение, чтобы проверить, не ожидает ли выполнения другой поток с тем же уровнем приоритета. quantum unit — квантовая единица ~ значение, которое отражает, сколько времени поток может выполняться до истечения его кванта. Это значение выражается не в едини! цах времени, а целым числом. queued spinlock — спинблокировка с очередью ~ спин!блокировка особого типа, ис! пользуемая исключительно ядром и не экспортируемая компонентам исполнительной си! стемы или драйверам устройств. Спин!блокировка с очередью обеспечивает более эффек! тивную работу многопроцессорных систем, чем стандартная. См. также spinlock. R RAID5 volume — том RAID5 ~ отказоустойчивый вариант обычного чередующегося тома. Отказоустойчивость достигается за счет выделения дополнительного диска для хранения информации о четности для каждой чередующейся области (stripe). realmode — реальный режим ~ режим, в котором трансляция виртуальных адресов в физические не поддерживается и программам доступен лишь первый мегабайт физичес! кой памяти. В этом режиме выполняются только простые программы MS!DOS. recoverability — восстанавливаемость ~ дополнительная возможность NTFS, позволя! ющая восстанавливать структуру тома после сбоя системы. В этом случае метаданные тома могут оказаться в рассогласованном состоянии, что приведет к повреждению большого числа файлов и каталогов. NTFS реализует восстанавливаемость за счет протоколирования изменений метаданных как транзакций, так что структуры файловой системы могут быть возвращены в согласованное состояние без потери информации о структуре каталогов и файлов. (Однако файловые данные могут быть потеряны.) redo information — информация для повтора ~ информация, включаемая в запись кон! трольной точки NTFS и указывающая, как повторить подоперацию полностью запротоко! лированной транзакции, если сбой системы произошел перед самым сбросом данных тран! закции из кэша на диск. reference count — счетчик ссылок ~ счетчик, поддерживаемый диспетчером объектов и сообщающий, сколько указателей на объект выдано системным процессам. Диспетчер объектов увеличивает счетчик ссылок на 1 при каждой выдаче указателя на данный объект; когда компоненты режима ядра заканчивают использование указателя, они вызывают дис! петчер объектов для уменьшения счетчика ссылок на соответствующий объект. reparse data — данные повторного разбора ~ пользовательские данные, сопоставлен! ные с файлом или каталогом, которые могут быть считаны из точки повторного разбора приложением, создавшим эти данные, дрaйвером фильтра файловой системы или диспет! чером ввода!вывода. reparse point — точка повторного разбора ~ NTFS!файл или каталог, с которым сопостав! лен блок данных, называемый данными повторного разбора. resident attribute — резидентный атрибут ~ атрибут, хранящийся непосредственно в главной таблице файлов. (Если файл невелик, все его атрибуты и их значения хранятся в записи этой таблицы.)
ГЛАВА 9 Словарь терминов 943 resource arbitration — арбитраж ресурсов ~ процесс, в ходе которого диспетчер Plug and Play (PnP) распределяет ресурсы между устройствами с учетом их требований. Посколь! ку устройства могут быть добавлены в систему после распределения ресурсов на этапе заг! рузки, диспетчер PnP должен уметь перераспределять ресурсы. restricted token — ограниченный маркер ~ маркер, созданный из основного маркера или из маркера олицетворения с помощью функции CreateRestrictedToken. Ограниченный маркер является копией маркера, из которого он создан, но в него может быть внесен ряд изменений, например удалены какие!либо привилегии. ring — кольцо ~ уровень привилегий, определенный в архитектурах процессоров x86 и x64 для защиты системного кода и данных от случайной или намеренной перезаписи ко! дом с меньшими привилегиями. Windows на платформах x86 и x64 использует уровень привилегий 0 (кольцо 0) в режиме ядра и 3 (кольцо 3) в пользовательском режиме. S safe mode — безопасный режим ~ конфигурация системы с минимальным набором драйверов устройств и сервисов. При этом драйверы и сервисы от сторонних поставщи! ков не загружаются. SAM database — база данных SAM ~ база данных (в разделе реестра HKLM\ SAM), в кото! рой хранятся определения пользователей и групп, а также их пароли и другие атрибуты. scatter/gather I/O — вводвывод по механизму «scatter/gather» ~ разновидность вы! сокопроизводительного ввода!вывода, поддерживаемая Windows и доступная через Windows!функции ReadFileScatter и WriteFileGather. Эти функции позволяют в рамках одной операции считывать или записывать данные из нескольких буферов в виртуальной памя! ти в непрерывную область дискового файла. Чтобы задействовать такой ввод!вывод, нуж! но открыть файл для некэшируемого асинхронного (перекрывающегося) ввода!вывода и выровнять пользовательские буферы по границам страниц. section object — объект «раздел» ~ объект, представляющий блок памяти, до!ступный двум и более процессам для совместного использования. Объект!раздел можно проецировать на страничный файл или другой файл на диске. Исполнительная система использует разделы для загрузки исполняемых образов в память, а диспетчер кэша — для доступа к данным в кэ! шированном файле. В подсистеме Windows такой объект называется проекцией файла. section object pointers — указатели объекта «раздел» ~ структура для каждого откры! того файла (представленного объектом «файл»), играющая ключевую роль в поддержании целостности данных при всех типах доступа к файлу и в обеспечении кэширования фай! лов. Эта структура указывает на одну или две области управления: одна из них использует! ся для проецирования файла при доступе к нему как к файлу данных, а другая — при его выполнении как исполняемого образа. sector — сектор ~ аппаратно адресуемый блок физического диска. Размер секторов на жестких дисках в x86!системах почти всегда равен 512 байтам. secure attention sequence (SAS) ~ комбинация клавиш, нажатие которой уведомляет Winlogon о запросе пользователя на вход в систему. Security Accounts Manager (SAM) service — Служба диспетчера учетных записей бе зопасности (SAM) ~ набор подпрограмм, отвечающих за управление базой данных, которая содержит имена пользователей и групп, определенных на локальной машине или в домене (если данная система является контроллером домена). SAM выполняется в контексте LSASS. security auditing — аудит безопасности ~ механизм, позволяющий Windows регистри! ровать события, связанные с защитой, а также любые попытки создания, удаления и обра! щения к системным ресурсам. При входе регистрируются идентификационные данные всех пользователей, что дает возможность легко выявить любого, кто попытался выполнить не! санкционированную операцию. security descriptor — дескриптор защиты ~ структура данных, указывающая, кто может выполнять операции над объектом и какие именно операции. Де!скриптор защиты состо! ит из атрибутов.
944 Словарь терминов БЕЗОПАСНОСТЬ security identifier (SID) — идентификатор защиты (SID) ~ средство уникальной иден! тификации сущностей, выполняющих какие!либо операции в системе. SID представляет собой числовое значение переменной длины, формируемое из номера версии структуры SID, 48!битного кода агента идентификатора (identifier authority value) и переменного ко! личества 32!битных кодов суб!агентов и/или относительных идентификаторов (relative identifiers, RID). Security Reference Monitor (SRM) — монитор состояния защиты (SRM) ~ компонент исполнительной системы (Ntoskrnl.exe), который вводит в действие политику безопасности на локальном компьютере. Он охраняет ресурсы операционной системы, обеспечивая защиту и аудит объектов периода выполнения. semaphore — семафор ~ счетчик, позволяющий обращаться к ресурсу некоему максималь! ному числу потоков. server process — серверный процесс ~ пользовательский процесс, выполняемый как сервис Windows, например Event Log и Schedule. Многие серверные приложения вроде Microsoft SQL Server и Microsoft Exchange Server включают компоненты, выполняемые как сервисы Windows. session — сеанс ~ состоит из процессов и других системных объектов (вроде WindowSta! tion, рабочих столов и окон). Эти объекты представляют сеанс единственного пользовате! ля, который зарегистрировался на рабочей станции. У каждого сеанса есть своя область пула подкачиваемой памяти, используемая Win32k.sys для выделения памяти под закрытые GUI! структуры данных сеанса. Кроме того, каждый сеанс получает свою копию процесса под! системы Windows (Csrss.exe) и Winlogon.exe. session space — пространство сеанса ~ часть системного пространства, на которую про! ецируются все общие для сеанса структуры данных. Список рабочего набора сеанса описы! вает части пространства сеанса, резидентные в памяти. shared cache map — общая карта кэша ~ структура, описывающая состояние кэшируе! мого файла, включая его размер и (из соображений безопасности) длину действительных данных. shared memory — разделяемая (общая, совместно используемая) память ~ память, видимая более чем одному процессу или присутствующая более чем в одном виртуальном адресном пространстве. signal state — свободное состояние ~ состояние синхронизирующего объекта. simple volume — простой том ~ набор объектов, который представляет секторы един! ственного раздела, управляемые драйвером файловой системы как единым целым. single signon — унифицированный вход в систему ~ возможность проверки регист! рационной информации сразу на нескольких системах. Например, пользователь, входящий в систему Windows, может быть одновременно аутентифицирован на UNIX!сервере. small memory dump — малый дамп памяти ~ тип дампа памяти (вариант по умолчанию в системах Windows Professional) объемом 64 Кб. Он включает в себя стоп!код с параметра! ми, список загруженных драйверов устройств, структуры данных, описывающие текущие процесс и поток (EPROCESS и ETHREAD), а также стек ядра для вызвавшего крах потока. spanned volume — перекрытый том ~ единый логический том, состоящий максимум из 32 разделов на одном или нескольких дисках. Отдельные разделы объединяются в перекры! тый том (с помощью оснастки Disk Management консоли Microsoft Management Console), ко! торый после этого можно отформатировать под любую файловую систему, поддерживае! мую Windows. sparse file — разреженный файл ~ файлы, часто очень большие, но содержащие лишь малые объемы ненулевых данных. spinlock — спинблокировка ~ механизм взаимоисключающей блокировки, используе! мый ядром. См. также queued spinlock. stream — поток данных ~ последовательность байтов в файле. striped volume — чередующийся том ~ набор разделов (максимум 32, по одному разде! лу на одном диске), объединенных в единый логический том. Чередующиеся тома также
ГЛАВА 9 Словарь терминов 945 называются томами RAID уровня 0 (RAID!0). Раздел чередующегося тома не обязательно должен охватывать целый диск; единственное ограничение — все разделы должны быть равного размера. stop code — стопкод ~ код, который классифицирует тип ошибки, обнаруженной компо! нентом, вызвавшим крах системы. structured exception handling — структурная обработка исключений ~ разновидность обработки исключений, позволяющая приложениям получать управление при возникнове! нии исключений. При этом приложение может исправить ситуацию, которая привела к ис! ключению, провести раскрутку стека (завершив таким образом выполнение подпрограммы, вызвавшей исключение) или уведомить систему о том, что данное исключение ему не извес! тно, и тогда система продолжит поиск подходящего обработчика для данного исключения. subsection — подраздел ~ структура с информацией о проецировании каждого раздела файла (атрибуты защиты страниц и т. д.). subsystem DLL — DLL подсистемы ~ DLL!модуль, транслирующий вызов документиро! ванной функции в вызов соответствующего недокументированного системного сервиса Windows. symbolic link — символьная ссылка ~ механизм косвенной ссылки на имя объекта. symmetric encryption algorithm — алгоритм симметричного шифрования ~ алго! ритм, в котором для шифрования и расшифровки данных используется один и тот же ключ. Такие алгоритмы работают, как правило, очень быстро, и их можно применять для шиф! рования больших объемов данных, например файлов. Однако слабая сторона алгоритмов симметричного шифрования в том, что защита легко обходится при наличии ключа. symmetric multiprocessing (SMP) — симметричная многопроцессорная обработка (SMP) ~ многопроцессорная обработка, при которой не выделяется главный процессор, — код операционной системы и пользовательские потоки могут выполняться на любом про! цессоре. Все процессоры делят единое пространство памяти. synchronization — синхронизация ~ способность потока синхронизировать свое выпол! нение, ожидая перехода какого!либо объекта из одного состояния в другое. Поток можно синхронизировать с использованием таких объектов, как процесс, поток, файл, событие, семафор, мьютекс и таймер. Объекты вроде раздела, порта, маркера доступа, каталога объек! тов, символьной ссылки, профиля и раздела реестра синхронизацию не поддерживают. synchronous I/O — синхронный вводвывод ~ модель ввода!вывода, в которой устрой! ство передает данные и возвращает код состояния только по завершении ввода!вывода. Сразу после этого программа получает доступ к переданным данным. Windows!функции ReadFile и WriteFile при использовании в простейшей форме выполняются синхронно. Они возвращают управление вызвавшему потоку, только когда полностью завершают операцию ввода!вывода. system accesscontrol list (SACL) — системный список управления доступом (SACL) ~ список, указывающий, какие операции и каких пользователей следует регистрировать в журнале аудита безопасности. system audit ACE — ACE системного аудита ~ ACE в SACL, которые наряду с ACE объек! тов системного аудита определяют, какие операции, выполняемые над объектами конкрет! ными пользователями или группами, подлежат аудиту. ACE объектов системного аудита со! держат GUID, указывающий типы объектов или подобъектов, к которым применим данный ACE, и необязательный GUID, контролирующий передачу ACE дочерним объектам конкрет! ных типов. При SACL, равном null, аудит объекта не ведется. system page table entry (PTE) — системный элемент таблицы страниц (PTE) ~ PTE, используемый при проецировании системных страниц, например пространства ввода!вы! вода, стеков ядра и списков дескрипторов памяти (MDL). system service dispatch table — таблица диспетчеризации системных сервисов ~ таблица, в которой каждый элемент содержит указатель на системный сервис, а не на про! цедуру обработки прерывания. system services (executive system services) — системные сервисы (сервисы испол нительной системы) ~ встроенные функции операционной системы Windows, которые
946 Словарь терминов БЕЗОПАСНОСТЬ можно вызывать из пользовательского режима. Например, NtCreateProcess — это внутрен! ний системный сервис, вызываемый Windows!функцией CreateProcess при создании ново! го процесса. system thread — системный поток ~ поток, выполняемый только в режиме ядра. Систем! ные потоки всегда выполняются в системном процессе (с идентификатором, равным 2). У этих потоков имеются все атрибуты и контексты обычных потоков пользовательского ре! жима (аппаратный контекст, приоритет и др.), но они работают только в режиме ядра в коде, загруженном в системное пространство, — будь то Ntoskrnl.exe или какой!нибудь драйвер устройства. У системных потоков нет пользовательского адресного пространства и поэтому они выделяют память из куч операционной системы вроде пула подкачиваемой или неподкачиваемой памяти. system worker threads — системные рабочие потоки ~ потоки, создаваемые в процессе System при инициализации системы и существующие только для того, чтобы выполнять работу в интересах других потоков. system working set — системный рабочий набор ~ физическая память, занятая системным кэшем, пулом подкачиваемой памяти, а также подкачиваемым кодом Ntoskrnl.exe и драйверов устройств. См. также process working set. T thread — поток ~ некая сущность внутри процесса, получающая процессорное время для выполнения. Поток включает содержимое набора переменных регистров, отражающих со! стояние процессора, два стека (один используется при выполнении потока в режиме ядра, а другой — при выполнении в пользовательском режиме), закрытую область памяти (ис! пользуемую подсистемами, библиотеками периода выполнения и DLL), а также уникальный идентификатор потока (внутреннее название — идентификатор клиента). thread context — контекст потока ~ переменные регистры, стеки и локальная область памяти потока. Поскольку эта информация различна на каждой аппаратной платформе, на которой может работать Windows, соответствующая структура данных (CONTEXT) специ! фична для конкретной платформы. Фактически CONTEXT, возвращаемая Windows!функци! ей GetThreadContext, является единственной открытой структурой данных в Windows API, зависящей от аппаратной платформы. transaction — транзакция ~ операция ввода!вывода, изменяющая данные файловой сис! темы или структуру каталогов тома. Отдельные изменения на диске, составляющие тран! закцию, выполняются атомарно: в ходе транзакции на диск должны быть внесены все тре! буемые изменения. Если транзакция прервана сбоем системы, часть изменений, уже внесен! ных к этому моменту, нужно отменить. Такая отмена называется откатом. После отката база данных возвращается в исходное согласованное состояние, в котором она была до начала транзакции. transaction table — таблица транзакций ~ таблица, предназначенная для отслеживания начатых, но еще не зафиксированных транзакций. В процессе восстановления результаты подопераций этих транзакций должны быть удалены с диска. translation lookaside buffer — ассоциативный буфер трансляции ~ кэш централь! ного процессора, в котором хранятся недавно транслировавшиеся номера виртуальных страниц. trap — ловушка ~ аппаратный механизм, благодаря которому при прерывании или исклю! чении процессор перехватывает контроль над выполняемым потоком, переключает его из пользовательского режима в режим ядра и передает управление определенной части опе! рационной системы. В Windows процессор передает управление обработчику ловушек. trap frame — фрейм ловушки ~ структура данных, в которой сохраняется информация о состоянии потока, выполнявшегося на момент прерывания. Эта информация позволяет ядру возобновить выполнение потока после обработки прерывания или исключения. Фрейм ловушки обычно является подмножеством полного контекста потока. trap handler — обработчик ловушки ~ модуль в ядре, действующий как коммутатор, ко! торый перенаправляет исключения и прерывания соответствующему коду.
ГЛАВА 9 Словарь терминов 947 trusted facility management — управление доверительными отношениями ~ требует поддержки набора ролей (различных типов учетных записей) для разных уровней работы в системе. Например, функции администрирования доступны только по одной группе учетных записей — Administrators (Администраторы). trusted path functionality — функциональность пути доверительных отношений ~ предотвращает перехват имен и паролей пользователей программами — троянскими ко! нями. Эта функциональность реализована в Windows в виде входной сигнальной комбина! ции клавиш Ctrl+Alt+Del и не может быть перехвачена непривилегированными приложе! ниями. Такая комбинация клавиш, известная как SAS (secure attention sequence), вызывает диалоговое окно входа в систему, обходя вызов его фальшивого эквивалента из троянско! го коня. type object — объект типа ~ внутрисистемный объект, который содержит информацию, общую для каждого экземпляра данного объекта. U Unicode ~ международный стандарт кодировки символов, определяющий уникальные 16! битные коды для большинства известных в мире наборов символов. update record — запись модификации ~ запись, которую NTFS часто помещает в файл журнала. Каждая запись модификации содержит информацию, которая потребуется в слу! чае повторения операции, изменяющей структуру файловой системы. user mode — пользовательский режим ~ непривилегированный режим работы процес! сора, в котором выполняются приложения. В этом режиме доступен ограниченный набор интерфейсов; кроме того, ограничен доступ к системным данным. См. также kernel mode. V VACB index array — массив индексов VACB ~ массив указателей, поддерживаемый дис! петчером кэша для отслеживания представлений для данного файла, проецируемых в сис! темный кэш. view — представление ~ часть объекта «раздел», затребованная процессом. Объект «раз! дел» может ссылаться на файлы, длина которых намного превышает размер адресного про! странства процесса. (Если раздел поддерживается страничным файлом, в нем должно быть достаточно места для размещения всего раздела.) Используя очень большой объект «раз! дел», процесс может проецировать лишь его представление, которое создается вызовом функции MapViewOfFile с указанием проецируемого диапазона. Это позволяет процессам экономить адресное пространство, так как на память проецируются только нужные в дан! ный момент представления объекта «раздел». См. также section object. virtual address control block (VACB) — блок управления виртуальными адресами (VACB) ~ структуры данных, используемые диспетчером кэша для управления системным ад! ресным пространством, на которое проецируются файлы. virtual address descriptor (VAD) — дескриптор виртуального адреса (VAD) ~ структура данных, поддерживаемая диспетчером памяти для отслеживания виртуальных адресов, заре! зервированных в адресном пространстве процесса. Для большей эффективности поиска информации VAD организованы в виде двоичного дерева с автоматической балансировкой (self!balancing binary tree). virtual cluster number (VCN) — виртуальный номер кластера (VCN) ~ VCN нумеруют кластеры, принадлежащие конкретному файлу (от 0 до m). VCN не обязательно должны быть физически непрерывны и могут отображаться на любой LCN в пределах тома. virtual device drivers (VDD) — драйверы виртуальных устройств ~ драйверы, исполь! зуемые для эмуляции 16!разрядных программ MS!DOS. Они перехватывают ссылки из про! грамм MS!DOS на порты ввода!вывода и транслируют их в вызовы Windows!функций вво! да!вывода. Поскольку Windows — полностью защищенная операционная система, пользо! вательские программы MS!DOS не имеют прямого доступа к оборудованию и должны об! ращаться к нему через драйверы устройств реального режима.
948 Словарь терминов БЕЗОПАСНОСТЬ virtual memory manager — диспетчер виртуальной памяти ~ реализует виртуальную память — схему управления памятью, в соответствии с которой каждый процесс получает боль! шое закрытое адресное пространство, по своим размерам намного превышающее реальный объем физической памяти. volume — том ~ один или несколько дисковых разделов, рассматриваемых как единое целое. volume file — файл тома ~ системный файл (с именем $Volume), содержащий имя тома, версию NTFS, для которой отформатирован том, и бит, устанавливаемый при повреждении диска (он сигнализирует о необходимости запуска утилиты Chkdsk). volume manager — диспетчер томов ~ обобщенное название драйверов FtDisk и DMIO, поскольку они оба поддерживают одни и те же типы составных томов. W wait block — блок ожидания ~ у каждого потока, находящегося в состоянии ожидания, имеется список блоков ожидания — структур данных, представляющих объекты, на кото! рых ждет этот поток. А у каждого объекта диспетчера ядра есть список блоков ожидания — структур данных, представляющих потоки, которые ждут на этом объекте. WDM drivers — WDMдрайверы ~ драйверы устройств, отвечающие спецификации Windows Driver Model (WDM). WDM требует от драйверов поддержки управления электро! питанием, Plug and Play и WMI. WDM реализована в Windows 2000 (и выше), а также в Windows Millennium Edition, поэтому WDM!драйверы этих операционных систем совместимы на уров! не исходного кода, а во многих случаях и на уровне двоичного кода. Существует три типа WDM!драйверов: драйверы шин, функциональные драйверы и драйверы фильтров. Windows API ~ 32!разрядный интерфейс в 32! и 64!разрядных операционных системах семейства Windows. Windows services — Windowsсервисы ~ механизм запуска процессов, которые предос! тавляют сервисы и не требуют привязки к интерактивному пользователю. Сервисы анало! гичны демонам UNIX и часто реализуются на серверной стороне клиент!серверных при! ложений. WindowStation — объект WindowStation ~ объект, содержащий рабочие столы, которые в свою очередь содержат окна. Только один объект WindowStation может быть видим на консоли и принимать пользовательский ввод (с клавиатуры и от мыши). В среде Terminal Services видим один объект WindowStation в каждом сеансе, но все сервисы выполняются как часть консольного сеанса. Windows drivers — драйверы Windows ~ драйверы устройств, интегрируемые с диспет! черами Plug and Play и электропитания в Windows. К ним относятся драйверы устройств мас! совой памяти, стеков протоколов и сетевых адаптеров. Windows Management Instrumentation (WMI) manager — диспетчер WMI ~ компонент исполнительной системы, который позволяет драйверам устройств публиковать информа! цию о своих рабочих характеристиках и конфигурации и принимать команды от службы WMI пользовательского режима. Потребители WMI!информации могут находиться как на локальной машине, так и на удаленных компьютерах в сети. work item — рабочий элемент ~ некое задание, помещаемое в специальную очередь (объект диспетчера ядра), проверяемую системными рабочими потоками. Драйвер устрой! ства или компонент исполнительной системы запрашивает сервисы системных рабочих потоков через функцию исполнительной системы ExQueueWorkItem или IoQueueWorkItem. Рабочий элемент включает указатель на процедуру и параметр, передаваемый потоком этой процедуре при обработке рабочего элемента. Процедура реализуется драйвером устройства или компонентом исполнительной системы, выполняемым при IRQL уровня «passive». working set — рабочий набор ~ набор виртуальных страниц, резидентных в физической па! мяти. Существует два типа рабочих наборов — системный и процесса. working set manager — диспетчер рабочих наборов ~ процедура, выполнямая в кон! тексте системного потока диспетчера настройки баланса; инициирует автоматическое усе! чение рабочего набора для увеличения объема доступной в системе свободной памяти.
ГЛАВА 9 Словарь терминов 949 writeback — обратная запись ~ алгоритм кэширования, используемый файловой систе! мой с отложенной записью для повышения производительности. При обратной записи файловая система записывает изменения в кэш, а затем сбрасывает его содержимое на диск (обычно в фоновом режиме). writethrough — сквозная запись ~ алгоритм, применяемый файловой системой FAT для немедленной записи изменений на диск. В отличие от алгоритма точной записи не требует упорядочения операций записи. См. также careful write. Z zero page thread — поток обнуления страниц ~ системный поток режима ядра (поток 0 в системном процессе), который обнуляет страницы из списка свободных страниц.
Предметный указатель 951 Предметный указатель A ACE (AccessControl Entry) 522–533 — битовые флаги, определяющие пра вила наследования 534 ACL (AccessControl List) 533 — присвоение 537–538 Active Directory 515, 892–893 — архитектура 894 ADSI (Active Directory Service Interfaces) 893 Advanced RISC Computing 270 AFD (Ancillary Function Driver) 844 Alpha AXP 43 APC (Asynchronous Procedure Call) 117–118 — объект 117 — очереди 117 APIC (Advanced Programmable Interrupt Controller) 95–96 API, сетевые 839 AppleTalk 872 AuthZ API 543–544 AWE (Address Windowing Extensions) 17, 422–424 C CIFS (Common Internet File System) 739 — обмен файлами 739 CIM (Common Information Model) 255–258 CIMOM (CIM Object Manager) 255 — репозитарий 265 CLR (Common Language Runtime) 4 Common Criteria 510–514 CryptoAPI 826 CScript 263 CSRSS 121 CurrentControlSet 247 — обработка 114 — объект 113 — очереди 113 — правила генерации прерываний 114 — процедура обработки прерываний 579 Driver Verifier Manager (Диспетчер провер ки драйверов) 434, 916 E EFS (Encrypting File System) 771–772, 822–825 — архитектура 825 — схема работы 830 EM64T 43 ESE (Extensible Storage Engine) 893 Event Tracing for Windows 187 F FAT (File Allocation Table) 734 FCB (File Control Block) 776 FDO (Functional Device Object) 632 FEK (File Encryption Key) 823 FiberChannel 845 FiDO (Filter Device Object) 632 File System Recognizer 682 Filesystem Filter Manager 749 FSD — локальный 737–738 — удаленный 738–740 FtDisk 659 G GDI 60–61 GINA (Graphical Identification and Authen tication) 87, 239, 515 GUID (Globally Unique Identifier) 533 D H DACL (Discretionary AccessControl List) 525, 533 DCOM (Distributed Component Object Model) 864 DDE (Dynamic Data Exchange) 529 DDK (Device Driver Kit) 36 DEP (Data Execution Prevention) 412 — параметры 413 — программный вариант 414 DFS (Distributed File System) 896–897 DIRQL (Device IRQL) 103 DISPATCHER_HEADER 172 Distributed Management Task Force 254 DLL 6 — Hell 329 — подсистемы 59 DNS (Domain Name System) 871 DPC (Deferred Procedure Call) 81, 112–113, 115 HAL (Hardware Abstraction Layer) 42, 73 Hardware Compatibility List 433 HSM (Hierarchical Storage Management) 676 HTTP 853 HTTP API 853 Hyperthreading 45, 379, 386 I IA64 43 — компоненты, участвующие в процес се загрузки 281–282 — контроллеры прерываний 97 — структура адресного пространства 447 IDL (Interface Definition Language) 849 IDT (Interrupt Dispatch Table) 94–95 IKE (Internet Key Exchange) 879 InfiniBand 845 IPI (Interprocessor Interrupt) 102 IPSec (Internet Protocol Security); см. IPбе зопасность
952 Предметный указатель IPSec Policy Agent (Агент политики IPбезопасности) 879 IPбезопасность 878 IPфильтр 877 IPфильтрация 876–877 IRP (I/O Request Packet) 568, 595–596, 745–746 — блок стека 597 — сопоставленный 614–615 IRQL (Interrupt Request Level) 98 — предопределенные 103–104 — уровни приоритетов 100, 352 iSCSI 652 — Software Initiator 653 ISR (Interrupt Service Routine) 93 K Kerberos 559 KSecDD (Kernel Security Device Driver) 515 L LANA 861 LANE (LAN Emulation) 885 LANMan Redirector 738 LANMan Server 739 LBN (Logical Block Number) 652 LCN (Logical Cluster Number) 778 LDAP C API 893 LFH (Low Fragmentation Heap) 418–420 Local Security Policy Editor (Редактор ло кальной политики безопасности) 301 LPC (Local Procedure Call) 70, 183–186 — использование портов 187 LSASS (Local Security Authentication Subsystem) 87, 514, 561, 826 — взаимодействие с SRM 517 LSN (Logical Sequence Number) 696 LUID (Locally Unique Identifier) 525–526 LUN (Logical Unit Number) 271 M MAPI (Messaging API) 893 MBR (Master Boot Record) 269–270, 659 — повреждение 298 MCM (Miniport Call Manager) 885 Message Queuing 865 MFT (Master File Table) 778–779 — зона 772 Microsoft Base Cryptographic Provider 1.0 830 Microsoft Corporate Error Reporting (CER) Toolkit 908 Microsoft OCA (Online Crash Analysis) 899 Microsoft Shadow Copy Provider 687 Microsoft WHQL 638 Microsoft Windows Installer 759 Microsoft Windows Services for UNIX 65 Microsoft Windows Support Tools 29 MIDL (Microsoft Interface Definition Language) 849 MIPS 43 MKS Toolkit 65 MOF (Managed Object Format) 256 Motorola PowerPC 43 MPIO (Multipath I/O) 653 MPR (Multiple Provider Router) 289, 866–867 — компоненты 866 MSV1_0 555, 559–560 MUP (Multiple UNC Provider) 866, 869 N NAT (Network Address Translation) 876 NDIS 880–881 — библиотека 838 — драйвер, промежуточный 884 — компоненты 880 — минипортдрайверы 838 — — для сетевого USBустройства 888 — ориентированный на логические со единения 885 — преимущества 881–882 Net API 893 .NET Framework 4 — взаимосвязи компонентов 5 NetBIOS 861 — API 863 — имена 861 — функционирование 862 — эмулятор 863 Network Load Balancing (Балансировка нагрузки сети) 894–895 NT Kernel Logger 188 NTDS API 893 NTFS 736 — атрибуты файлов 786–787 — безымянный поток данных 764 — группа (run) 783 — дополнительные возможности 763 — идентификатор защиты 803 — индекс имен файлов для корневого каталога тома 800 — индексация — — $Quota 802 — — $Secure 803 — каталоги 799 — компоненты 775 — механизм универсальной индекса ции 804 — множественные потоки данных 763–764 — проходы анализа, повтора и отмены 815–816 — размеры кластеров по умолчанию 736 — структуры данных 776 — сценарии восстановления данных 822 — дисковый формат тома 777 — универсальный механизм индексации 766 Ntldr 651 NUMA (NonUniform Memory Architecture) 45–46, 380–382 NWLink 872 O OLEсвязи 771 oplock 740–741 P PAE (Physical Address Extension) 458–460 PCR (Processor Control Region) 101, 165
Предметный указатель PDE (Page Directory Entry) 452–454 PDO (Physical Device Object) 632 PEB (Process Environment Block) 307, 312 — поля 313 — — начальные значения 324–325 PFN (Page Frame Number) 502–503 PIC (Programmable Interrupt Controller) 95 Platform Software Development (SDK) Kit 3, 36 POSIX 57, 64–65, 416 — жесткие связи 789 — процессы 324 PRCB (Processor Control Block) 101, 377 PTE (Page Table Entry) 439, 449 — аппаратные — — в IA64системах 461 — — в x64системах 462 — битовые флаги 455 — действительный 454 — недействительный 464 — — указывающий на прототипный PTE 466 — прототипный 465–467 — системный 446 Q QoS (Quality of Service) 889 — архитектура 890 R Raw FSD 737 RDMA (Remote Direct Memory Access) 845–846 Recovery Agent Wizard (Мастер добавления агента восстановления) 828 Remote NDIS 888–889 RID (Relative Identifier) 521 RPC (Remote Procedure Call) 847–850 — асинхронный 849 — локальный 851 — публикация имени сервера 850 — реализация 851 — универсальный интерфейс провайде ров транспорта 849 RSVP (Resource Reservation Setup Protocol) 889 RTC (RealTime Communications) 864 S SACL (System AccessControl List) 533–534 SAM (Security Account Manager) API 893 SAN (Storage Area Networking) 652 — применение в трехуровневой архи тектуре электронной коммерции 845 — соединения 845 SAPIC (Streamlined Advanced Programmable Interrupt Controller) 97 SAS (Secure Attention Sequence) 87–88 — реализация 558 SCB (Stream Control Block) 776 SChannel (Secure Channel) 851 SCM (Service Control Manager) 288, 294 SEH (Structured Exception Handling) 118 SID — групп в маркере 525 — общеизвестные 522 953 — ограниченный 531 — с атрибутом проверки только на зап рет (denyonly) 531 Smss 286 SoftICE 35 Software Restriction Policies (Политики ограниченного использования программ) 563 SRM (Security Reference Moni tor) 69, 151, 514, 520 T Task Manager (Диспетчер задач) 9 TCP/IP 871 — аппаратное ускорение операций 881 — архитектура расширений 876 TCSEC (Trusted Computer System Evaluation Criteria) 510–512 — рейтинги безопасности 511 TDI (Transport Driver Interface) 873 — IRPпакеты 874 — клиенты 837 — транспорты 837 TEB (Thread Environment Block) 331 Terminal Services 23 TLS (Thread Local Storage) 13 U UNC (Universal Naming Convention) 854 UNCпровайдер, многосетевой; см. MUP (Multiple UNC Provider) Unicode 27 UPnP (Universal Plug and Play) 865 User State Migration Wizard 331 V VACB (Virtual Address Control Block) 707 — массив — — индексов 708–710 — — многоуровневый 711 — — системный 707 VAD (Virtual Address Descriptor) 14, 473–474 VCN (Virtual Cluster Number) 778 — для нерезидентного атрибута данных 793 VERITAS Software 661–662 VPB (Volume Parameter Block) 679 W WBEM 256–258 WDM (Windows Driver Model) 572 WebDAV 739 Win32 API 5 Windows API 3–4 — атрибуты защиты памяти 410–411 — взаимосвязь приоритетов с приори тетами в ядре 347 Windows Application Compatibility Toolkit 414 Windows Debugging Tools 31 Windows Error Reporting 127–128, 906–907 Windows File Protection 300 Windows Firewall 877 Windows Installable File System (IFS) Kit 737 Windows System Resource Manager 351
954 Предметный указатель Windows — 32разрядные адресные пространст ва 17 — 64разрядные адресные простран ства 17 — Windows NT и Windows 95 2–3 — архитектура 56 — выпуски 1 — клиентские и серверные версии 50–53 — компоненты — — защиты 516 — — подсистемы вводавыво да 567–568, 774 — крах или зависание после вывода экраназаставки 302 — микроядро 40 — многопроцессорная операционная система 50 — настройка LargeSystemCache 700 — обработка данных в реальном времени 110–111 — основные системные файлы 43 — перевод USER и GDI в режим ядра 62–64 — переносимость между платформами 44 — повреждение системных файлов 299 — причины краха 898–899 — проверочная версия 53–55 — процесс входа 80, 87 — ресурсы 29 — сервисы 6 — сетевые компоненты 837–838 — средства просмотра внутренней ин формации 28 — стек драйверов устройств внешней памяти 650–654 — упрощенная схема архитектуры 41 — усовершенствования в модели драй веров 76 — файловые системы 732 WinFX 5 WinHTTP 852 WinInet 852 Winlogon 87–88, 247, 288, 556–557 — инициализация 557–558 — компоненты, участвующие в процес се входа 556 WINS (Windows Internet Name Service) 871 Winsock (Windows Sockets) 839–841 — расширения 841–842 — реализация 844 — традиционная модель и модель WSD 846 WMI (Windows Management Instrumenta tion) 253–254 — CIM Studio 259 — COM 256 — Object Browser 263 — архитектура 255 — классификация провайдеров 257 — параметры защиты 266 — подпрограммы WDM 69 WMIC 265 Wow64 190–195 — архитектура 191 WSD (Windows Sockets Direct) — архитектура 846 845 X x64 44 — виртуальный адрес 461 — компоненты, участвующие в процес се загрузки 268–269 — контроллеры прерываний 96 — структура адресного пространства 448 — трансляция адреса 462 x86 — компоненты, участвующие в процес се загрузки 268–269 — контроллеры прерываний 95–96 — структуры адресных пространств 440 — трансляция виртуального адреса 449–451 А агент восстановления 828 алгоритм — AES 823 — CLOOK 652 — FIFO 487 — LRU 487 — вычисления виртуального размера системного кэша 701 — дерева AVL 473 — криптографической пары 824 — определения прав доступа к объекту 538–540 — отложенной записи 807 — отложенной оценки 416, 473 — отложенной фиксации 817 — подкачки по требованию 473 — — с кластеризацией 482–483 — принятия решений по быстрому вво дувыводу 720 — расчета порогового числа изменен ных страниц 728 — симметричного шифрования 824 — сквозной записи 807 — шифрования FEK (стойкость) 823–824 арбитраж ресурсов 622 атрибут — $STANDARD_INFORMATION 802 — PAGE_EXECUTE 410 — PAGE_EXECUTE_READ 411 — PAGE_EXECUTE_READWRITE 411 — PAGE_EXECUTE_WRITECOPY 411 — PAGE_GUARD 411 — PAGE_NOACCESS 410 — PAGE_NOCACHE 411 — PAGE_READONLY 410 — PAGE_READWRITE 410 — PAGE_WRITECOMBINE 411 — PAGE_WRITECOPY 411 — запрет на выполнение 411 — нерезидентный 791–792 — — сопоставления VCNLCN 793
Предметный указатель — резидентный 790–791 — список атрибутов 793 Б база данных — LDM 662 — PFN 494–497 — — состояния записей 502 — — списки страниц 497 — — флаги в записях 503 — SAM 514 — диспетчера ядра 356–357, 378 — образов 243 — политики LSASS 514 — сервисов 240 блокировка — с заталкиванием указателя 177–178 — страниц в памяти 406 блок — логический номер 652 — ожидания 172 брандмауэр 877 буфер — трансляции, ассоциативный 457–458 — индексный 792 В вводвывод — DMIO 684 — асинхронный 592 — без управления 601 — блок статуса 604 — буферизованный 600 — быстрый 593, 719–721 — в проецируемые файлы 594–595 — завершение обработки запроса 606 — — к многоуровневым драйверам 613 — по механизму scatter/gather 595 — по нескольким путям 653 — прямой 600 — синхронный 592 — схема — — обработки типичного запроса 570 — — управления 593 — файловый, явный 743–745 взаимоблокировка 178 взаимоисключение 161–162 волокно 14 Г гиперпространство 439 группа, дисковая 662 Д дамп — аварийный 898 — — генерация файла — — параметры 902 — памяти — — малый 903 — — полный 903 — — ядра 903, 905 дейтаграмма 841 906 955 дескриптор — виртуальных адресов; см. VAD (Virtual Address Descriptor) — защиты 533 — — указатель 535 диск 649 — базовый 659–661 — динамический 661–663 — — внутренняя организация 666 — логический 659 — различие между базовыми и динамическими 657 — сетевой (буквы) 241–242 — сигнатура 271 диспетчер — Plug and Play (PnP) 69, 622 — вводавывода 69, 568–569 — вызовов 885 — исключений 119 — конфигурации 69, 222 — куч 416–417 — — средства отладки 421 — — уровни 418 — кэша 70, 692–694, 775 — логических дисков (LDM) 661 — монтирования 674–675 — настройки баланса 82, 491–492 — объектов 70, 133–134, 139, 144 — памяти 70, 398, 402 — привязки 420 — процессов и потоков 69 — рабочих наборов 396, 489 — разделов 657 — сеансов 86, 294 — системных ресурсов Windows 351 — системных сервисов 130 — томов — — на базовых дисках 661 — — на динамических дисках 666–667 — управления сервисами 88, 239 — устройств 629 — учетных записей безопасности (SAM) 514 — электропитания 69, 642–643 — ядра 345 — — ожидание на объектах 168–169 драйвер — DiskPerf 668 — DMIO 667–668 — Fastfat 292 — FtDisk 661 — Kbdclass 611 — MPIO 653–654 — NDIS, ориентированный на логичес кие соединения 886 — PnP 571 — Raw 681 — TCP/IP IPv4 872 — Volsnap 689 — WMI 188 — Wmixwdm 188 — аппаратных устройств 75 — виртуальных устройств (VDD) 571
956 Предметный указатель — диспетчера — — разделов 661 — — томов 659 — добавление промежуточного 575 — класса — — дисков 651 — — устройств 573 — компоненты, участвующие в установ ке 636 — ловушки — — брандмауэра 877 — — фильтра 877 — не отвечающий спецификации Plug and Play 571 — параметры проверки — — использования памяти 435–437 — — цифровых подписей 638 — порядок загрузки и инициализа ции 629–630 — потокового фильтра ядра 75 — принтера 571 — протоколов 75, 871 — структура 578 — устройства 42, 75 — — NAT 876 — — основные процедуры 578–579 — — синхронизация 607–608 — файловой системы 75, 571, 737 — файлсервера 82, 705 — фильтра 76–77, 572 — — файловой системы 75, 748 — функциональный 76, 572 — шины 76, 103, 572 дросселирование записи 727–728 Е единица сжатия 796 Ж журнал — изменений 769 — типы записей 811–814 З запись — MFT — — для несжатого файла 795 — — для пользовательского файла с плохим кластером 819 — — для сжатого файла 798 — — для сжатого файла, содержащего разреженные данные 796 — трассировки 188 — учетная — — Local Service 236 — — Network Service 236 — — локальной системы 234 — — права 546 запрет на выполнение 412 защита системного кода от записи 918 И идентификатор — защиты (SID) 521 — устройства 632 — экземпляра 632 — — устройства 633 имя — разрешение 870 — — сетевого ресурса 868 индекс байта 450 инициатор 653 инструкция — epc 130 — int 0x2e 128 — iretd 129 — syscall 129–130 — sysenter 129 — sysexit 129 — sysret 129 — testandset 164 интерфейс — недокументированный 78–79 — сетевого доступа 867 исключение 92, 120 — в системах типа x86 и соответствую щие им номера прерываний 119 — диспетчеризация 121 — необработанное 121–122 К канал, именованный 853–855 каталог — \BaseNamedObjects 155 — \BaseNamedObjects 158 — \Global?? 155, 581, 744 — \Harddisk 656 — \Knowndlls 286 — \Prefetch 484 — \System Volume Information 301, 827 — \Windows\Minidump 904 — \Windows\System32\Config\Sam 298 — \Windows\Syswow64 191 — страниц 451–452 — точки восстановления 752 квант 345, 358 — внутреннее представление величи ны 359 — динамическое увеличение 361 — задание 360 класс — сопоставления 262 — трассировки 188 кластер 731 — переназначение плохих 766, 819–820 — узлы 894 ключ — /DEBUG 54 — /NOEXECUTE 413–414 — /USERVA 440 — восстановления 828 — связка 827 — элементы 827 код — ATTEMPTED_EXECUTE_OF_NOEXE CUTE_MEMORY 412 — BAD_POOL_HEADER 915 — FSCTL_ DELETE_OBJECT_ID 771 — FSCTL_CREATE_OR_GET_OBJECT_ID 771
Предметный указатель — FSCTL_CREATE_USN_JOURNAL 769 — FSCTL_GET_COMPRESSION 768, 794 — FSCTL_GET_REPARSE_POINT 768 — FSCTL_GET_RETRIEVAL_POINTERS 773 — FSCTL_GET_VOLUME_BITMAP 773 — FSCTL_QUERY_ALLOCATED_RANGES 768 — FSCTL_SET_COMPRESSION 768, 794 — FSCTL_SET_SPARSE 768 — FSCTL_SET_ZERO_DATA 768 — IRQL_NOT_LESS_OR_EQUAL 107, 901 — KMODE_EXCEPTION_NOT_HAND LED 920 — MANUALLY_INITIATED_CRASH 922 — SESSION5_INITIALIZATION_FAILED 285 — STATUS_SYSTEM_PROCESS_ TERMINA TED 86 кольцо 18 команда — !analyze 924 — !analyze –v 912 — !apic 97 — !ca 479, 712 — !chkimg 919 — !dbgprint 55 — !defwrites 728–729 — !devnode 630 — !devobj 584, 681, 872 — !devstack 609 — !drivers 83 — !drvobj 584, 593, 597, 680, 872 — !exqueue 180 — !filecache 703, 711 — !fileobj 589 — !gflag 183 — !gflags 183 — !handle 134, 150, 479 — !idt 94 — !irp 600, 611 — !irpfind 610 — !irql 101 — !locks 176 — !lookaside 432 — !lpc 185 — !memusage 402, 480, 497 — !miniport 882 — !miniports 882 — !numa 380 — !object 141, 582 — !pcr 101 — !peb 313 — !pfn 505 — !pic 97 — !pocaps 645 — !poolused 430 — !popolicy 646 — !process 141, 174, 316, 599 — !process 0 0 310, 392 — !pte 456 — !qlock 165 — !reg dumppool 219 — !reg findkcb 224 — !reg hivelist 220 — !reg kcb 224 957 — !reg openkeys 224 — !session 444 — !smt 379 — !sprocess 444 — !stacks 83 — !teb 338 — !thread 175, 336, 599 — !vad 474 — !vm 400, 426 — !vm 4 445 — !vpb 680–681 — !wsle 490 — .crash 924 — .dump /m 904, 924 — cmd /c 349 — dt 174 — dt _OBJECT_HEADER 536 — dt _TOKEN 526 — dt eprocess 309 — dt nt!_ejob 393 — dt nt!_EPROCESS_QUOTA_ENTRY 154 — dt nt!_ethread 334 — dt nt!_file_object 586 — dt nt!_kinterrupt 108 — dt nt!_knode 380 — dt nt!_kthread 335 — dt nt!_ktrap_frame 93 — dt nt!_prcb 377 — k 84 — listen 862 — lm kv 577 — nbtstat 862 — openfiles /query 133 — queryremove 624–625 — querystop 625 — RunAs 827 — startdevice 624–625 — stop 625 — surpriseremove 625 компонент режима ядра 42–43 консоль восстановления 296 контекст — защиты 7, 518 — переключение 72, 345, 365 — потока 13 конфигурация, последняя удачная 291 копирование при записи 415 куча (типы) 417 кэш — дополнительная память 701 — карта — — закрытая 708 — — общая 708 — когерентность 694–695 — метода доступа к данным 713–714 — принудительное включение сквоз ной записи на диск 725 — с обратной отложенной записью 724 — системный 439, 698 — — адресное пространство 697 — — виртуальный размер 701 — — размер и местонахождение 699–701 — — физический размер 704–705
958 Предметный указатель — структуры данных, индивидуальные для файлов 709 кэширование — виртуальных блоков 695 — на основе логических блоков 695 — потоков данных 695 — с обратной записью 807 Л ловушка 91 — диспетчеризация 92 М макрос ASSERT 54 манифест 330 маркер — доступа 7, 14, 524–525 — ограниченный 531 — список сопоставленных привилегий 525 маршалинг 848 маршрутизатор многосетевого доступа; см. MPR (Multiple Provider Router) маска — активных процессоров 377 — привязки к процессорам 382 масштабируемость 50 метаданные 696, 732 механизм scatter/gather 569 минидамп 903–904 минипортдрайвер 573, 651 многозадачность 44 множитель, кластерный 777 модель OSI, эталонная 836 модуль записи 686 монитор состояния защиты; см. SRM (Secu rity Reference Monitor) мутант 137 мьютекс 136–137 — быстрый 175 — защищенный 175 Н набор — рабочий 395 — — верхний лимит на максимальные размеры 488 — — виды 482 — — поле индекса 504 — — системного кэша 702 — — системный 492 — репликации 896 О область управления 478 обработка — асимметричная многопроцессорная 45 — запроса — — асинхронного к многоуровневым драйверам 610 — — синхронного 602 — симметричная многопроцессорная 45 обработчик — SEHфрейма 120 — ловушек 91 — ошибок страниц 748 объект 24–25 — IoCompletion 616, 618 — SvcCtrlEvent_A3752DX 239, 241 — SystemRestore 753 — Win32Provider 264 — WindowStation 158 — — список 238 — атрибут 24 — базовые сервисы 139–140 — диспетчера 71 — драйвер 584 — задание 15, 389, 391 — — привязка к процессорам 390 — защита 518 — идентификатор 771 — имена 154–155 — исполнительной системы 135–137 — каталог объектов 157 — методы 144 — порт (типы) 186 — прерывание 107–108, 111–112 — проекция файла 408 — раздел 396, 408, 475, 477 — — атрибуты 476 — — внутренние структуры 477 — — структура указателей 478 — синхронизирующий (состояния) 169 — стандартные атрибуты заголовка 138–139 — стандартные каталоги 155–156 — структура 138 — типа 24, 140, 143 — — атрибут 143 — управляющий 71 — условия перехода в свободное состояние 169–171 — устройство 581 — — для дисков 655 — — драйвера DMIO 668 — файл 585, 588–589 — — открытие 587 — физическое устройство; см. PDO (Physical Device Object) — функциональное устройство; см. FDO (Functional Device Object) — хранение в памяти 152 — ядра 71, 135 окно — — Advanced Settings (редактирование привязок) 891 — — File And Printer Sharing For Micro soft Networks Properties 700 — — Power Options Properties (Свойст ва: Электропитание) 646 — — System Information в Process Explo rer 706 — — для принудительного закрытия программы 305 — — настройки Error Reporting 907 — — настройки отчетов об ошибках 127 олицетворение 529–530 — уровни 530 — уровня делегирования 530
Предметный указатель операция — взаимоблокирующая 163 — идемпотентная 813 описатель 145 — файла 590 оснастка — Computer Management (Управление компьютером) 741 — Disk Management (Управление дис ками) 666–667 — IP Security Policy Management (Управле ние политикой безопасности IP) 879 — Performance (Производитель ность) 22, 29 отладка — в пользовательском режиме 31 — ядра 30 — — локальная 32 отладчик ядра 31–32 очередь 618 — регулярная 729 П пакет — аутентификации 515, 555, 559 — запроса вводавывода; см. IRP (I/O Request Packet) память — внешняя 649 — — эволюция управления 658 — гранулярность выделения 406 — оптимизаторы 507–509 — проецирование виртуальной на фи зическую 16 — прямой доступ 718 — разделение между процессами 407 — уведомления о малом или большом объеме 506 параметр — /3GB 16, 422 — /BOOTLOG 294 — /NOLOWMEM 460 — /SAFEBOOT 293 — /USERVA 16, 422 — ObjectAttributes 24 переменная — CcDataFlushes 726 — CcDataPages 726 — CcFastReadNotPossible 722 — CcFastReadNoWait 722 — CcFastReadResourceMiss 722 — CcFastReadWait 722 — CcLazyWriteIos 725 — CcLazyWritePages 725 — CcReadAheadIos 723 — CcVacbs 707 — InitSafeBootMode 293 — KeActiveProcessors 377 — KeNumberProcessors 324 — KiDispatcherReadyListHead 357 — KiIdleSummary 377 — KiReadySummary 357 — MiSystemCacheEndExtra 443, 702 959 — MiSystemCacheStartExtra 442, 702 — MmAvailablePages 505 — MmCriticalSectionTimeout 324 — MmHeapDeCommitFreeBlockThreshold 325 — MmHeapDeCommitTotalFreeThreshold 324 — MmHeapSegmentCommit 324 — MmHeapSegmentReserve 324 — MmMaximumNonPagedPoolInBytes 425 — MmMaximumWorkingSetSize 488 — MmMinimumFreePages 500 — MmModifiedPageLifeInSeconds 501 — MmModifiedPageMaximum 501 — MmNonPagedPoolEnd 443 — MmNonPagedPoolExpansionStart 443 — MmNonPagedPoolStart 443 — MmNonPagedSystemStart 443 — MmNumberOfPhysicalPages 505 — MmPagedPoolEnd 443 — MmPagedPoolPage 425 — MmPagedPoolStart 443 — MmProcessCommit 323 — MmResidentAvailablePages 323, 505 — MmSizeOfNonPagedPoolInBytes 425 — MmSizeOfPagedPoolInBytes 425 — MmSizeOfSystemCacheInPages 702 — MmSystemCacheEnd 442, 702 — MmSystemCachePage 703 — MmSystemCacheStart 442, 702 — MmSystemCacheWorkingSetList 442 — MmSystemCacheWs.MaximumWorking SetSize 494 — MmSystemCacheWs.MinimumWorking SetSize 494 — MmSystemCacheWs.PageFaultCount 703 — MmSystemCacheWs.Peak 703 — MmSystemCacheWs.Working 703 — MmSystemRangeStart 442 — MmTotalCommittedPages 323 — NtBuildNumber 325 — NtGlobalFlag 181, 324 — NtMajorVersion 325 — NtMinorVersion 325 — PsActiveProcessHead 314 — PsIdleProcess 314 — PsInitialSystemProcess 314 — PsMaximumWorkingSet 322 — PsMinimumWorkingSet 322 — PspCidTable 314 — PspCreateProcessNotifyRoutine 314, 338 — PspCreateProcessNotifyRoutineCount 314 — PspCreateThreadNotifyRoutine 338 — PspCreateThreadNotifyRoutineCount 338 — PspLoadImageNotifyRoutine 314 — PspLoadImageNotifyRoutineCount 314 — PsPrioritySeparation 369 — SAFEBOOT_OPTION 294 подсистема — OS/2 66–67 — POSIX; см. POSIX — Windows 60–62 — — процесс 58 — загрузкивыгрузки 492 — записи
960 Предметный указатель — — модифицированных страниц 396, 500–501 — — модифицированных и спроециро ванных страниц 747 — — отложенной 747 — — спроецированных страниц 396 — локальной аутентификации; см. LSASS (Local Security Authentication Subsystem) — окружения 42, 57 — поддержки окон и графики 43 портдрайвер 573 порт завершения 616–617, 620 поток 13 — MiMappedPageWriter 501 — MiModifiedPageWriter 500 — вводавывода на смонтированном томе 682 — выполняющий опережающее чте ние 747–748 — вытеснение 364 — готовый 357 — динамическое изменение приорите та 368 — завершение 365 — загрузки и выгрузки стеков 396 — необработанного ввода 23 — обнуления страниц 397, 499 — простоя 366 — рабочий, системный 178–180 — самостоятельное переключение 363 — сегмента разыменования 397 — состояния — — в Windows 2000 и Windows XP 353 — — в Windows Server 2003 356 — стартовый адрес 342 — стек пользовательского режима 406 — уровни приоритета 346 права доступа — желательные 151 — предоставленные 151 — пример проверки 541 правила — замены 487 — размещения 487 представление 408 — проецируемое системой 439 прерывание 92 — APC 117–118 — DPC 81 — маскирование 100 — межпроцессорное 102 — программное 112–115 — увязка с IRQL 102–103 — уровни запросов 98–99 привилегия 544–546 — Increase Scheduling Priority 351, 488 — Lock Pages In Memory 422 — SeSystemTimePrivilege 547 — список 548–551 привязка 890–891 — к процессорам 344 приложение, сервисное 228 принцип пространственной локальности 722 провайдер 867 — аппаратного уровня 686 — программного уровня 685 — сервисов Winsock (WSP) 846 — транспортных сервисов 842 программа — Accvio 126 — Clockres 358 — Network Monitor (Сетевой монитор) 886 — Testlimit 148 проецирование 395 пространство — виртуальное адресное 7 — — резервирование 405 — имен 158 — сеанса 438 — — параметры конфигурации 444 — — структура (x86) 443 — системное 438–439 — — структура (x86) 442 протоколирование 809 — изменений 769 — опережающее 809 — с циклическими буферами 768 профиль роуминга 203 процедура — KeAcquireInterruptSpinLock 608 — KeSynchronizeExecution 608 — NtfsFastIoCheckIfPossible 594 — выгрузки 580 — диспетчеризации 579 — добавления устройства 579 — инициализирующая 578 — инициации вводавывода 579 — обслуживания прерываний (ISR) 93, 579 — отмены вводавывода 580 — регистрации ошибок 580 — уведомления о завершении работы системы 580 процесс 6, 7 — Idle 23, 80–81, 366 — SvcHost 250–251 — System 80–83 — блок управления 312 — входа (Winlogon) 515 — дерево при входе 289 — локальной аутентификации, сервер ный 87 — пользовательский (типы) 41–42 — ресурсы 15 — системный (начальное дерево) 81 — уровень завершения 328 процессор — идеальный 385–387 — последний 385 пул — максимальные размеры 425 — особый 916 — памяти — — неподкачиваемой 401, 424
Предметный указатель — — подкачиваемой 424 — структуры управления 915 Р раздел — HKEY_CLASSES_ROOT 202–203 — HKEY_CURRENT_CONFIG 204 — HKEY_CURRENT_USER 200 — HKEY_LOCAL_MACHINE 203–204 — HKEY_PERFORMANCE_DATA 205 — HKEY_USERS 201 — блок управления 223 — — именами 227 — диска 649 — общей памяти 14 — поддерживаемый страничными фай лами 408 — разбиение — — по схеме GPT 660 — — по схеме MBR 659 разрешение, цепочечное 772 редактор порядка провайдеров 867 редиректор 891 реестр 26, 196–198 — дисковые файлы, соответствующие путям 212 — карты ячеек 218–219 — куст 211 — — System 301 — — внутренняя структура 217 — — лимиты на размеры 213 — — регистрационный 225 — — синхронизация 225 — настройка кванта 362 — оптимизация операций 226–227 — параметры для сервисов и драйве ров 229–231 — подразделы 198 — — в HKEY_CURRENT_USER 201 — предназначение корневых разде лов 200 — разделы, корневые 200 — типы данных в ячейках 216 — типы параметров 199 режим — безопасный 291 — защищенный 272 — пользовательский 18 — — переключение в режим ядра 19 — ядра 18, 39 — — механизмы синхронизации 167 репликация, распределенная с несколькими хозяевами 896 С сборка — общая 330 — существующая в нескольких верси ях 329–331 сводка — готовности 357 — простоя 377 связь, жесткая 766 961 сеанс 438 — консольный 23 — — отключение 160 — удаленный 23 сектор 269, 649, 731 — загрузочный (повреждение) 298 секция, критическая 161 семафор 136 сервис 6, 227 — SrService 750 — интерактивный 237 — привилегии учетной записи 235 — программы управления 252–253 — системный 68 — — диспетчеризация 132 — — трансляция номера 131 — файла журнала (LFS) 775, 809–810 — членство учетной записи в группах 235 синхронизация 143, 162 — доступа к куче 419 система — исполнительная 42, 68–69 — — подпрограммы поддержки 70 — — ресурсы 168, 175–176 — — CDFS 732 — — FAT12 и FAT16 733–734 — — FAT32 735–736 — — NTFS; см. NTFS — — UDF 732–733 — — взаимодействие драйвера с драй вером диска 574 — — взаимодействие с диспетчерами кэша и памяти 714 — — восстанавливаемая 807–808 — — генерации краткого MSDOSиме ни из длинного 789–790 — — компоненты, участвующие в опе рациях вводавывода 743 — — с отложенной записью 807 — — с точной записью 806–807 — — форматы 731 служба — Kerberos Key Distribution Center 560 — LDM Disk Administrator 666 — Routing and Remote Access Service (Служба маршрутизации и удаленного доступа) 892 — System Restore (Восстановление сис темы) 749–752 — Windows Remote Storage Service (RSS) 676 — виртуального диска (VDS) 684–685 — инициатора 653 — локальной безопасности (LSA) 545 — репликации файлов 895–896 — сетевого входа (Netlogon) 515 — теневого копирования тома 686–687 событие с ключом 172 сопоставление безопасности (SA) 879 состояние — active/valid 466 — Deferred Ready 356 — demand zero 466
962 Предметный указатель — Initialized 354 — mapped file 466 — modifiednowrite 466 — page file 466 — Ready 353, 365 — Running 353, 365 — Standby 353 — Terminated 354, 365 — Transition 354, 466 — Waiting 353 — системы с различным энергопотреб лением 640–641 — тревожного ожидания 118 спецификация — Advanced Configuration and Power In terface (ACPI) 640 — EFI (Extensible Firmware Interface) 660 — Extensible Firmware Interface (EFI) 280 — Multiprocessor (MP) Specification 96 спинблокировка 163–164 — обмена контекста 377 — с очередью 164–165 — — внутристековая 166 список — ассоциативный 432, 419–420 — дескрипторов памяти (MDL) 718 — обнуленных страниц 499 — простаивающих страниц 499 — системного рабочего набора 439 средство логической предвыбор ки 70, 483–485 ссылка — символьная 157, 215 — файловая 785 стек — засорение 920 — протоколов 837 стопкод 900 страница — большая (побочные эффекты приме нения) 404 — возврат 405 — возможные состояния 494–495 — индекс — — каталога 450 — — таблицы 450 — конфликт ошибок 468 — ошибка 462–463 — — причины 463 — передача 405 — пороговое число измененных 728 — размеры 403 — — списков 402 — сторожевая 406 — схема состояний фреймов 498 структура — _LIST_ENTRY 34 — CONTEXT 121 — DeviceMap 159 — EPROCESS 307–308, 310–312 — ETHREAD 331 — KPROCESS 309–310, 323 — KTHREAD 117, 333–334 — KWAIT_BLOCK 173 — MM_SESSION_SPACE 444 — SectionObjectPointers 713 — TEB 331–332 — VACB 707 — VPB 679 — W32PROCESS 328 — индекса ячейки 222 — куста 215, 217 — сегмента 478 — типа b+ tree 799 суперпривилегия 552–553 счетчик производительности — быстрый вводвывод 722 — интенсивность операций фиксации и проецирования 717–718 — операции — — MDLчтения из кэша 719 — — сброса кэша 726 — — чтения из кэша 715–716 — переданная память и страничный файл 471 — подсистема отложенной записи 725 — потоки 339 — процессы 315 — рабочий набор 490 — — системный 493 — системные пулы 425 — системный кэш и ошибки страниц 703 Т таблица — диспетчеризации — — прерываний 94 — — системных сервисов 130 — описателей — — процесса 147–148 — — структура элемента 150 — — ядра 150 — отложенного закрытия 227 — разделов 659 — — GUID (GPT) 660 — страниц 438, 450 — — измененных 814 — — элемент; см. PTE (Page Table Entry) — транзакций 814 том 777 — RAID1 671 — RAID5 673–674 — восстановление 810–811 — загрузочный 665 — зеркальный 671–672 — — создание с помощью оснастки Disk Management 672 — монтирование 679 — окно свойств 770 — перекрытый 669 — простой 650 — системный 665 — составной 650, 657, 668–669 — чередующийся 670 — — с записью четности 673–674
963 Предметный указатель точка — восстановления 750 — монтирования 676–677 — повторного разбора 804, 676, 767 — соединения 766–767 транзакция — атомарная 762 — откат 762 — отмена 817 — фиксация 812 У уровень — APC_LEVEL 101 — DISPATCH_LEVEL 103 — SYNCH_LEVEL 98, 377 — — в многопроцессорных системах 378 — абстрагирования от оборудова ния 42, 73 — канальный 837 — поддержки Plug and Play 623 — презентационный 836 — прикладной 836 — сеансовый 836 — сетевой 837 — транспортный 836 — физический 837 устройство — PnPсостояния 626 — дерево 628 — обслуживание прерываний 603–605 — узел 628 — — внутренняя структура 631 утилита — Autoruns 289–290 — Bootcfg 273 — Chkdsk 682, 821 — ChkReg 301 — cipher 823 — Corporate Error Reporting 128 — CPU Stress 369, 374 — Dbgview 55 — Dependency Walker 74 — Disk Defragmenter 773 — Disk Probe 217 — Diskmon 654 — Dr. Watson 124–125 — Driver Verifier 433–437, 620 — — обнаружение взаимоблокировки 178 — — параметры проверки вводавыво да 620–621 — Drivers 77 — Dumprep 907 — EFSDump 833–834 — Exetype 59 — Filemon 486, 677, 749, 755 — — базовый и расширенный режи мы 755 — — методики анализа проблем 756–761 — Fsutil.exe 785 — Gflags 181–182, 427 — Handle 133, 147, 562 — Imagecfg 382 — Junction 768 — Kernrate 104 — LDMDump 664 — LiveKd 32–35 — LogonSessions 561 — Msinfo32.exe 576 — Nfi 779, 834 — NotMyFault 430–431, 909–910, 915 — NTFSInfo 785 — Object Viewer 476 — Oh.exe 133, 476 — Pagedefrag 469 — Pageheap 421 — Pendmoves 287 — Pfmon 500 — PipeList 858 — Poolmon 400, 428–429 — Process Control Manager 391 — Process Explorer 10–13, 90, 147, 251, 350, 409, 588 — Process Viewer 250 — PsExec 210–211, 516, 751 — PsGetSid 522 — Pstat 83, 122 — Pviewer.exe 83 — QuickSlice 20 — Regedit.exe 197 — Regedt32.exe 197 — Regmon 206–211 — SrvAny 233 — Strings 429, 485 — System Information 902 — TDImon 874 — Tlist 337 — WbemTest 260 — Windows Sockets Configuration 843 — Winobj 133, 156, 160, 184, 506, 590 — WMI Object Browser 262 — для исследования потоков и их фун кций 341 — для отключения или извлечения пла ты PC Card 625 — на сайте Sysinternals 36 — резервного копирования 689 участник безопасности (principal) 850 Ф файл — — — — — — — — — — — — — — — — $AttrDef 784 $BadClus 784 $Bitmap 783 $Boot 784 $LogFile 783 $MftMirr 783 $MountMgrRemoteDatabase $ObjId 784 $Quota 784 $Reparse 784 $Secure 784, 803 $UpCase 784 $UsnJrnl 784 $Volume 784 \$Extend\$Reparse 677 \$Extend\$UsnJrnl 798 677
964 — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — Предметный указатель \Windows\Repair\Setup.log 46 Advapi32.dll 43, 826 Afd.sys 844 Aha154x.sys 652 Application.exe.local 329 Atapi.sys 651–652 Autochk.exe 682 Boot.ini 270–273 — неправильная конфигурация — параметры 273–278 Bootvid.dll 283 Bugcodes.h 901 CAT 638–639 Cdfs.sys 737 Comctl32.dll 330 Defrag.exe 773 Dfrg.msc 773 Dfs.sys 897 Dfssvc.exe 897 Disk.sys 651 Diskperf.sys 668 Dllhost.exe 484 Dmadmin.exe 666 Dmboot.sys 667 Dmconfig.dll 667 Dmdskmgr.dll 666 Dmio.sys 666 Dmload.sys 667 Dns.exe 871 Dumprep.exe 907 Fastfat.sys 737 Feclient.dll 826 Fltmgr.sys 749 Fpswa.efi 281 Fs_rec.sys 682 Ftdisk.sys 661 Gdi32.dll 43 Gv3.sys 105 Hal.dll 43–44 Hiberfil.sys 272, 641 Http.sys 853 Httpapi.dll 853 Ia64ldr.efi 281 INF 637 Ipfltrdrv.sys 877 Ipnat.sys 876–877 Ipsec.sys 879 Iscsicli.exe 653 Iscsium.dll 653 Kdcsvc.dll 560 Kernel32.dll 43 Ksecdd.sys 826 Layout.ini 486 Localtag.txt 429 Lsasrv.dll 826 Migwiz.exe 331 Mountmgr.sys 674 Mountvol.exe 677 Mpdev.sys 654 Mpio.sys 654 Mpr.dll 289 Mpsfltr.sys 654 Mrxdav.sys 739 299 — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — Mrxsmb.sys 739 Msafd.dll 845 Msfs.sys 857 Msgina.dll 87 Msgpc.sys 890 Msiscis.sys 653 Mswsock.dll 844 Ndis.sys 838, 880 Netapi32.dll 863 Netbios.sys 863 Npfs.sys 857 Ntbootdd.sys 272 Ntdetect.com 279 Ntdll.dll 43, 67–68 Ntds.dit 893 Ntdsa.dll 560 Ntfrs.exe 896 Ntfs.sys 737 Ntkrnlmp.exe 47 Ntkrnlpa.exe 43, 413 Ntkrpamp.exe 47 Ntlanman.dll 867, 897 Ntldr 272 NTOSBOOTB00DFAAD.PF Ntoskrnl.exe 43, 44 Partmgr.sys 661 Pciide.sys 652 Pciidex.sys 652 Pooltag.txt 429 Psched.sys 890 Psxdll.dll 66 Psxss.exe 66 Rdbss.sys 738 Rpcss.dll 852 Rsaenh.dll 826 Rsfilter.sys 677 Rstrui.exe 754 Savedump.exe 906 Schedsvc.dll 484 Scsiport.sys 652 Secpol.msc 823 Services.exe 293 Setupdd.sys 297 Sfc.dll 300 Sfc_os.dll 300 Spcmdcon.sys 297–298 Splwow64.exe 194 Sporder.exe 843 Sr.sys 750 Srsvc.dll 750 Srv.sys 82, 705, 738 Storport.sys 652 Svchost.exe 750 System.sav 226 Tcpip.sys 872 Tcpip6.sys 872 Tdi.sys 873 Traffic.dll 890 Udfs.sys 733, 737 User32.dll 43 Userenv.dll 827 Userinit.exe 294, 524 Vds.exe 684 485
Предметный указатель — Vdsldr.ex 686 — Volsnap.sys 687 — Vssvc.exe 686 — Win32k.sys 43, 61 — Winmgmt.exe 264 — Wow64.dll 190 — Wow64Cpu.dll 190 — Wow64Win.dll 190 — Ws2_32.dll 844 — Wshtcpip.dll 844 — аварийного дампа 125 — атрибут 786 — битовой карты 783 — журнала изменений 798–799 — каталога 330 — несжатый (группы данных) 794 — — атрибуты 586 — отключение отложенной записи 725 — проекция 14 — разреженный 768, 798 — сжатый (группы данных) 795, 797 — символов 30 — страничный 468–469 — — размеры по умолчанию 470 — уведомление об изменениях 755 флаг — Accessed 489 — CONTAINER_INHERIT_ACE 534 — CREATE_SEPARATE_WOW_VDM 321 — CREATE_SHARED_WOW_VDM 321 — CREATE_SUSPENDED 318, 340 — DLL_PROCESS_ATTACH 329 — FILE_ATTRIBUTE_COMPRESSED 768 — FILE_ATTRIBUTE_REPARSE_POINT 768 — FILE_ATTRIBUTE_TEMPORARY 725 — FILE_FLAG_NO_BUFFERING 722 — FILE_FLAG_OVERLAPPED 592 — FILE_FLAG_RANDOM_ACCESS 698, 724 — FILE_FLAG_SEQUENTIAL_SCAN 699, 723 — FILE_FLAG_WRITE_THROUGH 725 — HEAP_NO_SERIALIZE 419 — IMAGE_FILE_LARGE_ADDRESS_AWA RE 441 — IMAGE_FILE_UP_SYSTEM_ONLY 325 — INHERIT_ONLY_ACE 534 — INHERITED_ACE 534 — MB_DEFAULT_DESKTOP_ONLY 238 — MB_SERVICE_NOTIFICATION 238 — MEM_PHYSICAL 422 — NO_PROPAGATE_INHERIT_ACE 534 — OBJECT_INHERIT_ACE 534 — QUOTA_LIMITS_HARDWS_ENABLE 488 — SE_DACL_PROTECTED 537–538 — SE_SACL_PROTECTED 538 — SECURITY_ANONYMOUS 530 — SECURITY_DELEGATION 530 — SECURITY_IDENTIFICATION 530 — SECURITY_IMPERSONATION 530 — глобальный 181–182 — — Show Loader Snaps 182 формат «8.3» 789 фрейм — ловушки 93 965 — стековый 120 — страниц 498 функциональность пути доверительных отношений 512 функция — accept 841, 874 — AcceptEx 842, 844 — AccessCheck 538 — AccessCheckByType 538 — AddAccessAllowedAce 540 — AddUsersToEncryptedFile 833 — AllocateUserPhysicalPages 422– 423, 499 — AssignProcessToJobObject 389 — AuthzAccessCheck 544 — bind 841, 874 — CallNamedPipe 855 — CcCanIWrite 727 — CcCopyRead 714–715, 745–746 — CcCopyWrite 714–715 — CcDeferWrite 727 — CcFastCopyRead 714–715, 747 — CcFastCopyWrite 715, 747 — CcInitializeCacheMap 713, 745 — CcMapData 716 — CcMdlRead 719 — CcMdlReadComplete 719 — CcMdlWrite 719 — CcMdlWriteComplete 719 — CcPinMappedData 716 — CcPinRead 716 — CcPreparePinWrite 716 — CcSetDirtyPageThreshold 728 — CcSetDirtyPinnedData 716 — CcUnpinData 716 — CloseEncryptedFileRaw 833 — connect 874 — ConnectEx 842 — ConnectNamedPipe 855 — ContinueDebugEvent 329 — ConvertThreadToFiber 14 — CreateFiber 14 — CreateFile 743, 855 — CreateFileMapping 408, 595 — CreateIoCompletionPort 617–618 — CreateJobObject 389 — CreateMailslot 855–856 — CreateMemoryResourceNotification 506 — CreateNamedPipe 854 — CreateProcess 315–329 — CreateProcessAsUser 244, 315, 323, 524, 530 — CreateProcessWithLogon 524 — CreateProcessWithLogonW 316 — CreateProcessWithTokenW 316 — CreateRemoteThread 327, 340 — CreateService 228, 253 — CreateThread 340 — DbgPrint 54 — DdeImpersonateClient 529 — DebugActiveProcess 31 — DecryptFile 772 — DefineDosDevice 590 — DeviceIoControl 768–769, 794
966 Предметный указатель — DeviceIoControlFile 194 — DisconnectEx 842 — DuplicateHandle 408, 589 — EfsReadFileRaw 833 — EfsWriteFileRaw 833 — EncryptFile 772, 826 — EndOfJobTimeAction 390 — EnterCriticalSection 172 — ExAcquireFastMutex 175 — ExAcquireFastMutexUnsafe 175 — ExAcquireResourceExclusiveLite 176 — ExAcquireResourceSharedLite 176 — ExAcquireSharedStarveExclusive 176 — ExAcquireWaitForExclusive 176 — ExAllocatePoolWithTag 80 — ExCreateHandle 519 — ExecNotificationQuery 264 — ExInitializeNPagedLookasideList 432 — ExInitializePagedLookasideList 432 — ExInterlockedInsertHeadList 166 — ExInterlockedPopEntryList 166 — ExInterlockedPushEntryList 166 — ExInterlockedRemoveHeadList 166 — ExitProcess 316 — ExitThread 340, 365 — ExitWindowsEx 249, 304, 754 — ExpInitializeExecutive 282–283 — ExpWorkerInitialization 179 — ExpWorkerThreadBalanceManager 180 — ExQueueWorkItem 84, 178 — ExTryToAcquireResourceExclusiveLite 176 — FileEncryptionStatus 772 — FindFirstChangeNotification 755, 769 — FindNextChangeNotification 755 — FlushFileBuffers 725 — FlushInstructionCache 316 — FlushViewOfFile 405, 475 — fopen 587 — fork 57, 416 — FsRtlRegisterUncProvider 869–870 — FtpFindFirstFile 852 — FtpFindNextFile 852 — FtpGetFile 852 — FtpPutFile 852 — getaddrinfo 840, 843 — GetCommandLine 316 — GetCurrentProcess 59, 316 — GetCurrentProcessId 59, 316 — GetCurrentThread 340 — GetCurrentThreadId 340 — GetEffectiveRightsFromAcl 538–539 — GetEnvironmentStrings 316 — GetEnvironmentVariable 316 — GetExitCodeProcess 316 — GetExitCodeThread 340 — GetFileAttributes 768 — GetFileSecurity 519 — GetGuiResources 316 — gethostbyname 840 — GetLogicalProcessorInformation 348 — getnameinfo 843 — GetNumaHighestNodeNumber 382 — GetNumaNodeProcessorMask 382 — GetNumaProcessorNode 382 — GetOverlappedResult 853 — GetPriorityClass 348 — GetProcessAffinityMask 348 — GetProcessHeap 417 — GetProcessHeaps 417 — GetProcessPriorityBoost 348 — GetProcessShutdownParameters 316 — GetProcessTimes 316 — GetProcessVersion 316 — GetQueuedCompletionStatus 391, 592, 617, 619 — GetStartupInfo 316 — GetSystemInfo 406 — GetSystemMetrics 294 — GetSystemTimeAdjustment 358 — GetThreadContext 14, 340 — GetThreadId 340 — GetThreadPriority 348 — GetThreadPriorityBoost 348 — GetThreadSelectorEntry 340 — GetThreadTimes 340 — HalInitializeProcessor 282 — HalInitSystem 282 — HalpGetSystemInterruptVector 103 — HalQueryRealTimeClock 284 — HasOverlappedIoCompleted 592 — HeapAlloc 417 — HeapCreate 417 — HeapDestroy 417 — HeapFree 417 — HeapLock 417 — HeapReAlloc 417 — HeapSetInformation 420 — HeapUnlock 417 — HeapWalk 417, 419 — HttpAddToFragmentCache 853 — HttpAddUrl 853 — HttpCreateHttpHandle 853 — HttpInitialize 853 — HttpReceiveHttpRequest 853 — HttpSendHttpResponse 853 — ImpersonateNamedPipeClient 529, 855 — ImpersonateSecurityContext 529 — ImpersonateSelf 529 — InterlockedCompareExchange 163 — InterlockedDecrement 163 — InterlockedExchange 163 — InterlockedIncrement 163 — InterlockedPopEntrySList 419 — InterlockedPushEntrySList 419 — InternetConnect 852 — IoAttachDeviceToDeviceStackSafe 749 — IoCallDriver 602, 745 — IoCompleteRequest 367, 602–604 — IoConnectInterrupt 111 — IoCreateDevice 581 — IoCreateDeviceSecure 581 — IoDisconnectInterrupt 111 — IoIs32bitProcess 194 — IoPageRead 746 — IopBootLog 294 — IopCallDriverAddDevice 293
Предметный указатель — IopCopyBootLogRegistryToFile 295 — IopInvalidDeviceRequest 597 — IopLoadDriver 293 — IopParseDevice 744–745 — IopSafeBootDriverLoad 293–294 — IoQueueWorkItem 178 — IoReadPartitionTable 655, 657 — IoReadParititionTableEx 655 — IoRegisterDeviceInterface 581 — IoRegisterFileSystem 679 — IoSetDeviceInterfaceState 582 — IoSynchronousPageWrite 747 — KeAcquireGuardedMutex 175 — KeAcquireInStackQueuedSpinlock 166 — KeAcquireQueuedSpinlock 165 — KeAcquireSpinlock 164 — KeAddSystemServiceTable 132 — KeBalanceSetManager 491 — KeBugCheckEx 93, 103, 899–900, 905–906 — KeDelayExecutionThread 619 — KeEnterCriticalRegion 175 — KeEnterGuardedRegion 117 — KeInitializeQueue 618 — KeInitThread 326 — KeInsertByKeyDeviceQueue 652 — KeInsertQueue 619 — KeLowerIrql 100 — KeRaiseIrql 100 — KeRegisterBugCheckCallback 900 — KeReleaseInStackQueuedSpinlock 166 — KeReleaseSpinlock 164 — KeRemoveByKeyDeviceQueue 652 — KeRemoveQueue 619 — KeSetEvent 371 — KeSetEventBoostPriority 368 — KeSwapProcessOrStack 492 — KeWaitForSingleObject 619 — KiActivateWaiterQueue 619 — KiAdjustLookasideDepth 432 — KiChainedDispatch 107 — KiInitializeKernel 282–283 — KiInterruptDispatch 107 — KiInterruptTemplate 107 — KiSystemService 130 — KiSystemStartup 282 — KiThreadStartup 327, 328 — KiUserExceptionDispatcher 191 — LdrInitializeThunk 329 — LeaveCriticalSection 172 — listen 841, 874 — LoadUserProfile 244, 827, 832 — LockFile 590 — LogonUser 522, 530 — LsaAddAccountRights 545 — LsaAuthenticationPort 557 — LsaEnumerateAccountRights 545–546 — LsaLogonUser 244, 525, 545 — LsaLookupAuthenticationPackage 559 — LsaRegisterLogonProcess 553, 557 — LsaRemoveAccountRights 545 — LsaStorePrivateData 244 — MapUserPhysicalPages 423 — MapUserPhysicalPagesScatter 423 — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — — 967 MapViewOfFile 408, 595, 694 MiApplyDriverVerifier 435 MiDispatchFault 746 MiZeroInParallel 397, 499 MmAccessFault 746, 748 MmAllocatePagesForMdl 499, 853 MmFlushSection 747 MmIsThisAnNtAsSystem 52 MmLockPagableCodeSection 406 MmLockPagableSectionByHandle 406 MmMapIoSpace 404 MmMapLockedPagesSpecifyCache 853 MmMapViewInSystemCache 746 MmPrefetchPages 485 MmProbeAndLockPages 406 MmSessionCreate 86 MmTrimAllSystemPagableMemory 437 MmUnmapLockedPages 853 MoveFileEx 287 NdisAllocatePacket 881 NdisSend 881 Netbios 862 NotifyBootConfigStatus 247, 288 NtCreateFile 136, 587 NtCreateIoCompletion 618 NtCreatePagingFile 470 NtCreateProcess 322 NtCreateThread 326 NtCreateToken 87 NtDeviceIoControlFile 600–601 NtInitializeRegistry 247 NtLoadDriver 245 NtQuerySystemInformation 484, 906 NtReadFile 745 NtSetEventBoostPriority 368 NtSetInformationFile 618–619 NtSetInformationProcess 348 NtSetIoCompletion 619 NtSetSystemInformation 86 NtSetSystemPowerState 306 NtShutdownSystem 246, 306 NtWriteFile 133, 520 ObCheckObjectAccess 519–520 ObDereferenceObject 152 ObOpenObjectByName 743 ObpCreateHandle 519 ObpIncrementHandleCount 519 ObpKernelHandleTable 150 ObReferenceObjectByHandle 520 ObReferenceObjectByPointer 152 OpenEncryptedFileRaw 833 OpenFileMapping 408 OpenJobObject 389 OpenPrinterRPC 343 OpenPrinterW 343 OpenProcess 31, 316 OpenSCManager 252 OpenService 253 Performance Data Helper 205 PnP_DeviceList 241 PoRegisterDeviceForIdleDetection 647 PoRequestPowerIrp 643 PoSetDeviceBusy 647
968 Предметный указатель — PostQueuedCompletionStatus 618–619 — PrivilegeCheck 546 — ProbeForRead 601 — ProbeForWrite 601 — PsCreateSystemThread 82 — PspCreateThread 326 — PspUserThreadStartup 328–329 — QueryDosDevice 590 — QueryInformationJobObject 389 — QueryMemoryResourceNotification 506 — QueryUsersOnEncryptedFile 833 — RcpAsyncGetCallStatus. 849 — ReadDirectoryChangesW 300, 755, 769 — ReadEncryptedFileRaw 833 — ReadFile 19 — ReadFileEx 118, 607 — ReadFileScatter 595 — ReadProcessMemory 405, 410 — recv 840–841 — RegCreateKeyEx 193 — RegisterHotKey 558 — RegisterServiceCtrlHandler 232 — RegisterServicesProcess 249 — RegNotifyChangeKey 198, 207 — RegOpenKeyEx 193 — RegQueryValueEx 205 — RegReplaceKey 216 — RegSaveKey 216 — RemoveUsersFromEncryptedFile 833 — ResumeThread 348 — RpcImpersonateClient 529, 851 — RpcRevertToSelf 851 — RpcRevertToSelfEx 851 — RtlAssert 54 — ScAutoStartServices 242–245 — ScCreateServiceDB 239–240 — ScGetBootAndSystemDriverState 241 — ScLogonAndStartImage 244 — ScRevertToLastKnownGood 246 — ScStartService 243 — send 840–841 — SePrivilegeCheck 546 — SeSinglePrivilegeCheck 546 — SetFileSecurity 519 — SetHandleInformation 145, 150 — SetInformationJobObject 348, 382–389 — SetNamedSecurityInfo 538, 540 — SetPriorityClass 348 — SetProcessAffinityMask 348, 382 — SetProcessPriorityBoost 348 — SetProcessShutdownParameters 304, 316 — SetProcessWorkingSetSize 406, 488–489 — SetProcessWorkingSetSizeEx 351, 488 — SetSecurityInfo 538, 540 — SetThreadAffinityMask 348, 382 — SetThreadContext 340 — SetThreadIdealProcessor 348, 386 — SetThreadPriority 348 — SetThreadPriorityBoost 348, 369 — SetupDiEnumDeviceInterfaces 582 — SetupDiGetDeviceInterfaceDetail 582 — SetWindowsHook 558 — Sleep 349 — SleepEx 118, 349 — socket 874 — SRRemoveRestorePoint 754 — SRSetRestorePoint 754 — startofprocess 122 — startofthread 122 — StartService 228 — StartServiceCtrlDispatcher 232 — SuspendThread 348 — SvcCtrlMain 239 — SwitchToFiber 14 — SwitchToThread 348 — SystemParametersInfo 391 — TerminateJobObject 389 — TerminateProcess 316 — TerminateThread 340 — TransmitFile 842–844 — TransmitPackets 842 — UnregisterHotKey 558 — VerifyVersionInfo 53 — VirtualAlloc 404, 417 — VirtualAllocEx 404 — VirtualFree 405 — VirtualFreeEx 405 — VirtualLock 406 — WaitForMultipleObjectsEx 118 — WakeOnLAN 881 — WNetAddConnection 867–868 — WriteEncryptedFileRaw 833 — WriteFile 520 — WriteFileEx 118, 607 — WriteFileGather 595 — WriteProcessMemory 405, 410 — WSARecvEx 844 — ZwMapViewOfSection 408 — ZwOpenSection 408 — ZwUnmapViewOfSection 408 — внутренняя стартовая (базовый код) 123–124 — дополнительный номер 597 — общеупотребительные префиксы 79 — основной номер 597 — ядра 6 Ч чтение — асинхронное опережающее с хроно логией 723 — интеллектуальное опережаю щее 722 Э экран, синий 900 эксперимент экспрессочередь 729 элемент, рабочий 179 Я ядро 42, 71–72 ящик, почтовый 855–856 — широковещательная передача 856
Дэвид Соломон Дэвид Соломон, президент David Solomon Expert Semi nars (www.solsem.com), в основном занимается разъяс нением внутреннего устройства линейки операционных систем Microsoft Windows NT с 1992 года. Он ведет ши роко известные курсы по внутреннему устройству Win dows для тысяч разработчиков и ИТспециалистов во всем мире. Его клиентами являются все основные компа нии компьютерной индустрии, в том числе Microsoft. В 1993 году был удостоен награды Microsoft Support Most Valuable Professional (MVP). Это его четвертая книга. А первой была «Windows NT for OpenVMS Professionals» (Digital Press/Butterworth Heinemann, 1996), в которой программистам и системным администраторам VMS объяснялись принципы ра боты Windows NT. Прежде чем учредить собственную компанию, Дэвид более де вяти лет работал руководителем проекта и был одним из разработчиков опера ционной системы VMS в Digital Equipment Corporation. Его вторая книга, «Inside Windows NT, Second Edition» (Microsoft Press, 1998), была посвящена внутренне му устройству Windows NT 4.0. Свою третью книгу, «Inside Windows 2000, Third Edition» (Microsoft Press, 2000) он написал в соавторстве с Марком Руссиновичем. Дэвид регулярно выступает на научнотехнических конференциях — Micro soft TechEd и Microsoft PDC; был научным председателем нескольких прошлых конференций по Windows NT. Кроме исследования Windows, Дэвид увлекается парусным спортом, чтением и любит сериал Star Trek. Марк Руссинович Марк Руссинович — главный архитектор программного обеспечения и один из учредителей Winternals Software (www.winternals.com), компании, специализирующейся на разработке «продвинутого» системного программного обес печения для Microsoft Windows. Марк является старшим ре дактором журнала «Windows IT Pro Magazine», где часто пи шет колонку «Windows Power Tools». Вместе с Дэвидом Со ломоном часто проводит общедоступные и закрытые семи нары по внутреннему устройству операционных систем Windows и методикам углубленного анализа проблем для многочисленных компаний и организаций, в том числе Mic rosoft. Также вместе они подготовили 12часовой учебный видеокурс по изучению внутреннего устройства Windows, который Microsoft ли цензировала у них для внутрикорпоративного использования по всему миру. Марк участвует в работе основных конференций вроде Microsoft Tech Ed, Micro soft IT Forum, Windows IT Pro Magazine’s Connections и MCP Magazine’s TechMentor. Марк — обладатель степеней бакалавра (Carnegie Mellon University) и магист ра (Rennselaer Polytechnic Institute) в области компьютерных технологий. В 1994 году он получил степень доктора философии в Carnegie Mellon University — так же в области компьютерных технологий. До учреждения компании Winternals Software работал в Compuware NuMega Laboratories и в исследовательском цент ре Thomas J. Watson Research Center корпорации IBM.
Руссинович Марк и Соломон Дэвид Внутреннее устройство Microsoft Windows: Windows Server 2003, Windows XP и Windows 2000. Мастеркласс 4е издание Перевод с английского под общей редакцией Ю. Е. Купцевича Главный редактор А. И. Козлов Подписано в печать Формат 70×100/16. Физ. п. л. 62 IW4_Exit_dop.PM6 970 26.10.2007, 12:47