Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Скачиваний:
90
Добавлен:
23.02.2015
Размер:
6.18 Mб
Скачать

3.3. Защита памяти

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

• контроль доступа к сегментам и страницам, который обеспечивается описанной ниже системой привилегий;

• контроль использования сегментов и страниц, который вводит ряд ограничений на возможные виды обращения к ним: запрещение записи в сегменты данных (страницы), разрешенные только для чтения, за­прещение чтения сегментов программ (страниц), разрешенных только для выполнения, запрещение обращения к незагруженным (отсутст­вующим) сегментам и страницам и ряд других;

•ограничение набора выполняемых команд в зависимости от уровня привилегий выполняемой программы (выделение привилегированных команд).

Для защиты информации, хранящейся в сегментах памяти, исполь­зуется система привилегий, которая регулирует доступ к тому или иному сегменту в зависимости от уровня его защищенности и от степени важно­сти (привилегированности) запроса. В процессорах Р6, так же как в более

ранних моделях 80286, 80386, 80486, Реntium установлены четыре уровня привилегий РL (privilege level), которые задаются номерами от 0 до 3. Наи­более привилегированным является уровень с меньшим номером. Сте­пень защищенности сегмента так же имеет четыре уровня, которые схема­тически представляются в виде вложенных колец защиты (рис. 3.10).

Рис. 3.10. Уровни привилегий и защиты

Соответствующие уровни защищенности иллюстрируются на примере сегментов программ. Наименее защищенными (привилегированными) являются прикладные программы пользователя, для которых выделяется уровень с номером РL=3. Уровни с номерами РL=0, 1, 2 отводятся для системных программ (супервизора), которые можно разделить на три уровня в зависимости от требований к их защи­щенности. Наиболее защищенная часть — ядро операционной системы (ОС) имеет уровень РL=0. В ядро входит часть ОС, обеспечивающая ини­циализацию работы, управление доступом к памяти, защиту и ряд других жизненно важных функций, нарушение которых полностью выводит систе­му из строя. Основная часть программ ОС (утилиты) должна иметь уровень РL=1. К уровню РL=2 обычно относят ряд служебных программ ОС, например, драйверы внешних устройств, системы управления базами данных, специализированные подсистемы программирования и другие.

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

В соответствии с уровнями привилегий и защищенности установле­ны следующие правила доступа для сегментов программ и данных.

1. Данные из сегмента, имеющего уровень защиты РL могут быть выбраны программой, имеющей такой же или более высокий уровень привилегий.

2. Сегмент программ (процедура), имеющий уровень защиты РL может быть вызван программой, имеющей такой же или более низкий уровень привилегий. Различные варианты вызова сегментов программ описаны ниже.

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

Уровень привилегий дескриптора DPL. задается битами 5,6 в бай­те доступа дескриптора (см. рис.3.5). Указывает уровень защищенности сегмента, то есть номер кольца защиты, к которому он относится.

Уровень привилегий запроса RPL задается битами 0,1 селектора, загружаемого в сегментный регистр. Этот уровень устанавливается выполняемой программой, ко­торая с помощью данного селектора обращается к памяти системы.

Текущий уровень привилегий CPL задается битами 0,1 селектора, размещенного в регистре сегмента программ СS. Определяет уровень привилегий выполняемого в настоящий момент сегмента программы.

Напомним, что меньшее значение DPL, RPL CPL соответствует бо­лее высокому уровню привилегий (защиты). Наиболее защищенный сег­мент имеет значение DPL=0, наименее защищенный — DPL=3. Для наи­менее привилегированных программ пользователя CPL=3, наиболее привилегированные программы ядра ОС имеют CPL=0.

Процессор имеет специальную команду ARPL используемую для коррекции значения RPL селектора. Данная команда вы­полняет сравнение двух младших битов селекторов, предварительно за­груженных в адресуемые командой регистры или ячейку памяти. Результа­том команды является селектор, в котором эти биты имеют максимальное из значений, заданных в исходных селекторах.

Обращение к сегментам программ и данных в защищенном режиме производится с учетом описанной выше системы привилегий. При этом правила обращения зависят от типа сегмента.

Обращение к сегментам данных производится с помощью селек­торов, загружаемых в регистры DS, ES, FS, GS. При обращении анали­зируются значения RPL селектора и CPL текущей программы. Эффектив­ный уровень привилегий для запроса данных в этом случае определяется максимальным значением из RPL и CPL.

Обращение к запрашиваемому сегменту данных разрешается, если его уровень защиты DPL >= max(RPL CPL). Нарушение этого правила при обращении вызывает исключение ти­па #GР "нарушение общей защиты".

Таким образом, задавая определенное значение RРL в селекторе, можно управлять доступом текущей программы к сегментам данных, имеющим различный уровень защиты. Например, при RРL=0 доступ к дан­ным будет определяться значением СРL текущей программы. Если задать RРL=3, то при любом СРL программа может обратиться только к наименее защищенным сегментам данных, относящимся к кольцу 3.

Обращение к сегменту стека выполняется путем загрузки селек­тора в регистр SS. Этот селектор должен выбирать дескриптор сегмента с разрешенной записью, то есть бит 1 в байте доступа должен иметь значе­ние W=1 (см. рис.3.5,б). Значения RРL и DPL должны быть равны СРL. Нарушение этих правил (обращение к сегменту, для которого W=0; использование селекторов и дескрипторов, имеющих значения RРL и DPL, не равные СРL) приводит к исключению типа #GР. При обращении к дес­криптору, имеющему значение бита присутствия Р=0 (отсутствующий сег­мент) возникает исключение типа #SS "ошибка обращения к стеку".

Обращение к сегментам программ (передача управления) реализуется при выполнении команд межсегментного перехода JMP, вы­зова подпрограммы CALL и возврата из подпрограммы RЕТ, прерывания INT и возврата из прерывания IRET. Правила обращения к сегментам программ зависят от значения бита подчиненности С в байте доступа дескриптора ( рис. 3.5,а).

Обращение к подчиненным сегментам, для которых установлено значение С=1, допускается только из программ, имеющих такой же или более низкий уровень привилегий. Таким образом, в программах с теку­щим уровнем привилегий СРL могут выполняться межсегментные команды JMP, CALL с передачей управления подчиненному сегменту, имеющему DPL= < CPL. При такой передаче значение СРL сохраняется, то есть со­храняется уровень привилегий исходной (вызывающей) программы.

Обычно бит подчиненности С=1 устанавливается для сегментов, ко­торые могут использоваться программами с различными уровнями приви­легий, например для системных библиотек. При этом подчиненные сег­менты должны размещаться в кольце защиты с номером, соответствую­щим максимальному уровню привилегий (минимальному значению СРL) вызывающих программ.

Обращение к неподчиненным сегментам, имеющим значение С=0, с помощью команд JMP и CALL допускается только в случае, если уро­вень привилегий текущей программы равен уровню защиты сегмента: СРL = DPL.

Обращение через шлюз используется для вызова неподчиненных сегментов программ с более высоким уровнем привилегий, чем текущая программа. Для реализации таких вызовов служат специально установ­ленные точки входа в программы, которые называются шлюзами (или вентилями) вызова. Менее привилегированная процедура может вызвать более привилегированную, обращаясь к ней через дескриптор шлюза вы­зова, определяющий доступную точку входа. Этот способ обращения по­зволяет программам пользователя обращаться за обслуживанием к операционной системе. При этом допускаются обращения только к определенным процедурам, которые санкционируются путем введения в систему соответствующего шлюза. Тем самым исключается возможность несанкционированного обращения менее привилегированных процедур к более привилегированным, что позволяет защитить их от возможных ис­кажений.

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

Для вызова более привилегированной программы команда CALL или JMP должна обратиться к хранящемуся в LDT дескриптору шлюза вы­зова, формат которого показан на рис.3.11,а.

Байты 7,6 Байт 5 Байт 4

31 16 15 14 13 12 11 8 7 5 4 0

Относительный адрес А31-16

Р

gDPL

1

TYPE

000

WC

Селектор сегмента

Относительный адрес А15-0

Байты 3,2 Байты 1,0

Рис. 3.11. Формат дескриптора шлюза

В байтах 2,3 дескриптора шлюза содержится селектор вызываемого сегмента программы, а байты 0, 1, 6, 7 задают относительный адрес ко­манды, являющейся точкой входа в эту программу. Байт доступа 5 со­держит бит присутствия Р и поле уровня привилегий дескриптора шлюза gDPL которые имеют такое же назначение, как и в дескрипторах сегмен­тов. Поле ТУРЕ в байте доступа шлюза (табл. 3.2) содержит код 0100, если вызываемая программа написана для 16-разрядного про­цессора 80286, или код 1100, если программа написана для 32-разрядных процессоров 386, 486, Pentium, Р6. Пяти битовое поле WC в байте 4 указы­вает количество параметров, которые переносятся из стека, обслуживаю­щего программы с текущим уровнем привилегий СРL, в стек, используе­мый программами с уровнем привилегий вызываемой программы. Параметры представляют собой 32-разрядные слова (16-разрядные для процессоров 80286), число которых может составлять от 0 до 31.

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

Значения RPL селектора, вызывающего шлюз, и СРL текущей программы должны быть меньше или равны значению gDPL в байте дос­тупа шлюза. Таким образом, дескриптор шлюза должен иметь такой же или меньший уровень привилегий, чем запрос и текущая программа: gDPL >= (DPL,СРL).

Значение gDPL шлюза вызова должно быть больше или равно уровню CРL вызываемого сегмента программ: gDPL>=DPL.

Вызываемый сегмент программ должен иметь такой же или более высокий уровень привилегий DPL чем текущая программа: DPL <= CPL.

Последнее из перечисленных правил реализуется при выполнении команды CALL с обращением к любым видам сегментов программ (подчи­ненным и неподчиненным) и команды JUMP, вызывающей подчиненный сегмент. Если команда JUMP осуществляет переход к неподчиненному сегменту программ, то необходимо выполнение правила DPL=CPL.

Примеры реализации этих правил при различных комбинациях зна­чений RPL, CPL gDPL DPL иллюстрируются на рис.3.12.

Если эти правила выполняются, то после вызова дескриптора шлю­за в сегментный регистр СS загружается селектор — байты 3,2 этого дес­криптора. Этот селектор выбирает из LDT дескриптор вызываемого сег­мента программы. При этом младшие два бита (поле RPL) селектора иг­норируются, а вместо них в регистр СS в качестве СРL заносится значение DPL из дескриптора вызываемого сегмента. В регистр ЕIР из дескриптора шлюза загружается относительный адрес входа в программу — байты О, 1, 6, 7 (для программ процессора 80286 в IР загружаются байты 0, 1).

Если вызванная программа имеет другой (более высокий) уровень привилегий, чем текущая, то при выполнении команд JMP, CALL с исполь­зованием шлюза вызова производится переключение стека. Выполняется обращение к стеку, организованному для программ с уровнем привилегий, соответствующим уровню вызванной программы. В этот стек последова­тельно вводятся старые значения SS и ЕSР; параметры, переносимые из старого стека; старые значения СS и ЕIР. Число переносимых параметров определяется полем WC (рис. 3.11), причем выбираются последние из параметров загруженных в старый стек. Последующие ячейки стека ис­пользуются для хранения новых параметров. Переключение стека произ­водится автоматически путем загрузки в регистры SS и ЕSP из сегмента состояния задачи ТSS нового содержимого, которое определяет началь­ный адрес стека для программ данного уровня привилегий.

Необходимо отметить, что переключение стека реализуется только при обращении к неподчиненным сегментам программ( имеющих в деск­рипторе значение бита С=0). Если через шлюз осуществляется вызов под­чиненного сегмента программ (значение бита С=1), то переключение стека не производится.

По команде RET производится восстановление из стека старого со­держимого регистров СS, ЕIР (IР) и SS, ESP (SP). Таким образом, одно­временно с возвратом к исходной программе происходит, и возвращение к старому стеку. Команда RET проверяет значение CPL и два младших разряда извлекаемого из стека старого содержимого СS, определяющие уровень привилегий программы, к которой осуществляется возврат. Ко­манда выполняется только в том случае, когда значение этих битов боль­ше или равно СРL, то есть возврат осуществляется к программе с таким же или меньшим уровнем привилегий.

Рис. 3.12. Варианты реализации передачи управления с использованием

шлюза вызова

Нарушение командами JMP, CALL RET указанных правил обращения к сегментам программ вызывает исключение типа #GР (нарушение защиты).

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

Команда LSL загружает в регистр значение границы сегмента, кото­рый выбирается таким же образом, как командой LAR. Используя полу­ченное значение этой границы, процессор может организовать контроль формирования адреса, чтобы избежать прерывания программы при вы­ходе за пределы адресуемого сегмента.

Команды VERR, VERW проверяют возможности записи в сегмент данных и чтения из сегмента программ, устанавливаемые соответствую­щими битами дескрипторов. Если запись или чтение разрешены, то устанавливается значение признака ZF=1 в регистре EFLAGS. Предваритель­ный анализ значения этого признака позволяет избежать запрещенных видов обращения к данному сегменту, вызывающих прерывание текущей программы. Адресация необходимого сегмента при выполнении команд VERR, VERW производится таким же образом, как и командой LAR.

Реализация ввода — вывода с помощью команд IN, OUT, INS, OUTS в защищенном режиме производится с учетом CPL выполняемой программы. Величина CPL сравнивается с значением поля IOPL в регистре EFLAG. Ввод-вывод производится только при выпол­нении условия CPL <= IOPL. Нарушение этого условия вызывает исключе­ние типа #GР, если доступ к адресованному командой порту не разрешен специальной битовой картой ввода/вывода, задаваемой при решении от­дельных задач.

Соседние файлы в папке УчПосбЧ-3