diff --git a/module2/02_mac_selinux/tasks.md b/module2/02_mac_selinux/tasks.md index e6e03af..b35c101 100644 --- a/module2/02_mac_selinux/tasks.md +++ b/module2/02_mac_selinux/tasks.md @@ -1,6 +1,6 @@ # Задания -### 0. Инициализация SELinux +## 0. Инициализация SELinux Источник: https://wiki.debian.org/SELinux/Setup @@ -10,9 +10,9 @@ $ sudo apt install selinux-basics selinux-policy-default auditd $ sudo selinux-activate $ reboot ``` -Вы установили утилиты для работы с selinux, политики по-умолчанию, созданные для популярных пакетов и демон для аудита всех действий пользователя. Активировали selinux, собрав модули политик по-умолчанию и добавив параметры запуска с selinux в grub. +Вы установили утилиты для работы с selinux, политики по-умолчанию, созданные для популярных пакетов и демон для логирования критичных с точки зрения безопасности системных событий. Активировали selinux, собрав модули политик по-умолчанию и добавив параметры запуска с selinux в grub. -После перезагрузки проверьте, что selinux активирован. К каждому файлу и процессу SELinux прикрепляет поля: пользователь, роль, домен(тип), чувствительность(степень секретности). Изменение файловой системы может занять какое-то время. +После перезагрузки проверьте, что selinux активирован. Все процессы и файлы помечены контекстом SELinux. Контекст содержит информацию, необходимую SELinux для принятия решений по управлению доступом. Контекст это поля: пользователь, роль, домен(тип), чувствительность (степень секретности). Современная реализация SELinux хранит контекст безопасности в атрибутах `xattrs`. Для установки этих атрибутов в файловой системе может потребоваться какое-то время. ``` $ sudo check-selinux-installation $ getenforce @@ -25,40 +25,904 @@ $ getenforce $ sestatus -v ``` -### 1. -Скачайте проект с примером политик SELinux c помощью `apt`: +## 1. Документация SELinux +Скомпилируйте в системе документацию из политик по-умолчанию selinux. ``` -$ sudo apt install selinux-policy-src +$ sudo sepolicy manpage -a -p /usr/local/man/man8 +$ sudo mandb +``` +или установитье её с помощью apt: ``` -Определите местоположение файла `selinux-policy-src.tar.gz` с помощью `dpkg` и распакуйте себе в домашнюю директорию пользователя. Изучите README и INSTALL. +$ sudo apt install selinux-policy-doc +``` +Проверьте, что открывается документация, например для `httpd_selinux`. + -### 2. -Установите в систему документацию для политик selinux. +## 2. Базовые команды и определения +Потренируемся далее с базовыми командами. + +### 2.1 Изучим установленные контексты безопасности + +Для начала давайте проверим контекст файла в домашнем каталоге пользователя `stud`: ``` -$ sudo sepolicy manpage -a -p /usr/local/man/man8 -$ sudo mandb +$ cd +$ ls -Z ``` -Проверьте, что открывается документация для `httpd_selinux`. Обратите внимание на строки с `ngnix`. +Флаг `-Z` присутствует в широком спектре распространенных инструментов CLI, включая `ls` и `ps`. При указании этого флага в дополнении к стандартным разрешениям UNIX, информации о пользователе и группе отображается контекст SELinux файла. + +Мы видим атрибуты: +- пользователь SELinux (`unconfined_u`), +- роль (`object_r`), +- тип (`user_home_t`), +- уровень секретности (`s` 0). -### 3. -Изучите ряд команд selinux. +Пользователь SELinux отличается от пользователя UNIX и существует исключительно для того, чтобы связать пользователя UNIX с набором ролей. Это позволяет пользователям UNIX быть ограниченными политикой SELinux. -Выведите булевые переменные для модуля `httpd_` командами `getsebool -a` и `semanage boolean -l`. По принятому соглашению, глобальные переключатели правил начинаются с `allow_` и `use_`, переключатели модулей начинаются с их названия. +В нашем случае пользователь `unconfined_u` означает, что пользователь сопоставлен с логином SELinux по умолчанию. Это означает, что пользователю разрешено запускать любое приложение, разрешенное стандартными разрешениями файловой системы. Однако, если приложение может перейти в другой домен, к нему будут применятся ограничения, задаваемые SELinux. -Выполните поиск правил на которые повлияет переключатель `httpd_enable_ftp_server`. +Список пользователей SELinux в системы можно посмотреть командами: ``` -sesearch –b httpd_enable_ftp_server –A +$ seinfo -u +$ semanage login -l ``` -Попробуйте также команды: -- `semanage fcontext -l` (информация о контекстах), -- `ls -Z` (SELinux настройки для файлов директории), -- `ps Zaux` (SELinux настройки для работающих процессов), -- `seinfo -t` (Вывести список контекстов). +### 2.2 Переход в другой домен +Чтобы продемонстрировать разницу между процессами c ограничениями и без, давайте запустим приложение, которого переход в другой домен не определён: +``` +# yes >/dev/null & +# ps -Z | grep yes +``` +Процесс `yes` помечен доменом `unconfined_t`, что указывает на то, что он по-прежнему обладает полными привилегиями `root` и может делать всё, что пожелает. + +Мы увидим другую картину для процесса `auditd`: +``` +# ps -eZ | grep audit +``` +Обратите внимание, что третье поле - `auditd_t`, означающее, что процесс `auditd` был ограничен доменом `auditd_t`. -### 4. -Хостинговые компании часто организуют для своих пользователей доступ к одной из папок в домашней директории пользователя по http по ссылке `http://site/~user/index.html`. Попробуем это повторить с политиками selinux, уменьшающими потенциальный ущерб для системы от взлома сервера. +Остановим запущенный фоновые процессы `yes` и двинемся дальше. +``` +# jobs +# kill %1 +# jobs +``` + +Изменение контекста при запуске приложения в наборе правил SELinux называется переход домена (domain transition). Пример записи правила: +``` +type_transition <текущий_домен> <тип_программы>: <целевой_домен> +``` + +Следующее правило гласит, что когда процесс в домене `initrc_t` запускает файл типа `acct_exec_t`, домен процесса должен быть изменен на `acct_t`, если это разрешено политикой. Чтобы это правило перехода домена работало, нужно также присутствие нескольких разрешений. +``` +type_transition initrc_t acct_exec_t:process acct_t; +allow initrc_t acct_exec_t:file execute; # Разрешение на запуск файла типа acct_exec_t в исходном домене initrc_t +allow acct_t acct_exec_t:file entrypoint; # Разрешение на наличие точки входа файла типа acct_exec_t в домен целевой домен acct_t +allow initrc_t acct_t:process transition; # Разрешение процессу на переход в домен целевой acct_t +``` +Подробнее в документации правила https://selinuxproject.org/page/TypeRules. + +Обычно в политиках используют макрос `domtrans_pattern` или `domain_transition_pattern` определённый в `/usr/share/selinux/devel/include/support/misc_patterns.spt` для указания правила перехода и разрешений вместе. + +### 2.3 Полезная утилита - restorecon +Если и есть, что посоветовать запомнить новому пользователю SELinux, так это `restorecon`. Restorecon приведет контекст SELinux к тому, что определено в базе данных контекста системы. + +Чтобы попробовать, давайте намеренно неправильно установим контекст в примере SELinux AVC log: +``` +# ls -Z ./testaudit +system_u:object_r:admin_home_t:s0 ./testaudit +# chcon -t httpd_sys_content_t ./testaudit +# ls -Z ./testaudit +system_u:object_r:httpd_sys_content_t:s0 ./testaudit +``` + +И мы можем волшебным образом изменить его обратно с помощью `restorecon`: +``` +# restorecon -v ./testaudit +Relabeled /root/testaudit from system_u:object_r:httpd_sys_content_t:s0 to system_u:object_r:admin_home_t:s0 +# ls -Z ./testaudit +-rw-------. root root system_u:object_r:admin_home_t:s0 ./testaudit +``` +Выше также применяется `chcon`, которой вы можете временного изменить контекст файла. + +Установка контекст на `httpd_sys_content_t` также устранила бы проблему, о которой сообщалось в нашем тестовом AVC. + +## 3. Установка тестового сервиса +Подготовим сервис, для которого далее будем писать собственную политику безопасности SELinux. + +Скачайте текущий репозиторий и перейдите в папку `linux_tasks/modeul2/test_service`. + +Настройте окружение разработчика, скачайте необходимые заголовочные файлы и установите сервис `testapp` с помощью `make`: +``` +$ sudo apt install build-essential libcurl4-openssl-dev +$ make +$ sudo make install +``` + +Взгляните на приложение и связанную с ним службу, которые вы только что установили: +``` +$ ls -l /usr/local/sbin/testapp +-rwxr-xr-x. 1 root root 48688 Feb 20 18:03 /usr/local/sbin/testapp +$ sudo systemctl status testapp +● testapp.service - Testing SELinux app + Loaded: loaded (/usr/lib/systemd/system/testapp.service; disabled; vendor preset: disabled) + Active: inactive (dead) +``` + +``` +$ sudo systemctl enable testapp +$ sudo systemctl start testapp +``` + +Мы видим, что приложение было запущено `systemd`: +``` +$ sudo systemctl status testapp +● testapp.service - Testing SELinux app + Loaded: loaded (/lib/systemd/system/testapp.service; enabled; vendor preset: enabled) + Active: active (running) since Tue 2022-10-18 10:27:58 EDT; 1s ago + Process: 5791 ExecStart=/usr/local/sbin/testapp (code=exited, status=0/SUCCESS) + Main PID: 5792 (testapp) + Tasks: 1 (limit: 9496) + Memory: 3.3M + CPU: 14ms + CGroup: /system.slice/testapp.service + └─5792 /usr/local/sbin/testapp + +Oct 18 10:27:58 uefidebian systemd[1]: Starting Testing SELinux app... +Oct 18 10:27:58 uefidebian testapp[5791]: testapp parent process ended +Oct 18 10:27:58 uefidebian systemd[1]: Started Testing SELinux app. +``` +И мы также можем видеть, что приложение работает без ограничений, что означает, что оно работает без политики SELinux и может выполнять любые действия, которые оно захочет: +``` +# ps -efZ | grep testapp | grep -v grep +system_u:system_r:testapp_t:s0 root 5792 1 0 10:27 ? 00:00:00 /usr/local/sbin/testapp +``` + +## 4. Инициализация политики для тестового сервиса +Теперь сгенерируем автоматически структуру политики SELinux. Научимся обрабатывать сообщения AVC, которые генерируются SELinux, когда приложение нарушает политику. + +### 4.1 Сгенерируйте шаблон политики SELinux +Создайте каталог-проект политики и сгенерируйте в нём шаблонные файлы политики с помощью комадны `sepolicy generate`. +``` +$ mkdir policy +$ cd policy +$ sepolicy generate --init /usr/local/sbin/testapp +``` + +Обратите внимание на последние несколько строк в выходных данных `sepolicy generate`: +``` +Created the following files: +/home/stud/src/policy/testapp.te # Type Enforcement file +/home/stud/src/policy/testapp.if # Interface file +/home/stud/src/policy/testapp.fc # File Contexts file +/home/stud/src/policy/testapp_selinux.spec # Spec file +/home/stud/src/policy/testapp.sh # Setup Script +``` + +Исходные компоненты политики SELinux: +- `testapp.te` - это базовая политика для приложения. Он устанавливает правила для домена `testapp_t`, +- `testapp.if` - это файл интерфейса. Интерфейсы подобны общедоступным функциям в том смысле, что они предоставляют другим модулям SELinux способы взаимодействия с тем, который вы пишете, +- `testapp.fc` - это файл контекстов. Он содержит информацию о маркировке всех объектов файловой системы, на которые ссылается политика, +- `testapp.sh` это предоставленный Red Hat скрипт, который компилирует и загружает модуль политики SELinux. + +### 4.2. Скомпилируйте и загрузите политику + +Теперь скомпилируйте и загрузите политику SELinux, запустив `testapp.sh` сценарий. Скрипт необходимо запускать с правами суперпользователя, поскольку он изменяет конфигурацию запущенного SELinux: +```bash +$ sudo ./testapp.sh +``` + +Первые 9 строк выходных данных показывают компиляцию политики, загрузку политики в память и автоматическое создание справочной страницы для политики: +```bash +Building and Loading Policy ++ make -f /usr/share/selinux/devel/Makefile testapp.pp +Compiling targeted testapp module +/usr/bin/checkmodule: loading policy configuration from tmp/testapp.tmp +/usr/bin/checkmodule: policy configuration loaded +/usr/bin/checkmodule: writing binary representation (version 19) to tmp/testapp.mod +Creating targeted testapp.pp policy package +rm tmp/testapp.mod tmp/testapp.mod.fc ++ /usr/sbin/semodule -i testapp.pp ++ sepolicy manpage -p . -d testapp_t +./testapp_selinux.8 +``` + +В дополнение к компиляции и загрузке политики, `testapp.sh` скрипт создает RPM, содержащий политику, используя файл спецификации, сгенерированный `sepolicy generate`. Это упрощает распространение политики. + +Замечание. Игнорируйте в этом задании ошибку построения пакета rpm. + +### 4.3. Проверьте политику в действии +Если мы перезагрузим приложение, к нему будет прикреплен недавно скомпилированный и загруженный модуль политики: +``` +$ sudo systemctl stop testapp +$ sudo systemctl start testapp +$ ps -efZ | grep testapp | grep -v grep +system_u:system_r:testapp_t:s0 root 8737 1 0 20:51 ? 00:00:00 /usr/local/sbin/testapp +``` + +### 4.4. Как приложение в конечном итоге получает testapp_context? +Это связано с правилами перехода домена SELinux. Служба `testapp` запускается `systemd`, которая запускается с контекстом `init_t`, поскольку это наша служба инициализации. Из-за правил перехода он изменяет контексты при запуске службы. + +Чтобы просмотреть эти правила, введите: +``` +$ sesearch -T -s init_t -t testapp_exec_t +type_transition init_t testapp_exec_t : process testapp_t; +``` + +Правило гласит, что когда любой процесс, помеченный как `init_t`, выполняет любой двоичный файл, помеченный как `testapp_exec_t`, вновь созданный процесс будет помечен как `testapp_t`. + + +На данный момент у нас есть общая политика для приложения `testapp`, которая настроена на разрешающий режим. Таким образом, приложение может запускаться, и SELinux будет генерировать предупреждения при нарушении существующей системной политики, но не будет предпринимать никаких действий. + +## 5. Выявление проблем с SELinux политикой по умолчанию + +### 5.1 Проверьте наличие отказов AVC +Теперь, когда наше приложение запущено, мы можем проверить системные журналы на наличие сообщений об отказе AVC (access vector cache, где SELinux кэширует решения о предоставлении или отказе в доступе). +``` +$ sudo ausearch -m AVC -ts today +``` + +Будет (и должно быть!) довольно много отказов, возвращенных из поиска. Вот некоторые из примеров машины: +``` +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.393:375): avc: denied { read } for pid=5792 comm="testapp" laddr=192.168.1.3 lport=53423 faddr=1.1.1.1 fport=53 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1 +---- +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.393:376): avc: denied { create } for pid=5792 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +---- +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.393:377): avc: denied { setopt } for pid=5792 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +---- +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.393:378): avc: denied { connect } for pid=5792 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +---- +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.433:379): avc: denied { getopt } for pid=5792 comm="testapp" laddr=192.168.1.3 lport=40030 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +---- +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.433:380): avc: denied { getattr } for pid=5792 comm="testapp" laddr=192.168.1.3 lport=40030 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +---- +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.433:381): avc: denied { write } for pid=5792 comm="testapp" laddr=192.168.1.3 lport=40030 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +---- +time->Tue Oct 18 10:27:59 2022 +type=AVC msg=audit(1666103279.473:382): avc: denied { read } for pid=5792 comm="testapp" laddr=192.168.1.3 lport=40030 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +---- +time->Tue Oct 18 10:44:03 2022 +type=AVC msg=audit(1666104243.178:383): avc: denied { getattr } for pid=5792 comm="testapp" path="/etc/resolv.conf" dev="sda2" ino=6855 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1 +---- +time->Tue Oct 18 10:44:03 2022 +type=AVC msg=audit(1666104243.178:384): avc: denied { open } for pid=5792 comm="testapp" path="/etc/hosts" dev="sda2" ino=9026 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1 +type=AVC msg=audit(1666104243.178:384): avc: denied { read } for pid=5792 comm="testapp" name="hosts" dev="sda2" ino=9026 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1 +``` + +## 6. Создание правил политики для доступа к /proc + +### 6.1 Интерпретация сообщений AVC +В первом сообщении аудита мы видим эти сообщения AVC: +``` +type=AVC msg=audit(1552588580.764:25971): avc: denied { open } for pid=1022 comm="testapp" path="/proc/meminfo" dev="proc" ino=4026532040 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:proc_t:s0 tclass=file permissive=1 +type=AVC msg=audit(1552588580.764:25971): avc: denied { read } for pid=1022 comm="testapp" name="meminfo" dev="proc" ino=4026532040 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:proc_t:s0 tclass=file permissive=1 +``` + +Если мы внимательно посмотрим на них, то увидим, что процессу тестового приложения отказано в открытии в `/proc/meminfo` и в чтении в `/proc` в целом. Итак, нам нужно найти интерфейс, который позволит осуществлять эти доступы, и добавить его в наш файл `testapp.te`. + +### 6.2 Найдите правильный интерфейс +Определения интерфейса SELinux находятся в `/usr/share/selinux/devel/include`, если вы устанавливаете пакет `selinux-policy-devel`. Если мы ищем `/proc`, в файлах с именем `*.if` (определения интерфейса): +``` +$ cd /usr/share/selinux/devel/include +$ find . -type f -name "*.if" -exec grep -H '/proc' {} \; | grep "system state information" +``` +Мы видим, что в результатах есть строка, которая гласит: +``` +./kernel/kernel.if:## Allows caller to read system state information in /proc. +``` +Это имеет смысл, так что давайте посмотрим, в каком интерфейсе есть этот комментарий. В самом файле: +```bash +######################################## +## +## Allows caller to read system state information in /proc. +## +## +##

+## Allow the specified domain to read general system +## state information from the proc filesystem (/proc). +##

+##

+## Generally it should be safe to allow this access. Some +## example files that can be read based on this interface: +##

+## +##

+## This does not allow access to sysctl entries (/proc/sys/*) +## nor process state information (/proc/pid). +##

+##
+## +## +## Domain allowed access. +## +## +## +## +# +interface(`kernel_read_system_state',` + gen_require(` + attribute kernel_system_state_reader; + ') + + typeattribute $1 kernel_system_state_reader; +') +``` + +Этот интерфейс принимает один параметр (смотрите в разделе ``), который является именем домена SELinux, к которому должен быть разрешен доступ. В этом случае доменное имя - `testapp_t`, соответствующее имени вашего приложения и модуля политики. + +### 6.3 Добавьте интерфейс к политике +Чтобы разрешить это, добавьте интерфейс в `testapp.te` со строкой в разделе локальной политики `testapp`, например: +``` +kernel_read_system_state(testapp_t) +``` + +Теперь файл должен выглядеть следующим образом: +``` +$ cat ~/src/policy/testapp.te +policy_module(testapp, 1.0.0) + + +# +# Declarations +# + +type testapp_t; +type testapp_exec_t; +init_daemon_domain(testapp_t, testapp_exec_t) + +permissive testapp_t; + +type testapp_var_run_t; +files_pid_file(testapp_var_run_t) + + +# +# testapp local policy +# +allow testapp_t self:process { fork }; +allow testapp_t self:fifo_file rw_fifo_file_perms; +allow testapp_t self:unix_stream_socket create_stream_socket_perms; + +manage_dirs_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_lnk_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +files_pid_filetrans(testapp_t, testapp_var_run_t, { dir file lnk_file }) + +domain_use_interactive_fds(testapp_t) + +files_read_etc_files(testapp_t) + +kernel_read_system_state(testapp_t) + +logging_send_syslog_msg(testapp_t) + +miscfiles_read_localization(testapp_t) +``` + +Хранение данных в алфавитном порядке не имеет никакого значения для SELinux, но облегчает чтение файла. + +### 6.4 Перекомпилируйте и перезагрузите политику +Теперь давайте перекомпилируем политику и перезагрузим ее в память. +``` +$ sudo ./testapp.sh +``` + +### 6.5 Перезапустите приложение +Чтобы посмотреть, устранило ли это проблему, давайте перезапустим приложение: +``` +$ sudo systemctl restart testapp +``` +...и посмотрите, есть ли какие-либо сообщения AVC о `/proc`: +``` +$ sudo ausearch -m AVC -ts recent | grep meminfo | wc -l +0 +``` +Ура! Одна AVC проблема решена. + +Далее наша цель - разрешить тестовому приложению генерировать сетевой трафик. + +## 7.1 Разрешение подключения к HTTP-порту +### 7.1.1 Проверьте наличие отказов AVC +Давайте перезапустим наше приложение, чтобы получить обновленный список отказов: +``` +$ sudo systemctl restart testapp +``` +Начнем с одного из отказов, которые будут присутствовать в результатах поиска аудита, связанного с подключением по TCP-порту 80: +``` +$ sudo ausearch -m AVC -ts recent | grep 'dest=80' +type=AVC msg=audit(1553181380.518:2594): avc: denied { name_connect } for pid=31221 comm="testapp" dest=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket permissive=1 +``` + +Вы можете получить более одного из этих сообщений, в зависимости от времени. + +### 7.1.2 Интерпретация сообщений AVC +В приведенном выше сообщении вы можете видеть, что система попыталась подключиться к удаленному хосту через порт 80. Это то, что мы хотим допустить. Итак, давайте поищем интерфейс, который позволял бы осуществлять такого рода подключение. Поскольку сетевое взаимодействие контролируется ядром, мы будем искать в каталоге ядра файлы интерфейса, связанные с сетевым взаимодействием: +``` +$ ls /usr/share/selinux/devel/include/kernel/*.if | grep net +/usr/share/selinux/devel/include/kernel/corenetwork.if +/usr/share/selinux/devel/include/kernel/unlabelednet.if +``` + +Поскольку это не немаркированная сеть, давайте посмотрим в `corenetwork.if`. Поскольку это действие `name_connect`, давайте посмотрим на `connect` и `http`. Используя эти критерии, мы находим: +``` +######################################## +## +## Make a TCP connection to the http port. +## +## +## +## Domain allowed access. +## +## +# +interface(`corenet_tcp_connect_http_port',` + gen_require(` + type http_port_t; + ') + + allow $1 http_port_t:tcp_socket name_connect; +') +``` + +#### 7.1.3 Добавьте интерфейс +Итак, как и раньше, добавьте интерфейс в свой файл `testapp.te`, используя строку, подобную этой: +``` +corenet_tcp_connect_http_port(testapp_t) +``` + +И скомпилируйте свою политику, и перезапустите службу: +``` +$ sudo ./testapp.sh +$ sudo systemctl restart testapp +``` + +...и последнее, проверьте, есть ли еще отказ AVC: +``` +$ sudo systemctl restart testapp +$ sudo ausearch -m AVC -ts recent | grep 'dest=80' | wc -l +0 +``` + +Да! Исправлен еще один отказ AVC. + + +## 8.2. Разрешения для сокетов + +### 8.1 Воспользуемся коротким путём! +Мы временно перейдём от интерфейсов к настройкам разрешения/запрета в файле `testapp.te`. У нас есть несколько отказов AVC в системных вызовах сокетов TCP и UDP, которые блокирует SELinux. + +AVC решения, о которых идет речь, находятся здесь (вероятно, на вашем хостинге их будет больше, но все они относятся к одной категории).: +``` +$ sudo ausearch -m AVC -ts recent | egrep 'tcp|udp' +type=AVC msg=audit(1553190979.189:2931): avc: denied { create } for pid=2042 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +type=AVC msg=audit(1553190979.189:2932): avc: denied { connect } for pid=2042 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +type=AVC msg=audit(1553190979.379:2933): avc: denied { getopt } for pid=2042 comm="testapp" laddr=10.0.2.5 lport=60848 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +type=AVC msg=audit(1553190979.379:2934): avc: denied { getattr } for pid=2042 comm="testapp" laddr=10.0.2.5 lport=60848 faddr=5.9.243.187 fport=80 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=tcp_socket permissive=1 +type=AVC msg=audit(1553191083.531:2965): avc: denied { create } for pid=2042 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1 +type=AVC msg=audit(1553191083.531:2966): avc: denied { connect } for pid=2042 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1 +type=AVC msg=audit(1553191083.548:2967): avc: denied { getattr } for pid=2042 comm="testapp" path="socket:[314409]" dev="sockfs" ino=314409 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1 +``` + +### 8.2 Позвольте audit2why интерпретировать для вас +Далее, давайте попросим систему преобразовать AVC в английский для нас: +``` +$ sudo ausearch -m AVC | egrep 'udp' | head -1 | audit2why +type=AVC msg=audit(1553112150.906:909): avc: denied { create } for pid=9772 comm="testapp" scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:system_r:testapp_t:s0 tclass=udp_socket permissive=1 + + Was caused by: + Missing type enforcement (TE) allow rule. + + You can use audit2allow to generate a loadable module to allow this access. +``` + +Вы можете видеть, что в данном случае `audit2why` не принес существенной пользы, кроме сообщения нам о том, что нам нужно добавить новую инструкцию `allow` в наш файл `testapp.te`. + +### 8.3 Используйте audit2allow, чтобы предложить изменения +Итак, теперь мы воспользуемся советом, который дал нам `audit2why`, и позволим `audit2allow` сгенерировать некоторые заявления о разрешении политики. Вы всегда должны быть осторожны с `audit2allow`, поскольку он будет генерировать правила для всего, что вы ему передаете, и не обязательно выберет наиболее оптимальное решение. +``` +$ sudo ausearch -m AVC -ts recent | egrep 'tcp|udp' | audit2allow +#============= testapp_t ============== +allow testapp_t self:tcp_socket { connect create getattr getopt setopt }; +allow testapp_t self:udp_socket { connect create getattr setopt }; +``` + +Эти правила выглядят хорошо, так что продолжайте и добавьте их в свой тестовый файл `app.te`. + +Теперь файл должен выглядеть следующим образом: +``` +$ cat ~/src/policy/testapp.te +policy_module(testapp, 1.0.0) + + +# +# Declarations +# + +type testapp_t; +type testapp_exec_t; +init_daemon_domain(testapp_t, testapp_exec_t) + +permissive testapp_t; + +type testapp_var_run_t; +files_pid_file(testapp_var_run_t) + + +# +# testapp local policy +# +allow testapp_t self:process { fork }; +allow testapp_t self:fifo_file rw_fifo_file_perms; +allow testapp_t self:tcp_socket { connect create getattr getopt }; +allow testapp_t self:udp_socket { connect create getattr }; +allow testapp_t self:unix_stream_socket create_stream_socket_perms; + +manage_dirs_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_lnk_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +files_pid_filetrans(testapp_t, testapp_var_run_t, { dir file lnk_file }) + +corenet_tcp_connect_http_port(testapp_t) + +domain_use_interactive_fds(testapp_t) + +files_read_etc_files(testapp_t) + +kernel_read_system_state(testapp_t) + +logging_send_syslog_msg(testapp_t) + +miscfiles_read_localization(testapp_t) +``` + +Хранение данных в алфавитном порядке не имеет никакого значения для SELinux, но облегчает чтение файла. + +Примечание: Пожалуйста, обратите внимание, что исходные разрешающие правила заканчиваются точкой с запятой, но для правил интерфейса нет ограничителя. + +### 8.4 Перекомпилируйте и перезагрузите политику + +Теперь давайте перекомпилируем политику и перезагрузим ее в память. +``` +$ sudo ./testapp.sh +``` + +Чтобы посмотреть, устранило ли это проблему, давайте перезапустим приложение: +``` +$ sudo systemctl restart testapp +``` + +...и посмотрите, есть ли какие-либо сообщения AVC о TCP или UDP: +``` +$ sudo ausearch -m AVC -ts recent | egrep 'tcp|udp' | wc -l +0 +``` + +Фантастика! + +Нам осталось обработать всего несколько отказов AVC. + +## 9. Создание правил политики для чтения сертификатов + +Разрешим политике testapp SELinux считывать сертификаты в системе. + +### 9.1 Проверьте наличие отказов AVC +Давайте снова перезапустим наше приложение, чтобы получить обновленный список отказов. +``` +$ sudo systemctl restart testapp +``` + +Мы сосредоточимся на отказах SELinux, связанных с чтением файла конфигурации openssl. +``` +$ sudo ausearch -m AVC -ts recent | egrep 'cert_t' +type=AVC msg=audit(1585733765.866:2797): avc: denied { search } for pid=26898 comm="testapp" name="pki" dev="xvda2" ino=12583606 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:cert_t:s0 tclass=dir permissive=1 +type=AVC msg=audit(1585733765.866:2797): avc: denied { read } for pid=26898 comm="testapp" name="openssl.cnf" dev="xvda2" ino=320001 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:cert_t:s0 tclass=file permissive=1 +type=AVC msg=audit(1585733765.866:2797): avc: denied { open } for pid=26898 comm="testapp" path="/etc/pki/tls/openssl.cnf" dev="xvda2" ino=320001 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:cert_t:s0 tclass=file permissive=1 +type=AVC msg=audit(1585733765.867:2798): avc: denied { getattr } for pid=26898 comm="testapp" path="/etc/pki/tls/openssl.cnf" dev="xvda2" ino=320001 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:cert_t:s0 tclass=file permissive=1 +``` + +### 9.2 Интерпретация сообщений AVC +Из имеющихся у нас AVCS кажется очевидным, что приложение хочет попытаться разрешить сертификаты доступа и файлы, связанные с SSL. Большинству приложений, получающих доступ к сети, необходимо иметь возможность читать эти файлы, и интерфейс для этого находится в `/usr/share/selinux/devel/include/system/miscfiles.if` и называется `miscfiles_read_generic_certs`. +``` +######################################## +## +## Read generic SSL certificates. +## +## +## +## Domain allowed access. +## +## +## +# +interface(`miscfiles_read_generic_certs',` + gen_require(` + type cert_t; + ') + + allow $1 cert_t:dir list_dir_perms; + read_files_pattern($1, cert_t, cert_t) + read_lnk_files_pattern($1, cert_t, cert_t) +') +``` + +### 9.3 Добавьте интерфейс +Итак, как и раньше, добавьте интерфейс в свой файл `testapp.te`, используя строку, подобную этой: +``` +miscfiles_read_generic_certs(testapp_t) +``` + +Теперь файл должен выглядеть следующим образом: +``` +$ cat ~/src/policy/testapp.te +policy_module(testapp, 1.0.0) + + +# +# Declarations +# + +type testapp_t; +type testapp_exec_t; +init_daemon_domain(testapp_t, testapp_exec_t) + +permissive testapp_t; + +type testapp_var_run_t; +files_pid_file(testapp_var_run_t) + + +# +# testapp local policy +# +allow testapp_t self:process { fork }; +allow testapp_t self:fifo_file rw_fifo_file_perms; +allow testapp_t self:tcp_socket { connect create getattr getopt }; +allow testapp_t self:udp_socket { connect create getattr }; +allow testapp_t self:unix_stream_socket create_stream_socket_perms; + +manage_dirs_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_lnk_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +files_pid_filetrans(testapp_t, testapp_var_run_t, { dir file lnk_file }) + +corenet_tcp_connect_http_port(testapp_t) + +domain_use_interactive_fds(testapp_t) + +files_read_etc_files(testapp_t) + +kernel_read_system_state(testapp_t) + +logging_send_syslog_msg(testapp_t) + +miscfiles_read_localization(testapp_t) + +miscfiles_read_generic_certs(testapp_t) +``` + +И скомпилируйте свою политику, и перезапустите службу: +``` +$ sudo ./testapp.sh +$ sudo systemctl restart testapp +``` + +...и последнее, проверьте, есть ли еще какие-либо отказы AVC: +``` +$ sudo ausearch -m AVC -ts recent | grep cert_t | wc -l +0 +``` +На данный момент нам осталось обработать всего несколько отказов AVC. Надеюсь, вы разбираетесь в том, как найти подходящие интерфейсы и разрешить правила для SELinux. + +В этом заключительном упражнении мы завершим тестовое приложение SELinux policy. + +## 10. Последний интерфейс + +### 10.1 Проверьте наличие отказов AVC + +Давайте снова перезапустим наше приложение, чтобы получить обновленный список отказов. +``` +$ sudo systemctl restart testapp +``` + +У нас осталось всего несколько отказов, и вы увидите, что все они (вероятно!) ссылаются на `/etc/resolv.conf` или на `/etc/hosts`. +``` +$ sudo ausearch -m AVC -ts recent | egrep '^type=AVC' +type=AVC msg=audit(1553195947.854:3270): avc: denied { getattr } for pid=4651 comm="testapp" path="/etc/resolv.conf" dev="dm-0" ino=9311517 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1 +type=AVC msg=audit(1553195947.854:3271): avc: denied { open } for pid=4651 comm="testapp" path="/etc/hosts" dev="dm-0" ino=8389746 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1 +type=AVC msg=audit(1553195947.854:3271): avc: denied { read } for pid=4651 comm="testapp" name="hosts" dev="dm-0" ino=8389746 scontext=system_u:system_r:testapp_t:s0 tcontext=system_u:object_r:net_conf_t:s0 tclass=file permissive=1 +``` + +### 10.2 Интерпретация AVC сообщений + +Из имеющихся у нас AVCS кажется очевидным, что приложение хочет попытаться преобразовать некоторые имена хостов в IP-адреса. Большинству приложений, получающих доступ к сети, необходимо иметь возможность считывать конфигурацию системной сети, и интерфейс для этого находится в `/usr/share/selinux/devel/include/system/sysnetwork.if` и называется `sysnet_read_config`. +``` +####################################### +## +## Read network config files. +## +## +##

+## Allow the specified domain to read the +## general network configuration files. A +## common example of this is the +## /etc/resolv.conf file, which has domain +## name system (DNS) server IP addresses. +## Typically, most networking processes will +## require the access provided by this interface. +##

+##

+## Higher-level interfaces which involve +## networking will generally call this interface, +## for example: +##

+##
    +##
  • sysnet_dns_name_resolve()
  • +##
  • sysnet_use_ldap()
  • +##
  • sysnet_use_portmap()
  • +##
+##
+## +## +## Domain allowed access. +## +## +# +interface(`sysnet_read_config',` + gen_require(` + type net_conf_t; + ') + + files_search_etc($1) + allow $1 net_conf_t:file read_file_perms; + + ifdef(`distro_debian',` + files_search_pids($1) + allow $1 net_conf_t:dir list_dir_perms; + read_files_pattern($1, net_conf_t, net_conf_t) + ') + + ifdef(`distro_redhat',` + files_search_all_pids($1) + init_search_pid_dirs($1) + allow $1 net_conf_t:dir list_dir_perms; + allow $1 net_conf_t:lnk_file read_lnk_file_perms; + read_files_pattern($1, net_conf_t, net_conf_t) + ') +') +``` + +#### 10.3 Добавьте интерфейс +Итак, как и раньше, добавьте интерфейс в свой файл `testapp.te`, используя строку, подобную этой: +``` +sysnet_read_config(testapp_t) +``` + +И скомпилируйте свою политику, и перезапустите службу: +``` +$ sudo ./testapp.sh +$ sudo systemctl restart testapp +``` + +...и последнее, проверьте, есть ли еще какие-либо отказы AVC: +``` +$ sudo systemctl restart testapp +$ sudo ausearch -m AVC -ts recent | wc -l +0 +``` + +Разве это не здорово - быть почти готовым? + +## 11. Установите Принудительный режим + +### 11.1 Change the Domain to Enforcing + +Последний шаг, который нам нужно предпринять, - это изменить ваш файл `testapp.te`, чтобы домен применял принудительные меры. Все, что нам нужно сделать, чтобы достичь этого, - это закомментировать строку, в которой говорится: +``` +permissive testapp_t; +``` + +Также вывод семантики команды `permissive -l` говорит, что она разрешающая: +``` +$ sudo semanage permissive -l + +Builtin Permissive Types +testapp_t + +Customized Permissive Types +``` + +Как только мы это сделаем, окончательная версия вашей политики должна выглядеть следующим образом: +``` +$ cat testapp.te +policy_module(testapp, 1.0.0) + + +# +# Declarations +# + +type testapp_t; +type testapp_exec_t; +init_daemon_domain(testapp_t, testapp_exec_t) + +# permissive testapp_t; + +type testapp_var_run_t; +files_pid_file(testapp_var_run_t) + + +# +# testapp local policy +# +allow testapp_t self:process { fork }; +allow testapp_t self:fifo_file rw_fifo_file_perms; +allow testapp_t self:tcp_socket { connect create getattr getopt }; +allow testapp_t self:udp_socket { connect create getattr }; +allow testapp_t self:unix_stream_socket create_stream_socket_perms; + +manage_dirs_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +manage_lnk_files_pattern(testapp_t, testapp_var_run_t, testapp_var_run_t) +files_pid_filetrans(testapp_t, testapp_var_run_t, { dir file lnk_file }) + +corenet_tcp_connect_http_port(testapp_t) + +domain_use_interactive_fds(testapp_t) + +files_read_etc_files(testapp_t) + +kernel_read_system_state(testapp_t) + +logging_send_syslog_msg(testapp_t) + +miscfiles_read_localization(testapp_t) + +miscfiles_read_generic_certs(testapp_t) + +sysnet_read_config(testapp_t) +``` + +### 11.2 Перекомпилируйте и перезагрузите политику + +Теперь давайте перекомпилируем политику и перезагрузим ее в память. +``` +$ sudo ./testapp.sh +``` +Чтобы подтвердить, что политика testapp_t находится в принудительном режиме, пожалуйста, повторите: +``` +$ sudo semanage permissive -l +``` +Как вы можете видеть, выходных данных нет, что означает отсутствие политики в разрешающем режиме. + +### 11.3 Перезапустите приложение + +Чтобы посмотреть, устранило ли это проблему, давайте перезапустим приложение: +``` +$ sudo systemctl restart testapp +``` + +...и посмотрите, остались ли какие-нибудь сообщения AVC: +``` +$ sudo ausearch -m AVC -ts recent | wc -l +0 +``` + +Ура! Мы завершили конфигурацию политики для нашего сервиса. + + +### 12. +Упражнение на закуску. Хостинговые компании часто организуют для своих пользователей доступ к одной из папок в домашней директории пользователя по http по ссылке `http://site/~user/index.html`. Попробуем это повторить с политиками selinux, уменьшающими потенциальный ущерб для системы от взлома сервера. Создайте папку www в домашней директории. Добавьте пользователя в группу `www-data` и установите права на директорию `~/www` 0755. @@ -77,4 +941,13 @@ location ~ ^/~(.+?)(/.*)?$ { setsebool –P httpd_enable_homedirs on ``` -Проверьте, что доступ появился. \ No newline at end of file +Проверьте, что доступ появился. + + +# Релевантные ссылки +- https://wiki.debian.org/SELinux/Setup +- https://github.com/SELinuxProject/refpolicy/wiki/GettingStarted, +- https://debian-handbook.info/browse/en-US/stable/sect.selinux.html, +- https://selinuxproject.org, +- https://seedit.sourceforge.net/, +- https://selinux-ide.sourceforge.net/download.php. \ No newline at end of file diff --git a/module2/02_mac_selinux/test_service/Makefile b/module2/02_mac_selinux/test_service/Makefile new file mode 100644 index 0000000..3accd08 --- /dev/null +++ b/module2/02_mac_selinux/test_service/Makefile @@ -0,0 +1,9 @@ +all: testapp.c + g++ -std=c++11 -g -o testapp testapp.c -lcurl + +clean: + rm testapp + +install: testapp + install -m 0755 testapp /usr/local/sbin + install -m 0644 testapp.service /usr/lib/systemd/system/ diff --git a/module2/02_mac_selinux/test_service/testapp.c b/module2/02_mac_selinux/test_service/testapp.c new file mode 100644 index 0000000..433d502 --- /dev/null +++ b/module2/02_mac_selinux/test_service/testapp.c @@ -0,0 +1,200 @@ +#include //printf(3) +#include //exit(3) +#include //fork(3), chdir(3), sysconf(3) +#include //signal(3) +#include //umask(3) +#include //syslog(3), openlog(3), closelog(3) +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#define MAXHOSTNAME 256 +#define DESTURL "http://wttr.in/" +#define DESTURLEND "?format=3" +using namespace std; + +const char* offices[] = { + "Brisbane", + "Canberra", + "Melbourne", + "Perth", + "Sydney", + "Beijing", + "Shanghai", + "Shenzhen", + "Hong Kong", + "Bangalore", + "New%20Delhi", + "Kolkata", + "Mumbai", + "Pune", + "Jakarta", + "Tokyo", + "Nagoya", + "Osaka", + "Fukuoka", + "Seoul", + "Kuala%20Lumpur", + "Auckland", + "Wellington", + "Makati%20City", + "Singapore", + "Taipei", + "Bangkok", + "London", + "Amsterdam", + "Barcelona", + "Berlin", + "Brno", + "Brussels", + "Copenhagen", + "Berlin", + "Cork", + "Dublin", + "Düsseldorf", + "Farnborough", + "Frankfurt%20am%20Main", + "Helsinki", + "Madrid", + "Milan", + "Moscow", + "Grasbrunn", + "Neuchâtel", + "Newcastle%20Upon%20Tyne", + "Oslo", + "Prague", + "Puteaux", + "Rome", + "Stockholm", + "Stuttgart", + "Cherkasy", + "Vienna", + "Warsaw", + "Waterford", + "Zürich", + "Dubai", + "İstanbul", + "Ra’anana", + "Riyadh", + "Sandton", + "Buenos%20Aires", + "Brasília", + "Fortaleza", + "Rio%20de%20Janeiro", + "São%20Paulo", + "Santiago", + "Bogota", + "Ciudad%20de%20México", + "Monterrey", + "Lima", + "Montreal", + "Toronto", + "Raleigh", + "Boston", + "Ann%20Arbor", + "Atlanta", + "Washington", + "North Charleston", + "Charlotte", + "Chicago", + "San%20Francisco", + "New%20York", + "Dallas", + "Denver", + "Durham", + "Huntsville", + "Los%20Angeles", + "Mahwah", + "Minneapolis", + "Richmond", + "St.%20Louis", + "Sunnyvale", + "McLean", + "Westford", + NULL }; + +int curlUrl( const char* myOffice, size_t myUrlLength ) +{ + std::string fullUrl; + CURL *curl; + CURLcode res; + + // create a URL from 2 constants and an office string + fullUrl.append( DESTURL ); + fullUrl.append( myOffice ); + fullUrl.append( DESTURLEND ); + // make a C string of the same size and copy to it + int fullUrlSize = fullUrl.length(); + char charFullArray[ fullUrlSize + 1 ]; + strcpy( charFullArray, fullUrl.c_str() ); + + // setup curl, grab the combined URL, and clean up + curl = curl_easy_init(); + if(curl) + { + curl_easy_setopt(curl, CURLOPT_URL, charFullArray); + res = curl_easy_perform(curl); + curl_easy_cleanup(curl); + } + + return res; +} + +int main() +{ + int ttl=999999; + int delay=10; + + pid_t pid = fork(); + + if (pid == 0) + { + // child process + openlog("testapp",LOG_PID,LOG_DAEMON); + + // iterate over the list of Red Hat offices and get the weather for each + for ( int i=0; offices[i] != NULL; i++ ) + { + curlUrl( ( "http://wttr.in?%sformat=3", offices[i]), sizeof( ( "http://wttr.in?%sformat=3", offices[i]) ) ); + sleep(delay); + } + + syslog(LOG_NOTICE,"testapp child process ended"); + closelog(); + return(EXIT_SUCCESS); + } + if (pid > 0) + { + // parent process + string filename = "/var/run/testapp.pid"; + ofstream o(filename.c_str()); + o << pid << endl; + + ifstream meminfo; + meminfo.open("/proc/meminfo"); + meminfo.close(); + + openlog("testapp",LOG_PID,LOG_DAEMON); + + /* disabling this due to startup timeout + do + { + syslog(LOG_NOTICE,"daemon ttl %d",ttl); + sleep(delay); + ttl-=delay; + } while ( ttl > 0 ); + syslog(LOG_NOTICE,"daemon ttl expired");*/ + + syslog(LOG_NOTICE,"testapp parent process ended"); + closelog(); + return(EXIT_SUCCESS); + } +} diff --git a/module2/02_mac_selinux/test_service/testapp.service b/module2/02_mac_selinux/test_service/testapp.service new file mode 100644 index 0000000..d95b99d --- /dev/null +++ b/module2/02_mac_selinux/test_service/testapp.service @@ -0,0 +1,10 @@ +[Unit] +Description=Testing SELinux app + +[Service] +Type=forking +ExecStart=/usr/local/sbin/testapp +ExecStop=/usr/bin/killall testapp + +[Install] +WantedBy=multi-user.target