Процессор INTEL в защищенном режиме.

Выпуск №12


Уголовный кодекс процессоров Intel c архитектурой IA32 (с изменениями и дополнениями)


В выпуске:
- ГЛАВА 1 УК IA-32: Общие положения
- ГЛАВА 2 УК IA-32: Нарушение границ
а также:
- Зубков тоже ошибается...

Глава I: ОБЩИЕ ПОЛОЖЕНИЯ (важно прочитать и запомнить!)

В некоторых браузерах ползунка справа (для перемещения по странице) может быть не видно - не обращайте внимания, на самом деле он там есть :)

Механизм защиты процессора Intel обеспечивается 3-мя флагами (+ еще 2 дополнительных при использовании страничной адресации) и 5-тью полями. Казалось бы, какую защиту могут обеспечить эти несчастные 8 (+2 до кучи) ребят? На самом же деле все довольно продумано и все что надо они обеспечивают.

Флаги, обеспечивающие защитный механизм:

- Тип дескриптора (S) – бит 12 во втором двойном слове дескриптора сегмента. Собственно, отвечает за тип сегмента: системный, кода или данных.

- Флаг гранулярности (G) – бит 23 во втором двойном слове дескриптора сегмента. Вместе с полем «Лимит» дескриптора и флагом E (флаг направления роста) определяют размер сегмента.

- Флаг направления роста сегмента (E) – бит 10 во втором двойном слове дескриптора сегмента. Работает на пару с флагом G и полем «Лимит».

- Флаг пользователь/супервизор (U/S) – бит 2 элемента таблицы или каталога страниц. Определяет тип страницы: пользовательская или супервизорная. В прошлом выпуске упоминалось, что при использовании страничной адресации доступны некоторые дополнительные защитные механизмы. Этот флаг – один из них.

- Флаг чтения/записи (R/W) – бит 1 элемента таблицы или каталога страниц. Определяют тип доступа к странице: только для чтения или для чтения/записи. Флаг R/W – второй (он же последний) дополнительный механизм защиты при использовании страничной адресации.



Поля, обеспечивающие защитный механизм:

- Поле «Тип» - биты 8-11 во втором двойном слове дескриптора сегмента. Определяет тип сегмента кода, данных или системного сегмента. В принципе, работает на пару с флагом S (см. выше).

- Поле «Лимит» - биты 0-15 первого двойного слова и биты 16-19 второго двойного слова дескриптора сегмента. Вмести с флагом G и E определят размер сегмента. С этим полем все ясно.

- Поле «Уровень привилегий дескриптора» (DPL) – биты 13 и 14 во втором двойном слове дескриптора сегмента. Название поля немного сбивает с толку – на самом деле поле DPL задает уровень привилегий описываемого им сегмента, дескриптору уровень привилегий по сути ни к чему. Чем меньшее значение содержит это поле, тем описываемый сегмент круче (0 – самый крутой, 3 – сегмент-лох). Чем же крутой сегмент круче сегмента-лоха? Да всем. Сегмент с нулевым уровнем привилегий может исполнять ЛЮБЫЕ инструкции, обращаться к ЛЮБЫМ данным. По задумке, в сегментах с 0-ым уровнем должно располагаться ядро ОС, другие части ОС – в сегментах с 1-ым уровнем, драйвера – со 2-ым, пользовательские программы – с 3-им. На деле программисты из Microsoft при проектировании ОС «Винды» решили «упростить» модель до двухуровневой: все что не пользовательские программы – то в 0-ом уровне, пользовательские – в третьем. 1-й и 2-й уровни не используются. По сути, если бы Intel IA32 эксплуатировался только под осью Windows (что и происходит в 90% случаях), то для полей DPL, RPL и CPL с головой хватило бы одного бита вместо двух :) и инженеры Intel-а немного перестарались.

- Поле «Запрашиваемый уровень привилегий» (RPL) – биты 0 и 1 ЛЮБОГО (!) сегментного селектора. Кто у кого чего запрашивает и зачем вообще это поле – это отдельная песня, она будет в следующей главе.

- Поле «Текущий уровень привилегий» (CPL) – биты 0 и 1 сегментного регистра CS (!). Фактически определяет уровень привилегий ТЕКУЩЕЙ исполняемой программы (процедуры), в общем – это уровень привилегий исполняемого в данный момент кода.



THAT’S ALL! (это все!). Вся аппаратная защита такого монстра, как, скажем, Pentium 4, целиком и полностью стоит на описанных выше битиках! (я от нечего делать даже подсчитал – всего 35 бит! Т.е. все аппаратные защитные структуры умещаются (почти) в одно двойное слово! Честно говоря, это немного шокирует...

Если кому-то вздумается взглянуть на картинки (где расположены все эти флажочки и полянки – они есть в предыдущих выпусках.


Глава II: НАРУШЕНИЕ ГРАНИЦ

Поле «Лимит» дескриптора сегмента призвано уберечь программы (процедуры) от незаконного обращения к памяти за пределами, установленными этим полем. Эффективное (реальное) значение лимита зависит от флага гранулярности G. Для сегментов данных, лимит также зависит от флага E (направление роста) и флага B дескриптора.

Влияние бита G на поле «Лимит» изучено и рассмотрено со всех сторон в предыдущих выпусках, но напомню: если бит G=0, то лимит сегмента совпадает со значением одноименного поля дескриптора; очевидно, что в данном случае сегмент может иметь длину от 0 до FFFFFh (1Мб). Если флаг G=1, то реальный лимит сегмента равен содержимому поля «Лимит» дескриптора, умноженному на 4Кб (FFFh). Очевидно, сегмент в этом случае может занимать от 4Кб до 4Гб.

ВАЖНО! Если бит G=1, то младшие 12 бит адреса НЕ ПРОВЕРЯЮТСЯ НА ПРЕВЫШЕНИЕ ЛИМИТА! Т.е. если создать дескриптор сегмента с G=1, и полем «Лимит» равным 0, то смещения от 0 до FFFh ВСЕ РАВНО ДОСТУПНЫ ДЛЯ ОБРАЩЕНИЯ! Т.е. процессор ИГНОРИРУЕТ младшие 12 бит при проверке на превышение лимита. Вообще, как где-то было верно подмечено, бит гранулярности – это чисто радиолюбительский трюк. Что еще небезынтересно знать – умножение на 4Кб равносильно сдвигу на 12 влево, причем младшие 12 бит при этом заполняются единицами.

Итак, процессор сгенерирует исключение #GP (самое страшное и главное, недаром ему присвоили 13 номер) в следующих случаях:

- Обращение к байту по смещению БОЛЬШЕМУ, чем эффективный лимит
- Обращение к слову по смещению БОЛЬШЕМУ, чем (эффективный лимит-1)
- Обращение к двойному слову по смещению БОЛЬШЕМУ, чем (эффективный лимит-3)
- Обращение к учетверенному слову по смещению БОЛЬШЕМУ, чем (эффективный лимит-7)

Это 4 заповеди данной главы.

Существует еще один размытый момент, который мы сейчас обсудим во всех нюансах. Этот момент – растущие «ВНИЗ» сегменты данных. Тут сразу нужно сказать – сегмент никуда не растет, это образное выражение. Все дело в том, что у растущих «ВНИЗ» сегментов поле «Лимит» в дескрипторе определяет НИЖНЮЮ границу сегмента, а ВЕРХНЯЯ граница ВСЕГДА (!) (подчеркнуть три раза) равна FFFFh (1Мб) если бит B=0 и FFFFFFFFh (4Гб) если бит B=1. Откуда взялся бит B? Вспоминаем структуру дескриптора, помните флаг D/B? Вот это он и есть. Теперь у некоторых возникает вопрос: если у нас определена НИЖНЯЯ граница сегмента (поле «Лимит») и верхняя (1Мб или 4Гб), то нахрена тогда поле БАЗА в дескрипторе? Спокойно! Стоит лишь чуть-чуть подумать и все станет ясно: поле «Лимит» хоть и определяет нижнюю границу, но все равно ОТСЧИТЫВАЕТСЯ ОТ БАЗЫ! Т.е. фактически нижняя граница у растущих ВНИЗ сегментов равна: содержимое поля «Лимит» дескриптора + содержимое поля «База» дескриптора. Вот для того нам база и нужна... (вообще с тем что поле «Лимит» всегда зависит от поля «База» интеловцы imho погорячились, т.к. весь этот механизм в конечном счете выгоден только при использовании 36-разрядного механизма адресации PAE-36. У кого есть какие-нибудь соображения на этот счет – прошу поделиться).

Здесь интересен другой момент (подумайте и вышлите свои соображения на brokensword@mail.ru): если у нас есть растущий ВНИЗ сегмент, у которого сброшен бит B, т.е. верхняя граница этого сегмента равна FFFFh, а поле «База» в дескрипторе ПРЕВЫШАЕТ значение 1Мб. Кто может ответить - какие смещения доступны в таком сегменте?

Наконец, позволю себе привести фрагмент из книги тов. Зубкова С.В. по поводу растущих вниз сегментов: «Бит направления роста сегмента (E) обращает смысл лимита сегмента. В сегментах с этим битом, сброшенным в ноль, разрешены абсолютно все смещения от 0 до лимита, а если этот бит 1, то допустимы все смещения, кроме от 0 до лимита. Про такой сегмент говорят, что он растет сверху вниз, так как если лимит, например, равен -100, допустимы смещения от -100 до 0, а если лимит увеличить, станут допустимыми еще меньшие смещения». Здесь уважаемый Зубков запорол страшную ерунду, т.к., во-первых, не «от 0 до лимита», а от «(базы) до (база+лимит)», и в случае растущих вниз сегментов, помимо той же самой ошибки, он рассмотрел только случай когда B=1 (т.е. верхняя граница равна 4Гб), тогда действительно доступны ВСЕ смещения, кроме от база+лимит до 0 («вниз»). Да и с примером он тоже намудрил. Если кто-то не согласен – прошу, пишите, обсудим.

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

Данная глава была бы не полной, если не вспомнить о том, что процессор (помимо проверки лимитов сегментов) проверяет также лимиты таблиц дескрипторов, инфа о которых содержится в регистрах GDTR, IDTR, LDTR и TR. #GP будет сгенерировано, если произойдет попытка обращения к дескриптору, находящемуся за пределами таблицы дескрипторов.

Вот теперь по теме «Проверка границ» больше добавить действительно нечего. В следующем выпуске мы рассмотрим следующую главу УК IA-32 под названием «Проверка типов».

здесь можно скачать архив рассылки.
wasm.ru – сайт, посвященный программированию на асме под win (и не только), самая крупная коллекция статей в рунете, все самое новое и нужное
rusfaq.ru - задай любой вопрос по асму (и жди ответа).


© Broken Sword, 2003 - Рассылка
© Алексеенко Д.В., 2003 - Дизайн


Hosted by uCoz