6

I just bumped into another SELinux related problem. It would seem my haproxy wasn't allowed to open TCP connections to the backend and I was able to fix it quickly using Google. Now, I would like to know how one would fix this problem if one actually knew how to work with SELinux?

The Problem

I want to use haproxy to forward my publicly accessible port 5000 to 127.0.0.1:5601. I configured haproxy accordingly, and did systemctl restart haproxy and immediately got this beauty in the syslog:

May  9 09:38:45 localhost haproxy[2900]: Server kibana/app1 is DOWN, reason: Layer4 connection problem, info: "General socket error (Permission denied)", check duration: 0ms. 0 active and 0 backup servers left. 0 sessions active, 0 requeued, 0 remaining in queue.

permission denied --> SELinux has become the dominant short circuit evaluation in my Linux problem solving. Hasn't failed me in years!

The Solution

The solution to this problem according to our friends over at Serverfault is

semanage port --add --type http_port_t --proto tcp 5601

because

SELinux only allow[s] the web server to make outbound connections to a limited set of ports

and apparently the semanage command adds port 5601 to that list. This works and now my haproxy serves me Kibana. Great!

What I don't get/know

When I ps fauxZ I see the context of haproxy is system_u:system_r:haproxy_t:s0. With the available commands on my Linux, how can I find out that haproxy is restricted by the ports associated with http_port_t?

8

SELinux has a bit of a reputation for being arcane - and one that I think is well deserved.

The way I understand it, the context of a program that is running defines what the current policy will permit it to access or do. As such, as you've surmised, the haproxy_t type is allowed some permissions based on the http_port_t type.

Now let's try to actually figure out how to find this relationship.

Get SELinux label

As you know, ps -eZ will list the SELinux labels of running processes - in the case of haproxy, that user:role:type:sensitivity is system_u:system_r:haproxy_t:s0. The important bit is the type, in this case haproxy_t.

Permissions

Now to find out which permissions this type has, we can use sesearch[1]:

sesearch -d -A -s haproxy_t
  • -d shows only direct results - if you omit this, this will also show all objects from seinfo --type=haproxy_t -x!
  • -A searches for allow rules
  • -s haproxy_t defines the source type as haproxy_t

Now we get quite a lot of results (106 on my CentOS 7 VM), because, as it happens, there are a lot of different, granular permissions defined. At this point you need to to know something more about what you're searching for - either the class of what the permission applies to, the target type or the permission name itself.

Search by class

Let's go with class first: so we know that our source type is haproxy_t, and we think that our class might be something to do with the internet, so it's a good bet that it might be tcp_socket.

sesearch -d -A -s haproxy_t -c tcp_socket

This will list all allow rules for the source type haproxy_t that have anything to do with tcp_socket. That's narrowed it down quite a bit, but it's still anyone's guess which one of these could be the ones we're looking for.

Search by specific permissions

Next, let's try with permissions - we know that we need our haproxy to bind and connect on specific ports, right? so we try the name_bind and the name_connect permissions.

sesearch -d -A -s haproxy_t -p "name_bind, name_connect"

Found 4 semantic av rules:
    allow haproxy_t http_cache_port_t : tcp_socket { name_bind name_connect } ;
    allow haproxy_t commplex_main_port_t : tcp_socket { name_bind name_connect } ;
    allow haproxy_t http_port_t : tcp_socket { name_bind name_connect } ;
    allow haproxy_t port_type : tcp_socket name_bind ;

This shows only 4 results, only 3 of which could be our culprit! These results are, as far as SELinux is concerned, the only ports any process with the context of haproxy_t is allowed to bind to.

Search by target type

This one is a bit of a cheat, because in this case we're actually looking for the target type! But, for the sake of completeness - for instance, if we wanted to find out what permissions haproxy_t gets from http_port_t, we can use the following:

sesearch -d -A -s haproxy_t -t http_port_t

Found 1 semantic av rules:
    allow haproxy_t http_port_t : tcp_socket { name_bind name_connect } ;

and that, of course, gives us only one result, and the permissions that apply.

Ports

Now that we know the target objects, and that they are definitions of ports, we can find out exactly which ports they encompass. Well, let's find out:

semanage port -l | grep -E 'http_cache_port_t|commplex_main_port_t|http_port_t'

commplex_main_port_t        tcp    5000
commplex_main_port_t        udp    5000
http_cache_port_t           tcp    8080, 8118, 8123, 10001-10010
http_cache_port_t           upd    3130
http_port_t                 tcp    80, 81, 443, 488, 8008, 8009, 8443, 9000
pegasus_http_port_t         tcp    5988

And so, we see that tcp port 5601 is nowhere on that list. Now, as far as SELinux cares, you can add that port to any of those types with the semanage port --add --type XXX --proto tcp 5601 command, and it'll work out. But since this is serving http, http_port_t seems the most applicable type.

Hopefully that demystifies it just a little bit.

[1] Available in the setools-console package.

  • 1
    If I understand this correctly, then this also answers my other question concerning listenting-on vs. connecting to: We use the type http_port_t with the permissions name_bind and name_connect we indeed use this one list for whitelisting everything we can connect to as well as for whitelisting everything we can listen on. Is that correct? – Bananguin May 9 '17 at 15:54
  • 1
    I have tried to answer your other question as well. As for whitelisting, http_port_t is an umbrella type that tells SELinux all ports that have something to do with HTTP. Whichever port you add to http_port_t will then add that port to any service that uses the this type to figure out permissions. In the case of haproxy, that indeed means name_bind and name_connect permissions, but for others, it might be different. – Rabban May 10 '17 at 8:01
  • 1
    The most SELinux "friendly" solution would be to define a new port type, generate a new policy that allows name_bind and name_connect to haproxy_t on that type and then enforce it. But that's a different beast entirely - probably a question of its own. – Rabban May 10 '17 at 8:07
  • Great explanation. Although I don't have sesearch installed, thumbs up for listing all allowed ports in http_port_t. Allowed me to get the stats listener up on one of those ports – Alex Leach Jul 26 at 11:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.