РАСЧЕТНО-ПОЯСНИТЕЛЬНАЯ ЗАПИСКА
к курсовому проекту на тему:
Security-Enhanced Linux — линукс с улучшенной безопасностью
Содержание
2.1.2. Используемая терминология.
2.1.4. Задачи целевых политик.
2.1.5. Компилирование и загрузка целевой политики.
2.1.6. Редактирование целевой политики.
2.1.7. Написание новой политики для демона.
2.2.1. Понятие и структура процесса.
2.2.3. Создание новых процессов.
3.3. Политика для созданного демона.
3.4. Демонстрация работы демона.
Введение
Мир операционных систем предоставляет пользователям достаточно большое их количество. ОС выступает в качестве программы, которая управляет ресурсами вычислительной системы и процессами, использующих эти ресурсы при вычислениях.
Условно ОС можно разделить на серверные и пользовательские, обслуживаемые и нет, встраиваемые (Embedded) и загружаемые, ОС реально времени с гарантированным временем отклика на события и нет. Также раздел можно провести по платформе, для которой предназначена ОС, по назначению, по занимаемому объему и т.д.
Приведем список наиболее часто используемых ОС:
DOS (MS-DOS, DR-DOS и их клоны);
OS/2;
Windows 3.1x;
Windows 9x;
Windows NT (Windows 2000, Windows XP, Windows 2003 Server);
Embedded Windows;
Windows CE;
Mac OS;
Mac OS X;
Семейство UNIX;
FreeBSD, OpenBSD, NetBSD;
Linux;
Embedded Linux;
BeOS;
QNX;
PalmOS;
Symbain;
Данная работа посвящена ОС Linux. Это POSIX-совместимая (благодаря этому стандарту любое приложение можно перенести из одного представителя семейства UNIX в другой) UNIX-подобная система. На сегодняшний день это самая распространенная бесплатная ОС с открытым исходным кодом. При ее разработке из мира семейства UNIX старались взять все лучшее. Благодаря участию десятков тысяч разработчиков программного обеспечения и координации их действий через Интернет Linux и ПО для нее развивается очень динамично, ошибки и различные проблемы в ПО, как правило, исправляются в считанные часы после их обнаружения. Все, что справедливо для семейства UNIX, справедливо и для Linux. Широчайшая поддержка аппаратных платформ, малая требовательность к аппаратным ресурсам, масштабируемость, поддержка мультипроцессорных систем, кластеризация, поддержка распределенных вычислений, десятки графических оболочек – и это далеко не все. И при всей мощи это достаточно дружественная ОС, способная работать как на мощнейшем сервере, так и на домашнем ПК.
Поскольку в данной работе нас интересует Linux, а ОС Windows 9x или Windows NT/2000/XP установлены приблизительно на 90% PC-совместимых персональных компьютеров, то все сравнения в дальнейшем будем производить относительно этих трех ОС.
В идеале ОС должна удовлетворять, по меньшей мере, семи достаточно противоречивым требованиям:
Быть легкой в освоении и дружественной к пользователю (User Friendly).
Быть мощной и универсальной (способной работать на любом оборудовании).
В ней все должно настраиваться и довольно просто.
Она должна быть очень надежна (в идеале – сверхнадежна).
Занимать как можно меньше места.
Разработчики моментально должны реагировать на проблемы, обнаруженные в процессе эксплуатации.
Под нее должен быть широкий выбор ПО.
Теперь оценим ОС на соответствие вышеперечисленным требованиям:
Windows 3.1x – удовлетворяет п.1 с оговорками, частично п.3 и п.5, удовлетворяет п.7.
Windows 9x – удовлетворяет п.1, частично п.3, безусловно удовлетворяет п.7;
Windows NT – удовлетворяет п.1, п.2 (с учетом одноплатформенности и непомерных требований к аппаратному обеспечению), п.3 и п.4 с оговорками, безусловно удовлетворяет п.7;
Linux – безусловно удовлетворяет всем пунктам, особенно п.2, п.3, п.6 и п.7;
Linux по всем параметрам на порядок превосходит Windows. Единственное, в чем Windows пока впереди – это в количестве и разнообразии прикладного ПО. Надо, признать, что чаще всего все же с Linux и UNIX-подобными системами работают либо администраторы сетей, либо программисты.
Факт остается фактом: системное администрирование и программирование – сложная задача. UNIX-системы исключительно мощны, а подобное достоинство всегда сопровождается повышением степени сложности.
Разработчики ОС Linux не придавали особого внимания вопросам защиты, и по этой причине ни одну из UNIX-систем нельзя сделать по-настоящему безопасной. На протяжении всей истории UNIX-систем их регулярно взламывают, портят, увечат, а также незаконно присваивают и модифицируют данные. С появлением сети Интернет начался новый этап «холодной войны».
Кое-что для повышения надежности UNIX-системы, разумеется сделать можно. Но полная нирвана безопасности все же недостижима, ибо в модели UNIX есть несколько фундаментальных изъянов, которые невозможно устранить.
ОС UNIX ориентирована прежде всего на удобство в применении, что отнюдь не предполагает естественность и простоту ее защиты. Эту систему разрабатывали исследователи для исследователей, и концепции UNIX заключаются в обеспечении удобного манипулирования данными в сетевой многопользовательской среде.
Стратегия защиты в UNIX, по сути, предполагает всего два статуса пользователя: пользователь, не обладающий привилегиями, и суперпользователь. Такая возможность UNIX, как выполнение программ с установленным битом смены идентификатора пользователя, обеспечивает привилегированный доступ ко все вычислительным ресурсам системы. При этом из-за незначительных огрехов в защите может быть поставлено под угрозу нормальное функционирование системы как таковой.
Большинство административных функций реализовано вне ядра, поэтому к ним можно без особого труда получить доступ с целью просмотра и внесения изменений. Это открывает широкое поле деятельности для хакеров.
В системе защиты UNIX существует множество всем известных изъянов, которые никогда не будут устранены, и просчетов, которые одни производители устранили, а другие – нет. Помимо этого, многие организации на одну - две версии программного обеспечения отстают: либо по причине сложности локализации, либо потому, что они не заключили с поставщиком договор о сопровождении системы. Если производитель заткнул маленькую дырочку в системе защиты, это не означает, что окно для взлома исчезнет на следующий же день.
Раньше считалось, что по мере выявления и устранения брешей безопасность операционной системы UNIX будет непрерывно повышаться. Суровая реальность оказалась иной. Сложность системного программного обеспечения стремительно растет, хакерская деятельность все больше приобретает черты организованной преступности, компьютеры оказываются все более тесно связанными посредством сети Internet. Война переходит в новые измерения, и, похоже, победителей не будет.
Существует формулу:
Чем безопаснее системы, тем труднее в ней работать пользователям.
1. Постановка задачи
Linux традиционно считается хорошо продуманной с точки зрения безопасности операционной системой, и попытки поставить под сомнение этот тезис обычно вызывает недоумение. Однако, следует помнить, что Linux унаследовала систему безопасности Unix, реализованную еще в 70-х годах и не во всем соответствующую требованиям сегодняшнего дня.
Чтобы сделать систему безопаснее специалисты выявили ряд аспектов, которые нужно учитывать при настройки и администрировании ОС Linux. Взглянем на основные источники неприятностей:
Человеческий фактор. Пользователи (и администраторы) системы являются ее слабейшим звеном.
Ошибки в программах. За много лет в ПО UNIX было выявлено несметное число ошибок, связанных с безопасностью. Используя незаметные программистские прочеты или архитектурные зависимости, хакерам удавалось манипулировать системой по своему усмотрению.
Открытые двери. Многие компоненты программного обеспечения можно сконфигурировать в режиме полной или не очень полной безопасности. К сожалению, по умолчанию чаще всего принимается второй вариант.
Проще всего устранить проблемы последней категории, хотя их может быть очень много и не всегда очевидно, что именно следует проверять.
В данной работе рассматривается одно из возможных решений проблемы безопасности Linux. Остановимся на использовании SELinux - набора технологий расширения системы безопасности Linux.
В данной работе будет продемонстрировано, как с помощью технологии SELinux поставить ограничения для демона, запущенного суперпользователем.
2. Конструкторская часть
2.1 Обзор SELinux
2.1.1 Введение в SELinux
SELinux (Security-Enhanced Linux) - набор технологий расширения системы безопасности Linux. Сегодня основу набора составляют три технологии: мандатный контроль доступа, ролевой доступ RBAC и система типов (доменов). SELinux включает модули ядра, разделяемые библиотеки для создания приложений, использующих особенности SELinux, утилиты и другие файлы. SELinux можно установить с любым дистрибутивом Linux, начиная с ядра версии 2.2.x.
Архитектурно SELinux подчиняется трем принципам, способствующим максимально безболезненной интеграции SELinux в Linux-системы:
параллельное сосуществование с классической системой безопасности Linux;
независимость от классической системы безопасности Linux;
приоритет запретов классической системы безопасности Linux над SELinux (то, что запрещено классической системой безопасности, не может быть разрешено SELinux).
SELinux зародился в недрах Агентства национальной безопасности США (непосредственно разработкой занимались компании Network Associates и MITRE) и был выпущен в виде общедоступного открытого программного продукта в декабре 2000 года. Для систем с ядрами 2.2 и 2.4 он выпускался в виде заплаты, а с введением модуля Linux Security Module (LSM) в ядре 2.4 была выпущена версия SELinux для LSM. В ядре 2.6 он также поддерживается посредством LSM. Кроме того, многие элементы SELinux были включены в само ядро. Однако, если операционная система использует ядро 2.6, это еще не означает, что там обязательно есть SELinux или что эту систему легко активировать. Это означает только, что установить SELinux будет проще.
В настоящее время SELinux полностью поддерживается в дистрибутивах RedHat Enterprise Linux 4, Fedora Core 2 и 3, Gentoo Hardened Linux, в каждом из которых имеется параметр включения SELinux во время установки ОС.
SE Linux обеспечивает большую безопасность вашей системы. Пользователям могут быть назначены предопределённые роли таким образом, что они не смогут получить доступ к файлам и процессам, которыми они не владеют. При этом не существует эквивалента операции "chmod 777". Это отличается от обычной системы Unix-привилегий в том, что определённые пользователем роли, или контексты безопасности в которых они находятся, имеют ограниченный, но более управляемый доступ к файлам и другим ресурсам. Рассмотрим пользовательский файл .rhosts на обычной Unix системе. Если всем дать доступ на запись в этот файл, тогда кто угодно сможет зайти в систему и причинить массу неприятностей. Используя SE Linux, вы можете контролировать возможность пользователя изменять права доступа в своему файлу .rhosts, а кроме того запретить другим людям писать в этот файл даже после того, как владелец это разрешил.
Частый вопрос, это как связаны права доступа SE Linux и стандартные права Unix. Когда вы выполняете какую-либо операцию, в первую очередь проверяются права доступа Unix. Если они разрешают выполнить операцию, тогда проверяются права SE Linux. Только тогда операция будет разрешена или запрещена. Но если права доступа Unix запрещают операцию, то проверка прав SE Linux не производится, а операция запрещается.
Рассмотрим другой пример. Допустим, есть ошибка в программе /usr/bin/passwd, которая позволяет выполнить команду chmod 666 /etc/shadow. В этом случае вступают в действия права SE Linux, которые предотвратят неавторизированный доступ к файлу.
2.1.2 Используемая терминология
Cущность (identity)
Сущность в SE Linux это не то же, что и традиционный идентификатор пользователя (Unix uid, user id). Они могут сосуществовать в одной системе, но их смысл совершенно разный. Сущность в SE Linux формирует часть контекста безопасности, который задает домены, в которые можно войти. Т.е. что собственно можно сделать. Сущность SE Linux может иметь одинаковое с именем пользователя символьное представление (чаще всего так и есть), но важно понимать, что это две разные вещи. Выполнение команды su не меняет сущности пользователя в SE Linux.
Пример:
Непривилегированный пользователь test выполняет команду id (в SE Linux) и видит свой контекст безопасности:
context=test:user_r:user_t
Часть контекста "test" представляет сущность. Теперь, пользователь test выполняет su, чтобы получить привилегии пользователя root, и вызывает id, и видит, что контекст всё ещё:
context=test:user_r:user_t
то есть, контекст остался прежним и не изменился на контекст пользователя root. Однако, если сущность test разрешает доступ к роли sysadm_r, и пользователь это сделает (введя команду newrole -r, детальнее команда рассматривается ниже), и снова выполнит id, то увидит уже:
context=test:sysadm_r:sysadm_t
Итак, сущность осталась той же, но роль и домен (второе и третье поле соответственно) изменились. Такой стиль работы с сущностью обеспечивает возможность идентификации пользователя. Ключевым моментом в безопасности системы является то, что сущность пользователя определяет какие роли и домены могут быть использованы.
Субъекты, объекты и политики.
Тремя важнейшими концепциями структуры безопасности SELinux являются субъекты (subject), объекты (object) и действия (action). С точки зрения SELinux всю работу системы можно описать как выполнение субъектами действий над объектами. Субъектами считаются процессы, действующие как от имени определенных пользователей, так и самостоятельно (серверные процессы). Объектами являются, прежде всего, объекты файловой системы (файлы, каталоги, ссылки), процессы (когда один процесс-субъект выполняет операции с другим процессом, второй процесс выступает в роли объекта), а также дескрипторы файлов (в том числе сокеты, что повышает безопасность работы с сетью) и объекты межпроцессного взаимодействия, не связанные с дескрипторами файлов. Действия в SELinux — это любые операции, которые субъект может выполнить над объектом. Собственно говоря, основная часть работы системы безопасности как раз и заключается в принятии решения о том, имеет ли право данный субъект выполнить данное действие над данным объектом.
Решение о допустимости или не допустимости действия принимается системой на основе политик, представляющих собой способ описания поведения системы безопасности, абстрагирующийся от таких низкоуровневых понятий как векторы доступа (аналоги масок доступа в обычной Linux-системе). Формирование политик безопасности в SELinux напоминает программирование: политика описывается на специальном языке, затем файл политики компилируется в двоичный модуль (обычно при этом используется хорошо знакомая программистам утилита make), а скомпилированный файл динамически загружается в ядро операционной системы.
Политики SELinux позволяют определить, какое решение следует принять для отдельных операций и классов операций: allow (разрешить операцию); auditallow (занести операцию в журнал, независимо от того, разрешена она или нет); dontaudit (запретить операцию, но не вносить данные о попытке выполнить операцию в журнал). Описать логику совместной работы подобных установок можно так: если операция разрешена, она заносится в журнал только в том случае, если принято решение auditallow. Если операция не разрешена, она не заносится в журнал только в том случае, если принято решение dontaudit. Таким образом, в SELinux политика разрешения операций тесно связана с их журналированием.
Домен (domain).
Каждый процесс выполняется в домене. Домен однозначно определяет привилегии процесса. По существу домен это список того, что может делать процесс, или какие действия процесс может выполнять над различными типами. Представляйте себе домен, как стандартный Unix uid. Пускай у пользователя root есть какая-то программа, для которой он выполнил команду chmod 4777 (установил атрибут setuid). Кто угодно в системе, даже пользователь nobody, может выполнить эту программу с полномочиями пользователя root, тем самым, нарушая безопасность системы. При использовании SE Linux, процесс, инициирующий переход в привилегированный домен, должен иметь роль, которой разрешено использовать этот домен, иначе процесс работать не сможет.
В качестве примеров доменов можно привести sysadm_t, домен системной администрации, и user_t, который является общим доменом для непривилегированных пользователей. Процесс init выполняется в домене init_t, а named -- в домене named_t.
Тип (type).
Тип задаётся для объекта и определяет доступ к этому объекту. Т.е. это приблизительно то же самое, что и домен, но домен относится к процессам, а тип к таким объектам, как каталоги, файлы, сокеты и т.п.
Типы объединяют группы субъектов и объектов, предоставляя им определенные права. Важной функцией типов является ограничение возможных действий субъекта над объектом. По этой причине типы иногда называют «песочницами SELinux» (SELinux sandbox).
В классических работах по безопасности систем (в частности, в модели Flask) понятия «тип» и «домен» имеют разные значения, однако в SELinux эти понятия почти синонимы. Мы говорим о типах, когда речь идет об объектах и о доменах, когда речь идет о субъектах. Домены можно описать как множества процессов (субъектов), обладающих одинаковыми правами. Например, Web-сервер Apache принадлежит домену (типу) httpd_t и обладает всеми правами, связанными с этим доменом. К этому же типу относятся файлы, к которым демон httpd должен иметь полный доступ. В SELinux действует механизм принудительного присвоения типов (type enforcement). В соответствии с этим механизмом каждый процесс оказывается принадлежащим к определенному типу (домену), определяющему права этого процесса. Очевидно, что без принудительного присвоения типов система обязательного контроля доступа не могла бы работать.
Роль (role).
Роль определяет, какие домены могут быть использованы. Домены, к которым имеет доступ пользовательская роль, предопределяются в конфигурационных файлах политики. Если роль не имеет доступа к заданному домену (в базе данных политики), то при попытке выполнить это действие доступ будет запрещён.
Роли представляют собой наборы привилегий. В любой момент времени каждый пользователь может выступать в одной из доступных ему ролей. Роли позволяют предоставлять пользователю дополнительные привилегии, не утрачивая его идентичности, как это происходит при применении команды su в традиционных системах Unix/Linux. Политика безопасности SELinux может налагать ограничения не только на количество ролей, доступных процессу, но и определять правила перехода из одной роли в другую. Не всякий переход из одной роли в другую допустим.
Очевидно, что роли гораздо чаще используются субъектами, чем объектами, а некоторые объекты (скажем, дисковые файлы), вообще не нуждаются в ролях. Таким объектам присваиваются «пустые роли», не влияющие на безопасность.
Пример:
для того, чтобы разрешить пользователю из домена user_t (домен непривилегированных пользователей) выполнять команду passwd, в соответствующем файле конфигурации указано:
role user_r types user_passwd_t
Она означает, что пользователь с ролью user_r может входить в домен user_passwd_t, т.е. может выполнять команду passwd.
Контексты безопасности.
Права субъектов и объектов определяются в SELinux контекстами безопасности, состоящими из идентификатора, роли и типа объекта. Идентификатор субъекта — это идентификатор пользователя SELinux, создавшего процесс-субъект. Идентификатором объекта является идентификатор пользователя-владельца объекта (обычно это пользователь, создавший объект).
Каждый субъект и объект идентифицируется собственным контекстом безопасности, которому соответствует идентификатор безопасности SID, причем система контекстов сильно отличается от традиционной системы учетных записей в ОС Linux поэтому возникает задача их взаимодействия. В соответствии с принципом независимости SELinux поддерживает таблицу контекстов безопасности, независимую от таблицы учетных записей Linux. При этом возможно отображение нескольких учетных записей Linux на одну учетную запись SELinux. Таким образом, изменения в учетных записях Linux не влияют на параметры безопасности SELinux.
Модель безопасности SELinux требует, чтобы каждый файл в системе был связан с определенным контекстом безопасности, поэтому в ходе установки всегда выполняется маркировка (labeling) объектов файловой системы. В соответствии с принципом независимости маркировка файлов не влияет на маски доступа к файлам, а в соответствии с принципом приоритета традиционной системы безопасности запреты, наложенные маской доступа, отменяют разрешения SELinux.
Контекст безопасности это набор всех атрибутов, связанных с объектами типа файлов, каталогов, процессов, TCP сокетов и т.п. Контекст безопасности состоит из сущности, роли и домена или типа. Увидеть свой собственный контекст вы можете, выполнив команду id в SE Linux.
Важно понимать различие между доменом и типом.
У процессов есть домен. Когда вы смотрите контекст безопасности процесса (пример команды приведен в следующем разделе), последнее поле -- это домен, например user_passwd_t (если выполняется программа passwd).
Такие объекты как файлы, каталоги, сокеты и т.п. имеют типы. Например, при выполнении команды ls --context для файла, последнее поле представляет тип, такой как user_home_t для файлов, созданных в домашнем каталоге пользователя с ролью user_r.
Вот здесь и накапливается непонимание, где есть домен, а где тип. Рассмотрим файловую систему /proc. У каждого процесса есть домен, а в файловой системе /proc для каждого процесса есть каталог. Каждый процесс имеет метку, или точнее, контекст безопасности, в применении к файлу. Но в файловой системе /proc, метка содержит тип, а не домен. Не смотря на то, что /proc представляет собой выполняющиеся процессы, содержимое /proc является файлами, а потому имеет тип, а не домен.
Вызов команды ls --context /proc выдаёт следующую информацию для процесса init (процесс с идентификатором 1):
dr-xr-xr-x root root system_u:system_r:init_t 1
Метка, или контекст безопасности, говорит нам о том, что этот файл имеет тип init_t. Но, кроме того, это значит, что процесс init выполняется в домене init_t. Каждый файл и каталог файловой системы /proc, соответствующий некоторому процессу, также следует этому соглашению, т.е. тип, указанный в выводе команды ls --context соответствует, так же, домену в котором выполняется процесс.
Ещё одним важным моментом является то, что команды chsid (изменить идентификатор безопасности) и chcon (изменить контекст) не работают на файловой системе /proc, т.к. она не поддерживает изменение меток.
Контекст безопасности файла, например, может варьироваться в зависимости от домена, который создал файл. По умолчанию, новый файл или каталог наследует тип от родительского каталога, однако вы можете задать иную политику.
Пример:
пользователь sasha создаёт файл test в своем домашнем каталоге. После чего выполняет команду ls --context test и видит:
-rw-r--r-- sasha sasha sasha:object_r:user_home_t test
Теперь sasha создаёт файл в каталоге /tmp с именем tmptest и выполняет команду ls --context /tmp/tmptest. Теперь результат такой :
-rw-r--r-- sasha sasha sasha:object_r:user_tmp_t /tmp/tmptest
В первом примере контекст безопасности включал тип "user_home_t", который является типом по умолчанию для домашнего каталога непривилегированного пользователя с ролью user_r. После выполнения второй команды ls --context, видим, что тип теперь user_tmp_t. Это тип по умолчанию для файлов, созданных процессами домена user_t в каталоге типа tmp_t.
Переход (transition).
Решение о переходе, определяет контекст безопасности, который будет назначен запрошенной операции. Есть два основных типа переходов. Первый тип, это переход домена процесса. Он используется при выполнении процесса определённого типа. Второй, это переход типа файла, который применяется при создании файла в определённых каталогах.
Пример:
Пример перехода второго типа (переход типа файла) приведён в предыдущем разделе "контекст безопасности". При выполнении команды ls --context вы можете видеть тип файла (т.е. user_home_t и user_tmp_t в вышеприведённом примере). Итак, при создании пользователем файла в каталоге /tmp происходит переход в тип user_tmp_t и новый файл помечается соответствующим образом.
Рассмотрим теперь пример перехода домена процесса. Запустите ssh из-под обычного пользователя, или, точнее, из домена user_t (помните, что для проверки текущего контекста безопасности можно использовать команду id). Теперь выполите ps ax --context и найдите строку с данными о команде ssh. Полагая, что это сделал пользователь sasha, она, в частности, увидит:
sasha:user_r:user_ssh_t
Процесс ssh выполняется в домене user_ssh_t потому что программа имеет тип ssh_exec_t, а роль user_r имеет право доступа в домен user_ssh_t.
Все ниже изложенные операции и команды будут рассмотрены для Fedora Core 4 (выбор именно этого дистрибутива будет пояснен чуть ниже, в соответствующей главе).
SELinux входит в стандартную установку данного дистрибутива, поэтому не пришлось делать перекомпиляцию ядра для включения поддержки данной технологии и установки дополнительных модулей и заплаток на ядро. В Приложении 1 приведен краткий алгоритм установки поддержки SELinux в более старых версиях Fedora Core.
2.1.3 Виды политик
В SELinux доступны для использования два вида политик: целевая политика (targeted policy) и строгая политика (strict policy).
Fedora Core 4 не содержит поддержки строгих политик, при этом вы можете использовать этот тип в Fedora Core 3. Впервые целевая политика была представлена в составе Fedora Core 3. Ее задача заключается в предоставлении дополнительной защиты некоторым наиболее часто используемым демонам: ttpd, dhcpd, mailman, named, portmap, nscd, ntpd, portmap, mysqld, postgres, squid, syslogd, winbind, и ypbind при помощи внедрения Мандатного Управления Доступом (Mandatory Access Control, MAC). Подобные демоны запускаются в собственном домене, например httpd_t для httpd и named_t для named. Другие демоны в системе, для которых не написана специализированная политика, запускаются в домене unconfined_t. Демоны и системные процессы, работающие в домене unconfined_t, могут использовать только стандартный для Linux Дискреционный метод управления доступом (Discretionary Access Control, DAC), т.к. SELinux разрешает полный доступ. При использовании SELinux доступ предоставляется процессам на основе доменов, каждый домен имеет собственный разрешенный набор операций над файлами, каталогами или другими ресурсами.
Строгая политика принуждает каждую программу работать в ограниченном домене. Данный подход использовать не так просто, и задача целевой политики увеличить защищенность в наиболее важных областях, без уменьшения удобства использования.
Для определения работаете ли вы с целевой политикой, нужно сделать следующее:
Файл /etc/selinux/config должен включать строку SELINUXTYPE=targeted. Обратите внимание, что таким образом вы определяете тип политики используемой при загрузке системы. Если вы переходите с одной политики на другую, задайте переменной SELINUXTYPE значение отличное от используемой в данный момент политики до выполнения перезагрузки.
Запустите команду id, и ее вывод будет выглядеть примерно так:
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=root:system_r:unconfined_t
Последняя часть контекста безопасности root`а сообщает нам, что оболочка пользователя root запущена в домене unconfined_t, указывающем на использование целевой политики. На системах с примененной строгой политикой контекст SELinux оболочки root`а будет либо root:staff_r:staff_t, либо root:sysadm_r:sysadm_t. Вы также можете выполнить команду id -Z для вывода контекста безопасности без отображения информации о Unix UID/GID (это удобно для сценариев оболочки).
2.1.4 Задачи целевых политик
Целевая политика была разработана, т.к. строгая политика оказалась слишком сложной в использовании многими администраторами. После ее первого представления в составе Fedora Core 2, было получено множество негативных откликов о сложности ее применения. В выпуске Fedora Core 3, по умолчанию, была настроена целевая политика, и нареканий стало значительно меньше. Простой расчет подсказывает, что, по крайней мере, два миллиона людей используют Fedora Core 3, не предполагая, что они используют SELinux. Их системы выполняют то, что требуется, и они не замечают, что демонам запрещено выполнение некоторых операций - подобные действия не выполняются демонами при нормальной работе системы с типовой конфигурацией.
Основная цель разработки политик - это упрощение настройки строгой политики и лучшая настройка для начальной конфигурации, в то время как целевая политика будет наращивать количество "целей" для поддержки большего количества демонов. Можно сказать, что целевая и строка политика сближаются, т.к. строгая политика становится более простой в использовании, а целевая политика - более строгой. Но представляется маловероятным, что когда-либо в ближайшем будущем удастся объединить обе эти политики. Фундаментальная разница между строгой и целевой политиками заключается в том, что строгая политика использует возможности SELinux идентификации и ролей, а целевая - нет.
Некоторые из возможностей целевой политики вытекают из того, что множество демонов работает в домене unconfined_t. Со временем, будем надеяться, что большая часть демонов будет хорошо работать в более ограниченных доменах. Самое большое преимущество, с точки зрения удобства использования, - это отсутствие ограничивающего домена для пользовательских сессий. Поэтому, объединения строгой и целевой политик не произойдет.
2.1.5 Компилирование и загрузка целевой политики
Для изменения существующей целевой политики безопасности можно воспользоваться стандартной программой system-config-securitylevel.
Сервер httpd имеет самое большое количество параметров, т.к. он является гибко настраиваемым и конфигурация политики SELinux должна соответствовать настройке демона.
Возможно, наиболее частым использованием булевых переменных в целевой политике будет выключение защиты SELinux для демонов, которые были настроены так, что они не работают совместно с SELinux. Мы не рекомендуем использовать такие переменные. Они предоставляются в качестве аварийного варианта. Если требования бизнеса заставляют вас запустить демон в конфигурации, где SELinux не может защитить, выключение защиты для конкретного демона предпочтительнее, чем выключение защиты для всей системы целиком.
system-config-securitylevel предполагает просмотр и изменение булевых параметров для ограниченного числа демонов, т.е. дописать политику, используя данную программу, представляется для программиста невозможным.
Из вышесказанного следует, что для изменения политики разработчику придется редактировать исходный код политики, компилировать ее и загружать потом в ядро.
Исходные тексты targeted policy не поставляются вместе с дистрибутивом Fedora Core 4, поэтому их придется скачивать и устанавливать из Интернета отдельно. Чаще всего они (тексты) распространяются в RPM-пакетах.
RPM расшифровывается как Red hat linux Package Management или, по-русски, система управления пакетами для операционной системы Red Hat Linux. Говоря проще, RPM представляет из себя файловый формат, предназначенный для автоматизации процедуры инсталляции (а также обновления и удаления) новых программ на машину под управлением Linux: используя специальную утилиту с тем же названием (rpm), можно быстро установить (удалить/обновить) на свой компьютер любую программу, распространяемую в виде RPM-файла. Команды и пример работы с RPM-пакетом можно посмотреть в Приложении 2.
Имя пакета с исходными кодами целевой политики будет иметь вид: selinux-policy-targeted-sources-<номер_версии>.noarch.rpm
После установки исходные коды можно будет найти в директории: /etc/selinux/targeted/src/policy/
Для компиляции политики нужно сделать следующее:
cd /etc/selinux/targeted/src/policy/ (Перейти в директорию с исходными кодами).
make <make_policy_target> (Программа make запускает на исполнение так называемые MakeFile – некоторый аналог командных файлов BAT в Windows)
make install (Устанавливает политику в систему, но не загружает в ядро)
shutdown –r now (Перезагрузка системы. После перезагрузки новая политика будет загружена в систему и внесенную изменения вступят в силу)
Makefile компиляции целевой политики поддерживает следующие параметры:
install – компилирует, устанавливает политику, но не загружает в ядро. Правила установленной политики вступят в силу только после перезагрузки машины.
load - компилирует, устанавливает, и полностью загружает политику в память.
reload - компилирует, устанавливает, и загружает или перезагружает политику. Перезагрузка позволяет загружать политику без перезагрузки компьютера.
policy – только компилирование политики без ее установки в систему. Используется в основном для тестирования при разработке.
relabel - повторно маркирует файловую систему, используя источники политики, расположенные в файле $SELINUX_SRC/file_contexts/file_contexts. Такая операция проделывается при установки SELinux в систему. Данный параметр не рекомендуется к использованию без крайней необходимости.
enableaudit – разрешает журналировать те правила, которые помечены как dontaudit.
После компиляции мы получаем политику в двоичном формате имя которой имеет вид: policy.<XY>, где XY – это номер версии политики. Скомпилированная политика будет находиться в корне в папке с исходными файлами.
После загрузки в систему ее можно будет найти по пути /etc/selinux/targeted/policy.
2.1.6 Редактирование целевой политики
Файлы, содержащие политики для демонов, при использовании целевой политики располагаются в каталоге /etc/selinux/targeted/src/policy/domains/program/. Файлы с исходным кодом политик, обычно имеют расширение .te и соответствуют соглашению об именовании, например syslog.te.
Политики, или .te файлы, содержат правила для соответствующих доменов. Например, syslogd.te определяет правила работы в домене syslogd_t, включая такие операции как вывод журналов на консоль, изменение и создание файлов журналов, журналирование на внешний сервер и так далее.
Файл политики должен соответствовать файлу контекстов, или файлу .fc, расположенному в /etc/selinux/targeted/src/policy/file_contexts/program/. Файл контекстов содержит список контекстов безопасности, которые должны быть применены к файлам и каталогам, используемым демоном. Например, файл named.fc включает в себя:
/var/named(/.*)? system_u:object_r:named_zone_t
/var/named/data(/.*)? system_u:object_r:named_cache_t
Первая строка сообщает нам, что каталог /var/named/ имеет тип named_zone_t. Вторая строка сообщает, что каталог /var/named/data/ имеет тип named_cache_t.
/usr/sbin/named -- system_u:object_r:named_exec_t
Сообщает нам, что исполняемый файл named имеет тип named_exec_t. Соглашение об именовании для исполняемых файлов демонов выглядит так: X_exec_t, где X - это название домена демона.
Этот подход вызывает смену домена с unconfined_t на домен демона (в нашем примере, named_t) при запуске демона. При использовании строгой политики для корректной работы демоны должны быть запущены из административной сессии (роль sysadm_r и домен sysadm_t). При использовании целевой политики, данное требование не обязательно, т.к. unconfined_t - это единственный домен для входа пользователей (администратора или обычного пользователя).
Основной файл политики для named - это named.te, который содержит правила разрешающие доступ к домену named_t и определяет домен и смену домена на него. Наиболее важная часть в файле named.te: daemon_domain(named, `, nscd_client_domain')
Она определяет домен named_t и разрешает выполнение основных операций, таких как запись pid файла в /var/run, запуск порожденных процессов, журналирование с помощью syslog и так далее. Он также имеет политику для автоматической смены домена с unconfined_t на named_t при запуске исполняемого файла с типом named_exec_t.
Создание нового домена
Чтобы создать новый домен, администратор сначала должен создать новый файл .te в директории policy/domains и записать в него надлежащие TE правила и объявления. Чтобы задать новому домену набор базовых разрешений, следует использовать следующий макрос: general_domain_access(имя домена)
Создание нового типа
Чтобы создать новый тип, администратор должен сначала добавить его объявление в конфигурацию TE. Если этот тип ассоциирован с конкретным доменом, то его объявление следует поместить в файле .te этого домена. Если же это общий тип, то его объявление может быть помещено в один из файлов директории policy/types.
Далее необходимо задать правила доступа доменов к новому типу, а также правила перехода для этого типа. После этого политика вновь компонуется и загружается при помощи команды make load. Затем новый тип можно применить к файлу, путем обновления конфигурации файловых контекстов и запуска команды restorecon для этого файла.
В качестве примера возьмем именованный канал /dev/initctl, который используется для взаимодействия с процессом init. Тип initctl_t для этого файла определен в файле policy/domains/program/init.te, как показано ниже:
type initctl_t, file_type, sysadmfile;
Так как этот файл создается во время работы, должно быть создано правило перехода типов, чтобы гарантировать, что он всегда создается с этим типом. Это правило приведено ниже:
file_type_auto_trans(init_t, device_t, initctl_t)
Два других домена нуждаются в доступе к этому объекту: домен для скриптов /etc/rc.d и домен системного администратора. Отсюда, следующие правила TE разрешений добавлены в файлы политики policy/domains/program/initrc.te и policy/domains/admin.te:
allow initrc_t initctl_t:fifo_file rw_file_perms;
allow sysadm_t initctl_t:fifo_file rw_file_perms;
Далее политика может быть перегружена с помощью make load. Администратор должен добавить следующую запись в файл policy/file_contexts/program/init.fc и применить команду restorecon для файла:
dev/initctl system_u:object_r:initctl_t
Процесс создания пользователей, ролей и правил переходов будет рассмотрен на конкретном примере.
2.1.7 Написание новой политики для демона
Мы работаем с обычным демоном под Red Hat Enterprise Linux. Это значит, что есть его инициализирующий скрипт в /etc/init.d/ и им можно управлять используя chkconfig. К примеру, эта процедура подразумевает, что вы собираетесь использовать сервисную команду для управления запуском и остановкой демона.
По этой процедуре, вы пишете политику для пакета foo и ассоциированного с ним foo-демона.
Создайте файл $SELINUX_SRC/domains/program/foo.te.
Поместите макрос вызова демона в файл: daemon_domain(foo)
Создайте файл контекста файлов: $SELINUX_SRC/file_contexts/program/foo.fc.
Поместите первый список контекстов файлов в file.fc. Вам может понадобиться добавить кое-что к нему в дальнейшем, в зависимости от нужд демона
/usr/bin/foo -- system_u:object_r:foo_exec_t
/var/run/foo.pid -- system_u:object_r:foo_var_run_t
/etc/foo.conf -- system_u:object_r:foo_conf_t
Загрузите новую политику, используя make load.
Пометьте foo-файлы: restorecon /usr/bin/foo /var/run/foo.pid /etc/foo.conf
Запустите демона, service foo start.
Просмотрите лог аудита в поисках сообщений об отказе:
grep "avc: denied" /var/log/messages > /tmp/avc_denials
cat /tmp/avc_denials
Посмотрите, что foo_t домен пытается создать сетевой сокет, это udp_socket или tcp_socket, как объект класса в отказе AVC.
avc: denied { create } for pid=7279 exe=/usr/bin/foo \
scontext=root:system_r:foo_t tcontext=root:system_r:foo_t\
tclass=udp_socket
В таком случае, добавьте макрос can_network() в foo.te: can_network(foo_t)
Продолжайте эти действия по базовым шагам, чтобы создать все правила, которые вы хотите. Каждый набор правил, добавленный к политике, может потребовать дополнительных разрешений для foo_t домена.
Запустите демона.
Прочтите AVC сообщения.
Составьте правило используя эти сообщения и свои знания, пытаясь по возможности использовать макрос.
Загрузите новую политику.
Вернитесь к началу – запустите демона.
Если демон пытается получить доступ к port_t, который связан с tclass=tcp_socket или tclass=udp_socket в логе АВЦ сообщений, вам необходимо определить, какой номер порта foo хочет использовать. Для диагностики (чтобы определить), поместите следующие правила в foo.te:
allow foo_t port_t:tcp_socket name_bind;
auditallow foo_t port_t:tcp_socket name_bind;
Продолжайте в том же духе по оставшимся AVC отказам. Когда они будут разрешены новой политикой, вы можете настроить уникальные требования для foo_t домена.
Запустив демона, определите, какой порт использует foo. Посмотрите на сообщение, разрешенное AVC и увидите, к какому порту подключен демон:
lsof | grep foo.*TCP
foo 2283 root 3u IPv6 3192 TCP *:4242 (LISTEN)
Foo-демон слушает порт 4242
Удалите общее правило port_t, заменив его специальным правилом для нового порта, основанным на домене foo_t.
type foo_port_t, port_type;
allow foo_t foo_port_t:tcp_socket name_bind;
Добавьте эту строку в $SELINUX_SRC/file_contexts. Это зарезервирует порт 4242 для домена foo_t:
ifdef(`foo.te', `portcon tcp 4242 system_u:object_r:foo_port_t')
2.2 Процессы в системе UNIX
2.2.1 Понятие и структура процесса
Процесс – это абстракция, применяемая в UNIX для описания выполняющейся программы. Это системный объект, посредством которого можно контролировать обращения программы к памяти, процессору и ресурсам ввода-вывода.
Компоненты процесса.
Процесс состоит из адресного пространства и набора структур данных, содержащихся внутри ядра. Адресное пространство представляет собой совокупность страниц памяти (базовые блоки размером, как правило, от 1 до 8 Кб), которые ядро выделило для выполнения процесса. В него загружается код процесса и используемые им библиотеки функций, переменные, стек и различная вспомогательная информация, необходимая ядру во время работы процесса. Поскольку в UNIX поддерживается концепция виртуальной памяти, страницы адресного пространства процесса в конкретный момент времени могут либо находиться в физической памяти целиком или частично, либо вообще отсутствовать там.
В структурах данных ядра хранится различная информация о каждом процессе. К наиболее важным относятся:
идентификационная информация о процессе;
статус процесса (неактивен, приостановлен, выполняется и т.п.);
информация для планировщика;
информация для организации межпроцессорного взаимодействия;
ссылки и связи процесса;
информация о времени исполнения и таймеры;
информация об используемых процессом ресурсах файловой системы;
информация о выделенном процессу адресном пространстве;
контекст процесса (информация о состоянии регистров процессора, стеке и т.д.)
Идентификатор процесса (PID).
Каждому новому процессу, созданному ядром, присваивается уникальный идентификатор (Process ID, PID). Большинство команд и системных вызовов, работающих с процессами, требуют указания конкретного идентификатора, чтобы был ясен контекст операции. Идентификационные номера присваиваются процессам по порядку по мере их создания. Когда номера заканчиваются, ядро сбрасывает счетчик в единицу и снова присваивает их по порядку, пропуская те идентификаторы, которые еще используются.
Идентификатор родительского процесса (PPID).
В UNIX нет системного вызова, который создавал бы новый процесс для выполнения конкретной программы. Вместо этого существующий процесс должен клонировать сам себя, чтобы породить новый процесс. Путь, по которому осуществляется клон, может отличаться от пути выполнения породившего его процесса.
Исходный процесс в терминологии UNIX называют родительским, а его клон – порожденным или дочерним. Помимо собственного идентификатора, каждый процесс имеет атрибут PPID (Parent Process ID), который равен идентификатору родительского процесса, породившего данный процесс.
Идентификатор пользователя (UID) и идентификатор группу (GID).
UID (User ID) – это идентификатор пользователя, создавшего данный процесс. Вносить изменения в процесс могут только его создатель (владелец) и пользователь root.
GID (Group ID) – это идентификатор группы, к которой относится владелец процесса.
Приоритет и значение nice.
От приоритета процесса зависит, какую долю времени ЦП он получит. Ядро применяет динамический алгоритм назначения приоритетов, учитывающий, сколько времени ЦП уже использовал процесс и сколько времени он ожидает своей очереди. Кроме того, учитывается заданный административным путем так называемый фактор уступчивости (устанавливается с помощью команды nice), определяющий, в какой степени программа может «делиться» процессором с другими программами. Чем выше значение nice, тем «уступчивее» программа.
Управляющий терминал.
Большинство процессов имеют связанный с ними управляющий терминал. Он определяет базовую конфигурацию стандартных каналов ввода, вывода и ошибок. Когда пользователь вводит какую-либо команду в интерпретаторе shell, его терминал, как правило, становится управляющим терминалом процесса. От управляющего терминала также зависит распределение сигналов.
2.2.3 Создание новых процессов
Новые процессы создаются в Linux методом «клонирования» какого-то уже существующего процесса, путем вызова системных функций clone() и fork(). Процедура порождения нового процесса выполняется в режиме ядра и происходит следующим образом.
Создается новая структура в таблице процессов ядра и содержание такой же структуры старого (или текущего) процесса копируется в новую структуру.
Назначается идентификатор (PID) нового процесса. PID – это уникальное положительное число, которое присваивается каждому процессу при его рождении. Именно по этим идентификаторам система различает процессы.
Увеличиваются счетчики открытия файлов (порожденный процесс наследует все открытые файлы родительского процесса).
После того, как процесс создан, запускается выполняемая им программа с помощью одного из вариантов системного вызова exec. Параметрами функции exec является имя выполняемого файла и, если нужно, параметры, которые будут переданы этой программе. Программа из указанного файла загружается в адресное пространство процесса, порожденного с помощью fork(), счетчик команд устанавливается в начальное значение и вновь созданный процесс переходит в режим ожидания того момента, когда планировщик выделит ему время центрального процессора.
В том процессе, откуда вызывались функции fork() и exec, управление передается в точку возврата из системного вызова и выполнение этого процесса продолжается. Родительский процесс может дожидаться окончания выполнения всех своих процессов-потомков с помощью системного вызова wait.
При чтении описания процедуры создания нового процесса может возникнуть вопрос: а зачем нужно копировать в новый процесс все данные процесса-родителя (например, код программы) и не слишком ли много времени займет копирование. Ответ на этот вопрос заключается в том, что при создании копии процесса его индивидуальные данные физически никуда не копируются. Вместо этого используется метод copy-on-write (копирование при записи): страницы данных обоих процессов особым образом помечаются, и только тогда, когда новый процесс пытается изменить содержимое какой-либо своей страницы, она дублируется.
2.2.3 Выполнение процесса
Процессы могут выполняться на переднем плане (foreground) – режим по умолчанию и в фоновом режиме (background). На переднем плане в каждый момент для текущего терминала может выполняться только один процесс. Однако пользователь может перейти в другой терминал и запустить на выполнение еще один процесс, а на другом терминале еще один и т.д. Процесс переднего плана – это процесс, с которым вы взаимодействуете, он получает информацию с клавиатуры (стандартный ввод) и посылает результаты на экран (стандартный вывод).
Фоновый процесс после своего запуска благодаря использованию специальной командой оболочки отключается от экрана и клавиатуры, т.е. не ожидает ввода данных со стандартного вывода и не выводит информацию на стандартный вывод, а командная оболочка не ожидает окончания запущенного процесса, что позволяет пользователю немедленно запустить еще один процесс.
Процессы так же могут быть отложенными. Отложенный процесс – это процесс, который в данный момент не выполняется и временно остановлен. После того как вы остановили процесс, в дальнейшем вы можете его продолжить как на переднем плане, так и в фоновом режиме. Возобновление приостановленного процессора не изменит его состояния – при возобновлении он начнется с того места, на котором был приостановлен.
Надо отметить, что запущенные процессы будут строго привязаны к конкретному терминалу и если пользователь отключится от него, то процессы не смогут продолжать свою работу и будут остановлены.
2.2.4 Демоны
Среди всех процессов можно выделить несколько особых типов процессов.
Системные процессы являются частью ядра и всегда находятся в оперативной памяти. Такие процессы не имеют соответствующих им программ в виде исполняемых файлов и запускаются особым образом при инициализации ядра системы. Примерами системных процессов являются планировщик процессов, диспетчер свопинга, диспетчер буферного кэша, диспетчер памяти ядра. Такие процессы являются фактически потоками ядра.
Демоны отличаются от обычных процессов только тем, что они работают в неинтерактивном режиме. Если с обычным процессом всегда ассоциирован какой-то терминал или псевдотерминал, через который осуществляется взаимодействие процесса с пользователем, то демон такого терминала не имеет. Демоны обычно используются для выполнения сервисных функций, обслуживания запросов от других процессов, причем не обязательно выполняющихся на данном компьютере. Пользователь не может непосредственно управлять демонами, он может влиять на их работу, только посылая им какие-то задания, например, отправляя документ на печать.
Одним из главных, если можно так выразиться, демонов в системе является демон init. Как уже говорилось, init является прародителем всех процессов в системе и имеет идентификатор 1. Выполнив задачи, поставленные в ему в файле inittab, демон init не завершает свою работу – он постоянно находится в памяти и отслеживает выполнение других процессов. Надо отметить, что init становится родителем «осиротевших» процессов (дочерних процессов, у которых родитель завершил свою работу), называемых зомби, для поддержания строгой иерархии процессов в системе.
3. Технологическая часть
3.1 Выбор дистрибутива
Дистрибутив – это определенный набор программ, утилит и документации, объединенный логичной системой установки и сопровождения программных пакетов, ориентированный на определенную группу пользователей и определенный тип задач.
По большому счету, обладая достаточными знаниями, можно накачать из Интернета ядро операционной системы, загрузчик, драйверы, программное обеспечение, и все это установить вручную, а потом долго подгонять и настраивать. Но все же проще взять готовый и настроенный дистрибутив.
На сегодняшний день существуют три базовых дистрибутива и множество их потомков, причем некоторые из них уже имеют крайне мало общего с родителями.
Вот эти три дистрибутива: Debian, Read Hat, Slackware.
Поддержка технология SELinux изначально заложена только в дистрибутивы группы Read Hat, поэтому была выбрана именно она.
Группа Read Hat включает в: Red Hat, Fedora Core, KSI, Black Cat, ASP Linux, AltLinux, Mandrake, BestLinux, TurboLinux и др.
Родителем всей этой группы является дистрибутив Red Hat. На сегодня это один из самых популярных дистрибутивов. Компания Red Hat представляет несколько вариантов поставки, но все они платные. Поэтому выбор пал на дистрибутив Fedora Core – настольную версию Red Hat, отправленной в свободное плавание.
Т.к. поддержка SELinux была включена в дистрибутивы Fedora Core только с версии 2, а последняя 5-ая версия считается еще не устоявшейся, то был выбран дистрибутив Fedora Core 4.
3.2 Создание демона
Демон – это консольное приложение, т.к. он работает в неинтерактивном режиме и графическая оболочка ему не нужна.
Создание демона можно логически разделить на три части:
Создание процесса с помощью fork();
Отрыв от управляющего терминала;
Обработка сигналов или событий (совершение так называемой полезной работы)
Системный вызов fork создает новый процесс. Возвращает идентификатор дочернего процесса или 0 в случае успеха и -1 в случае ошибки (код ошибки – в переменной errno).
На языке Си создание нового процесса будет выглядеть так:
int pid = fork();
if( pid = = -1 ) // fork failed
{perror(“Невозможно создать процесс!”);
exit( 1 );}
else
{if( pid <> 0 ) exit( 0 ); // parent process exits}
Возвращаемое значение -1 свидетельствует об ошибке, но поскольку fork не имеет входных аргументов, то ошибочная ситуация никак не связана с вызывающим процессом. Единственная возможная ошибка – исчерпывание системных ресурсов, то есть либо нехватка места в файле подкачки, либо в системе исполняется слишком много процессов.
Т.к. по завершению fork оба процесса (потомок и предок) получают от него возвращаемое значение, а нам интересен потомок, то строкой «if( pid <> 0 ) then exit( 0 );» мы завершаем процесс предок (процесс-потомок получает от fork значение 0, родительский процесс – идентификатор процесса-потомка), в то время как дочерний процесс продолжает выполняться.
После завершения родительского процесса контроль над терминалом возвращается запустившей его программе (оболочке), а новый процесс, созданный функцией fork, выполняется в фоновом режиме. Однако наш процесс все еще принадлежит той же группе, что и создавший его процесс. Для того чтобы демон стал полностью независим от запустившего его терминала, новый процесс следует поместить в новую группу, а самый простой способ сделать это - создать новую сессию.
Новая сессия создается вызовом функции setsid:
pid = setsid();
if( pid = = -1 ) // setsid failed
{perror(“Невозможно создать новую сессию”);
exit( 1 );}
Теперь процесс выполняется в режиме демона.
Демон обычно несет на себе какие-либо полезные функции (например, демон диспетчера печати обрабатывает задания, отправленные на печатающее устройство), иначе его создание было бы лишено смысла.
В связи с этим было решено написать свой обработчик сигналов.
Сигналы – это запросы на прерывание на уровне процессов. В UNIX определено свыше тридцати различных сигналов. Когда поступает сигнал, возможен один из двух вариантов развития событий. Если процесс назначил данному сигналу подпрограмму обработки, то она вызывается, и ей предоставляется информация о контексте, в которой был сгенерирован сигнал. В противном случае ядро выполняет от имени процесса действия, определенные по умолчанию. Эти действия различны для разных сигналов.
Процесс вызова обработчика называют перехватом сигнала. Когда выполнение обработчика завершается, процесс возобновляется с той точки, где был получен сигнал.
Чтобы сигналы не поступали в программу, можно указать, что они должны игнорироваться или блокироваться. Игнорируемый сигнал просто пропускается и не оказывает на процесс никакого влияния. Блокируемый сигнал ставится в очередь на обработку, но ядро не требует от процесса никаких действий до явного разблокирования сигнала. Обработчик вызывается для разблокированного сигнала только один раз, даже если в течение периода блокировки поступило несколько таких сигналов.
В данной работе демон обрабатывает только сигналы SIGUSR1, SIGUSR2, SIGTERM, SIGINT, SIGQUIT. Остальные сигналы игнорируются, ну кроме сигнала SIGKILL (данный сигнал не может блокироваться и приводит к безусловному завершению процесса на уровне операционной системы).
Сигналы SIGUSR1 и SIGUSR2 не имеют стандартного назначения. Ими можно пользоваться в различных ситуациях.
При получении сигнала SIGUSR1 демон выводит на терминал информацию о программе, при получении SIGUSR2 – системную информацию(PID, PPID, UID, GID).
Все полученные сигналы протоколируется в файл с указанием времени получения сигнала.
3.3 Политика для созданного демона
По умолчанию, в целевой политике все процессы, для которых не определены собственные политики, запускаются в домене unconfined_t, в котором SELinux разрешает все.
На специальном языке программирования создадим собственную политику безопасности, разрешающую демону записывать сообщения в файл лога, который будет находиться в домашнем каталоге сущности hevil (в моем случаем это будет /home/hevil).
Для этого придется отредактировать несколько файлов, ну а потом скомпилировать и загрузить политику вышеуказанными способами.
Для начала нужно создать саму сущность hevil. Прошу заметить, что в настоящий момент мы находимся от имени пользователя root системы UNIX, но в SELinux это будет сущность (пользователь) hevil.
В конец файла /ets/selinux/targeted/policy/src/users.te нужно добавить следующее объявление:
user hevil roles { user_r hevil_r };
Данная строчка означает, что будет создан пользователь hevil с ролями user_r и hevil_r.
Чтобы можно было запустить демона под данной сущностью нужно прописать роль hevil_r в /ets/selinux/targeted/policy/src/domains/misc/hevil.te:
full_user_role(hevil); # Создание обычной пользовательской роли (назначение
# соответствующих прав)
in_user_role(hevil_daemon_t); # Объявление перехода контекста роли user_r в домен
# hevil_daemon_t
Добавим правило перехода между ролями в /ets/selinux/targeted/policy/src/rbac:
allow user_r hevil_r;
allow hevil_r user_r;
Теперь можно будет свободно переходить из роли user_r в hevil_r.
Определим макрос перехода контекста, для этого нужно отредактировать файл
/ets/selinux/targeted/policy/src/ /macros/user_macros.te, добавив следующие строки:
undefine(`in_user_role')
define(`in_user_role', `
role user_r types $1;
role staff_r types $1;
role hevil_r types $1;')
Устанавливаем с командной строки контекст для домашнего каталога /home/hevil:
find /home/hevil -print0|xargs -0 chcon --h hevil:object_r:hevil_home_t
chcon -h hevil:object_r:hevil_home_dir_t /home/hevil
Типы hevil_home_dir_t и hevil_home_t автоматически создались при создании сущности.
Для корректной работы политики необходимо создать еще тип директории с демоном, тип файла с демоном и исполняемого файла. Это достигается редактированием файла /ets/selinux/targeted/policy/src//types/hevil_types.te:
# Создание соответствующих типов
type hevil_daemon_t, domain;
type hevil_daemon_dir_t, dir_type;
type myapp_exec_t, file_type, sysadmfile, exec_type;
# Правило перехода от типа hevil_daemon_t
# к hevil_daemon_exec_t
type_transition hevil_daemon_t hevil_daemon_exec_t:{ file }
Далее установим контекст для этой директории и файла. Эти действия аналогичны, как и для домашнего каталога.
find /root/daemon -print0|xargs -0 chcon --h hevil:object_r:hevil_home_t
chcon -h hevil:object_r:hevil_home_dir_t /root/daemon
Устанавливаем правило доступа hevil_r к hevil_daemon_t и hevil_daemon_dir_t.
hevil_t - это пользовательский домен роли hevil_r (создается автоматически).
hevil_daemon_exec_t - тип исполняемого файла.
# Разрешение записи в директорию с демоном
rw_dir_create_file(hevil_t, hevil_daemon_dir_t)
# Разрешение запуска демона
can_exec(hevil_t, hevil_daemon_exec_t)
Создаем домен, в котором выполняется демон. В файл /ets/selinux/targeted/policy/src/domains/program/hevil.te вписываем строчку:
daemon_domain(daemon_t);
Данный макрос создаст стандартный домен для демона.
В этот же файл добавим еще правило для демона:
role system_r types daemon_t; #разрешен доступ суперпользователя
role hevil types daemon_t; #разрешен доступ для hevil
in_iser_role(daemon_t) #объявление перехода контекста hevil в #daemon_t
# Автоматически при запуске демона осуществляется переход
# в домен демона
domain_auto_trans(hevil_t, hevil_daemon_exec_t, daemon_t)
# Разрешаем init переходить в daemon_t при загрузке
domain_auto_trans(initrc_t, daemon_exec_t, daemon_t)
#hevil_t может перейти в daemon_t во время запуска демона
domain_auto_trans(hevil_t, daemon_exec_t, daemon_t)
#доступ к терминалу
allow daemon_t admin_tty_type:chr_file rw_file_perms;
#разрешение на запись в файл
allow daemon_t { ttyfile ptyfile }:chr_file rw_file_perms;
#разрешение писать в файл домашнего каталога
rw_dir_create_file(daemon_t, hevil_home_dir_t)
Теперь остается самый ответственный этап: компилирование и загрузка политики в память. make load
3.4 Демонстрация работы демона
Суперпользователь имеет максимальные права в системе, поэтому все процессы, запущенные от его имени будут иметь такой же уровень привилегий.
Регистрируемся в системе под root.
Запускаем демона командой ./hevil (в каталоге с программой).
Получается, что демон, запущенный пользователем root, будет имеет максимальные, ничем не ограниченные права.
С помощью команды kill [номер сигнала] [PID процесса] посылаем различные сигналы демону. Просмотрев журнал можно убедиться, что все записано в лог, т.е. демон работоспособен.
Теперь с помощью команды make load загружаем новую политику в память.
Теперь посылаем сигналы демону. Он выдаст сообщение об ошибки, что невозможно записать в файл. Это объясняется тем, что правила политики, запрещают производить запись в заданный файл, в то время как классическая система безопасности это разрешает.
Для проверки можно зайти в каталог с логом непосредственно пользователем root и убедиться, что доступ для самого пользователя в заданный каталог разрешен.
Заключение
В данной работе была освещен Security-Enhanced Linux — линукс с улучшенной безопасностью.
Достоинства данной технологии очевидны, т.к. он базируется на принципе наименьших прав, т.е. запущенному процессу дается именно столько прав, сколько ему требуется. Более того, SELinux существует параллельно с классической системой безопасности Linux, независим от нее. SELinux обрабатывает только те запросы, которые разрешены классической системой безопасности и не может разрешить то, что запрещено последней. На примере демона, запущенного от имени root (т.е. с нулевым уровнем привилегий) было продемонстрирована «сила» Security-Enhanced Linux.
Недостатком SELinux является то, что отсутствует удобное ПО по разработке своей собственной политики. Вариант редактирования исходных кодов политик, компилирования, просмотра логов и внесение изменений в код, двигаясь пошагово в цикле – является неудовлетворительным.
В настоящее время ведутся активные работы как по переводу документации SELinux на русский язык, так и попыток создания ПО.
Несомненно, нужно отметить, что LUG (Linux User Group) нашего университета тоже присоединилось к этому движению. Несколько студентов решили объединить свои силы для помощи мировому сообществу.
Ознакомиться с задачами, которые были поставлены в LUG можно на сайте http://www.selinux.ru .
Список литературы
Эви Немеет, Гарт Снайдер, Скотт Сибасс, Трент Р.Хейн «UNIX. Руководство системного администратора для профессионалов», 3-е издание
Марк Дж. Рочкинд «Программирование для UNIX. Наиболее полное руководство в подлиннике», 2-е издание
Алексей Стахнов «Linux. Наиболее полное руководство в подлиннике», 2-е издание
http://www.redhat.ru/docs/manuals/enterprise/RHEL-4-Manual/selinux-guide/index.html - официальное руководство по SELinux для Red Hat 4 [03.06.2006].
http://www.nsa.gov/selinux - Официальный сайт NSA [03.06.2006].
http://www.nsa.gov/selinux/faq.html - Официальный документ SE Linux FAQ [03.06.2006].
http://www.nsa.gov/selinux/docs.html - Опубликованные NSA материалы, отчёты и презентации. [03.06.2006].
http://www.rhd.ru/docs/articles/selinux_rhel4/ - Получите преимущества SELinux в Red Hat® Enterprise Linux® 4. Фай Кокер и Рассел Кокер. [03.06.2006].
http://gazette.lrn.ru/rus/articles/intro_selinux.html - Введение в SE Linux: новый SE Linux. Фей Кокер. [03.06.2006].
http://ru.wikipedia.org/wiki/SELinux - Материал из Википедии
http://www.osp.ru/text/302/185543/ - SELinux — система повышенной безопасности. Андрей Боровский. [03.06.2006].
Приложение 1
Установка основных пакетов SELinux для Fedora.
Пакеты RPM с новой реализацией SE Linux могут быть получены с узла ftp://people.redhat.com/dwalsh/SELinux
Эти пакеты поддерживаются Дэном Уолшем (Dan Walsh).
Для установки SE Linux на тестовой машине с дистрибутивом Fedora нужно сделать следующее:
Отредактировать файл yum.conf, чтобы он содержал такие строки:
[main]
cachedir=/var/cache/yum
debuglevel=2
logfile=/var/log/yum.log
pkgpolicy=newest
distroverpkg=fedora-release
tolerant=1
exactarch=1
[development]
name=Fedora Core $releasever - Development Tree
#baseurl=http://download.fedora.redhat.com/pub/fedora/linux/core/development/i386
baseurl=http://mirror.dulug.duke.edu/pub/fedora/linux/core/development/i386
[SELinux]
name=SELinux repository
baseurl=ftp://people.redhat.com/dwalsh/SELinux/Fedora
Установить соответствующие пакеты.
yum install policy checkpolicy policycoreutils policy-sources pam passwd vixie-cron
После этого, выполнить такие команды:
cd /etc/security/selinux/src/policy
make load
make relabel
Перезагрузить машину.
Приложение 2
Работа с RPM-пакетами.
Основные команды:
rpm -i <имя_пакета> - установка пакета
rpm -q -p <имя_пакета> -i – краткая информация о пакете: размер, автор и т.д.
rpm -q -p <имя_пакета> -il | less – просмотр информации постранично (параметр l означает, что нужно выводить содержимое данного пакета)
rpm -q -f <имя_файла> -i – определение к какому пакету относится данный файл.
rpm -U <имя_пакета> - обновление пакета (данная команда не только установит пакет, но также удалит все предыдущие версии)
rpm -e <имя_пакета> - удаление пакета
Более подробную информацию можно найти в man rpm, но вышеперечисленных команд вполне достаточно для комфортной работы.
Типичный пример использования RPM таков: предположим, нам нужно установить на машину некую игру, хранящуюся в файле tetris.rpm
Установка программы
rpm -i tetris.rpm
Через месяц вышла новая версия, tetris_1.rpm. Обновление программы:
rpm -U tetris_1.rpm
Ещё через месяц игра надоела. Удаляем её с машины:
rpm -e tetris.rpm
Управлять пакетами можно также с помощью программ Midnight Commander (mc), purp и ряда других, имеющихся практически в любом Linux-дистрибутиве.
Приложение 3
Исходный код демона.
#include <unistd.h>
#include <stdio.h>
#include <syslog.h>
#include <signal.h>
#include <time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <fcntl.h>
#include <grp.h>
#include <errno.h>
int errno;
#define PATH "hevil.l"
inline void do_packet_loop();
void fsignal(int sig);
void open_mesg();
/*Здесь идет собственно тело демона, в моем случае программа
приостанавливает свою работу до получения какого-то сигнала*/
inline void do_packet_loop()
{while(1)pause();}
// Собственный обработчик сигналов
void fsignal(int sig)
{// Открытие файла лога
FILE* fp;
if( (fp = fopen(PATH, "a")) == NULL )
{open_mesg();
_exit(0);}
// Определяем текущее время
time_t timv = time(NULL);
struct tm *local_tm = localtime(&timv);
switch(sig)
{case SIGUSR1:
fprintf(fp, "[СИГНАЛ] Получен сигнал № %d в %s", sig, asctime(local_tm));
printf("\n .:Информация о демоне:.\n Данный демон перехватывает и обрабатывает некоторые сигналы, \n протоколирует в лог все происходящие с ним события. \n GID и UID присваивается в зависимости от пользователя, запустившего данный демон.\n\n Автор: Тармолов А.В. \t Группа: ИУ7-63\n\n");
break;
case SIGUSR2:
fprintf(fp, "[СИГНАЛ] Получен сигнал № %d в %s", sig, asctime(local_tm));
printf("\n .:Системная информация о демоне:.\n PID = %d \n PPID = %d \n GID =A%d \n UID = %d\n\n", getpid(), getppid(), getgid(), getuid());
break;
case SIGTERM:
case SIGINT:
case SIGQUIT:
fprintf(fp, "[СИГНАЛ] Демоном получен сигнал завершения № %d в %s", sig, asctime(local_tm));
fclose(fp);
_exit(0);
break;
default:
fprintf(fp, "Сигнал %d не обработан(пропущен)\n",sig);
break;}
fclose(fp);}
int main(int argc,char** argv)
{chdir("/"); // Переходим на рут, чтоб не блокировать файловые системы
if(fork()) _exit(0); // Форкаемся.
FILE* fp;
if( (fp = fopen(PATH, "w")) == NULL )
{open_mesg();
_exit(0);}
// Определяем текущее время
time_t timv = time(NULL);
struct tm *local_tm = localtime(&timv);
fprintf(fp, "[СИГНАЛ] Демоном стартовал в %s", asctime(local_tm));
fclose(fp);
setsid(); // Отрываемся от управляющего терминала и переходим в фоновый режим
int j;
for(j=1; j<32; j++) /*настраиваем обработчиком всех сигналов функцию fsignal*/
signal(j,fsignal);
printf("PID = %d\n\n", getpid()); // В принципе это для отладки
do_packet_loop(); // "Демонизируем" программу. В бесконечном цикле будет ожидать сигнала.}
void open_mesg()
{perror("[daemon] Ошибка открытия файла лога!");
printf("[daemon] Демон аварийно завершает свою работу!");}