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

У меня был случай, когда один из моих знакомых, поработав на UnixWare, заявил, что всегда любил Solaris. Конечно, это был человек, не очень много работавший в Unix. Администратор и продвинутый пользователь, конечно, разницу заметят, но это уже совсем не то, что переходить, например, с NT на Unix. А для того чтобы все варианты Unix были похожи как близнецы (или как родные братья), необходимы стандарты. Одним из таких стандартов и является Posix.

О стандартах можно говорить много. Столь же велика и тема компьютерной безопасности. Учитывая необъятность двух этих тем, в своей статье я буду говорить только о тех свойствах Unix, которые предлагаются для внесения в Posix и которые предлагают новые стандарты на механизмы защиты системы. Проект изменений, предлагаемых для внесения в Posix можно найти в Сети (см. ftp://ftp.guug.de/pub/members/truemper/posix.1e/ Posix_1003.1e-990310.pdf.bz2). Далее в этой статье вместо «проект изменений, вносимых в Posix» я буду для краткости говорить просто Posix, хотя это и несколько преждевременно.

Так что же в «старом» Unix плохо, и что предлагается добавить?

Все или ничего

В Unix при определении прав пользователей действует принцип «все или ничего». Есть суперпользователь — root, которому разрешено все. Он может исполнять любые программы, читать и писать любые файлы. Программы, которые он исполняет, могут делать любые системные вызовы. Он может создавать и удалять учетные записи пользователей, прерывать сессии пользователей, останавливать работу любого сервиса и всей системы. Одно слово — суперпользователь. Конечно, есть некоторые ограничения, но и эти ограничения легко обойти. Скажем, даже если писать в каталог ему запрещено, используя возможность записи на диск минуя файловую систему, он может написать и в этот файл.

Хуже всего то, что любая программа, которую исполняет root, пользуется всеми его правами. К каким последствиям это приводит, знает любой системный администратор, хоть раз выдававший команду «rm -rf *», находясь в каком-нибудь важном каталоге. Это же свойство открывает возможность подложить суперпользователю «троянского коня» — программу, которая кроме своих декларированных возможностей, скрыто или явно наносит какой либо ущерб системе. Именно поэтому каждый администратор старается работать от имени root как можно реже, как можно меньше.

Механизм SUID/SGID, дающий возможность пользователям временно повышать свои привилегии, тоже дает программам слишком большие полномочия. Напомню, что при исполнении программы с установленным флагом SUID, эта программа пользуется всеми правами владельца файла, а не пользователя, ее исполняющего. Ключевое слово здесь: «всеми». Зачем, спрашивается, команде passwd нужны все права root? Единственное, что она должна делать — читать и писать в файл, где хранятся пароли пользователей. Хорошо, это легко исправить существующими средствами Unix. Определяем новую группу (назовем ее, например, auth), делаем эту группу владельцем парольных файлов, разрешаем группе писать и читать эти файлы, делаем passwd программой SGID с группой auth. Это получилось. Но что делать, например, с командой mount, если мы хотим дать пользователям возможность монтировать некоторые устройства, такие как дискеты? В этом случае программе mount нужна только очень небольшая часть прав root, а мы вынуждены давать ей все? Что делать с программами-демонами, которые также вынуждены работать с root правами из-за требования небольшой части прав root? Они, конечно, могут сбрасывать на время свои суперпользовательские права и восстанавливать их, только когда эти права непосредственно требуются. Однако это свойство системный администратор контролировать никак не может и вынужден доверять автору программы. А авторы программ — тоже люди и тоже ошибаются, а иногда «ошибаются» очень правильно.

Столько, сколько нужно

Для решения этой проблемы необходим механизм, позволяющий давать определенные права на основе тех функций, которые определенный пользователь исполняет в системе. Хотелось бы, будучи системным администратором, передать часть своих прав другому человеку, и быть уверенным что он не сможет использовать их не по назначению. В одном случае пользователь — просто пользователь информационной системы, в другом — он должен иметь возможность запускать и останавливать систему, в третьем — он должен иметь возможность осуществлять резервное копирование системы. В зависимости от этого он должен иметь разные возможности и, желательно, чтобы этим мог управлять системный администратор, а не только программист, разрабатывавший систему. С другой стороны, даже имея все права системного администратора, хотелось бы, чтобы административные привилегии были более управляемыми. Хотелось бы, сказав rm -rf * в корне, и, даже будучи системным администратором, получить «permission deny». Достичь этих целей можно разными путями. Новый Posix предлагает механизм «возможностей» (capabilities).

Для реализации механизма возможностей предлагается ввести набор флагов, которые будут определять возможности определенного процесса. Так, для проведения резервного копирования необходимо иметь возможность читать файлы, которые закрыты на чтение согласно определенным для них прав доступа. Например, пользователь запустил команду fbackup, сам пользователь не имеет права читать файлы (например, с помощью vi), а fbackup, которую этот пользователь запустил — может. Поэтому пользователь может осуществлять резервное копирование. Для того, чтобы смонтировать файловую систему, программа должна иметь возможность выполнить привилегированный системный вызов mount, а другая программа, запущенная тем же самым пользователем, может этих возможностей не иметь. И так далее. Каждой такой возможности в соответствие поставлен флаг. Если он у процесса установлен — процесс имеет эту возможность, не установлен — не имеет.

Но опыт использования Unix показывает, что чем меньше времени программа пользуется определенными правами, тем лучше для безопасности. Даже при использовании механизма SUID предусмотрено, что программа может не все время пользоваться всеми правами. Поэтому вводится понятие потенциальной и эффективной возможности. При определении прав процесса используются только эффективные возможности. Процесс может управлять своими эффективными возможностями, сбрасывать их или устанавливать, но только в том случае, если у него есть соответствующие потенциальные возможности. Например, определено, что процесс потенциально может читать чужие файлы, и он пробует их прочитать. У него ничего не получается, если не поднят соответствующий флаг эффективной возможности. Но он может установить соответствующий флаг и тогда получить реальные возможности прочитать необходимые файлы. А потом его сбросить и опять забыть, как читаются чужие файлы. И так сколько угодно раз, пока не сбросит флаг потенциальной возможности, потому что сбросить он его может, а вот поднять вновь — нет. Предполагается, что программы будут писаться таким образом, чтобы обладать установленными эффективными возможностями как можно более короткое время.

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

Т.е., с одной стороны, возможности привязаны к файлу с исполняемой программой. Исполняемый файл может иметь атрибуты, определяющие, какие эффективные и потенциальные возможности будет иметь процесс, исполняющий эту программу. Этот механизм немного напоминает механизм SUID, т.е. работу с программами, пользующимися не правами пользователя, который их запустил, а правами владельца файла.

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

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

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

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

В то же время набор флагов наследуемых возможностей процесса определяет максимум тех возможностей, которые могут получить потомки этого процесса. Например, если пользователь исполняет программу из файла, в атрибутах которого установлена возможность монтирования файловых систем (скажем, mount), но у программы оболочки пользователя sh в наследуемых возможностях нет права монтирования, программа mount этих прав не получит. Устанавливать наследуемые права может только привилегированная программа.

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

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

Другой важной функцией многопользовательской системы является определение доступности различных ресурсов различным пользователям. В Unix разделение доступа основано на так называемом «избирательном» (discretional) принципе присвоения прав доступа к объектам (файлам, например). Согласно этому принципу пользователь сам регулирует, кто может читать или писать файлы, владельцем которых он является. В настоящее время считается, что определение прав доступа на избирательном принципе не всегда удовлетворяет всем потребностям защиты. Предлагается ввести дополнительные механизмы (об этом несколько позже). Однако даже механизм избирательного присвоения прав реализован в Unix недостаточно гибко. При определении прав доступа в Unix различают только владельца файла, группу, владеющую файлом (владелец не обязательно входит в эту группу) и всех остальных. Однако при реальной работе часто бывает необходимо дать доступ к какому-либо файлу одному из своих коллег. Стандартным в этом случае решением является обращение к системному администратору с просьбой создать новую маленькую группу, в которую входит только владелец файла и тот, кому надо дать доступ. Иногда такое решение работает очень хорошо, а иногда плодится большое число маленьких групп, разобраться в которых чрезвычайно сложно. А сложность в понимании приводит к возможности ошибок. Кроме того, при таком решении резко возрастает нагрузка на системного администратора, ведь именно ему приходится разбираться с группами, особенно если они достаточно динамичны.

Списки доступа

Очевидно, необходимо введение более гибкого механизма разграничения доступа. Такой механизм известен, это так называемый механизм списков контроля доступа (ACL — access control list). Это давно известный механизм и многие коммерческие реализации Unix уже его имеют.

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

Итак, Posix предусматривает введение так называемых списков ACL. Многие из читающих, вероятно работали в системах, которые имеют механизм ACL или, по крайней мере, знают, что это такое. В принципе, стандартный механизм Unix с различением владельца, группы и остальных пользователей, также является механизмом списков ACL, только с предопределенными элементами; это делает его недостаточно гибким. Наличие списков ACL с переменным числом элементов позволяет определить права доступа к файлу с точностью до отдельного пользователя или группы пользователей. Для сохранения совместимости со старым, добрым Unix, в Posix элементы ACL разделяются на обязательные и расширенные. Обязательные элементы — это хорошо известные нам владелец, группа и остальные, с соответствующими правами по отношению к данному файлу. Расширенные элементы — это либо пользователь и его права, либо группа и ее права. Стандартная Unix-программа chmod меняет обязательные атрибуты, а новая программа setacl — и обязательные, и расширенные. И совместимость соблюдена, и новые свойства добавлены.

Классно. Теперь можно предоставить коллеге доступ к какому-нибудь своему файлу, просто добавив к базовым правам доступа расширенные права, написав регистрационное имя коллеги и назначив права. Но не все так просто, а если мне надо сделать, чтобы все файлы, создаваемые в рамках одного проекта имели такой элемент в списках доступа и, следовательно, давали доступ моему коллеге? Можно, конечно, сказать программе, которая создает эти файлы, чтобы она ставила эти права. А если это старая программа, которая вообще ничего не знает об ACL? И вообще эта программа не берет в голову, какие ей права на файл поставить, надеется на работу стандартного для Unix-механизма umask? Надо на каждый файл отдельно ставить эти права вручную или скрипт написать? Для решения этой задачи вводится понятие «список контроля доступа по умолчанию». Для каждого каталога определяются списки, которые будут ставиться на все создаваемые в этом каталоге файлы. И этот механизм, в общем, тоже не новость. Здорово, и это решили.

Рассмотрим теперь следующую ситуацию. Пусть какая-нибудь старая программа хочет поставить на файл замок (lock) и для этого поставит на него права 000, т.е. запретит любой доступ. Это, конечно, добровольное блокирование: просто остальные программы ждут, когда они смогут начать писать в этот файл или читать из него; подобные права используются просто как семафор. Но теперь в этом каталоге определены списки ACL по умолчанию, и доступ оказывается открытым. И пойдут все программы, использующие этот замок, писать одновременно. Не работает замок. Для решения подобных проблем введен еще один обязательный элемент — маска. (Обязательный в том смысле, что если есть расширенные атрибуты, должна быть и маска.) Этот элемент определяет максимальные права доступа, которые могут быть получены благодаря любым элементам списка ACL, кроме владельца и «остальных». Т.е., если я предоставляю права на запись какому-либо пользователю или группе, но эти права не даны в маске, пользователь или группа этого права не получат. А chmod при изменении прав доступа для группы файла (например, chmod g+rx) меняет не обязательный элемент ACL, соответствующий группе, а маску; в правах для группы по команде ls -l показывается именно маска. Нетрудно понять, что chmod 000 в этом случае действительно запретит, как это и ожидается, любой доступ к файлу, а chmod 700 оставит доступ только владельцу файла, вне зависимости от любых расширенных списков ACL. Таким образом, за счет небольшого усложнения логики удается решить проблемы совместимости со старыми программами. И логика chmod в какой то степени сохраняется. Действительно, теперь, меняя права доступа с помощью chmod для владельца, мы получаем смену прав именно для владельца. А вот меняя с помощью chmod права для группы, мы меняем максимальные права для тех, кто обозначен в расширенных списках ACL, — для некоторой виртуальной группы. Таким образом, с помощью расширенных списков ACL я смогу предоставить все права (rwx) тем, с кем я работаю, а потом с помощью chmod работать с ними, как с группой и соответственно эти права ограничивать, просматривая эти права обычной командой ls -l.

Стоит поздравить того, кто все это придумал!

Контроль по принуждению

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

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

Таким образом, Unix нуждается в дополнительном механизме разграничения доступа. Такой механизм известен давно и в течение определенного времени используется, оставаясь, тем не менее, достаточно экзотическим. Речь идет о механизме принудительного контроля доступа (mandatory access control).

Рис. 1. Схема

Принудительный контроль доступа основан на присвоении каждому файлу метки, определяющей его важность. Такая же метка присваивается и каждому процессу. Очень важным является то, что метка присваивается каждому процессу и каждому файлу. Если метка не присваивается явно, должна быть присвоена метка по умолчанию. Между метками определено отношение частичной упорядоченности, так называемое доминирование. Так пусть между метками A, B, C, D и E определены отношения как на рис. 1. Тогда мы можем говорить, что метка A доминирует над меткой A, B, C, D, E, метка В — над метками B, C, D и E, метка C и метка D доминируют над меткой E, а вот про соотношение между C и D мы сказать ничего не можем, поэтому такое отношение и называется частичным упорядочиванием. По определению, метка доминирует над самой собой. Метки и отношения между ними определяются на стадии разработки системы в зависимости от целей, стоящих перед разработчиками. Так для госучреждений, например, могут быть определены метки типа «не секретно», «конфиденциально», «секретно», «совершенно секретно» и «особой важности». Между этими метками определено очевидное линейное отношение доминирования. Для примера на рис. 1 можно определить, что метку A имеют файлы директора банка, B — его заместителя, а C и D — файлы менеджеров, которые занимаются взаимодействием с разными клиентами. Меткой E помечаются файлы, содержащие информацию, с которой можно знакомить всех, например, системные файлы, файлы с рекламой и так далее.

При использовании принудительного контроля доступа действует следующее правило: процесс может читать из файла, только если метка, присвоенная данному процессу, доминирует над меткой этого файла. И наоборот, он может записать в файл, только в случае, если метка файла доминирует над меткой процесса. И читать, и писать в один и тот же файл можно, если его метка равна метке процесса. Таким образом, директор банка, имея метку A, может читать все файлы в системе, так как его метка доминирует над всеми метками в системе. В то же время, поскольку его метка доминирует над всеми метками, то он сможет писать в файлы только с меткой A. Таким образом, ни одна программа, даже запущенная директором банка, не сможет, прочитав информацию из файла директора, записать ее в файл, доступный для чтения конкуренту. Аналогично, заместитель директора сможет писать только в свои файлы и файлы директора. Заметим, что так как между метками C и D не определено соотношение, процесс с меткой C ни при каких условиях не сможет читать или писать файл с меткой D и наоборот. При таком построении системы информация гарантированно движется только вверх.

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

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

При введении принудительного контроля доступа в Unix возникают интересные задачи. Так, каталог в Unix — тоже файл, и для него определяется метка. Корневой каталог должны иметь возможность читать все процессы; значит, он должен иметь метку, над которой доминируют все остальные метки в системе. Для примера, приведенного на рис. 1, метка E и будет выполнять такую функцию. Аналогично, для любого вложенного каталога, для того чтобы обеспечить доступ к файлам в каталоге, необходимо, чтобы ко всем каталогам в маршрутном имени был доступ на чтение. Т.е. в нормальном случае уровень секретности возрастает с уровнем вложенности. Это означает, что должна быть возможность разместить в каталоге ссылки на файлы с меткой, доминирующей над меткой каталога. Таким образом, имя файла и содержимое файла будут иметь разные метки. Поскольку процесс с меткой, доминирующей над меткой каталога, не может писать в этот каталог (действительно, имя файла тоже информация), то для того чтобы создать в этом каталоге более секретный файл, пользователь должен создать новый процесс с меньшей меткой, создать файл, а потом поставить на него другую метку с помощью привилегированной программы. Либо системный администратор изначально создает структуру каталогов с заданными метками, и пользователь будет писать в уже существующий каталог с соответствующей меткой. Но существуют еще и каталоги, которые традиционно считаются открытыми для всех. Это, например, каталог /tmp. Существуют специальные файлы, про которые предполагается, что каждая программа может его и читать и писать, например /dev/null. Все это вопросы, ответов на которые стандарт Posix не дает и которые придется решать разработчикам конкретной системы.

Вот еще одна проблема для разработчиков. Информация, касающаяся файла в Unix, хранится на диске в трех местах. Про два мы уже поговорили: это собственно информация, содержащаяся в файле, и имя этого файла, хранящееся в каталоге. Но есть еще и атрибуты файла, такие как размер, время доступа и другие, хранящиеся в специально отведенном месте, так называемом описателе inode. Возникает вопрос, если на содержимое файла должна быть установлена метка B, какие метки должны быть установлены на атрибуты файла? Вопрос, казалось бы, достаточно прост. Обычно, для того чтобы посмотреть атрибуты файла в Unix, не обязательно иметь возможность читать из этого файла, достаточно иметь соответствующий доступ к каталогу. Значит можно (в соответствии с традицией Unix) поставить на атрибуты файла ту же метку, что и на каталог. Но в случае принудительного контроля доступа это не хорошая идея. Пусть программа, работающая с высокой меткой (запущена директором банка и имеет метку A), хочет передать информацию злоумышленнику. И пусть этот злоумышленник имеет право читать каталог, в котором находится файл с меткой A, и, следовательно, как мы предположили, атрибуты файла. Тогда эта программа может передавать желаемую информацию, манипулируя атрибутами файла, например временем модификации. Изменился этот файл в последнюю минуту — 1, не изменился — 0. Это, конечно, медленный канал, но не будем забывать, что цена информации велика. Поэтому пришлось установить, что атрибуты файла должны иметь ту же метку, что и содержимое файла. Таким образом, их имеет право читать только программа, метка которой доминирует над меткой файла. При подобном построении системы может сложиться странная для Unix ситуация: пользователь имеет все права для доступа к каталогу, но не может получить информацию о атрибутах файла, и это в принципе может смутить некоторые старые программы, которые ничего не знают об принудительном контроле доступа. Но ничего не поделаешь — безопасность требует жертв, и здесь стандарт не может ничего сделать для сохранения совместимости.

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

Куда течет информация

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

Именно для подобных целей и предназначен механизм автоматической маркировки файлов и программ. Подчеркну, что этот механизм отделен от любых других механизмов, обеспечивающих управление привилегиями или распределяющих доступ. Для работы данного механизма вводится еще один набор меток. Каждый процесс и каждый файл получает свою метку. Как только процесс считывает информацию из файла, его метка модифицируется. Значение новой метки высчитывается из значения старой метки процесса и значения метки файла. Как только процесс пишет в файл, значение метки файла меняется. И опять значение новой метки высчитывается исходя из старой метки файла и метки записывающего процесса. Но что значит «высчитывается»? Стандарт ничего об этом не говорит, оставляя и этот вопрос на усмотрение разработчиков системы.

Рассмотрим простейший пример реализации этого механизма. Пусть новая метка определяет секретность информации, хранящейся в файле. Таким образом, метки как бы дублируют уже определенные метки принудительного контроля доступа. Возвращаясь к рис 1, пусть в системе уже определены метки принудительного контроля доступа A, B, C, D и E. Допустим также, что в нашей системе есть некоторое количество файлов с определенными для них метками. Промаркируем информацию, хранящуюся в этих файлах согласно меткам. Т.е. информация, хранящаяся в файле с меткой E, получит дополнительную метку EI, информация, хранящаяся в файле с меткой D, получит дополнительную метку DI и т.д. Как только процесс считает информацию из файла, он получает метку с наибольшей секретностью из старой метки процесса и метки файла. Например, процесс с меткой BI, читая из файла с меткой AI, получит новую метку AI. Как только процесс пишет в файл, информация в файле получает наибольшую из старой метки файла и метки процесса. Так, если процесс с меткой AI запишет в файл с меткой BI, новый файл получит метку AI. Еще раз напомню, что метки информации не используются при определении прав доступа, и процесс с меткой AI имеет право писать в файл с меткой BI.

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

В данном случае, поскольку информация читалась только из файлов с метками CI, информацию можно свободно рассекречивать. Важно только гарантированно знать, что туда писалась информация исключительно из файлов с метками C. Как раз эту работу для нас и выполнила маркировка информации. Проанализировав метку файла, и убедившись, что файл содержит только информацию с меткой CI, мы свободно можем присвоить файлу метку C для принудительного контроля доступа.

Аудит

И, наконец, о последнем механизме, который описывается стандартом Posix.

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

Отсюда и требование к системе, чтобы она содержала механизм протоколирования событий в системе — аудит.

С аудитом, казалось бы, нет никаких проблем. Многие варианты Unix имеют свой аудит. Обычно система аудита устроена так: регистрируются системные вызовы по выбору того, кто настраивает систему, и некоторые программы имеют право приостанавливать регистрацию их системных вызовов и вместо этого производят свои записи в аудит. Что тут еще надо? Ну конечно, надо бы программку, которая все это обрабатывает. И такая программка, конечно же, в этих системах есть. Но в большинстве систем программы обработки журнала аудита весьма примитивны. Кроме того, в каждой системе набор регистрируемых событий и формат записи свой. А ведь современный системный администратор вынужден работать в таком зверинце операционных систем! Кроме разнообразных вариаций на тему Unix, у него есть еще и всякие другие продукты. Хотелось бы иметь общий набор регистрируемых событий, общий формат записи аудита. Тогда информацию со всех узлов в сети можно будет обрабатывать на одной машине, одной программой. И тогда, возможно, появятся и хорошие программы для обработки аудита они будут работать на всех вариантах Unix и будут дешевле.

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

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

Заключение

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

Мы поговорили об очень небольшом наборе механизмов, обеспечивающих безопасность. Даже такой поверхностный разговор о всех механизмах потребовал бы гораздо больше места, чем предоставляют рамки журнальной статьи. Именно поэтому я ограничился разговором о тех относительно новых для Unix механизмах, которые предлагается стандартизировать новым проектом Posix.

Часть этих механизмов (ACL и аудит) так или иначе уже реализовано в большинстве коммерческих вариантов Unix. Они реализованы, так как их наличие требуется для класса защиты C2. Реализация принудительного контроля доступа открывает Unix дорогу в группу классов защиты B. Однако следует заметить, что само по себе наличие механизмов не гарантирует удовлетворения всех требований соответствующего класса защиты. В свою очередь удовлетворение всех требований класса защиты не гарантирует безопасного использования системы. Но это уже тема для другой статьи.

Геннадий Махметов (gena@ph-elec.phsys.msu.su) - научный сотрудник физического факультета МГУ (Москва)