# Network policies under AppArmor/SELinux

I am attempting to sandbox some untrusted processes using Linux's MAC frameworks -- either SELinux or AppArmor.

I see that both SELinux and AppArmor allow the selected granting of socket level access to the program being sandboxed. However, is it possible to perform finer grained control, such as restricting network activity to only a set of IP addresses, and/or specific types of traffic (say only TCP/UDP)?

Disclaimer: I'm far from expert on SELinux or AppArmor, so you'll need to check everything I say for yourself.

I think there's a way to make SELinux and IPTables work together. SELinux can label packets with a tag that indicates the SELinux context/origin/provenance that applies to the packet. You can then write IPTables rules that inspect this tag to apply a different firewall policy depending upon the value of this tag. This seems like one potential way to perform finer-grained control, e.g., to enforce that a particular application can only talk to a certain port number or protocol. References: making SELinux and IPTables talk to each other, an article on this and the corresponding discussion on LWN, and background on secmark, the packet marking subsystem.

For AppArmor, as far as I know this is not currently supported. There is a bug tracker entry requesting this feature.

I believe Systrace already has support for this kind of finer-grained control, built-in.

To add a personal experience note to the above -- using selinux in conjunction with iptables makes both the policy and your iptables look extremely complicated and convoluted. It's one of those cases where the complexity trade-off must really be worth the trouble -- unless you are securing a military installation where correct packet labelling means life or death, I wouldn't recommend it.

SELinux does provide some basic port/protocol labelling that doesn't tie in with iptables. E.g. if you run semanage port -l it will give you a list of all ports defined in the targeted policy. You can use this to restrict which ports an SELinux domain can communicate on. For example, you can write a policy stating that myapp_t can only bind to myapp_port_t and connect to http_port_t. This is already pretty good -- if an attacker manages to exploit the app, they would not be able to bind to any other ports or connect to anything other than 80/tcp (e.g. this would foil an attempt to connect to IRC).

If you were really into it, you could then go further and say -- label all packets created by myapp_port_t as myapp_packet_t and configure the firewall to only pass myapp_packet_t to -d 10.10.10.1 --dport 443. Then, if an attacker managed to exploit that app, they would only be able to communicate with 10.10.10.1 on port 443, while other apps, such as a browser, would not otherwise be restricted.

That being said, while it's awesome in theory, in practice apps produce a lot more packet traffic than just that one outgoing tcp on port 443. An app would need to do nslookups (so you need to allow myapp_packet_t udp to port 53), and if your user info is coming from ldap, it would probably generate ldap traffic. As a result, your policies and your iptables quickly balloon into unmanageable monstrosities. I recommend sticking to basic port labelling. :)