Bug 1174405 - sshd can bind to ephemeral ports
Summary: sshd can bind to ephemeral ports
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Red Hat Enterprise Linux 7
Classification: Red Hat
Component: selinux-policy
Version: 7.0
Hardware: All
OS: Linux
high
medium
Target Milestone: rc
: 7.1
Assignee: Miroslav Grepl
QA Contact: Milos Malik
URL:
Whiteboard:
Depends On:
Blocks: RHEL7CCC
TreeView+ depends on / blocked
 
Reported: 2014-12-15 19:28 UTC by John T. Rose
Modified: 2018-02-13 13:18 UTC (History)
11 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2015-01-08 14:28:05 UTC


Attachments (Terms of Use)

Description John T. Rose 2014-12-15 19:28:52 UTC
Description of problem:


Version-Release number of selected component (if applicable):


How reproducible:


Steps to Reproduce:
1.
2.
3.

Actual results:


Expected results:


Additional info:

Comment 1 John T. Rose 2014-12-15 19:38:09 UTC
I noticed on RHEL7 that sshd can bind to ephemeral ports and it doesn't appear that it should be allowed to with nis_enabled being off.

# sepolicy network -a /usr/sbin/sshd
...
sshd_t: tcp name_bind
	22 (ssh_port_t)
	5900-5983, 5985-5999 (vnc_port_t)
	6000-6020 (xserver_port_t)
	32768-61000 (ephemeral_port_t) -- Allowed False [ nis_enabled=0 ]
	all ports > 500 and  < 1024 (rpc_port_type) -- Allowed False [ nis_enabled=0 ]
	all ports with out defined types (port_t) -- Allowed False [ nis_enabled=0 ]
...

# sestatus
SELinux status:                 enabled
SELinuxfs mount:                /sys/fs/selinux
SELinux root directory:         /etc/selinux
Loaded policy name:             targeted
Current mode:                   enforcing
Mode from config file:          enforcing
Policy MLS status:              enabled
Policy deny_unknown status:     allowed
Max kernel policy version:      28


Regardless of whether nis_enabled is on or off setting the port in /etc/ssh/sshd_config to anything in the ephemeral_port_t range and running systemctl start sshd results in sshd being permitted to bind to the ephemeral port.

It appears this same behavior occurs on relatively recent versions of Fedora as well as RHEL6.

Comment 3 Miroslav Grepl 2015-01-07 15:00:21 UTC
This is correct if you use NIS.

Comment 4 John T. Rose 2015-01-07 15:43:31 UTC
Hi Miroslav,

I don't use NIS and sshd happily binds to ephemeral ports. I'm pretty confident this is a bug, perhaps a kernel bug rather than an selinux policy bug. Since the policy isn't being enforced I guessed this was the proper component to open this against.

Comment 5 Milos Malik 2015-01-07 15:59:57 UTC
I modified the /etc/ssh/sshd_config file (Port 50022) and the daemon is really able to run and bind to that port. The nis_enabled boolean is off.

# seinfo --portcon=50022
	portcon tcp 32768-61000 system_u:object_r:ephemeral_port_t:s0
	portcon udp 32768-61000 system_u:object_r:ephemeral_port_t:s0
# sesearch -s sshd_t -t ephemeral_port_t -c tcp_socket -p name_bind -A -C
Found 2 semantic av rules:
DT allow sshd_t ephemeral_port_t : tcp_socket { name_bind name_connect } ; [ nis_enabled ]
DT allow nsswitch_domain ephemeral_port_t : tcp_socket { name_bind name_connect } ; [ nis_enabled ]

#

Comment 6 Milos Malik 2015-01-08 11:01:23 UTC
I can reproduce the problem with nrpe too (original port: 5666, new port: 56666). It seems that kernel does not enforce selinux-policy on ports > 32767. For example sshd cannot name_bind to port 32767 (unreserved_port_t) but it can name_bind to port 32768 (ephemeral_port_t).

There are no AVCs even if following policy module was enabled:

# cat mypolicy.te 
policy_module(mypolicy,1.0)

require {
  attribute domain;
  type ephemeral_port_t;
  class tcp_socket { name_bind };
}

auditallow domain ephemeral_port_t : tcp_socket { name_bind };
#

# seinfo --portcon=32767
	portcon tcp 1024-32767 system_u:object_r:unreserved_port_t:s0
	portcon udp 1024-32767 system_u:object_r:unreserved_port_t:s0
# seinfo --portcon=32768
	portcon tcp 32768-61000 system_u:object_r:ephemeral_port_t:s0
	portcon udp 32768-61000 system_u:object_r:ephemeral_port_t:s0
#

Comment 7 Milos Malik 2015-01-08 11:03:21 UTC
Good catch, John.

Comment 8 Milos Malik 2015-01-08 11:10:55 UTC
There is something which respects the ephemeral_port_t definition, because my experiments show that sshd can name_bind to 32767 < port < 61001.

Comment 9 Miroslav Grepl 2015-01-08 11:32:14 UTC
Yes, it relates with 

/proc/sys/net/ipv4/ip_local_port_range

Comment 10 Paul Moore 2015-01-08 14:00:49 UTC
When attempting to bind() a socket to a port, the kernel only enforces SELinux access controls when the port number is:

#1 In the "reserved" range, 0 through 1024

 -or-

#2 Not in the "local port" range as defined by /proc/{...}/ip_local_port_range
   (see comment #9)

You could rerun the experiment with sshd bound to a port beyond the top of the local port range and I expect that you will see an AVC denial (assuming the sshd_t domain policy blocks it of course).

Comment 11 John T. Rose 2015-01-08 17:33:31 UTC
I appreciate the time you have given to this but I'm still not understanding why this isn't viewed as a bug that needs to be addressed in some fashion.

How can it really be the intent to allow binding to all ports in the range 32768-61000? Why bother restricting port binding at all if that is the case?

When I ask selinux to show me the policy governing which ports a service can bind to it should not fail to mention the tens of thousands of ports in this range and it should not tell me incorrectly what the effect of setting a boolean variable is.

Something still feels very wrong about this being left as it is now to me.

Thanks.

Comment 12 Milos Malik 2015-01-09 09:35:01 UTC
I dislike the behavior too. Default value in /proc/sys/net/ipv4/ip_local_port_range prevents SELinux subsystem from enforcing the policy on almost half of ports. It also conflicts with the basic SELinux idea that by default everything is denied except for the accesses which are explicitly allowed.

Based on my experiments, auditallow rules do not catch the fact that a process binds to an ephemeral port and neverallow rules do not prevent a process from binding to an ephemeral port.

This problem should be at least documented and sesearch should show that { name_bind } to tcp_socket:ephemeral_port_t is allowed for all domains.

I'm worried that there might be other kinds of access which are allowed even if SELinux policy says otherwise.

Comment 13 Paul Moore 2015-01-09 14:22:55 UTC
FWIW, the behavior described in comment #10 has been in place for a quite a while.  Granted, this may not make it "right", but it does mean that we can't change the behavior without some discussion and likely some compatibility toggles so we don't break existing systems/policies.

If you are concerned about this behavior I would suggest bringing it up on the SELinux developers mail list (not the Fedora SELinux list, but rather the NSA list).


Note You need to log in before you can comment on or make changes to this bug.