Процессор INTEL в защищённом режиме #12 — Архив WASM.RU

Все статьи

Процессор INTEL в защищённом режиме #12 — Архив WASM.RU

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

В выпуске:

а также: Зубков тоже ошибается...

Глава 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 под названием "Проверка типов".

http://subscribe.ru/archive/comp.soft.prog.intelpm/ - здесь можно скачать архив рассылки.

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

rusfaq.ru - задай любой вопрос по асму (и жди ответа).

2002-2013 (c) wasm.ru