Log in

No account? Create an account

Previous Entry | Next Entry

Transitioning to Secmark

Back in the 2.6.18 timeframe James Morris developed a replacement for the now-named "compat_net" SELinux access controls which filtered packets based on network attributes, the replacement was called Secmark. Secmark was introduced to fix two major issues with the aging compat_net access controls; the first problem being that they were not as flexible as iptables/netfilter rules and the second, very related problem, was that the compat_net controls were slow and likely would always be slow due to fundamental design issues. The solution to both these problems was to leverage the existing iptables/netfilter mechanism to label packets and replace the crude packet matching mechanisms of the compat_net design. As of 2.6.29 release the compat_net functionality is deprecated and patches completely removing it from the kernel have been merged into the 2.6.30 release candidates.

Secmark works by using iptables/netfilter to assign a label, or "security mark" aka Secmark, to specific packets which are later used by SELinux when the per-packet access controls are applied. This approach allows administrators to match packets based not only on the existing compat_net attributes such as port and host, but also any network attribute supported by iptables/netfilter, including stateful connection matching. The article by James Morris (linked above) is an excellent introduction to Secmark and for those of you looking to get the most out of the new functionality I encourage you to head over there first. What I hope to do here is not duplicate James' article, but rather provide a quick guide on how to duplicate basic compat_net functionality using the new Secmark controls.

Before we start it is important to first identify if the system you are using has Secmark enabled, you can do this by looking at the value in "/selinux/compat_net". If the file does not exist on your system and you have SELinux enabled then you are either using a very old kernel which does not support Secmark, or a new kernel (2.6.30 or greater) that only supports Secmark. However, for those systems that do have the file, if the contents are "0" then Secmark is enabled, otherwise you are still using the older compat_net controls. If you want to enable Secmark you can do so by writing a "0" to the file but you may first want to ensure that your SELinux policy and iptables/netfilter toolchain are up to date and provides Secmark support.

# cat /selinux/compat_net

The first step in using Secmark is to define a new SELinux label for the network traffic we are labeling and write the corresponding SELinux policy to handle the newly labeled traffic. This highlights the major difference between compat_net and Secmark: with the compat_net controls you assign labels to ports and hosts, but with Secmark you label the packets themselves. The second step is to determine which network attributes you want to match on when you are labeling packets. Both compat_net and Secmark can match on any combination of port and host so you should be able to transition all of your existing compat_net rules to Secmark; the only difference here is that with compat_net each port and host entry received its own label but with Secmark each combination of port and host receives a label. In the example below, we are going to configure Secmark to label SSH packets from host foo.lan with the label "foo_ssh_packet_t" and allow it to connect to the SSH daemon running on our local system with label "sshd_t". Careful observers will note that I currently have the MLS policy installed but the same procedure will work equally well with the default targeted policy.

Since we using a custom SELinux label the first thing we need to do is write a SELinux policy module to define the new type and the policy allowing this type to be received by the SSH daemon over the network. The policy we are using is shown below:

# policy header
        type sshd_t;

# our new secmark packet type
type foo_ssh_packet_t;

# allow sshd_t to receive our new packet type
allow sshd_t foo_ssh_packet_t:packet recv;

We can quickly compile and install our new policy module with the following commands:

# cp /usr/share/selinux/devel/Makefile .
# make                                  
Compiling mls secmark_example module                      
/usr/bin/checkmodule:  loading policy configuration from tmp/secmark_example.tmp
/usr/bin/checkmodule:  policy configuration loaded                              
/usr/bin/checkmodule:  writing binary representation (version 10) to tmp/secmark_example.mod                                                                    
Creating mls secmark_example.pp policy package                                  
rm tmp/secmark_example.mod tmp/secmark_example.mod.fc                           
# ls                                                          
Makefile            secmark_example.if  secmark_example.te                      
secmark_example.fc  secmark_example.pp  tmp                                     
# semodule -i secmark_example.pp
# semodule -l | grep secmark_example
secmark_example 0.1.0

The next and final step is to setup the iptables/netfilter Secmark rules to label the packets correctly:

# host foo.lan
foo.lan has address
# iptables -t mangle -A INPUT -p tcp --src --dport 22 -j SECMARK --selctx system_u:object_r:foo_ssh_packet_t:s0
# iptables -t mangle -L
target     prot opt source               destination

Chain INPUT (policy ACCEPT)
target     prot opt source               destination
SECMARK    tcp  --  foo.lan              anywhere            tcp dpt:ssh SECMARK selctx system_u:object_r:foo_ssh_packet_t:s0

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

target     prot opt source               destination

At this point we are finished, packets coming from foo.lan and destined for port TCP/22 on our system will be labeled as "foo_ssh_packet_t" with SELinux providing assurance that only "sshd_t" can read "foo_ssh_packet_t" packets. You can verify this quite easily be removing the allow rule from the custom SELinux policy and watching SSH traffic from foo.lan stop, you will also see new SELinux AVC denial messages with the "foo_ssh_packet_t" type.

One final note, remember that with modern Linux Kernels there are two types of SELinux security labels assigned to a packet, the Secmark labels described here and the peer labels described previously. These two types of packet labels operate differently and subject to their own, independent set of SELinux access controls. The Secmark packet labels are used to represent the network attributes of a packet such as IP addresses and ports, while the peer packet labels are used to represent the security attributes of the sender such as the SELinux label of the process which generated the network packet.

UPDATE: Laszlo Beres has been kind enough to provide a Hungarian translation.
counter create hit


( 7 comments — Leave a comment )
May. 17th, 2013 01:50 pm (UTC)
Thanks for example, but i have an strange result from using this. Just one rule added to table, and netlabel labeling become broken. For example, nc -l 5000 executed under user_u:user_r:user_t:s4 label. Without secmark rules, i can establish connection to this port under this user. After adding rule for completely different port (9000) i got an avc denie

type=AVC msg=audit(1368798120.534:1294): avc: denied { recv } for pid=2906 comm="telnet" saddr= src=48931 daddr= dest=5000 netif=lo scontext=user_u:user_r:user_t:s4 tcontext=system_u:object_r:unlabeled_t:s15:c0.c1023 tclass=packet

Huh, source label is correct, but destination is completely incorrect. Is this mean, that secmark and netlabel is incompatible? netlabel config is similary like from this post http://paulmoore.livejournal.com/7632.html
May. 17th, 2013 02:18 pm (UTC)
The denial you are seeing, packet:recv, is due to secmark and not NetLabel. What likely happened is that when you created your single secmark rule you enabled the secmark access controls in the kernel and as a result every packet is now being checked via the SELinux/secmark rules. If you don't explicitly assign a secmark label using the iptables/secmark rules then the "unlabeled_t" label is used by the kernel.
May. 17th, 2013 05:36 pm (UTC)
Is me understanding right, that after secmark enabled, no any netlabel rules in effect and no any way to 'bypass' trafic via secmark for handling by netlabel? If so, thats limiting usability :( I had hoped, that can make a fine tune for some packets by secmark rules, and don't touch other.
May. 17th, 2013 06:18 pm (UTC)
No, both the NetLabel and secmark controls can be enabled at the same time. In your particular case you mentioned that the NetLabel based access control was working, but when you added a secmark configuration the network traffic was denied; both access control checks are taking place, but in your example only the secmark access control is failing.
May. 17th, 2013 08:48 pm (UTC)
Huh, i feared that become mad before understandinghow this work, but hope all clear now and i still normal.

1) I thinked, that labels that set on packets by secmark is passthrough to netlabel. And i was wrong.
2) Consequence of 1 - if netlabel known, that specified network (unlbl for example) have label :::s0, there are no way to 'relabel' packet by secmark for netlabel subsystem.
3) At final: labels that produced by secmark and netlabel labels do not interference in any way. So, for secmark, packet may be marked as :::s4, but netlabel known nothing about that and mark packet by his own rule. This is just two different system without any integration.


Edited at 2013-05-17 08:50 pm (UTC)
May. 17th, 2013 08:51 pm (UTC)
Yes, a packet can actually have two SELinux labels: the NetLabel packet labels are called "network peer labels" which are independent of the secmark labels.
May. 17th, 2013 09:11 pm (UTC)
Excellent, thanks for explanation :)
( 7 comments — Leave a comment )


Paul Moore

Latest Month

August 2015
Powered by LiveJournal.com
Designed by Tiffany Chow