Почему Windows обрабатывает полосы прокрутки в ядре?

Новый 1-битный эксплойт «всех» версий Windows использует ошибку в коде ядра, которая обрабатывает полосы прокрутки. Это заставило меня задуматься. Почему окна обрабатывают полосы прокрутки в ядре, а не в пользовательском режиме? Исторические причины? Любая другая ОС делает это?


person Filip Haglund    schedule 15.02.2015    source источник
comment
Серверная часть USER32 и GDI32 раньше работала в пользовательском режиме. Он размещался в процессе клиент-серверной подсистемы CSRSS.EXE, который запускается под учетной записью SYSTEM. NT 4 переместила их в режим ядра (win32k.sys) по соображениям производительности.   -  person Eryk Sun    schedule 16.02.2015
comment
IIRC, Microsoft также заявила, что упростила способ перехода из пользовательского режима в режим ядра во время работы с графическим интерфейсом. По-видимому, графическая подсистема до NT 4 имела специально спаренные потоки пользовательского режима и режима ядра, и существовал некий специальный механизм для перехода от одного к другому. Очевидно, было сложно доказать свойства безопасности для этого перехода, и избавление от него облегчило процесс сертификации. (Я не уверен, какую сертификацию они собирались получить в то время; возможно, это была Оранжевая книга.)   -  person Harry Johnston    schedule 16.02.2015


Ответы (1)


Вкратце: Microsoft пожертвовала безопасностью ради производительности.


Полосы прокрутки немного особенные в Windows. Большинство полос прокрутки не являются настоящими окнами, а реализованы как украшения. в «родительском» окне. Это приводит нас к более общему вопросу; почему окна реализованы в режиме ядра в Windows?

Давайте посмотрим на альтернативы:

  1. За процесс в пользовательском режиме.
  2. Одиночный «главный» процесс в пользовательском режиме.

Вариант 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 и непонятной функции, называемой парными потоками.

person Anders    schedule 01.01.2017