Сегментная защита памяти
Определения
Существует четыре уровня привилегий (PL) сегментов (0–3). Привилегированность увеличивается с уменьшением номера (т. е. нулевой – самый привилегированный). Уровни 0–2 соответствуют супервизору (Supervisor), 3 – пользователю (user). На нулевом уровне позволяется использование привилегированных инструкций.
Уровень привилегий сегмента (DPL англ. Descriptor Privilege Level) соответствует значению поля DPL в дескрипторе сегмента.
Текущий уровень привилегий (CPL англ. Current Privilege Level) соответствует уровню привилегий сегмента кода, селектор которого загружен в регистр CS (т. е. уровню привилегий выполняющегося сегмента кода).
Запрашиваемый уровень привилегий (RPL англ. Requested Privilege Level) находится в двух младших битах селектора (задаётся программой).
Условия и принцип защиты
При загрузке селектора в сегментный регистр и при обращении к памяти проверяются условия сегментной защиты, и при несоблюдении вызывается обработчик исключения #GP.
Условия защиты следующие:
- Нельзя обращаться за пределы сегмента, обозначенные лимитом[1];
- В сегментные регистры ES, CS, SS, DS, FS, GS нельзя загружать селекторы, указывающие на системные сегменты (в которых бит S=0);
- В регистры ES, DS, FS, GS можно загружать селекторы таких сегментов, у которых DPL>=Max(CPL, RPL);
- В регистры ES, DS, FS, GS можно загружать только селекторы сегментов данных или сегментов кода для выполнения/чтения;
- В регистр CS нельзя загружать селектор сегмента данных;
- В регистр CS можно загружать селектор сегмента кода только при CPL=DPL;
- В регистр SS можно загружать только селектор сегмента данных для чтения/записи с DPL = CPL;
- В сегмент кода нельзя писать;
- В сегмент данных только для чтения нельзя писать;
- В системные регистры LDTR, TR можно загружать только селекторы сегментов LDT и TSS соответственно;
Взаимодействие уровней привилегий
Взаимодействие четырёх уровней между собой осуществляется посредством шлюзов. Дескриптор шлюза так же, как и дескриптор сегмента имеет поле PL. Обращение к шлюзу подчинено вышеописанным правилам, но существуют дополнительные правила, накладывающие естественные ограничения на сегмент кода/TSS, указанный в шлюзе:
- DPL вызываемого сегмента не должен быть численно больше CPL;
- DPL шлюза не дожен быть численно меньше DPL указанного в нём сегмента;
- В шлюзе должен быть указан только сегмент кода или TSS (если это шлюз задачи);
Если посредством шлюза происходит обращение к неподчинённому сегменту с таким же уровнем привилегий, или к подчинённому сегменту кода с таким же или численно меньшим уровнем привилегий, то происходит простой переход: <source lang="Asm"> Push Flags ; Только для шлюзов прерывания и ловушки Push CS Push IP Jmp FAR Gate_Address </source>
Переключение стека
Если же происходит переход к неподчинённому сегменту кода с численно меньшим уровнем привилегий, то происходит переключение стека во избежание его переполнения на верхних (численно меньших) уровнях. Напр. если происходит ошибка стека на нулевом уровне, то процессор останавливается.
Сегмент TSS содержит три дальних адреса стека — для уровней привилегий 0 – 2.
При переходе с больших на меньшие уровни через шлюзы происходит смена привилегий, и, соответственно, переключение стеков.[2]
Алгоритм переключения выглядит несколько сложнее:
- Из соответствующих полей TSS загружаются новые значения SS, (E)SP;
- В новый стек сохраняются предыдущие значения SS, (E)SP (до вызова);
- Если шлюз является шлюзом вызова, то в новый стек копируются WC слов/двойных слов из стека вызывающей программы;
- Если это шлюз прерывания или ловушки, то сохраняется значение (E)Flags;
- Сохраняется текущее значение CS, (E)IP;
- Из дескриптора шлюза в регистры CS:(E)IP загружается новый дальний адрес, указанный в соответствующих полях дескриптора;
При выполнении команды RetF/IRet:
- Процессор извлекает из стека дальний адрес возврата (и регистр флагов);
- Если у команды RetF есть параметр, то увеличивает значение (E)SP на его значение (удаляет из стека переданные процедуре параметры);
- Анализирует RPL селектора CS[3]: если он численно больше CPL, то извлекает из стека дальний адрес прежней вершины стека и загружает его в SS:(E)SP. Таким образом происходит возврат к старому стеку;
Примечания
- ↑ Существует два вида сегментов: растущие вверх и растущие вниз. Допустимый диапазон сегментных адресов для растущих вверх сегментов: от нуля до лимита включительно. Для растущих вниз: от лимита (включительно) до $FFFFF при G=0 или до $FFFFFFFF при G=1.
- ↑ Всякий раз, когда происходит переход с большего на меньший уровень, стек меньшего уровня инициализируется заново.
- ↑ RPL, загруженный в CS всегда равен CPL
См. также
Ссылки
Если вам нравится SbUP.com Сайт, вы можете поддержать его - BTC: bc1qppjcl3c2cyjazy6lepmrv3fh6ke9mxs7zpfky0 , TRC20 и ещё....