Как Windows защищает переход в режим ядра? - PullRequest
12 голосов
/ 29 июня 2009

Как Windows защищает поток пользовательского режима от произвольного перевода процессора в режим ядра?

Я понимаю, что это правда:

  1. Потоки пользовательского режима действительно переходят в режим ядра, когда системный вызов выполняется через NTDLL.
  2. Переход в режим ядра выполняется с помощью инструкций, специфичных для процессора.

Так что же особенного в этих системных вызовах через NTDLL? Почему поток пользовательского режима не может подделать его и выполнить специфичные для процессора инструкции для перехода в режим ядра? Я знаю, что здесь отсутствует какой-то ключевой элемент архитектуры Windows ... что это?

Ответы [ 5 ]

17 голосов
/ 29 июня 2009

Вы, вероятно, думаете, что поток, работающий в пользовательском режиме, вызывает кольцо 0, но на самом деле это не то, что происходит. Поток пользовательского режима вызывает исключение, которое перехватывается кодом Ring 0. Поток пользовательского режима останавливается, и ЦП переключается на поток ядра / кольца 0, который может затем проверить контекст (например, стек вызовов и регистры) потока пользовательского режима, чтобы выяснить, что делать. До системного вызова это действительно было исключение, а не специальное исключение, специально для вызова кода кольца 0.

Если вы воспользуетесь рекомендациями других ответов и прочитаете руководства Intel , вы увидите, что syscall / sysenter не принимает никаких параметров - ОС решает, что произойдет. Вы не можете вызвать произвольный код. WinNT использует номера функций, которые соответствуют функции режима ядра, которую будет выполнять код пользовательского режима (например, NtOpenFile - это fnc 75h на моем компьютере с Windows XP (числа меняются все время; одна из задач NTDll - сопоставить функцию вызовите номер fnc, поместите его в EAX, укажите EDX на входящие параметры, затем вызовите sysenter).

9 голосов
/ 29 июня 2009

Процессоры Intel обеспечивают безопасность с помощью так называемых «защитных колец».

Их 4, пронумерованных от 0 до 3. Код, выполняющийся в кольце 0, имеет самые высокие привилегии; он может (практически) делать все, что угодно с вашим компьютером. Код в кольце 3, с другой стороны, всегда на коротком поводке; у него только ограниченные полномочия влиять на вещи. А кольца 1 и 2 в настоящее время вообще не используются ни для каких целей.

Поток, работающий в более высоком привилегированном кольце (таком как кольцо 0), может переходить в более низкое привилегированное кольцо (такое как кольцо 1, 2 или 3) по желанию. Однако переход наоборот строго регламентирован. Так обеспечивается безопасность высокопривилегированных ресурсов (таких как память) и т. Д.

Естественно, ваш код пользовательского режима (приложения и все) выполняется в кольце 3, а код ОС - в кольце 0. Это гарантирует, что потоки режима пользователя не смогут связываться со структурами данных ОС и другими критическими ресурсами. *

Подробнее о том, как все это реализовано, вы можете прочитать в этой статье. Кроме того, вы также можете просмотреть руководства Intel, особенно том 1 и том 3А, которые можно загрузить здесь .

Это история для процессоров Intel. Я уверен, что в других архитектурах происходит нечто подобное.

7 голосов
/ 29 июня 2009

Я думаю (я могу ошибаться), что механизм, который он использует для перехода, прост:

  • Код пользовательского режима выполняет программное прерывание
  • Это (прерывание) вызывает переход в местоположение, указанное в таблице дескрипторов прерываний (IDT)

То, что не позволяет узурпировать код пользовательского режима, заключается в следующем: вам нужно иметь привилегию для записи в IDT; так что только ядро ​​может указать, что происходит при выполнении прерывания.

4 голосов
/ 29 июня 2009

Код, работающий в режиме пользователя (кольцо 3), не может произвольно перейти в режим ядра (кольцо 0). Это может быть сделано только с использованием специальных маршрутов - прыжковых ворот, прерываний и векторов сизентера. Эти маршруты высоко защищены, а входные данные очищаются, поэтому плохие данные не могут (не должны) вызывать плохое поведение.

Все это настраивается ядром, обычно при запуске. Его можно настроить только в режиме ядра, поэтому код режима пользователя не может его изменить.

3 голосов
/ 30 июня 2009

Вероятно, будет справедливо сказать, что он делает это (относительно) аналогично тому, что делает Linux. В обоих случаях это будет зависеть от процессора, но в x86 возможно либо программное прерывание с помощью инструкции INT, либо с помощью инструкции SYSENTER.

Преимущество того, как работает Linux, заключается в том, что вы можете делать это без исходной лицензии Windows.

Исходная часть пользовательского пространства находится здесь в LXR и бит ядра ядра - посмотрите на entry_32.S и entry_64.S

В Linux на x86 есть три разных механизма: int 0x80, syscall и sysenter.

Библиотека, которая создается во время выполнения ядром с именем vdso, вызывается библиотекой C для реализации функции syscall, которая использует другой механизм в зависимости от ЦП и того, какой системный вызов это. Затем ядро ​​имеет обработчики для этих механизмов (если они существуют в конкретном варианте процессора).

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...