Fedora 14, httpd is working correctly, however the httpd_can_network_connect boolean grants more access than I want. I'd like httpd to be able to open connections on any port, but only via a specific network interface (lo0) and no others (eth0, etc.), while still accepting HTTP connections on all interfaces.
I've set up iptables to label all packets in and out of the loopback interface:
iptables -t mangle -A INPUT -i lo -j SECMARK --selctx system_u:object_r:loopback_packet_t:s0 iptables -t mangle -A OUTPUT -o lo -j SECMARK --selctx system_u:object_r:loopback_packet_t:s0
and have permitted httpd to send and receive these:
allow httpd_t loopback_packet_t:packet { send recv }; allow httpd_sys_script_t loopback_packet_t:packet { send recv };
But the problem is that this does not permit httpd to connect:
type=AVC msg=audit(1299866424.466:17033): avc: denied { name_connect } for pid=28402 comm="test-script" dest=9000 scontext=unconfined_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket
Adding the following TE rule of course permits httpd to connect via any interface (equivalent to turning on httpd_can_network_connect):
allow httpd_sys_script_t http_port_t:tcp_socket name_connect;
What am I missing? Any suggestions? I've searched the web but haven't found anything. Thanks in advance for any help.
-- Mark Montague mark@catseye.org
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 03/11/2011 07:08 PM, Mark Montague wrote:
Fedora 14, httpd is working correctly, however the httpd_can_network_connect boolean grants more access than I want. I'd like httpd to be able to open connections on any port, but only via a specific network interface (lo0) and no others (eth0, etc.), while still accepting HTTP connections on all interfaces.
I've set up iptables to label all packets in and out of the loopback interface:
iptables -t mangle -A INPUT -i lo -j SECMARK --selctx system_u:object_r:loopback_packet_t:s0 iptables -t mangle -A OUTPUT -o lo -j SECMARK --selctx system_u:object_r:loopback_packet_t:s0
and have permitted httpd to send and receive these:
allow httpd_t loopback_packet_t:packet { send recv }; allow httpd_sys_script_t loopback_packet_t:packet { send recv };
But the problem is that this does not permit httpd to connect:
type=AVC msg=audit(1299866424.466:17033): avc: denied { name_connect } for pid=28402 comm="test-script" dest=9000 scontext=unconfined_u:system_r:httpd_sys_script_t:s0 tcontext=system_u:object_r:http_port_t:s0 tclass=tcp_socket
Adding the following TE rule of course permits httpd to connect via any interface (equivalent to turning on httpd_can_network_connect):
allow httpd_sys_script_t http_port_t:tcp_socket name_connect;
What am I missing? Any suggestions? I've searched the web but haven't found anything. Thanks in advance for any help.
I do not have much experience with networking and dwalsh probably has a better solution but consider the following:
you can label network interfaces (semanage interface ...) man semanage
the netif (network interface) object class takes the following permissions (tcp example) ( tcp_send tcp_recv egress ingress )
domains by default can sendrecv ( tcp_send tcp_recv egress ingress ) (also udp) generic network interfaces (netif_t:netif)
So you could maybe declare one or more new network interface object types.
label your network interfaces with the new types using semanage interface
then use the tcp_send tcp_recv egress ingress permissions to achieve what you want ( i am guessing you can use egress / ingress to allow input /output)
Problem is that if you label your interfaces, that no domain can use it unless you allow it.
May or may not work...
for udp its:
send: udp_send egress receive: udp_recv ingress
i think you can use (example netif_lo_t):
network_interface(lo, lo, s0 - mls_systemhigh)
to declare a network interface type (the above example is for mls)
or maybe just:
type mynetworkinterace_t, netif_type;
... works just fine
Again, not sure if this will help you achieve what you want but it should give you some more control. i guess its worth a try.
-- Mark Montague mark@catseye.org
-- selinux mailing list selinux@lists.fedoraproject.org https://admin.fedoraproject.org/mailman/listinfo/selinux
On March 11, 2011 13:38 , Dominick Grift domg472@gmail.com wrote:
On 03/11/2011 07:08 PM, Mark Montague wrote:
Fedora 14, httpd is working correctly, however the httpd_can_network_connect boolean grants more access than I want. I'd like httpd to be able to open connections on any port, but only via a specific network interface (lo0) and no others (eth0, etc.), while still accepting HTTP connections on all interfaces.
So you could maybe declare one or more new network interface object types.
label your network interfaces with the new types using semanage interface
then use the tcp_send tcp_recv egress ingress permissions to achieve what you want ( i am guessing you can use egress / ingress to allow input /output)
Thanks for the reply, Dominic. I added the following as a local module:
type loopbackif_t; allow httpd_t loopbackif_t : netif {tcp_send tcp_recv egress ingress }; allow httpd_sys_script_t loopbackif_t : netif {tcp_send tcp_recv egress ingress};
And then ran:
semanage interface -a -t loopbackif_t lo
Unfortunately, the result is the same as for labeling packets on the interface: No traffic is allowed through because httpd does not have permission for name_connect. And if I add a rule to permit this (equivalent to setting the httpd_can_network_connect boolean) then httpd can connect via ALL interfaces, not just via the loopback interface.
Does anyone have any other ideas or suggestions? In the meantime, I'll investigate whether it might be possible to change the targeted policy for httpd to use only packet labels for controlling network traffic instead of limiting system calls and ports.
-- Mark Montague mark@catseye.org
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 03/13/2011 07:15 PM, Mark Montague wrote:
On March 11, 2011 13:38 , Dominick Grift domg472@gmail.com wrote:
On 03/11/2011 07:08 PM, Mark Montague wrote:
Fedora 14, httpd is working correctly, however the httpd_can_network_connect boolean grants more access than I want. I'd like httpd to be able to open connections on any port, but only via a specific network interface (lo0) and no others (eth0, etc.), while still accepting HTTP connections on all interfaces.
So you could maybe declare one or more new network interface object types.
label your network interfaces with the new types using semanage interface
then use the tcp_send tcp_recv egress ingress permissions to achieve what you want ( i am guessing you can use egress / ingress to allow input /output)
Thanks for the reply, Dominic. I added the following as a local module:
type loopbackif_t; allow httpd_t loopbackif_t : netif {tcp_send tcp_recv egress ingress }; allow httpd_sys_script_t loopbackif_t : netif {tcp_send tcp_recv egress ingress};
And then ran:
semanage interface -a -t loopbackif_t lo
Unfortunately, the result is the same as for labeling packets on the interface: No traffic is allowed through because httpd does not have permission for name_connect. And if I add a rule to permit this (equivalent to setting the httpd_can_network_connect boolean) then httpd can connect via ALL interfaces, not just via the loopback interface.
Yes but can it also use the connection? I mean if it can name_connect but not really use the connection because it cant egress, ingress or whatever then you may be able to achieve your goals also.
not sure though.
Does anyone have any other ideas or suggestions? In the meantime, I'll investigate whether it might be possible to change the targeted policy for httpd to use only packet labels for controlling network traffic instead of limiting system calls and ports.
-- Mark Montague mark@catseye.org
-- selinux mailing list selinux@lists.fedoraproject.org https://admin.fedoraproject.org/mailman/listinfo/selinux
On March 13, 2011 14:18 , Dominick Grift domg472@gmail.com wrote:
No traffic is allowed through because httpd does not have permission for name_connect. And if I add a rule to permit this (equivalent to setting the httpd_can_network_connect boolean) then httpd can connect via ALL interfaces, not just via the loopback interface.
Yes but can it also use the connection? I mean if it can name_connect but not really use the connection because it cant egress, ingress or whatever then you may be able to achieve your goals also.
Yes, my test script (running under httpd) is able to connect to a web server via all interfaces (including eth0) and retreive data if I permit name_connect, regardless of whether I'm labeling the loopback interface, labeling packets on the interface, or not doing anything else at all. I'd like for httpd to be able to do this but only via the loopback interface, specifically excluding eth0 and all other interfaces.
I'm still investigating the feasibility of permitting all system calls and all ports, but labeling ALL packets to and from httpd via all interfaces. This seems like it would be a fairly big change to the httpd targeted policy, though, so any other suggestions are very welcome.
-- Mark Montague mark@catseye.org
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1
On 03/13/2011 02:31 PM, Mark Montague wrote:
On March 13, 2011 14:18 , Dominick Grift domg472@gmail.com wrote:
No traffic is allowed through because httpd does not have permission for name_connect. And if I add a rule to permit this (equivalent to setting the httpd_can_network_connect boolean) then httpd can connect via ALL interfaces, not just via the loopback interface.
Yes but can it also use the connection? I mean if it can name_connect but not really use the connection because it cant egress, ingress or whatever then you may be able to achieve your goals also.
Yes, my test script (running under httpd) is able to connect to a web server via all interfaces (including eth0) and retreive data if I permit name_connect, regardless of whether I'm labeling the loopback interface, labeling packets on the interface, or not doing anything else at all. I'd like for httpd to be able to do this but only via the loopback interface, specifically excluding eth0 and all other interfaces.
I'm still investigating the feasibility of permitting all system calls and all ports, but labeling ALL packets to and from httpd via all interfaces. This seems like it would be a fairly big change to the httpd targeted policy, though, so any other suggestions are very welcome.
-- Mark Montague mark@catseye.org
-- selinux mailing list selinux@lists.fedoraproject.org https://admin.fedoraproject.org/mailman/listinfo/selinux
I think you would need to define a type for all domain types to use it except apache types
type genif_t; allow (domain -httpd_t -http_sys_script_t) genif_t : netif {tcp_send tcp_recv egress ingress };
semanage interface -a -t genif_t eth0 semanage interface -a -t loopbackif_t lo
I do not know if you can use regular expressions for the specifications.
I was able to get a working solution. Dan Walsh provided the clue I needed -- the domain attribute (thanks, Dan!) I'm describing everything here in the hope that if someone else needs to use it, they'll be able to find it in the list archives.
The requirements are:
1. Allow httpd to serve any requests on ports 80 and 443 from any network interface. 2. Allow httpd and its scripts (CGIs) to access any resource (databases, back-end content web servers, etc.) on the local machine via the loopback interface. 3. Prohibit any other traffic from httpd. Specifically, do not allow any access by either httpd or its scripts to resources on remote (untrusted) machines. 4. Do not affect any other service or user running on the machine.
I haven't been able to solve the problem by labeling interfaces, yet -- requirement 1 keeps getting in my way.
However, I was able to solve the problem by labeling packets. First, the policy:
# ===== START POLICY =====# policy_module(secmark, 1.0)
require { type httpd_t; type httpd_sys_script_t; type kernel_t; class packet { send recv }; attribute domain; }
type httpd_packet_t; type default_packet_t; type loopback_packet_t;
# Let httpd send and receive packets which have been labled for it: # (Permitting kernel_t allows TCP reset packets back to web clients.) allow httpd_t httpd_packet_t:packet { send recv }; allow kernel_t httpd_packet_t:packet { send recv };
# Let all services send and receive anything via the loopback device: allow domain loopback_packet_t:packet { send recv };
# Let non-secmark-restricted services send and receive all other packets # (assuming their targeted policies allow the necessary system calls, ports, # interfaces, and nodes) allow { domain -httpd_t -httpd_sys_script_t } default_packet_t:packet { send recv }; #===== END POLICY =====#
Next, allow httpd and scripts to make network connections by setting the appropriate boolean. TE rules for this could easily be added to the above policy, but it'll hopefully be more obvious to others if we use the boolean:
setsebool -P httpd_can_network_connect=on
Finally, add the following iptables rules to label packets:
# set the default actions for the INPUT and OUTPUT chains in the "mangle" table iptables -t mangle -P INPUT ACCEPT iptables -t mangle -P OUTPUT ACCEPT
# First, label loopback traffic specially so that we can have our SELinux # policy always accept it. iptables -t mangle -N LOOPBACK_ACCEPT iptables -t mangle -A INPUT -i lo -j LOOPBACK_ACCEPT iptables -t mangle -A OUTPUT -o lo -j LOOPBACK_ACCEPT iptables -t mangle -A LOOPBACK_ACCEPT -j SECMARK --selctx system_u:object_r:loopback_packet_t:s0 iptables -t mangle -A LOOPBACK_ACCEPT -j ACCEPT
# Rules common to multiple services to copy connection labels to established # and related packets for a connection: iptables -t mangle -N SECMARK_RESTORE iptables -t mangle -A INPUT -m conntrack --ctstate ESTABLISHED,RELATED -j SECMARK_RESTORE iptables -t mangle -A OUTPUT -m conntrack --ctstate ESTABLISHED,RELATED -j SECMARK_RESTORE iptables -t mangle -A SECMARK_RESTORE -j CONNSECMARK --restore iptables -t mangle -A SECMARK_RESTORE -j ACCEPT
# Allow and label new incoming connections for httpd: iptables -t mangle -N HTTPD_SECMARK iptables -t mangle -A INPUT -p tcp -m multiport --dports 80,443 -m conntrack --ctstate NEW -j HTTPD_SECMARK iptables -t mangle -A HTTPD_SECMARK -j SECMARK --selctx system_u:object_r:httpd_packet_t:s0 iptables -t mangle -A HTTPD_SECMARK -j CONNSECMARK --save iptables -t mangle -A HTTPD_SECMARK -j ACCEPT
#...add rules to label packets for other services here...
# Anything else gets the default packet type: -A INPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0 -A OUTPUT -j SECMARK --selctx system_u:object_r:default_packet_t:s0
Of course, you'll also need to have rules in the filter table to allow incoming traffic to httpd, filter out illegal stuff, and so on -- but these are the same filter rules you'd need on any machine, regardless of whether you're running SELinux or not, so I won't list them here.
One downside to this solution is that some programs that I used in scripts (CGIs) to test the functionality will not notice the AVC denials and will endlessly retry, eating CPU and filling the audit log with lots of duplicate denials. curl is one example of such a program. So far, I've been able to work around the endless-retry problem by specifying a timeout in either the program or the web server; this isn't ideal, but it helps.
If anyone has improvements or alternate ways of meeting the four requirements above, that would be welcome. Otherwise I hope this writeup is useful to someone else at some point.
-- Mark Montague mark@catseye.org
On March 27, 2011 12:21 , Mark Montague mark@catseye.org wrote:
The requirements are:
- Allow httpd to serve any requests on ports 80 and 443 from any
network interface. 2. Allow httpd and its scripts (CGIs) to access any resource (databases, back-end content web servers, etc.) on the local machine via the loopback interface. 3. Prohibit any other traffic from httpd. Specifically, do not allow any access by either httpd or its scripts to resources on remote (untrusted) machines. 4. Do not affect any other service or user running on the machine.
I haven't been able to solve the problem by labeling interfaces, yet -- requirement 1 keeps getting in my way.
However, I was able to solve the problem by labeling packets.
I was also able to solve the problem another way, using a netfilter module: http://github.com/markmont/xt_selinux This has the advantage of allowing more flexible action than just an AVC denial (for example, sending a TCP reset to get a script such as curl to immediately give up and exit). But it is a horrible, hacky solution that brutalizes the SELinux LSM, is extremely fragile, and probably should not exist -- I'd like to apologize for that right now. But I thought it would be a useful thing to present for the sake of academic discussion.
Here are the commands (no local policy is needed, if you don't count the boolean):
setsebool -P httpd_can_network_connect=on
# Allow loopback device traffic to/from all services or users: iptables -A INPUT -i lo -j ACCEPT iptables -A OUTPUT -o lo -j ACCEPT
# Accept incoming web server traffic: iptables -A INPUT -p tcp -m multiport --dports 80,443 \ -m conntrack --ctstate NEW -j ACCEPT iptables -A INPUT -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
# Silently block all other incoming traffic: iptables -A INPUT -j DROP
# httpd is already allowed (by the rules above) to send any traffic # via the loopback device in order to access various local resources. # Also allow httpd to respond to incoming web server traffic (for # which we've already accepted the input, above). Prohibit httpd # from sending any other outbound traffic. iptables -N HTTPD_OUT iptables -A OUTPUT -m selinux --task-ctx system_u:system_r:httpd_t:s0 \ -j HTTPD_OUT iptables -A HTTPD_OUT -m conntrack --ctstate RELATED,ESTABLISHED \ -j ACCEPT iptables -A HTTPD_OUT -j REJECT
# Web server scripts (CGIs) are already allowed (by a rule above) to # send any traffic through the loopback device in order to access # various local resources. But prohibit scripts from accessing # anything else (such as remote machines). iptables -A OUTPUT \ -m selinux --task-ctx system_u:system_r:httpd_sys_script_t:s0 \ -j REJECT
# Permit all other services and users on the machine to send outbound # traffic without restriction: iptables -A OUTPUT -j ACCEPT
For the record, I'm not using the above solution myself: I'm using the SECMARK-based solution that I described in my previous message: http://lists.fedoraproject.org/pipermail/selinux/2011-March/013612.html
The xt_owner netfilter module used to support iptables matching against security contexts back in 2.6.13. I'm assuming that there is no interest in devising the "right way" to restore this functionality long term, since this would allow "policy" in multiple places. But if I'm wrong, please let me know -- I'd be happy to take a shot at proposing and writing new LSM hooks to properly support netfilter-based security context matching that worked with all applicable LSMs.
-- Mark Montague mark@catseye.org
selinux@lists.fedoraproject.org