Методы защиты в процессорах семейства Х86, страница 4

Напомним, что межсегментная передача управления осуществляется командами типа FAR, такими как команды безусловного перехода JMP, вызова процедур CALL и возврата из процедур RET, а также командами прерывания INT и возврата из прерывания IRET. Адресная часть таких команд представляет собой 48 – битный указатель «селектор:смещение». Этот указатель при прямой передаче управления содержится в самой команде, а в случае косвенной передачи – извлекается из памяти.

                             а) Подчиненные сегменты кода.

Сегмент кода становится подчиненным (или согласованным), если в байте прав доступа его дескриптора бит C (Conforming) установлен в состояние 1. Подчиненный сегмент не имеет своего индивидуального уровня привилегий. Его уровень привилегий становится тем уровнем привилегий, который имеет сегмент, где находится программа, передающая ему управление. Поэтому, в этом случае, обычные правила защиты по значениям CPL и DPL не действуют. При передаче управления  подчиненному сегменту, биты поля RPL регистра CS не изменяются на значение битов поля DPL дескриптора сегмента кода, в котором находится исполняемая программа (процесс), как это обычно бывает. Эти биты поля RPL регистра CS сохраняют значение поля DPL предыдущего последнего выполнявшегося неподчиненного сегмента кода.

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

Следует отметить, что в связи с такой легкой изменчивостью своего уровня привилегий, подчиненные сегменты не должны содержать привилегированные команды, например команды ввода/вывода.

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

    б) Передача управления с помощью шлюзов вызова.

Другим способом обращения к программным сегментам, находящихся на других уровнях привилегий является использование шлюзов вызова (CallGates). Команда передачи управления CALL в вызывающей программе обращается к шлюзу вызова, а шлюз вызова осуществляет косвенную передачу управления непосредственно на конкретную команду в программе целевого кодового  сегмента. Чаще всего, такая передача управления происходит от выполняемой пользовательской программы к конкретной процедуре сильно защищенной операционной системы.

Как уже говорилось ранее, дескрипторы шлюза вызова являются системными объектами, величиной 8 байт, которые могут размещаться как в глобальной, так и в локальных дескрипторных таблицах. Напомним формат дескриптора шлюза вызова (рис.VI.4).

Как видно из рисунка, дескриптор шлюза включает в себя селектор, по которому определяется базовый адрес сегмента, и смещение в этом сегменте, т.е. содержит полный 32 – разрядный адрес назначения. В этом его принципиальное отличие от дескрипторов сегментов, которые содержат только базовый адрес сегмента и его размер. Таким образом, дескриптор сегмента служит механизмом отображения области памяти, а дескриптор шлюза является механизмом перенаправления.

                Рис.VI.4. Формат дескриптора шлюза вызова

В дескрипторе шлюза вызова предусмотрено 5 бит счетчика слов (Word count). Эти биты позволяют передать до 32 параметров из старого стека в новый, который образуется на новом уровне привилегий, куда передается управление. Необходимость организации стека на новом уровне определяется тем, что одно из правил защиты по привилегиям требует, чтобы уровень привилегий стека должен быть всегда равен уровню CPL.

Отметим, что в процессорах Pentium+ вызов через шлюз может осуществляться командами как CALL, так и JMP, тогда как в более ранних моделях процессоров семейства Х86, такой вызов производился только командой CALL.

Подчеркнем, что сама команда CALL или JUMP должна адресовать шлюз

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

 Схема передачи управления вызываемой процедуре при помощи шлюзов вызова изображена на рис.VI.5. В команде FAR CALL, которая обращается к шлюзу вызова, имеющееся в ней смещение игнорируется, а селектор используется для определения дескриптора шлюза вызова. После того, как дескриптор шлюза вызова найден, из него берется селектор, помещается в кодовый регистр CS, и по нему, через дескрипторные таблицы, находится базовый адрес целевого сегмента CS. Затем, из дескриптора шлюза выбирается смещение в этом сегменте, которое, суммируясь с базовым адресом сегмента, образует конкретный физический адрес начала искомой процедуры.

Таким образом, задание в шлюзе вызова полного указателя адреса «селектор:смещение» обеспечивает вход только в строго определенных точках программного сегмента. Каждая точка входа в программный сегмент от менее привилегированного кода должна иметь соответствующий ей шлюз вызова.

Такой косвенный вызов привилегированных процедур имеет следующие преимущества.

1.  Привилегированные программы сильно защищены и вызывающие программы не могут их исказить.