Meet with SELinux. Basic guide.
This article pointed to selinux novice, and gve basic information about 'how to deal with selinux and do not search in google: omg, a got a permission denied, how to disable selinux???!!!111'. Text organized as a consistent description of configuration process, with additonal notes described different sides of selinux.  We'll start with fresh instance of rhel 6.4. Why not others? You can, but rhel is only one linux with commercial support of selinux and this mean that after enabling you got system look'l like alive, and not a died on mounting root on boot. Some special guys, test that eveything all right, test test test and test again. Believe me it means a lot. Another sign, that we can trust them - selinux is enabled by default not with strongest policy, but this is better than nothing. So, i taking you to share an adventure.

First, you need to install some extra packages:
yum install policycoreutils-python selinux-policy-mls netlabel_tools setools-console .

After that, we need to fix /etc/selinux/config that must become like this:

# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#     enforcing - SELinux security policy is enforced.
#     permissive - SELinux prints warnings instead of enforcing.
#     disabled - No SELinux policy is loaded.
# SELINUXTYPE= can take one of these two values:
#     targeted - Targeted processes are protected,
#     mls - Multi Level Security protection.

and 'touch /.autorelabel'. Attribute 'SELINUX=permissive' mean, that selinux will not deny access that violate policy rules (that need to relabel filesystem) and 'SELINUX=mls' mean that we use mandatory access control mode, that include 'strict' policy, and additional information label part needed by rules implementing Bell-LaPadula model. Why we need filesystem relabel? Every object in system MUST have a label. It is a prerequisite. If object have not a label, system do not known what to do with him and just deny access. Deal with it.

So, reboot system. Smart guy can use just 'reboot', expirenced guy, known what can happer after careless  'reboot' may use 'init 6'. In boot, we have a message like below


After relabelong, system return to multiuser mode.

Now, let's try to change state of selinux. First, let's look system status, executing 'sestatus' command.

[root@rh64-2 ~]# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /selinux
Current mode:                   permissive
Mode from config file:          permissive
Policy version:                 24
Policy from config file:        mls

Or by 'getenforce' command.

If you like extra output, for showing to boss and request respect for your skill, you can use 'sestatus -v'. For scirpting, simple 'getenforce' command exist.

[root@rh64-2 ~]# getenforce

Ok, all extra checking disabled. Now, we can change default selinux mode by set SELINUX=enforcing in /etc/selinux/config file. In runtume, you can execute 'setenforce 1' command, but result of it persist until restart.

Now, we have basic system installed, and let's take a look aroung. First you need to know, every instance in selinux (not only of course) devided in two: subject and object. Subject - who is wanna access, object - to what subject wanna access. For example, you are small boy and you wanna got an access to grandpa rifle.  There are small boy is subject, rifle - object, grandpa - selinux (that punch your dumb head before you got rifle in arm). Selinux policy is just a rules, that govern acess denied or allowed. That policy is very agile, for example, that can allow you looking rifle and walking around, but not got it and shooting your micky mouse (or bear). For identifiying objects and subjects in system, there are a concept of label (contexts) introduced. Let's see at labels on our root home. Everyone known command 'ls' let's execute them with argumen '-Z'.

[root@rh64-2 ~]# ls -alZ /root/
dr-xr-x---. root root system_u:object_r:admin_home_t:s0 .
dr-xr-xr-x. root root system_u:object_r:root_t:s0      ..
-rw-------. root root system_u:object_r:admin_home_t:s0 anaconda-ks.cfg
-rw-------. root root system_u:object_r:admin_home_t:s0 .bash_history
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 .bash_logout
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 .bash_profile
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 .bashrc
-rwxr-xr-x. root root root:object_r:admin_home_t:s0
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 .cshrc
-rw-r--r--. root root root:object_r:admin_home_t:s0    external-local.avc
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 install.log
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 install.log.syslog
-rw-r--r--. root root root:object_r:admin_home_t:s0    ll
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet-1.avc
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet-1.pp
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet-1.te
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet-2.avc
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet-2.pp
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet-2.te
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet.pp
-rw-r--r--. root root root:object_r:admin_home_t:s0    nc-telnet.te
-rwxr-xr-x. root root system_u:object_r:admin_home_t:s0
drwxr-xr-x. root root root:object_r:admin_home_t:s0    sepol
drwx------. root root system_u:object_r:ssh_home_t:s0  .ssh
-rw-r--r--. root root system_u:object_r:admin_home_t:s0 .tcshrc

Woow, we see an evil string, that horror everyone new in selinux: system_u:object_r:admin_home_t:s0 . This awesome string is a context This string, devided by a colon, is a selinux mark that used by selinux kernel module for identifiying everything in system. So, let me describe some fundamental concept of security model used here.

Label contain two main section: system_u:object_r:admin_home_t - is a selinux context (or label) and 's0 and all after' is a security label. To simplification, i will call first label as context (or selinux context) and second as label or security label. There are lot of objects and subjects in system, and system developers can going mad quickly by writing personal rules for every /bin/bash,/bin/sh,/bin/whatthehell in system. Therefore, to facilitate the work, all objects and subject combined into deriatives groups, that called 'context'. Contexts can assigned to programm groups, that not need to access control inside that group. For example, there are some fundamental libraires in system, that ussually used together. So, all of them assigned with 'system_u:object_r:lib_t' context and access allowed to entire group. Yeah , you can say: "Where are 'fine grained' access control you speaking about? You force me to allow access to all libraries that contain 'open,close,connect' and 'unlink' at last!". Sure, you right. But designing computer system is a balance between security and usability. Most secure system i known: is a powered-off, disconnected from all links and burned in place you only know. Yeah, and it is about to secured. But not usable. So, what would the developers had time to drink, some assumptuin made in design.

In most cases, you need see at last section of context, with postfix '_t'. It called 'domain' or 'type. Usually, domain used with subject and type with object. For example in our '/root' home list, most files have a type 'admin_home_t'. Subject can become an object, for example, process is a subject, yeah? They consumpt cpu, leak the memory and like to segfault just before project demo for customer. But if you try to kill them by sending signal, process become an object of access and your 'kill' tool as a subject.

In opposite from selinux contexts, security labels used for implementing 'Bell-LaPadula' security access model (BL-model for short). There are two subtypes, information level (public,confidential,secret, topsecret,myprojects .. etc) and category c0 (for example navy force), c1 (air force), c2 (jedi force), c3 (kitchen receips) ... etc. For example, information about 'jedi force' have different level of access. In public section contain information 'there are no jedi'. In confindential section 'jedi leaved in far far away galaxy'. In secret 'we known this galaxy' and top secret ' - 'i am jedi'. You can see, not everyone must have access to top secret section. But every next (dominated) access level contain more and more information. So, new concept introduced for every subject in system - clearance. Clearance is a top-level of information allowed for this subject. You friend have access to confidential and know, that far far away and star wars. You have clearance 'top secret' - you know, you're jedi. If your friend gain access that you are jedi, you meet a
psychiatrist shortly. So, MLS and BellLaPadulla model protect you privacy and liberty.

Ok, information labels now clear. What about category. This can be understood from name, category is a group of unificated information. You allowed only to kitchen receips? Well, you can read how to melt a magic potion and this is a secret. But you have not access to any information about air force, navy force or jedi. Even public. Nothing. In difference with information level (every next level is dominated previous), category access need equivalence. It's just a bitmask. Needed bit is one - you have access. Bit is zero - have no access. So, full mls label is writed like 's1:c0,c3'. Or with human readable format 'Public:navy force,kitchen receips. Information level can be written like 's0-s3' this mean s0,s1,s2,s3, and category can written as 'c0-c3' (c0,c1,c2,c3) or c0,c4,c5 (mean c0,c4,c5). There are label translation config file exist in /etc/selinux/mls/setrans.conf. So, human readable format made for user convenience.

Last important thing with mls access model is a 'write up, read down'. This mean, that your user (shell process) that have a label Secret:Recips can read any files with level below and  write only to files with labels Secret:Recips and TopSecret:Recips. Yes, this model allowing write a document with level that dominated you. Like to dominate? MLS is for your services.

Summing up, access to object allowed only when condition for both rules are satisfied. And of course, traditinal access control with posix-compilant permission, acl and etc must sutisfied too.

Good, now you have minimal information and let me moving forward. Let configuring user. There are 'semanage user' and 'semanage login' command exist, that manipulate selinux users and mapping system users to selinux users. Selinux users is not a same, that you have in /etc/passwd & etc. There are self operated database, that contain information about labels, contexts and other things. For looking selinux users, just type:

[root@rh64-2 ~]# semanage login -l
Login Name                SELinux User              MLS/MCS Range
__default__               user_u                    s0
root                      root                      s0-s15:c0.c1023
s1                        user_u                    s1
s4                        user_u                    s4
system_u                  system_u                  s0-s15:c0.c1023
There are __default__ mean - all not assigned user, So, all users you just created with smthing like  'useradd -d /dev/null -s /bin/idiot mylovelyboss'. will maped to __default_. Without additional action, user mapped with pre-defined selinux user 'user_u' and security label 's0'. 'root' is for superuser, that have access to entire label range, two my users have acccess to label same with name, and system_u - something like root but slighlty different.

Let's create a new user with  'useradd -d /home/frodo -m -Z user_u frodo'. There flag -Z appeared again, that will following us like a tail everywhere. It has added to every command may affect with selinux. After that, let see semenage output.

[root@rh64-2 mls]# semanage login -l
Login Name                SELinux User              MLS/MCS Range
__default__               user_u                    s0
frodo                     user_u                    s0-s15:c0.c255
root                      root                      s0-s15:c0.c1023
s1                        user_u                    s1
s4                        user_u                    s4
s5                        user_u                    s0-s15:c0.c255
system_u                  system_u                  s0-s15:c0.c1023
Well, there are new user frodo allowed to access entire range. But we do not want trust them, so let assign a clerance s5 with compartment c1 and look again at them

[root@rh64-2 mls]# semanage login -m -s user_u -r s5:c1 frodo
[root@rh64-2 mls]# semanage  login -l |grep frodo
frodo                     user_u                    s5:c1

Excellent, now we need to change label on user home directory. Object labels changed in two way. By 'chcon' command, and in configuration file. Last, used by 'restorecon' utility. Selinux security attributes saved in extended attribute security.selinux. So, we can look at label by:

[root@rh64-2 mls]# ls -lZ /etc/passwd
-rw-r--r--. root root system_u:object_r:etc_t:s0       /etc/passwd
and by

[root@rh64-2 mls]# getfattr -m . -d /etc/passwd
getfattr: Removing leading '/' from absolute path names
# file: etc/passwd

These attributes not created by aerial magic or a SantaClaus. This attr's added when we forced filesystem relabeling by touch /.autorelabel command. Attributes restoring using configs in  '/etc/selinux/$politic_type/contexts/files', where $politic_type is mls, targeted or something other. Every config just a path and corresponded with path label. For example:

[root@rh64-2 files]# head /etc/selinux/mls/contexts/files/file_contexts
/.*     system_u:object_r:default_t:s0
/[^/]+  --      system_u:object_r:etc_runtime_t:s0
/a?quota\.(user|group)  --      system_u:object_r:quota_db_t:s0
/nsr(/.*)?      system_u:object_r:var_t:s0
/sys(/.*)?      system_u:object_r:sysfs_t:s0
/xen(/.*)?      system_u:object_r:xen_image_t:s0
/mnt(/[^/]*)    -l      system_u:object_r:mnt_t:s0
/mnt(/[^/]*)?   -d      system_u:object_r:mnt_t:s0
/bin/.* system_u:object_r:bin_t:s0
/dev/.* system_u:object_r:device_t:s0
Relabling filesystem may take a long time, so it is not often used. Just runtime, context changes may reached by 'chcon' utility, that set attribute without save it in config or recheck entire filesystem. So, let's change home of our user "chcon -l s5:c1 /home/frodo" and look at them.

[root@rh64-2 files]# ls -aZ /home/frodo/
drwx------. frodo frodo user_u:object_r:user_home_dir_t:s0-s15:c0.c1023 .
drwxr-xr-x. root  root  system_u:object_r:home_root_t:s0-s15:c0.c1023 ..
-rw-r--r--. frodo frodo user_u:object_r:user_home_t:s0   .bashrc
[root@rh64-2 files]# chcon -l s0-s5:c1 /home/frodo/
[root@rh64-2 files]# ls -aZ /home/frodo/
drwx------. frodo frodo user_u:object_r:user_home_dir_t:s0-s5:c1 .
drwxr-xr-x. root  root  system_u:object_r:home_root_t:s0-s15:c0.c1023 ..
-rw-r--r--. frodo frodo user_u:object_r:user_home_t:s0   .bashrc
So, frodo's home directory now signed as container for files with label s0-s5:c1. This not mean, you cannot save file with different context or label with that directory. By override rules, you can create file with any context, but can get in trouble, when see a file with '????' instead size, date and permission. So,  just  did not that, if you don't known for what.


There are file created by root with label 's6'. So, by BL-model subject with lesser clearance, cannot access files for read with label above it's range, so  we can't did something with that. Anyway, we seeing filename and this is not good. Secret file out of our clearance can have a protected information in his name, like this example. Now, Frodo know that somebody wanna to deal with it pleasure. He don't know who is this guy, but sure, he is warned.  Usually, that workarounded by using polyinstantation directory that create split-instance of every writable (and not only) directory for every label, but in shared folder this issue can produce information leak.

Now, let's login with our user, and looking our context.

login as: frodo
frodo@'s password:
Last login: Sat May 25 17:52:52 2013
[frodo@rh64-2 ~]$ id
uid=502(frodo) gid=502(frodo) groups=502(frodo) context=user_u:user_r:user_t:s5:c1

Well, we have a user_t domain and s5:c1 as label.

So, we can advance to configure network. By default, network labeling is disabled and need something tune. There are basic config below, that limit information flow based on BL-model and using some base concepts of network protection. For disable firewall fules, that can hide network labeling misconfiguration, just disable iptables by 'iptables -I INPUT -j ACCEPT' for example.

Let install netcat by 'yum install nc' and execute them under user frodo:

login as: frodo
frodo@'s password:
Last login: Sat May 25 23:51:03 2013
[frodo@rh64-2 ~]$ nc -l 5000
nc: Permission denied

What the permission denied? This. Is. SPARTAA! Selinux. First you need to check when unexpected permission error occured - selinux error. That can be found in audit log: /var/log/audit/audit.log .Just let;s grep it out with 'comm=nc' string, and we found that:

[root@rh64-2 ~]# cat  /var/log/audit/audit.log |grep nc
type=AVC msg=audit(1369511732.199:54): avc:  denied  { name_bind } for  pid=1169 comm="nc" src=5000 scontext=user_u:user_r:user_t:s5:c1 tcontext=system_u:object_r:commplex_port_t:s0 tclass=tcp_socket
type=SYSCALL msg=audit(1369511732.199:54): arch=c000003e syscall=49 success=no exit=-13 a0=3 a1=b4f0b0 a2=10 a3=7fff50e69090 items=0 ppid=1076 pid=1169 auid=502 uid=502 gid=502 euid=502 suid=502 fsuid=502 egid=502 sgid=502 fsgid=502 tty=tty2 ses=2 comm="nc" exe="/usr/bin/nc" subj=user_u:user_r:user_t:s5:c1 key=(null)

There are two entries. We needed an AVC (type=AVC). There are a Access Vector Cache record with this type.This record let us know, that operaion 'name_bind' denied for pid 1169, comm=nc, port 5000. Scontext - is a context that 'call' this issue. We executed nc under frodo and context that is. tcontext - context of object, which we wanna get access, and tclass - is a object class. And entire record has occured at '1369511732.199'  and have serial number '54' By serial number you can group events, for example we have same events audited by AVC and SYSCALL types. Both of them have same time and serial. More information available here . So, permission denied called because user_t domain cannot allowed to bind a tcp_socket. What to do? Standart answer is found  in google 'disable selinux, stay dumb'. This is not a way. Yestarday you disable selinux for not touch a trouble, today you moving on red, tomorrow will open a gate for trojans, and day after tomorrow what? Betray your homeland? No no no. Let's explore.

It's time to look at another fearest thing of selinux. Glad to see you, policy. Selinux is all about policy. Most big policy called 'reference policy' or short 'refpolicy'. This rules developed by  wise guyz, that spend with computer more time that i am alive. They created a base rules, but we can extend them with rules needed without rewriting entire config. Thats because it is modular. Every module it's just a small config file, usually devided by target programm or function. So, we need to create our own module that will allow user_u to bind port and establish connect with them. For listing currently loaded policy is a command 'semodule'.

[root@rh64-2 ~]# semodule -l
accountsd       1.0.0
ada     1.4.0
afs     1.5.3
aide    1.5.0
aisexec 1.0.0
amanda  1.12.0
amavis  1.10.3
....there are lot of another lines ...

All modules uniquly identified by it's name. Version string (second colon) dos not matter, so you cannot load a module with same name and different version. semodule just replace old one. Good, let's make a policy. Simplest way to create it (but not a best choose) is using audit2allow. This tool read an avc and produce policy rule that allowed denied action. Let's try.

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 1369511732.199:54|audit2allow
#============= user_t ==============
#!!!! This avc can be allowed using the boolean 'user_tcp_server'
allow user_t commplex_port_t:tcp_socket name_bind;
First you need to read a line with '!!!!', trust me, this is important. Here, audit2allow warn us, that instead making a module, we can use boolean variable. Booleans is a system-wide variables configured by system administrator. There are many of variables, and you can list all of them:

[root@rh64-2 ~]# getsebool -a
allow_auditadm_exec_content --> on
allow_console_login --> off
allow_cvs_read_shadow --> off
allow_daemons_dump_core --> off
allow_daemons_use_tcp_wrapper --> off
... and more ...

Every variable can be off or on (0 and 1). Do not have to be Einsten, that 1 is appropriate flag is enabled, and 0 is disabled. To set variable there is a 'setsebool' command exist. So, instead understadning the modules, compiling and other pice of ... pieace, we can enable option and stay relax. This can did with ' setsebool user_tcp_server=1' command. Now, repat step with executing nc.

[frodo@rh64-2 ~]$ nc -l 5000

Wow, they run! Login to another console with frodo login and trying telnet to 5000. You must got a established connection and send/.recv data between peers. But ... what happen if we will not use recommended by audit2allow boolean, and walking with way of real man with steel balls? Well, let's disable boolean by 'setsebool user_tcp_server=0' and execute audit2allow with -M  module_name arguments that say to create and compile appripriate module named by 'module_name'. But let save avc record first, we use it in future.

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 1369511732.199:54 > nc-telnet.avc
[root@rh64-2 ~]# cat nc-telnet.avc|audit2allow -M nc-telnet
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nc-telnet.pp
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nc-telnet.pp
Woohoo! There are two files created in current directory, nc-telnet.te and nc-telnet.pp. FIrst of them is a source of module, and second - compiled module. You can load them now with command showed above, and check that loaded:

[root@rh64-2 ~]# semodule -l|grep nc-telnet
nc-telnet       1.0

Good, let;s try to execute our nc and telnet and must get a connection success. There are two ways to compile custom crteated module. For example, you can execute:

[root@rh64-2 ~]# make -f /usr/share/selinux/devel/Makefile
Compiling mls nc-telnet module
/usr/bin/checkmodule:  loading policy configuration from tmp/nc-telnet.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 10) to tmp/nc-telnet.mod
Creating mls nc-telnet.pp policy package
rm tmp/nc-telnet.mod tmp/nc-telnet.mod.fc
and got same nc-telnet.pp module file. If need, you can make all steps by self:

[root@rh64-2 ~]# checkmodule -M -m -o nc-telnet.mod nc-telnet.te
checkmodule:  loading policy configuration from nc-telnet.te
checkmodule:  policy configuration loaded
checkmodule:  writing binary representation (version 10) to nc-telnet.mod
[root@rh64-2 ~]# semodule_package -o nc-telnet.pp -m nc-telnet.mod
Excellent, everyting all right? Not yet. Let's create another user with label different that 'frodo' account.

[root@rh64-2 ~]# useradd -d /home/gollum -m -Z user_u gollum
[root@rh64-2 ~]# semanage login -m -s user_u -r s1:c1 gollum
[root@rh64-2 ~]# semanage login -l|grep gollum
gollum                    user_u                    s1:c1

And login them:

login as: gollum
gollum@'s password:
[gollum@rh64-2 ~]$ id
uid=503(gollum) gid=503(gollum) groups=503(gollum) context=user_u:user_r:user_t:s1:c1

Yaw, now execute 'nc -l 5000' with frodo and let's try to connect this service from gollum account. The must be denied, yeah? And you loose. Connection established. We can seen a process list

[root@rh64-2 ~]# ps -afZ|egrep "nc|telnet"
user_u:user_r:user_t:s5:c1      frodo     2022  1086  0 13:52 pts/1    00:00:00 nc -l 5000
user_u:user_r:user_t:s1:c1      gollum    2024  2003  0 13:52 pts/2    00:00:00 telnet 5000

We see, nc and telnet have a different label s5:c1 and s1:c1, but connection success. Hmm. let's try to connect to port from external network .. another  success... So any can connect to any, that is wrong. Why? For what? I was a good boy, i hate a capitalism, like opensource and have a photo with Statue of Liberty. Thats right, you are good citizen, but selinux do not limit network by default. We must add some basic rules, for taking system secure in network.

There are three implementation of network labeling: secmark, labeled ipsec and netlabel. Secmark is a labeling associated with iptables. You can mark any traffic by iptables rules with label you need, and selinux proceed checking like a subject-object. labeled ipsec leads to encrypt traffic for every label by self key. It applies to contexts and labels both. And last, netlabel static/fallback labeling. This part implement the cipsov4 protocol, that allow to transfer information security label (only label, not a context) via network. We configure only last subsystem, it enough to reach our target - prevent information leak between labels.

Netlabel configured by 'netlabelctl' command with first argument called 'module'. This module can be unlbl - for assigning labels to hosts not supported labeling, cipsov4 for hosts that supported cipsov4 and map, that allow configuring host/protcol association. At start, let's see unlabeled network configuration:

[root@rh64-2 ~]# netlabelctl -p unlbl list
Accept unlabeled packets : on
Configured NetLabel address mappings (0)

So, no config, go and fix:

[root@rh64-2 ~]# netlabelctl unlbl add interface:eth1 address: label:system_u:object_r:netif_t:s1:c1
[root@rh64-2 ~]# netlabelctl -p unlbl list
Accept unlabeled packets : on
Configured NetLabel address mappings (1)
interface: eth1
label: "system_u:object_r:netif_t:s1:c1"
There are eth1 as interface, as network, and last statement mean, that all traffic with with interface and network has forced to label 'system_u:object_r:netif_t:s1:c1' So, any traffic that come in from this address, will be labeled as s1:c1. I draw your attention - incoming, output traffic not covered by this option.

Now, we need to map protocol (unlabeled) with network. So, let's take a look at configuration, change it and look again:

[root@rh64-2 ~]# netlabelctl -p map list
Configured NetLabel domain mappings (1)
domain: DEFAULT
protocol: UNLABELED
[root@rh64-2 ~]# netlabelctl map del default
[root@rh64-2 ~]# netlabelctl map add default address: protocol:unlbl
[root@rh64-2 ~]# netlabelctl -p map list
Configured NetLabel domain mappings (1)
domain: DEFAULT
protocol: UNLABELED

Thus, by default all traffic unlabeled, we have deleted default configuration and have added new entry for our network. Of course, we can do not touch config, everyting will work fine in this part, but we'll need this config later.

For filtering output traffic, we use 'semanage interface' command. We print, configure and print again our configuration:

[root@rh64-2 ~]# semanage interface -l
SELinux Interface              Context
lo                             system_u:object_r:lo_netif_t:s0-s15:c0.c1023
[root@rh64-2 ~]#
[root@rh64-2 ~]# semanage interface -a -t netif_t -r s1:c1 eth1
[root@rh64-2 ~]# semanage interface -l
SELinux Interface              Context
eth1                           system_u:object_r:netif_t:s1:c1
lo                             system_u:object_r:lo_netif_t:s0-s15:c0.c1023

Let's test our configuration. Now, mr.Gollum execute 'nc -l 5000' that will have context s1:c1 (same that we assigned to external network) for incoming connection... and peer from external network with label s1:c1 will deny to connect, and just got time out. Tooking a deny record, will return following new record (i skip prevous avc for clean output):

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000
type=AVC msg=audit(1369596207.593:112): avc:  denied  { ingress } for  saddr= src=61412 daddr= dest=5000 netif=eth1 scontext=system_u:object_r:netif_t:s1:c1 tcontext=system_u:object_r:netif_t:s1:c1 tclass=netif

Hmm. strange.. tcontext values is not a user_t... That because assigned to address context netif_t not allowed to 'ingress' with netif_t (huh, not sure that my explanation is clearm you can see there here ). So, we call our friend audit2allow, but first grep out interested avc from audit, and dropping them to file, and use audit2allow with it. Do not forget, we have nc-telnet module installed already.

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000|grep ingress  > nc-telnet-2.avc
[root@rh64-2 ~]# cat nc-telnet-2.avc |audit2allow -M nc-telnet-2
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nc-telnet-2.pp
[root@rh64-2 ~]# cat nc-telnet-2.te
module nc-telnet 1.0;
require {
type netif_t;
class netif ingress;
#============= netif_t ==============
allow netif_t self:netif ingress;
[root@rh64-2 ~]# semodule -i nc-telnet-2.pp

We have installed our module into runtime policy by last command. Let's try again to connect ... and timed out again.. huh.. lets look audit again ... this soo.. no, just look.

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000
type=AVC msg=audit(1369598246.173:448): avc:  denied  { recvfrom } for  saddr= src=62356 daddr= dest=5000 netif=eth1 scontext=system_u:object_r:netif_t:s1:c1 tcontext=system_u:object_r:node_t:s0-s15:c0.c1023 tclass=node

Now, we have another scontext->tcontext denied but with different function: recvfrom.. Repeating trick with audit2allow (sooo magic tool):

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000 > nc-telnet-3.avc
[root@rh64-2 ~]# cat nc-telnet-3.avc |audit2allow -M nc-telnet-3
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nc-telnet-3.pp
[root@rh64-2 ~]# semodule -i nc-telnet-3.pp

connect .. and timed out again.. thats bored, but we about to finish ...

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000
type=AVC msg=audit(1369598433.023:538): avc:  denied  { recv } for  saddr= src=62435 daddr= dest=5000 netif=eth1 scontext=user_u:user_r:user_t:s1:c1 tcontext=system_u:object_r:netif_t:s1:c1 tclass=peer

Ouch, now 'recv'. Fix them:

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000 > nc-telnet-4.avc
[root@rh64-2 ~]# cat nc-telnet-4.avc |audit2allow -M nc-telnet-4
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nc-telnet-4.pp
[root@rh64-2 ~]# semodule -i nc-telnet-4.pp

and WoooHoo! Connection established. You can transfer data to and from.. but let's execute nc under 'frodo' that have a different label that network, and we got another deni with audit:

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000
type=AVC msg=audit(1369599135.160:754): avc:  denied  { egress } for  saddr= src=5000 daddr= dest=62747 netif=eth1 scontext=user_u:user_r:user_t:s5:c1 tcontext=system_u:object_r:netif_t:s1:c1 tclass=netif

Hmm.. egress... that is output traffic control.. why connection stopped when nc answered external? Thats right, BL-model allow information flow from down to up. External net have a s1:c1 label, that less than s5:c1 label, so packets from our external telnet succesfuly recived by nc .. nc tried to send answer, and got access denied.. If you try to allow this traffic, you got that:

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000
type=AVC msg=audit(1369599135.160:754): avc:  denied  { egress } for  saddr= src=5000 daddr= dest=62747 netif=eth1 scontext=user_u:user_r:user_t:s5:c1 tcontext=system_u:object_r:netif_t:s1:c1 tclass=netif
[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000|audit2allow
#============= user_t ==============
#!!!! This avc is a constraint violation.  You will need to add an attribute to either the source or target type to make it work.
#Contraint rule:
allow user_t netif_t:netif egress;

We see '!!!!' again, and this message usually say, that there are no problem with context access. We have a label issue and operation 'egress' violate BL-policy (s5 send traffic to s1) so you can't allow it so simple. There are way exist for WA this, but not in this article. We go forward and finish our configuration. Now, we'll configure a loopback. On loopback, we may use cipsov4 protocol, that allow label information transfered with ip header. This mode requiret both peer be a cipso-aware. As we have source and destination leaved on one system, let configure 'lo' with cipso.

This can be done with:

[root@rh64-2 ~]# netlabelctl cipsov4 add pass doi:32 tags:1
[root@rh64-2 ~]# netlabelctl map add default address: protocol:cipsov4,32
[root@rh64-2 ~]# netlabelctl map add default address: protocol:cipsov4,32
[root@rh64-2 ~]# netlabelctl -p map list
Configured NetLabel domain mappings (1)
domain: DEFAULT
protocol: CIPSOv4, DOI = 32
protocol: UNLABELED
protocol: CIPSOv4, DOI = 32
As you remember (or not, does not matter), we already deleted default rule for address/protocol mapping module, and now we have added another two entries, that mapped local addresses ( that is adress of my eth1) to cipsov4. Command with 'cipsov4 add pass ...' just say that we do not make any converse between label and transfer everything as is. DOI (domain of interpretation) - is a value, that transfered with cipso header too and can be used for different map rules with different DOI. So by this value, we just identity which cipsov4 rule will be used with network. There are more information available here .

Let gollum listen port 5000 and try to connect self by telnet.. and got 'no route to host. That's so boring. We try one trick. For speeding up deny collection, let disable selinux temporary with 'setenforce 0', establish connection and grep all deny that will produces by our action without step-by-step connection process:

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000
type=AVC msg=audit(1369677096.148:173): avc:  denied  { ingress } for  pid=1379 comm="telnet" saddr= src=58321 daddr= dest=5000 netif=lo scontext=system_u:object_r:netlabel_peer_t:s1:c1 tcontext=system_u:object_r:lo_netif_t:s0-s15:c0.c1023 tclass=netif
type=AVC msg=audit(1369678066.257:227): avc:  denied  { recvfrom } for  pid=1451 comm="telnet" saddr= src=58322 daddr= dest=5000 netif=lo scontext=system_u:object_r:netlabel_peer_t:s1:c1 tcontext=system_u:object_r:node_t:s0-s15:c0.c1023 tclass=node
So, we need to allow two rules for success. Did it.

[root@rh64-2 ~]# cat /var/log/audit/audit.log |grep 5000 > nc-telnet-5.avc
[root@rh64-2 ~]# cat nc-telnet-5.avc |audit2allow -M nc-telnet-5
******************** IMPORTANT ***********************
To make this policy package active, execute:
semodule -i nc-telnet-5.pp
[root@rh64-2 ~]# semodule -i nc-telnet-5.pp

Let's try, and gotcha! Gollum can connec to to Gollum. We congratulate him both, and try to connect our netcat under frodo acc, got a no route to host and see following entries n audit:

type=AVC msg=audit(1369678190.991:281): avc:  denied  { recv } for  pid=1509 comm="telnet" saddr= src=58324 daddr= dest=5000 netif=lo scontext=user_u:user_r:user_t:s1:c1 tcontext=system_u:object_r:netlabel_peer_t:s5:c1 tclass=peer
Ttanslating that to human language i leave with you. We about to end, but i am disturbed by one thing (don't known how are you). We written six different policies, loaded them all and this is bad. Let's merge them together and make a small phocus-pocus. Selinux have additional abstraction layer, that called 'interface macro' They give ability to merge multiply rules into one strings and get a compact, reader-friendly output. Audit2allow provide basic macro-replacing with -R argument, let's use them:

[root@rh64-2 ~]# cat *.avc|audit2allow -R
require {
  type netlabel_peer_t;
  type netif_t;
  type user_t;
  class peer recv;
#============= netif_t ==============
#============= netlabel_peer_t ==============
#============= user_t ==============
allow user_t netif_t:peer recv;
We see new lines, corenet_in.. blah blah blah.  This is a macro. Usually, they defined in .if' files, for example at '/usr/share/selinux/devel/include/services/' path you can found a 'corenetwork.if' contained multiply definition. So, instead using allow me eneme:thing anotherthing, you can add human clear macro, and be cool. As homework, remove all ours modules, make a merged policy with interface macro, and check that we got a same result.
One important note, all three labeling methods independent from each other. If you configure only netlabel - secmark and labeled ipsec left unconfigured, so your data will checked only by netlabel module only. After your configure secmark (with netlabel configured already for example) your data will checked twice, with secmark _and_ netlabel. So, data transfer allowed only when all configure methos allow it. Labels mark, tags, every peace of peace for secmark and netlabel not related between it. Traffic may be labeled in secmark by netlabel_peer_t and same time by 'node_t' in netlabel module, and it will require different rules to allow. You cannot 'relabel' incomfing traffic ..FIXME

Last tip. You can detect, that not all access denied showed in audit log. That's caused by 'dontaudit' rule, that implemented for hiding rapidly repeating messages from known sources that must be denied. For showing everything, you can use 'semanage -DB' command and see flood in log. Moe information available here

You are viewing vladhalilov