Программирование систем защиты

Шлюхи Липецка


Организация памяти в защищенном режиме работы процессора

Ранее мы кратко рассмотрели работу процессоров серии 1386 и выше в защищенном режиме, использующем организацию памяти, при которой используются два механизма преобразования памяти:

  • сегментация;
  • разбиение на страницы.

ОС NT в различной мере использует оба этих механизма.
Как уже говорилось, в защищенном режиме может быть определено до 213 (8192) сегментов. Каждый сегмент может иметь размер до 4 Гб (232 байт). Таким образом, максимальный размер виртуального адресного пространства составляет 64 Тб.
Каждый сегмент описывается 8-байтной структурой данных - дескриптором сегмента. Дескрипторы находятся в специальной таблице дескрипторов (GDT, см. рис. 5). Для указания конкретного сегмента используется 16-битный селектор. Он является индексом внутри таблицы дескрипторов. Младшие 2 бита селектора определяют номер привилегированного режима (DPL - уровень привилегий дескриптора), который может воспользоваться данным селектором для доступа к дескриптору, третий бит определяет локальную/глобальную дескрипторную таблицу, (отсюда максимальное число селекторов 213).
ОС NT, хотя и использует селекторы, но использует их в минимальной степени. NT реализует плоскую 32-разрядную модель памяти с размером линейного адресного пространства 4 Гб (232 байт). Это сделано следующим образом:

Рис. 5

В NT определено 11 селекторов, из которых нас будут интересовать всего 4:

Селектор Hex (bin]
Назначение
База
Предел
DPL
Тип
08 (001000)
Code32
00000000
FFFFFFFF
0
RE
10( )
Data32
00000000
FFFFFFFF
0
RW
lb (011011)
Code32
00000000
FFFFFFFF
3
RE
23 (100011)
Data32
00000000
FFFFFFFF
3
RW

Эти четыре селектора позволяют адресовать все 4Гб линейного адресного пространства, причем для всех селекторов при фиксированном контексте памяти производится трансляция в одни и те же физические адреса. Разница только в режиме доступа.
Первые два селектора имеют DPL=0 и используются драйверами и системными компонентами для доступа к системному коду, данным и стеку. Вторые два селектора используются кодом пользовательского режима для доступа к коду, данным и стеку пользовательского режима. Эти селекторы являются константами для ОС NT.
Сегментное преобразование пары селектор:смещение дает 32-битный линейный адрес (лежащий в диапазоне 4 Гб линейного адресного пространства). При этом линейный адрес совпадает со значением смещения виртуального адреса. Фактически, при такой организации памяти виртуальный и линейный адреса совпадают.
Наличие поля тип, определяющего возможность чтения/записи/исполнения кода в соответствующем сегменте может навести на мысль, что именно на этом уровне производится защита памяти от нецелевого использования. Например, при работе прикладной программы в пользовательском режиме ее код находится в сегменте с селектором 1b. Для этого сегмента разрешены операции чтения и исполнения. Используя селектор 1b, программа не сможет модифицировать свой собственный код. Однако, как уже было сказано, для всех сегментов производится трансляция в одни и те же физические адреса. Поэтому при обращении к данным или стеку (селектор 23) прикладная программа обнаружит свой код по тому же смещению, что и для селектора 1b, причем режим доступа к сегменту позволяет производить чтение/запись. (При этом важно помнить: одно и то же смещение в разных адресных пространствах указывает на разную физическую память.) Таким образом, способ использования сегментации в ОС NT не обеспечивает защиту кода от нецелевого использования.
Далее задействуется механизм страничной организации памяти и переключения контекста памяти.
Каждый контекст памяти (адресное пространство процесса) представляется собственной таблицей трансляции линейного адреса (совпадающего с виртуальным) в физический.
Каждый элемент таблицы страниц содержит бит, указывающий на возможность доступа к странице из пользовательского режима. При этом все страницы доступны из режима ядра.
Кроме того, каждый элемент таблицы страниц содержит бит, указывающий на возможность записи в соответствующую страницу памяти.
Эти два бита используются для управления доступом к страницам памяти и формируют следующий набор правил:

  1. 1. страница всегда может быть прочитана из режима ядра;
  2. 2. на страницу может быть произведена запись из режима ядра, только если установлен бит разрешения записи;
  3. 3. страница может быть прочитана из пользовательского режима, только если установлен бит доступа к странице из пользовательского режима;
  4. 4. на страницу может быть произведена запись из пользовательского режима, если установлены оба бита (разрешение записи и доступ из пользовательского режима);
  5. 5. если страница может быть прочитана, она может быть исполнена.

Страницы памяти с исполняемым кодом не будут иметь разрешения на запись,
если не предпринять никаких дополнительных действий. Поэтому при попытке использования селектора данных для модификации кода будет сгенерирована исключительная ситуация.
Для упрощения организации памяти, для всех контекстов памяти NT осуществляет одинаковую трансляцию для некоторого диапазона виртуальных адресов. Таким образом, при переключении контекста памяти, то есть переходе на новую таблицу трансляции виртуального адреса в физический, некоторая часть элементов этой таблицы останется неизменной.
Это нужно для того, чтобы ядро операционной системы (компоненты ОС и драйвера) всегда располагалось по фиксированным виртуальным адресам вне зависимости
от текущего контекста памяти. Таким неизменяемым диапазоном адресов являются верхние 2 Гб памяти.
Для защиты кода ОС соответствующие элементы таблицы трансляции виртуального адреса в физический помечены как недоступные из пользовательского режима.
Соответственно, диапазон виртуальных адресов 2-4 Гб называют системным адресным пространством (system address space), а диапазон 0-2 Гб - пользовательским адресным пространством (user address space).
Во избежание путаницы между терминами адресное пространство процесса и пользовательское/системное адресное пространство, где это возможно, вместо термина адресное пространство процесса мы будем пользоваться термином контекст памяти.
При этом возможная путаница вполне допустима, так как с точки зрения прикладного программиста пользовательское адресное пространство - и есть текущий контекст памяти.

Назад Начало Вперед