Я работаю над новым проектом, который должен быть защищен с помощью SELinux. У нас есть собственный двоичный файл, написанный на C (для ответа на этот вопрос он будет называться «testprog»), который должен переключиться на свой собственный контекст, чтобы мы могли ограничить его операции, а не позволять ему работать в неограниченном домене.
Я создал простой образец файла политики на основе полученных мной знаний, но bash не смог выполнить двоичный файл.
Вот файл политики в том виде, в каком он существует на данный момент:
policy_module(testprog, 0.1.6)
require {
type unconfined_t;
class file { ioctl getattr setattr create read write unlink open relabelto };
class process transition;
type fs_t;
class filesystem getattr;
}
type testprog_t;
type testprog_exec_t;
allow testprog_t fs_t:filesystem getattr;
allow testprog_t testprog_exec_t : file { ioctl read getattr lock execute execute_no_trans entrypoint open } ;
type_transition unconfined_t testprog_exec_t : process testprog_t;
allow unconfined_t testprog_t : process transition ;
Я установил контекст самого двоичного файла следующим образом:
-rwxr-xr-x. root root system_u:object_r:testprog_exec_t:s0 /usr/bin/testprog
Однако, если я попытаюсь выполнить команду из оболочки bash, я получу permission denied
ошибка и отказ зарегистрированы в audit.log:
[root@selinux-dev ~]# testprog
type=AVC msg=audit(1504546613.537:237): avc: denied { getattr } for pid=1300 comm="bash" path="/usr/bin/testprog" dev="dm-0" ino=34637336 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:testprog_exec_t:s0 tclass=file
type=SYSCALL msg=audit(1504546613.537:237): arch=c000003e syscall=4 success=no exit=-13 a0=2518ca0 a1=7ffd90223980 a2=7ffd90223980 a3=0 items=0 ppid=1296 pid=1300 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=PROCTITLE msg=audit(1504546613.537:237): proctitle="-bash"
type=AVC msg=audit(1504546613.537:238): avc: denied { getattr } for pid=1300 comm="bash" path="/usr/bin/testprog" dev="dm-0" ino=34637336 scontext=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 tcontext=system_u:object_r:testprog_exec_t:s0 tclass=file
type=SYSCALL msg=audit(1504546613.537:238): arch=c000003e syscall=4 success=no exit=-13 a0=2518ca0 a1=7ffd90223980 a2=7ffd90223980 a3=0 items=0 ppid=1296 pid=1300 auid=1000 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=2 comm="bash" exe="/usr/bin/bash" subj=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 key=(null)
type=PROCTITLE msg=audit(1504546613.537:238): proctitle="-bash"
-bash: testprog: command not found
Ясно, что моя политика немного чрезмерна. В конечном итоге я хочу иметь возможность запускать двоичный файл из systemd (мой файл модуля, очень простой, показан ниже), но я хочу перевести процесс из оболочки bash и из systemd в созданный мной тип testprog_t.
[Unit]
Description=SELinux Test Program
[Service]
#Type=forking
# The PID file is optional, but recommended in the manpage
# "so that systemd can identify the main process of the daemon"
PIDFile=/var/run/testprog.pid
ExecStart=/usr/bin/testprog /etc/testprog.conf /var/run/testprog.pid
[Install]
WantedBy=multi-user.target
Пожалуйста, может ли кто-нибудь помочь мне увидеть, где я ошибся? Базовая операционная система - RHEL 7.4.
Спасибо!
В конце концов, я добился того, что переход заработал, благодаря множеству ссылок - на самом деле он оказался невероятно простым, и я думаю, вы могли бы сказать, что связано с основным правилом хорошего программирования?
В политике, которую я разместил в вопросе, я определил два новых типа:
type testprog_t;
type testprog_exec_t;
А затем разрешил разные вещи происходить с этими типами, а также указал переход типа:
allow testprog_t fs_t:filesystem getattr;
allow testprog_t testprog_exec_t : file { ioctl read getattr lock execute execute_no_trans entrypoint open } ;
type_transition unconfined_t testprog_exec_t : process testprog_t;
allow unconfined_t testprog_t : process transition ;
Однако я ни разу не сказал SELinux, что это за типы на самом деле. Например, я установил контекст /usr/bin/testprog
файл в system_u:object_r:testprog_exec_t:s0
но я никогда не говорил SELinux через свою политику, что testprog_exec_t был файлом. Как только я изменил политику, добавив спецификации типов, все стало выглядеть более многообещающе. Мне также нужно было использовать оператор роли, чтобы разрешить testprog_t
бежать под unconfined_r
роль, под которой команды оболочки обычно выполняются в системе RHEL в целевом режиме SELinux. Текущий фрагмент политики по этому поводу выглядит так:
# Define our new types that testprog will use, and ensure that we tell the policy that testprog_exec_t is a file
type testprog_t;
domain_type(testprog_t);
type testprog_exec_t;
files_type(testprog_exec_t);
type testprog_etc_t;
files_type(testprog_etc_t);
type testprog_var_run_t;
files_type(testprog_var_run_t);
type testprog_data_t;
files_type(testprog_data_t);
# Allow the testprog_t type under the unconfined_r role
role unconfined_r types testprog_t;
# Tell SELinux that testprog_exec_t is an entrypoint to the tetprog_t domain
allow testprog_t testprog_exec_t : file { ioctl read getattr lock execute execute_no_trans entrypoint open } ;
# Make the type transition from unconfined_t (i.e. user shell) to testprog_t
type_transition unconfined_t testprog_exec_t : process testprog_t;
# Explicitly allow the type transition we have just created
allow unconfined_t testprog_t : process transition ;
После этого переход типа происходит идеально, и работа по завершению политики превратилась в использование sealert
изучить поведение программы и разработать правильную политику, позволяющую ей работать так, как нужно.
Я надеюсь собрать полностью рабочий пример приложения, не поддерживающего SELinux, которое должно работать в собственном ограниченном контексте, а не в неограниченном для моих коллег (и всех, кому это нужно) - сейчас все это довольно скелетно, но если кто-нибудь заинтересован в отслеживании, вы можете найти код здесь: