Свежий номер №6 (383) / Linux от АНБ

Эрл Беберт, boebert@swcp.com 15.02.2001

Copyright © 2001 Specialized Systems Consultants, Inc.

Оригинальная публикация: NSA Linux Release by Earl Boebert // Linux Journal.

Пер. с англ. и комментарии М.О.
Публикуется с любезного разрешения SSC, Inc. и автора.
Все права соблюдены.


За прошедшие годы я убедился в двух вещах: во-первых, общественная необходимость в высоконадежных программах (high assurance software) постоянно растет, а во-вторых, рынок до сих пор не смог их предложить.

Я хочу представить общий обзор технологии, лежащей в основе релиза Linux от АНБ.

Более глубокий замысел состоит, однако, в том, чтобы заставить сообщество открытых исходников активнее экспериментировать с этим релизом - и чтобы к тому времени, когда общество поймет, что такого рода вещи действительно очень нужны, было что предложить.

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

Надежность

Под «надежностью» (assurance) я понимаю процесс обретения уверенности в том, что устройство не выкинет какой-нибудь безвкусной шутки после того, как вы его запустите или подключите к сети.

Операционная надежность (подход «черного ящика») следует из опыта использования подобных устройств: если они еще никого не убили, вы можете быть уверены в их относительной безопасности. Полагаться на надежность такого рода - значит рисковать столкнуться однажды с весьма неприятным сюрпризом.

Формализованная надежность (подход «белого ящика») - это попытки обеспечить уверенность за счет некоей комбинации свойств дизайна, анализа и тестирования. Отсутствие неприятных сюрпризов не гарантируется, но обычно их бывает меньше (или, по крайней мере, в них легче разобраться постфактум).

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

Релиз АНБ использует идею принудительной типизации доступа (ПТ - Type Enforcement, TE 1), выдвинутой Диком Кейном (Dick Kain) и мной более пятнадцати лет назад в ходе исследовательского проекта, посвященного системам высокой надежности. Поддержка анализа и тестирования заложена в ее дизайн как неотъемлемое свойство, способствующее надежности. Наша старая статья  [1] описывает все это подробно, а сейчас я сконцентрируюсь на определении того, какие разработки в этой области должны быть проделаны на коротком и на длинном этапе.

Что такое принудительная типизация

Мне было проще всего объяснить, что такое ПТ, Батлеру Лэмсону (Butler Lampson): «Это лэмсонова матрица доступа, представленная, в целях эффективности, как классы эквивалентности».

Лэмсонова матрица доступа (Lampson Access Matrix) - это способ моделирования защищенности системы, позволяющий дедуцировать последствия реализации той или иной политики. Это двумерная матрица с активными сущностями (субъекты, процессы, потоки), отложенными по одной оси, и пассивными (объекты, файлы, сегменты) - по другой. Пересечение столбца и колонки определяет операции, которые соответствующая активная сущность может выполнить над пассивной. Такие матрицы описаны в работе  [2], входящей в классику компьютерной безопасности и все еще заслуживающей изучения.

Это теория, а вот как она реализуется на практике. Объектам-данным придается атрибут «тип», а процессам - атрибут «домен». По идее (хотя не всякая реализация идет этим путем), закладывается первичная матрица, по осям которой отложены типы и домены. Для каждой пары (тип, домен) эта матрица определяет права доступа. Для начала это могут быть права на чтение, запись и исполнение.

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

О первой писали Дэн Стерн (Dan Sterne) с коллегами 2, разработавшие так называемую принудительную типизацию и доменификацию, устанавливающую соответствие между иерархией файлов и матрицей доступа. Стоит разобраться в том, что они сделали, прежде чем работать над развитием релиза, представленного АНБ, - просто чтобы не изобретать велосипед.

А вот вторая - междоменная коммуникация - наиболее остро нуждается в инновациях.

Что с этим делать прямо сейчас

Во-первых, о том, чего не нужно с этим делать: не нужно пытаться строить ОС общего назначения для управления ресурсами, автоматически распространяя ее заявленные характеристики (безопасность, защищенность и любые другие) на каждое приложение, которому случится быть запущенным в ней. Это то, чего пытались достичь публикацией Оранжевой книги 3 - мы уже там были, мед и пиво пили… а в рот не попало.

Многолетние размышления о ПТ привели меня к более рафинированному определению: ПТ - это такой механизм интеграции приложения и используемого им менеджера ресурсов, который снижает вероятность неожиданной некорректности поведения. На самом деле, это средство построения специализированных устройств высокой надежности.

Получить немедленную выгоду от опубликованного АНБ кода можно, использовав его для построения пуленепробиваемых Web-серверов, почтовых серверов, серверов БД и т. п. Берете релиз, выкидываете все ненужные вашему приложению функции, прописываете политику типизации и запечатываете в коробку. («Что? И больше не будет сообщений типа «Ошибка в Sendmail открывает несанкционированный привилегированный доступ?» Куда катится мир?!»)

Для того чтобы это сделать, нужны две вещи: во-первых, умение распознать некорректность поведения, а во-вторых, нужно знать структуру самого приложения. Первое - это вопрос политики, и я вряд ли чем-то смогу помочь. А вот что касается второго, то ПТ можно рассматривать как механизм управления потоками данных, и именно структура потоков данных нуждается в определении.

Одну из структур, на реализацию которых была направлена ПТ, мы с Диком 4 назвали «надежными каналами» (assured pipelines). Она описывает случай, когда одна функция (например, криптопреобразования) должна с необходимостью выполняться между предшествующей (например, редактированием сообщения) и последующей (его отправкой).

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

Что с этим делать в перспективе

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

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

Но вначале (сказал он, подождав, пока перестанут шикать и свистеть) замечу, что надежность всегда достигается за счет производительности. Ситуация похожа на ту, которую описал один аэродинамик из Saab, в те давние дни, когда разрабатывался автопилот JA-37: боевой самолет располагает ограниченным количеством энергии, и задача проектировщика состоит в том, чтобы оптимально распределить ее в условиях конкуренции требований к скорости, высоте, дальности полета и вооруженности. То же самое относится к циклам процессора и памяти.

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

Анализ надежности покоится на рассуждении, основанном на спецификации системы, и достоверность описания многого стоит. В пределе, анализу должен подвергаться объектный код, однако, если есть надежный компилятор, можно анализировать и исходники.

Раньше это называли «статическим анализом» 5 и строили для его выполнения соответствующие инструменты. И использовали их.

Вы ищете дерево зависимостей, или то, что [Дэвид] Парнас ([David] Parnas) назвал «иерархией использования»: выявление модулей, на надежность которых полагается остальной код, уровень за уровнем. Выявление зависимостей сущностно важно для правильного тестирования и рекомпозиции кода. Необходимо расшивать порочные круги, когда A зависит от B, а B зависит от A (а также более длинные), поскольку они приводят к формированию «сгустков» кода, который приходится анализировать и тестировать как целое. (Упражнение для читателя: покажите, что невытесняющее мультипрограммирование 6 с необходимостью приводит к образованию порочных кругов.)

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

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

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

Пользователь: С ОС творится что-то странное.
Вендор: Воспроизведите.
[Пауза.]
Пользователь
: На этот раз все нормально.
Вендор: Ну и?

Летчику-испытателю, которому только что пришлось катапультироваться после выхода машины из-под контроля, не стоит советовать уложить парашют и попробовать еще раз. Лучше сесть и разобраться в том, что случилось, почему случилось и как предотвратить повторение этого случая. Рано или поздно такой подход распространится за пределы инженерии механических устройств, и проектировщикам ОС стоит подготовиться.

На каждый из упомянутых трех вопросов чертовски трудно ответить, если система управляется прерываниями. Такому управлению есть альтернативы, например, структура приоритетов (rate structure) - доведенная до предела идея циклического планирования (round-robin scheduling), или гибридная синхронная передача сообщений (post-and-wait), которую отдокументировали, выбив на камне где-то в Калифорнии, и которую стоило бы откопать и использовать как начальную точку для исследований в области планирования.

Степень неадекватности распространенной модели планирования подтверждается уже самой возможностью атаки на отказ (DoS). Я готов к тому, что по сети можно разослать такое количество пакетов, которое сделает сетевой интерфейс временно недоступным. Чего я никогда не приму, так это того, что любая атака на любой интерфейс должна заставлять всю ОС переворачиваться вверх тормашками и с грохотом падать.

А еще есть проблема стека. Какая жестокая шутка: это самое старое и самое глупое уязвимое место за всю историю ОС.

Идея смешения данных, указателей и управляющих инструкций в одном стеке восходит к началу шестидесятых и компилятору с Алгола GIER, разработанному Питером Науром (Peter Naur). Бурное это было время: [Эдсгар] Дейкстра ([Edsgar] Dijkstra) только что доказал сущностную идентичность магазинного стека и инфиксной нотации, и когда я учился в летней школе по разработке компиляторов у Наура, я думал, что обобщенная модель стека (он называл ее «монитором») - неимоверно крутая штука. Но потом мы поняли, что это не так.

Исправить ситуацию можно, начиная с нескольких точек. Лобовой подход - разделить стеки данных и команд.

Другой - держать в стеке только указатели, а параметры и буферы организовать вне кучи. Наилучшим его воплощением было бы внедрение адекватных дескрипторов, с полями базы и границ допустимых значений. Можно даже добавить бит «недоступно» и реализовать по-настоящему динамическое связывание. Вот это идея! А кто бы раньше мог подумать, что когда-нибудь придется обновлять софт на ходу! А можно заглянуть еще глубже в историю Multics и откопать там, например, идею организации подоменных стеков с выделенными процедурами «шлюзования», отвечающими за порядок в доме. («Что за шум там?» - «Это мальчишки-скриптовальщики, сэр, молящие о спасении их маленьких душ».)

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

Разработчики, желающие почерпнуть стимулы к размышлениям из истории («Да, Вирджиния, и до Web жили люди» 7), могут начать с изучения работы  [3].

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

Возможно, из этого воспоследует появление какого-нибудь ПО высокой надежности. Старика это весьма обрадовало бы.

[i38352]


Литература

[1] (обратно к тексту) Boebert, W. E., Kain, R. Y., A Further Note on the Confinement Problem. // Proc. 30th Annual Carnahan Conference on Security Technology, 1966, pp. 198-203, IEEE 0-7803-3537-6-9/96.

[2] (обратно к тексту) Lampson, Butler W. Protection. // Mar. Proc. 5th Princeton Symp. on Information Sciences and Systems, 1971, pp.437-443. В январе 1974 г. перепечатана в: ACM SIGOPS OSR 8(1), pp.18-24.

[3] (обратно к тексту) Kain, R. Y. Advanced Computer Architecture : A Systems Design Approach. Prentice Hall. ISBN: 0130077410.


Дополнительная литература

[Д1] Lee Badger, Daniel F. Sterne, David L. Sherman, Kenneth M. Walker, Sheila A. Haghighat. Domain and Type Enforcement UNIX Prototype // USENIX Security Symp., 1995

[Д2] Lee Badger, Daniel F. Sterne, David L. Sherman, Kenneth M. Walker, Sheila A. Haghighat. Practical Domain and Type Enforcement for UNIX // 1995 IEEE Symposium for Security and Privacy

[Д3] Зегжда Д. П., Ивашко А. М. Основы безопасности информационных систем. - М.: «Горячая линия-Телеком», 2000.


1 (обратно к тексту) - В отечественной литературе обычен перевод этого термина как «политика типов» (см., например, [Д3]), что несколько размывает различие между вопросами определения политики и ее технической реализации. - Здесь и далее прим. пер.
2 (обратно к тексту) - См. [Д1, Д2]. Краткое изложение по-русски см. [Д3, сс.188-195]. Один из коллег Стерна, Ли Бэджер (Lee Badger), активно участвует в проекте selinux.
3 (обратно к тексту) - «Оранжевая книга» - Trusted Computer Systems Evaluation Criteria. US Dept. of Defence, 1993.
4 (обратно к тексту) - Ричардом Кейном.
5 (обратно к тексту) - Термин «статический анализ» и сегодня используется в практике отечественной сертификации ПО для обозначения анализа кода в противоположность «динамическому анализу» хода его исполнения. - Ред.
6 (обратно к тексту) - Невытесняющее мультипрограммирование (non-preemptive multiprogramming) - имитация многозадачности системами, не обладающими таким свойством.
7 (обратно к тексту) - Аллюзия на известную (в англоязычном мире) колонку, написанную в 1897 году редактором газеты The New York Sun Фрэнсисом Чёрчем (Francis P. Church) в ответ на письмо восьмилетней девочки в редакцию. Колонка начиналась словами: «Да, Вирджиния, Санта-Клаус действительно существует».


Эрл Беберт
boebert@swcp.com
 


<< По мозгам
Все материалы номера
Патч национальной безопасности >>