Using SELinux and Iptables Together (2011)
Using SELinux and Iptables Together (2011)
One of the things I have wanted to do with SELinux for years is figure out a way to make SELinux and
iptables work together, but each time I looked at it, my use cases became too complicated. James Morris
and Paul Moore worked on a tool called Secmark way back in the Red Hat Enterprise Linux (RHEL) 5 time
frame. My simple implementation of Secmark is to use iptables rules to define labels on packets as they
flow within an SELinux system.
Secmark has been used for years in Multi-level Security (MLS) type environments, but pretty much ignored
in targeted policy. On an MLS system, the security label of the packet is more important then the type label.
Meaning you can prevent a process running as “unclassified†from reading a “Top Secretâ€
packet.
Note: This article is not about labeled networking. (Labels Packets passing between machines over the
Network).
In a targeted system, we do not usually use levels, so I wanted to use type enforcement, meaning
controlling which processes can send/recv packets based on the type of the process and the type of the
packet. Secmark allows you to write rules that label packets that come into port 80 allowing you to write a
rule that allows a process labeled httpd_t to send/recv packets labeled httpd_packet_t. But what about
Firefox, Squid, etc.? My fear about labeling packets was an explosion of packets would generate very
complicated policy. Taking this to the extreme you might end up with packet types for every port type,
httpd_packet_t, bind_packet_t, dns_packet_t .... Or even worse, a type for each port_types and network
combined. httpd_internet_packet_t versus httpd_intranet_packet_t, or httpd_eth0_packet_t and
httpd_eth1_packet_t.
As you can see this would quickly become confusing. And writing policy would become impossible for the
distributions.
unlabeled_t packet type
Currently, by default, we do not label any packets in policy, so the kernel labels these packets as
unlabeled_t. Because of this every SELinux domain on the system that uses the network, has the rules:
allow MYDOMAIN unlabed_t:packet { send recv };
This means that if you used Secmark to labeled packets, and you take the fire wall down, the kernel would
start labeling all packets as unlabeled_t. Every network domain would suddenly gain more access. This
means taking down your firewall or reloading your firewall, you would not only allow ports to be attacked
from outside, you would lower your SELinux protection, potentially allowing confined domains to start to
send/recv packets from untrusted networks.
Removing the unlabeled_t rules
In the latest Fedora Releases I added a module called unlabelednet containing all the rules to allow
MYDOMAIN unlabeled_t:packet {send recv }. If you disable this policy package, all confined domains will
loose the ability to send/recv unlabeled_t packets. I will be back porting this to RHEL6. This means you
can stop confined domains from using the network unless you write rules for a labeled packet.
Use Case
As I mentioned above, every time I looked into this problem, I ended up with an explosion of types. I finally
came upon a couple of use cases where I could write some simple rules and policy to further secure my
laptop. I wanted to write policy to prevent all confined domains that are started at boot (system domains)
from talking to the external network, and allow all domains started by my login process (user domains) to
talk to both the internal and external networks. The idea here is I do not want processes like avahi, or
sssd, or sshd or any other process that gets started at boot to be listening or affected by packets from an
untrusted network. I want processes started by my login, like Firefox or my VPN to be able to talk to the
network. If my vpn is shut down the system domains are off the network, while I can still use the Internet
for browsing and email.
The nice thing about this example is you could use it to setup an Apache server that could only talk to the
internal network and would reject packets from the external network.
I decided to create just three types for my network. I will explain the SELinux policy later in the article.
type internal_packet_t: Iptables will label all packets that originate or are destined for the internal
network as internal_packet_t;
type dns_external_packet_t: Iptables will label all packets destined to the external network on udp/tcp
port 53 as dns_external_packet_t. I added this type because I wanted to dontaudit certain confined
domains from talking to dns servers external to my private network.
Type external_packet_t: Will be the default label for all packets on the machine not covered by the the
first two definitions.
Introducing secmarkgen
I am no iptables expert. Calling me an iptables novice would be kind. So I asked Eric Paris to write up an
example of how you could write iptables rules to apply a label to a packet. I took his rules and generated a
helper shell script called secmarkgen, you can either use my secmarkgen script to generate iptables
rules or generate them yourself.
Running secmarkgen -h will show you the usage:
Usage: ./secmarkgen -i
###################################################################
# ./secmarkgen -i
###################################################################
iptables -F -t security
###################################################################
# ./secmarkgen -s INTERNAL
###################################################################
###################################################################
# ./secmarkgen -n
255.255.255.255,127/8,10.0.0.0/8,172.16.0.0/16,224/24,192.168/16 INTERNAL
###################################################################
###################################################################
###################################################################
I will leave it up to the reader to examine and understand the iptables rules. (I always loved that cop out
when I was in school.)
The secmark_test Script
Here is my full Secmark script (secmark_test.sh) that I use to generate the rules to confine my network:
./secmarkgen -i
./secmarkgen -s INTERNAL
./secmarkgen -n
255.255.255.255,127/8,10.0.0.0/8,172.16.0.0/16,224/24,192.168/16 INTERNAL
./secmarkgen -s DNS
./secmarkgen -s EXTERNAL
./secmarkgen EXTERNAL
./secmarkgen -T ip6tables -i
policy_module(secmark, 1.0)
gen_require(`
attribute domain;
attribute sysadm_usertype;
attribute staff_usertype;
attribute telepathy_domain;
type ping_t;
type vpnc_t;
type ssh_t;
type nsplugin_t;
type mozilla_plugin_t;
type ntpd_t;
type sssd_t;
')
# Type Definitions
attribute external_packet;
type internal_packet_t;
corenet_packet(internal_packet_t)
corenet_packet(dns_external_packet_t)
corenet_packet(external_packet_t)
# Allow Rules
gen_require(`
attribute domain;
attribute sysadm_usertype;
attribute staff_usertype;
attribute telepathy_domain;
type ping_t;
type vpnc_t;
type ssh_t;
type nsplugin_t;
type mozilla_plugin_t;
type ntpd_t;
type sssd_t;
')
When you are writing SELinux policy you have to reference all types/attributes before using them in an
allow rule. You can either define new types or in this case add a gen_requires block. The gen_requires
block tells SELinux to not install this policy, if any of these attributes or types are not defined in other parts
of policy.
Acouple of attributes to look at, in selinux policy domain, is an attribute of all processes types.
staff_usertype is an attribute that is given to all specific staff user processes. Similarly sysadm_usertype
is an attribute given to all specific sysadm user processes, If you added other user types like xguest or
user, you would have to add similar rules in policy. The telepathy_domain is the domain of all the telepathy
applications.
In this section I define the new types that I will use for identifying network packets on my system. I also
defined an attribute external_packet, so I can group rules related to external packets together. I am using
the corenet_packet interface, to identify to SELinux that these types are associated with packets.
attribute external_packet;
type internal_packet_t;
corenet_packet(internal_packet_t)
corenet_packet(dns_external_packet_t)
corenet_packet(external_packet_t)
The next rule allows the ntpd_t domain to send and receive external packets, since ntpd talks to time
servers on the public network. I could have defined an ntp_external_packet_t, and added iptables rules to
make this more secure, but I decided not, since I did not want an explosion of types.
allow ntpd_t external_packet:packet { recv send };
dontaudit sssd_t dns_external_packet_t:packet { recv send };
The sssd program looks at all entries in my /etc/resolv.conf and checks to see if it can use them.
When I use vpn to come into my network, I end up with dns records from the external and internal network
in my /etc/resolv.conf file.
Since I do not want sssd talking to any system other then on my private network, I want to dontaudit this
access.
Compile, Install and Run
Now it's time to pull everything together. First I compile my policy:
# make -f /usr/share/selinux/devel/Makefile
Then I install my policy:
# semodule -i secmark.pp
Now I can install the rules on my system:
# sh /tmp/rules
I want to tell iptables and ip6tables to remember for the next boot.
At this point every packet on my machine should have one of the three labels.
Now I can watch for avc messages concerning any of these labeled packets. If I see ones I can decide
whether or not I want to allow/dontaudit these avc messages, or try to figure out if something is going very
wrong on my system.
Daniel J. Walsh
Daniel Walsh has worked in the computer security field for over 25 years. Dan joined Red Hat in August
2001. He has led the SELinux project, concentrating on the application space and policy development.
Previously, Dan worked on Netect/Bindview on HackerShield and BVControl for Unix, Vulnerability
Assessment Products. Prior to this Dan worked for Digital Equipment Corporation on the Athena Project
along with designing and developing the AltaVista Firewall and AltaVista Tunnel (VPN) Products. Dan
has a BAin Mathematics from the College of the Holy Cross and a MS in Computer Science from
Worcester Polytechnic Institute.