В пакет policycoreutils-devel входит python-утилита sepolicy, которая сильно облегчает написание модуля. В этой статье мы рассмотрим процесс создания модуля для nmap с помощью этой утилиты.
TL; DR
В предыдущих статьях мы детально рассматривали создание policy module и связанные с этим вопросы. Сейчас же я расскажу о том, как значительно облегчить себе жизнь с man 8 sepolicy
Постановка задачи
Задачи, которые мы решим в статье:
- Написать модуль для nmap.
- Разрешить пользователям проводить сканы.
- Ограничить любые деструктивные действия.
Создание заготовки
У sepolicy есть режим генерации базовых модулей, вызываемый командой sepolicy generate (или sepolgen). Давайте создадим шаблон нашего модуля:
# sepolgen -n nmap --application /usr/bin/nmap -u user_u -u staff_u
Loaded plugins: fastestmirror
Created the following files:
/root/nmap_module/nmap.te # Type Enforcement file
/root/nmap_module/nmap.if # Interface file
/root/nmap_module/nmap.fc # File Contexts file
/root/nmap_module/nmap_selinux.spec # Spec file
/root/nmap_module/nmap.sh # Setup Script
Разберем аргументы командной строки:
- -n — имя модуля.
- --application — тип/приложение.
- /usr/bin/nmap — путь к исполняемому файлу.
- -u staff_u -u user_u — список пользователей, которые могут использовать это приложение.
Так как путь /usr/bin/nmap уже описан как traceroute_exec_t, сборка модуля as is вызовет конфликт. Поэтому удаляем файл nmap.fc перед сборкой модуля, а после сборки — делаем chcon.
# rm nmap.fc
rm: remove regular file 'nmap.fc'? y
# ./nmap.sh
Building and Loading Policy
+ make -f /usr/share/selinux/devel/Makefile nmap.pp
Compiling minimum nmap module
/usr/bin/checkmodule: loading policy configuration from tmp/nmap.tmp
/usr/bin/checkmodule: policy configuration loaded
/usr/bin/checkmodule: writing binary representation (version 17) to tmp/nmap.mod
Creating minimum nmap.pp policy package
rm tmp/nmap.mod tmp/nmap.mod.fc
+ /usr/sbin/semodule -i nmap.pp
...
# chcon -t nmap_exec_t /usr/bin/nmap
Отладка
Сейчас модуль работает в permissive-режиме, т. е. политики проверяются, но реальной блокировки не происходит. Это можно понять по строке permissive nmap_t в файле nmap.te.
Теперь запустим nmap с различными опциями для формирования достаточного количества логов. Предварительно рекомендую выполнить команду semodule -DB для отключения dontaudit-правил (правила, которые не дают писать в лог те или иные запреты).
# chmod u+s /usr/bin/nmap
# semodule -DB
$ id
user_u:user_r:user_t:s0
$ nmap -sS -A -PI jnode.in
....
$ nmap -A -sU -PI jnode.in
....
$ nmap jnode.in -o out.log
....
Смотрим результаты:
# audit2allow -bl -R -t nmap_t
allow nmap_t self:capability {net_raw dac_read_search dac_override};
allow nmap_t self:unix_dgram_socket { create ioctl };
allow nmap_t self:packet_socket { bind create getopt ioctl read setopt write };
allow nmap_t self:rawip_socket { create setopt write };
corenet_tcp_connect_http_port(nmap_t)
corenet_tcp_connect_smtp_port(nmap_t)
corenet_tcp_connect_ssh_port(nmap_t)
kernel_read_network_state(nmap_t)
kernel_read_system_state(nmap_t)
userdom_use_inherited_user_ptys(nmap_t)
Заодно видим, что out.log создался с контекстом user_home_dir_t — нужно создать новый тип (nmap_result_log_t) и дать необходимые права доступа.
Финализация
Итак, нам нужно сделать следующее:
- Разрешить необходимые доступы к сети.
- Разрешить писать логи.
- Сделать новый тип для логов.
- Сделать правило перехода типов для логов.
- Дать права пользователям и приложению на правку этих логов.
Правим модуль и получаем следующий код:
policy_module(nmap, 1.0.0)
########################################
#
# Declarations
#
attribute_role nmap_roles;
roleattribute system_r nmap_roles;
type nmap_t;
type nmap_exec_t;
application_domain(nmap_t, nmap_exec_t)
role nmap_roles types nmap_t;
# log files type
type nmap_result_log_t;
files_type(nmap_result_log_t)
# home transition
userdom_user_home_dir_filetrans(nmap_t, nmap_result_log_t, { dir file })
# permissive nmap_t;
########################################
#
# nmap local policy
#
allow nmap_t self:process { setrlimit };
allow nmap_t self:fifo_file manage_fifo_file_perms;
allow nmap_t self:unix_stream_socket create_stream_socket_perms;
domain_use_interactive_fds(nmap_t)
files_read_etc_files(nmap_t)
auth_use_nsswitch(nmap_t)
miscfiles_read_localization(nmap_t)
sysnet_dns_name_resolve(nmap_t)
optional_policy(`
gen_require(`
type user_t;
role user_r;
')
nmap_run(user_t, user_r)
# nmap log files access
manage_files_pattern(user_t, nmap_result_log_t, nmap_result_log_t)
')
optional_policy(`
gen_require(`
type staff_t;
role staff_r;
')
nmap_run(staff_t, staff_r) # autogenerated macro from nmap.if
# nmap log files access
manage_files_pattern(staff_t, nmap_result_log_t, nmap_result_log_t)
')
# from audit2allow
allow nmap_t self:capability { dac_override net_raw dac_read_search };
allow nmap_t self:packet_socket { bind create getopt ioctl read setopt write };
allow nmap_t self:rawip_socket { create setopt write };
kernel_read_network_state(nmap_t)
kernel_read_system_state(nmap_t)
userdom_use_inherited_user_ptys(nmap_t)
corenet_tcp_connect_all_ports(nmap_t)
#nmap log files access
manage_files_pattern(nmap_t, nmap_result_log_t, nmap_result_log_t)
Пересобираем модуль:
# ./nmap.sh
....
И проверяем в enforcing-режиме:
$ nmap -A -PI -sX -p 53 jnode.in -o out.log
Starting Nmap 6.40 ( http://nmap.org ) at 2018-05-13 13:29 CEST
WARNING: Running Nmap setuid, as you are doing, is a major security risk.
Nmap scan report for jnode.in (79.137.74.224)
Host is up (0.012s latency).
PORT STATE SERVICE VERSION
53/tcp open domain ISC BIND hostmaster
...
$ ls -laZ out.log
-rw-rw-r--. root user user_u:object_r:nmap_result_log_t:s0 out.log
$ rm out.log
$
Что еще может sepolicy?
Показать списки макросов интерфейсов
# sepolicy interface -v -l|grep filetrans|grep user_home_dir
userdom_user_home_dir_filetrans(domain, private_type, object_class, name) Create objects in a user home directory with an automatic type transition to a specified private type.
# sepolicy interface -v -l|grep corenet_tcp_connect|grep all
corenet_tcp_connect_all_ports(domain) Connect TCP sockets to all ports.
# sepolicy interface -v -l|grep files_pattern|grep manage
manage_files_pattern
Отслеживать возможные переходы типов
# sepolicy transition -s user_t -t nmap_t
user_t @ nmap_exec_t --> nmap_t
Отслеживать «общие» типы для обмена данными
# sepolicy communicate -s user_t -t nmap_t
xserver_tmpfs_t
user_tmp_t
user_fonts_t
nmap_result_log_t
А также генерировать документацию, показывать состояние booleans и прочие полезные вещи. Очень хорошая утилита, на самом деле.
Вместо заключения
SELinux не так страшен, как его малюют. Пользуйтесь вспомогательными утилитами, и написание полиси станет для вас легким и приятным делом.
Если вы хотите узнать больше — приходите на PHDays 18, где я буду вести четырехчасовой семинар по настройке SELinux-окружения.
P.S. Скачать исходники этого модуля (и других) можно здесь.
Автор: kreon