Sl

Материал из ALT Linux Wiki

Howto get working SeLinux AltLinux policy

Force relabeling

touch /.autorelabel

Update Grub config

Update configuration GRUB's file: /etc/sysconfig/grub2:

GRUB_CMDLINE_LINUX_DEFAULT='panic=30 quiet splash security=selinux selinux=1'

It is also possible to add:

  • enforcing=1
  • log_buf_len=1M
grub-mkconfig  > /boot/grub/grub.cfg

PAM configuration

  • Add to /etc/pam.d/newrole before pam_namespace.so module
session        required pam_exec.so debug /etc/security/alt.newrole/helper /etc/security/alt.newrole/config
  • Add to /etc/pam.d/common-login:
# The first `session' module
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
# The last `session' module
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open verbose

Reboot

reboot system with enabled selinux

Install policy

Install package selinux-policy-altlinux

Reboot system again

ALT Linux aspects

newrole modifications

Add patch for policycoreutils-newrole has patch, that adds to Linux capabilities: CAP_SETGID & CAP_AUDIT_WRITE. For more info look up at: http://git.altlinux.org/gears/p/policycoreutils.git

Users

When system's users login the __default__ rule takes action. This rule says that:

  • all system users are mapped to generic_u SeLinux user.
  • all OS users has access only to s0 level.
# semanage login -l
Login Name                SELinux User              MLS/MCS Range            
__default__               generic_u                 s0                       
root                      officer_u                 s0-s5:c0.c15       

Add for specfic user:

# semanage login -a -s generic_u -r s0-s3:c2.c14 stanv


Policy's internals

systemd

systemd-journald - выполняется в домене trusted_t. Это обусловленно тем, что ему необходимо читать статус процессов из /proc/<PID>. В свою очередь, proc-файлы для каждого процесса имеют контекст процесса.

Network

IPv6 не поддерживается!
/* since we don't support any IPv6 labeling protocols right
 * now we can optimize everything away until we do */
Для конечного дистрибутива должно быть собрано специальное ядро, без IPv6.

Одна TCP транзакция для auditallow unconfineddomain file_type:{ peer } recv;

# ./getpeercon_server 777
-> running as officer_u:generic_r:generic_t:s3:c3-s15:c0.c31
-> creating socket ... ok
-> listening on TCP port 777 ... ok
-> waiting ... 


Посылает сообщение nc из s4:c4

# echo 'Hello world!' | nc localhost 777

выглядит следующим образом:

granted  { recv } for  pid=9879 comm="nc" saddr=127.0.0.1 src=58387 daddr=127.0.0.1 dest=777 netif=lo scontext=officer_u:generic_r:generic_t:s3:c3-s15:c0.c31 tcontext=generic_u:object_r:unlabeled:s4:c4 tclass=peer
granted  { recv } for  pid=9879 comm="nc" saddr=127.0.0.1 src=777 daddr=127.0.0.1 dest=58387 netif=lo scontext=officer_u:generic_r:generic_t:s4:c4-s15:c0.c31 tcontext=generic_u:object_r:unlabeled:s0 tclass=peer
granted  { recv } for  pid=9879 comm="nc" saddr=127.0.0.1 src=58387 daddr=127.0.0.1 dest=777 netif=lo scontext=officer_u:generic_r:generic_t:s3:c3-s15:c0.c31 tcontext=generic_u:object_r:unlabeled:s4:c4 tclass=peer
granted  { recv } for  pid=9879 comm="nc" saddr=127.0.0.1 src=58387 daddr=127.0.0.1 dest=777 netif=lo scontext=officer_u:generic_r:generic_t:s4:c4 tcontext=generic_u:object_r:unlabeled:s4:c4 tclass=peer
granted  { recv } for  pid=9867 comm="gs" saddr=127.0.0.1 src=777 daddr=127.0.0.1 dest=58387 netif=lo scontext=officer_u:generic_r:generic_t:s4:c4-s15:c0.c31 tcontext=generic_u:object_r:unlabeled:s4:c4 tclass=peer
granted  { recv } for  pid=9879 comm="nc" saddr=127.0.0.1 src=58387 daddr=127.0.0.1 dest=777 netif=lo scontext=officer_u:generic_r:generic_t:s4:c4 tcontext=generic_u:object_r:unlabeled:s4:c4 tclass=peer
granted  { recv } for  pid=9867 comm="gs" saddr=127.0.0.1 src=777 daddr=127.0.0.1 dest=58387 netif=lo scontext=officer_u:generic_r:generic_t:s4:c4-s15:c0.c31 tcontext=generic_u:object_r:unlabeled:s4:c4 tclass=peer
granted  { recv } for  pid=9867 comm="gs" saddr=127.0.0.1 src=58387 daddr=127.0.0.1 dest=777 netif=lo scontext=officer_u:generic_r:generic_t:s4:c4 tcontext=generic_u:object_r:unlabeled:s4:c4 tclass=peer


Разбор:

  1. getpeercon_server работает как s3:c3-s15:c0.c31<br\>
  2. nc работает как s4:c4-s15:c0.c31<br\>
  3. трафик от s4:c4-s15:c0.c31 получается s4:c4<br\>
  4. tcontext=generic_u:object_r:unlabeled:s0 - SYN, SYN+ACK (видимо, от ядра, поэтому s0)
  5. tclass == peer относится только к классу трафика
  6. define(`all_peer_perms',`{ recv }') - у этого класса (трафика) есть только один метод recv
  7. в сокет scontext=officer_u:generic_r:generic_t:s4:c4 припёрся пакет с tcontext=generic_u:object_r:unlabeled:s4:c4
  8. получается, что где-то в районе accept новому сокету назначается контекст в соответствии с тем, кто туда пришёл. Cубъект тут — именно сокет, поскольку пакет кладётся в буфер сокета, а какой именно процесс потом его оттуда будет брать, неизвестно.
  9. сокет - можно и другому процессу передать. смысл в том, что читать из сокета может совсем не тот процесс, который его создавал.
  10. при системном вызове проверка SOCKET__READ, и вот тут уже субъектом будет процесс, а объектом — сокет
  11. sid нового сокета делается через security_sid_mls_copy(sksec->sid, peersid, &newsid);
  12. без CIPSO у тебя peersid не приедет с другого конца
  13. security_sid_mls_copy() - computes a new sid based on the given * sid and the mls portion of mls_sid.
  14. вот так у сокета и получается s4:c4, поскольку оно из пакета приходит
  15. s3:c3 создал себе сокет, в него пришел трафик, и сокет стал == уровню трафика который туда попал.
 вот нашёл место, где sock->sk->sk_security->sid всё-таки попадает в SOCK_INODE(sock)->i_security->sid
 selinux_sock_graft
 вызывается из inet_accept
 так что по идее в проверках read для socket можно ловить приём не тем процессом, каким надо с учётом изменения уровня сокета


CIPSOv4

Пакеты маркируются утилитой netlabelctl.

В заголовок IP пакета добавлется security option 134 (0x86)

http://tools.ietf.org/html/draft-ietf-cipso-ipsecurity-01

После добавления в IP заголовок пакета security option некие сетевые протоколы начинают странно себя вести.

ICMP

Каждый ответ приходит с сообщением: unknown option 86. Что само по себе, режет глаза. Но по словам Paul Moore:

I agree it is annoying, but ping is a rather unusual application in that it deals with raw packets (at least the last time I looked at the code). At some point I should probably submit a patch to quiet the CIPSO option but that is a very low priority item on my todo list.

# ping 192.168.55.2
PING 192.168.55.2 (192.168.55.2) 56(84) bytes of data.
64 bytes from 192.168.55.2: icmp_req=1 ttl=64 time=0.125 ms
unknown option 86
64 bytes from 192.168.55.2: icmp_req=2 ttl=64 time=0.085 ms
unknown option 86
22:36:34.316321 IP (tos 0x0, ttl 64, id 0, offset 0, flags [DF], proto 
ICMP (1), length 96, options (unknown 134,EOL))
    192.168.55.2 > 192.168.55.1: ICMP echo request, id 3627, seq 1, 
length 64

TCP

TCP подглючивает местами, и именно неправильно выставляется cksum:

192.168.55.1.8811 > 192.168.55.2.38542: Flags [S.], cksum 0xef7a (incorrect -> 0xce92), seq 3815783505, ack 2513766785, win 14600, options [mss 1460,nop,nop,sackOK,nop,wscale 7], length 0
или
22:40:35.038984 IP (tos 0x0, ttl 64, id 47912, offset 0, flags [DF], proto TCP (6), length 52, options (unknown 134,EOL)) 
192.168.55.1.8811 > 192.168.55.2.38543: Flags [F.], cksum 0xef6e (incorrect -> 0x73c6), seq 1, ack 8, win 115, length 0 

Paul Moore отвечает как:

I remember there being an issue with IP/TCP checksum offload and tcpdump/wireshark if it was run on the system being monitored. You can always use netstat or similar tools to verify the number of dropped/bad packets on a system.

А еще некто ответил:

так кривые контрольные суммы для своих исходящих пакетов там всегда были
надо сетевуху отупить совсем, чтобы там всё заполнено было
в сеть они нормальные уходят
просто считаются аппаратно
можно в ethtool -K поотрубать всё

sshd

Для openssh нужен патч, иначе sshd демон будет закрывать все соединения со следующим сообщением:

Jul  5 22:29:21 se1 sshd[4881]: fatal: Connection from D*\v\312\230\177 with IP options: 86 0b 00 00 00 01 01 05 00 04 04 00

Клиент будет обламываться как:

# ssh 192.168.55.1
 ssh: ssh_exchange_identification: Connection closed by remote host

Для этого нужно приложить патч: openssh-5.2p1-allow-ip-opts.patch.

ALT Linux

В ALT Linux решено, отключить маркировку трафика s0.
Но, в тоже самое время маркировать трафик, например, s0:c1.
Это достигнуто изменением:

  • netlabel_tools. В команду netlabelctl добавлен переключатель: s0 on|off. С помощью этого переключателя можно указать ядру, следует ли маркировать трафик s0.
  • Пропатчено ядро. git.alt. Данный патч должен быть в ядре std-def.

Создатель защищенного дистрибутива должен иметь файл конфигурации для netlabel следующего содержания:

# cat /etc/netlabel.rules
cipsov4 add pass doi:1 tags:1
map del default
map add default protocol:cipsov4,1
map s0 off

И должен быть настроен systemd, чтобы правила для netlabel применялись при загрузке ОС:

# systemctl enable netlabel

CUPS

Поток задания в CUPS

  • CUPS должен быть собран с cups-1.6.1-rh-lspp.patch

Патч позволяет при печати документов локально через сокет: /var/run/cups/cups.sock передавать контекст отправителя.

  • Файл настройки /etc/cups/cupsd.conf должен быть отредактирован:
    1. Закоментировать строку Listen *:631 (при этом отключится WEB-интерфейс). К сожалению патч выше не умеет доставать SeLinux контекст из сетевых пакетов. Думаю этому можно его научить (stanv@).
    2. Добавить строку ClassifyOverride No -- что запретит пользователю передавать опцию -o job-sheets=none (запретит пользователю вручную отключать печать сумирующей страницы для задания).
    3. Добавить строку Classification selinux -- или Classification te или Classification mls. После чего в CUPS будет создаваться переменная: security-context которую можно потом прочитать: cupsGetOption("security-context", noptions, options). Эта опция указывает что для каждого задания печатать дополнительно две страницы (вначале и в конце).
  • При указании опции Classification <banner> должна присутствовать страница-банер по пути: "/usr/share/cups/banners/<banner>

Вот тут начинается самое интересное.

    1. До недавного времени страница-баннер могла быть в формате PostScript. В PostScript передаются содержимое всех переменных (security-context) и потом можно запрограммировать на PostScript как красиво создать стреницу баннер с имеющимися переменными. В RHEL (в *) можно "украсть" красивые баннеры в формате PostScript, которые умеет печатать содержимое переменной security-context. Проблема кроется в том что переменные в CUPS будут содержать UTF8 текст. И в PS документе они будут искажены.
  • Мы создали патч для фильтра bannertopdf который позволяет заполнять готовые PDF-формы.

В багзиле мантейнера заведена ошибка, где можно получить дополнительную информацию: openprinting bugzilla Порядок работы:

  1. В OpenOffice создается документ.
  2. Документ должен состоять не более одной страницы.
  3. Документ заполняется согласно требованиям.
  4. В места где должна выводится информация из окружения CUPS нужно вставить поле текст.
  5. Назначить полю нужное имя.
  6. Доступные имена полей можно посмотреть в файле cups-filters/filter/bannertopdf.c, функция get_known_opts()
  7. Документ сохранятся, потом экпортируется в PDF.
  8. Полученный PDF-файл сохраняем в /usr/share/cups/data
  9. Пишем новый banner для фильтра bannertopdf и кладем его в /usr/share/cups/banners. Примером может служить файл form
  10. В cups используем опцию: -o job-sheets=secret или правим конфигурационные файлы соответственно для использования этой опции.

В refpolicy для домена cupsd_t определены следующие свойства:

mls_fd_use_all_levels(cupsd_t)                                                  
mls_file_downgrade(cupsd_t)                                                     
mls_file_write_all_levels(cupsd_t)                                              
mls_file_read_all_levels(cupsd_t)                                               
mls_rangetrans_target(cupsd_t)                                                  
mls_socket_write_all_levels(cupsd_t)