If you attempt to have httpd listen on a non-standard port (we’ll get to what’s “standard” and what isn’t in a moment) on an SELinux enabled host, SELinux will deny the request. Let’s try it out (on a CentOS 6.4 box):
|
1 2 3 4 5 6 7 8 9 10 |
# cd /etc/httpd/conf.d # echo "Listen 8585" > listen.conf # service httpd restart Stopping httpd: [ OK ] Starting httpd: (13)Permission denied: make_sock: could not bind to address [::]:8585 (13)Permission denied: make_sock: could not bind to address 0.0.0.0:8585 no listening sockets available, shutting down Unable to open logs [FAILED] |
Kaboom! As you can see, the error message is quite clear “(13)Permission denied: make_sock: could not bind to address”. Let’s take a look at the audit logs and see what’s going on:
|
1 2 3 4 |
type=AVC msg=audit(1371477046.382:20195): avc: denied { name_bind } for pid=16429 comm="httpd" src=8585 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket type=SYSCALL msg=audit(1371477046.382:20195): arch=c000003e syscall=49 success=no exit=-13 a0=6 a1=7fd0fa0ede00 a2=1c a3=7fffb095d3ec items=0 ppid=16428 pid=16429 auid=666 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=674 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null) type=AVC msg=audit(1371477046.382:20196): avc: denied { name_bind } for pid=16429 comm="httpd" src=8585 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket type=SYSCALL msg=audit(1371477046.382:20196): arch=c000003e syscall=49 success=no exit=-13 a0=5 a1=7fd0fa0edd40 a2=10 a3=7fffb095d3ec items=0 ppid=16428 pid=16429 auid=666 uid=0 gid=0 euid=0 suid=0 fsuid=0 egid=0 sgid=0 fsgid=0 tty=pts0 ses=674 comm="httpd" exe="/usr/sbin/httpd" subj=unconfined_u:system_r:httpd_t:s0 key=(null) |
There are two sets of messages there, one for the IPv4 bind, the other for the IPv6 bind. The AVC message actually makes it clear what’s going on:
type=AVC msg=audit(1371477046.382:20195): avc: denied { name_bind } for pid=16429 comm="httpd" src=8585 scontext=unconfined_u:system_r:httpd_t:s0 tcontext=system_u:object_r:port_t:s0 tclass=tcp_socket
You can see that the violation is from source context (scontext) unconfined_u:system_r:httpd_t which is the httpd process, and the target context (tcontext) is system_u:object_r:port_t with target class (tclass) tcp_socket. The denied port (8585 in this case) is also logged in the src field.
SELinux will only allow httpd to bind to ports of type http_port_t. Here, we can see that httpd is attempting to bind to a port of type port_t - which is going to be denied by the policy. We need to define port 8585 as a port of type http_port_t. semanage is the tool for that - and you’ll need the policycoreutils-python package installed:
|
1 2 3 |
# yum install policycoreutils-python # rpm -qf `which semanage` policycoreutils-python-2.0.83-19.30.el6.x86_64 |
First, let’s look at which ports are currently defined as type http_port_t:
|
1 2 |
# semanage port -l | grep '^http_port_t' http_port_t tcp 80, 443, 488, 8008, 8009, 8443 |
And add our desired listen port, 8585/tcp to the list:
|
1 2 3 |
# semanage port -a -t http_port_t -p tcp 8585 # semanage port -l | grep '^http_port_t' http_port_t tcp 8585, 80, 443, 488, 8008, 8009, 8443 |
Looks good. Fire up httpd:
|
1 2 |
# service httpd start Starting httpd: [ OK ] |
And test with nc or similar:
|
1 2 3 4 5 |
# echo "GET /" | nc localhost 8585 ... <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN"> <html> <head> |