Новый 1-битный эксплойт «всех» версий Windows использует ошибку в коде ядра, которая обрабатывает полосы прокрутки. Это заставило меня задуматься. Почему окна обрабатывают полосы прокрутки в ядре, а не в пользовательском режиме? Исторические причины? Любая другая ОС делает это?
Почему Windows обрабатывает полосы прокрутки в ядре?
Ответы (1)
Вкратце: Microsoft пожертвовала безопасностью ради производительности.
Полосы прокрутки немного особенные в Windows. Большинство полос прокрутки не являются настоящими окнами, а реализованы как украшения. в «родительском» окне. Это приводит нас к более общему вопросу; почему окна реализованы в режиме ядра в Windows?
Давайте посмотрим на альтернативы:
- За процесс в пользовательском режиме.
- Одиночный «главный» процесс в пользовательском режиме.
Вариант 1 имеет большое преимущество при работе с вашими окнами; нет переключения контекста/перехода ядра. Проблема, конечно, в том, что окна из разных процессов живут на одном экране, и кто-то должен нести ответственность за определение того, какое окно является активным, и координировать изменения, когда пользователь переключается на другое окно. Этот кто-то должен быть специальным системным процессом или ядром, потому что эта информация не может быть для каждого процесса, она должна храниться где-то глобально. Этот двойной информационный дизайн будет сложным, потому что глобальный оконный менеджер не может доверять информации о каждом процессе. Я уверен, что у этого теоретического дизайна есть масса других недостатков, но я не собираюсь тратить на него больше времени.
В Windows NT 3 реализован вариант альтернативы 2. Оконный менеджер был переведен в режим ядра в NT 4 в основном для причины производительности:
... диспетчер окон (USER) и интерфейс графических устройств (GDI) были перемещены из подсистемы Win32 в исполнительную систему Windows NT. Драйверы устройств пользовательского режима Win32, включая драйверы графического дисплея и принтера, также были перемещены в исполнительную систему. Эти изменения предназначены для упрощения обработки графики, снижения требований к памяти и повышения производительности.
...и далее в том же документе есть дополнительные технические подробности и обоснования:
Когда Windows NT была впервые разработана, подсистема среды Win32 была разработана как одноранговая с подсистемами среды, поддерживающими приложения в MS-DOS, POSIX и OS/2. Однако приложения и другие подсистемы должны были использовать графические, оконные функции и функции обмена сообщениями в подсистеме Win32. Чтобы избежать дублирования этих функций, подсистема Win32 использовалась как сервер для графических функций для всех подсистем.
Этот дизайн хорошо работал для Windows NT 3.5 и 3.51, но недооценивал громкость и частоту графических вызовов. Наличие таких базовых функций, как обмен сообщениями и управление окнами, в отдельном процессе приводило к значительным накладным расходам памяти из-за передачи сообщений клиент-сервер, сбора данных и управления несколькими потоками. Это также требовало нескольких переключений контекста, которые потребляли такты ЦП, а также память. Объем вызовов графической поддержки в секунду снижал производительность системы. Было ясно, что переработка этого аспекта в Windows NT 4.0 могла бы вернуть эти потраченные впустую системные ресурсы и повысить производительность.
Остальные подсистемы не так актуальны в наши дни, но проблемы с производительностью остаются.
Если мы посмотрим на простую функцию, например IsWindowVisible, то когда оконный менеджер находится в режиме ядра, не так много накладных расходов: функция выполнит пару инструкций в пользовательском режиме, а затем переключит ЦП на кольцо 0, где вся операция (проверка дескриптора окна передается и, если он действителен, извлекает видимое свойство) выполняется в режиме ядра. Затем он переключается обратно в пользовательский режим, и на этом все.
Если оконный менеджер живет в другом процессе, то вы по крайней мере удвоите количество переходов ядра, и вы должны каким-то образом передавать входные и выходные функции в процесс оконного менеджера и из него, и вы должны каким-то образом заставить процесс оконного менеджера выполняться, пока вы ждете за результат. В NT 3 для этого использовалась комбинация разделяемой памяти, LPC и непонятной функции, называемой парными потоками.