Bug 1482251 - pydns source port selection does not use ephemeral range
Summary: pydns source port selection does not use ephemeral range
Keywords:
Status: CLOSED WONTFIX
Alias: None
Product: Fedora EPEL
Classification: Fedora
Component: python-pydns
Version: epel7
Hardware: All
OS: Linux
unspecified
medium
Target Milestone: ---
Assignee: Paul Wouters
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2017-08-16 21:00 UTC by exions
Modified: 2023-07-06 19:06 UTC (History)
2 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed: 2023-07-06 19:06:05 UTC
Type: Bug
Embargoed:


Attachments (Terms of Use)
Example script (274 bytes, text/x-python)
2017-08-16 21:00 UTC, exions
no flags Details
Example TE policy (484 bytes, text/plain)
2017-08-16 21:01 UTC, exions
no flags Details
Example file context for policy (83 bytes, text/plain)
2017-08-16 21:02 UTC, exions
no flags Details

Description exions 2017-08-16 21:00:12 UTC
Created attachment 1314403 [details]
Example script

Description of problem:
PyDNS randomly binds to TCP or UDP source ports from the range 1024-65535 as a defense against cache poisoning.  Some ports in this range are defined as SELinux ports.  Someone who is writing an SELinux policy to confine a python script that uses PyDNS will either have to:

* Accept that ~1% of TCP queries will fail
* Make the SELinux policy allow more than needed (i.e. corenet_tcp_bind_all_ports)


Version-Release number of selected component (if applicable):
2.3.6-2.el7


How reproducible:
Basic SELinux policy files and python script to demonstrate the issue are attached.


Steps to Reproduce:
1. Build and install SELinux policy
Place pydnstest.te and pydnstest.fc in ~/pydnstest/
$ cd ~/pydnstest
$ make -f /usr/share/selinux/devel/Makefile
# semodule -i ~/pydnstest/pydnstest.pp
# semanage dontaudit off

2. Install script
Place pydnstest.py in /usr/local/bin/
# restorecon /usr/local/bin/pydnstest.py

3. Run script
$ runcon system_u:system_r:pydnstest_t:s0 /usr/local/bin/pydnstest.py


Actual results:
SELinux denials occur during approx. 1% of lookups.

$ runcon system_u:system_r:pydnstest_t:s0 /usr/local/bin/pydnstest.py 
Lookup 107 failed: SocketError(error(13, 'Permission denied'),)
Lookup 176 failed: SocketError(error(13, 'Permission denied'),)

# ausearch -ts today 20:21 -i -m avc -su pydnstest_t | audit2allow


#============= pydnstest_t ==============
allow pydnstest_t i18n_input_port_t:tcp_socket name_bind;
allow pydnstest_t munin_port_t:tcp_socket name_bind;

In this case, ports 4949 and 9010 were among the 200 randomly selected source ports.  Since they were already defined as SELinux ports (i18n_input_port_t and munin_port_t), it resulted in denials.


Expected results:
DNS lookups use source ports in the ephemeral range, avoiding conflicts with defined SELinux ports.


Additional info:
Changing source_port to 0 makes the kernel assign a random-looking port in the ephemeral range.  Making this change resulted in no SELinux denials with the attached script/policy:

--- /usr/lib/python2.7/site-packages/DNS/Base.py.orig	2017-05-18 16:17:50.000000000 +0000
+++ /usr/lib/python2.7/site-packages/DNS/Base.py	2017-08-16 20:30:05.717033232 +0000
@@ -181,7 +181,7 @@
         "Pick random source port to avoid DNS cache poisoning attack."
         while True:
             try:
-                source_port = random.randint(1024,65535)
+                source_port = 0
                 self.s.bind(('', source_port))
                 break
             except socket.error, msg:

This reduces the pool of random source ports from 64512 to 28232.  This shouldn't matter for TCP, but will weaken this defense against DNS cache poisoning attacks for UDP queries.

Comment 1 exions 2017-08-16 21:01:23 UTC
Created attachment 1314404 [details]
Example TE policy

Comment 2 exions 2017-08-16 21:02:03 UTC
Created attachment 1314405 [details]
Example file context for policy

Comment 3 Fedora Admin user for bugzilla script actions 2021-04-26 12:34:16 UTC
This package has changed maintainer in Fedora. Reassigning to the new maintainer of this component.

Comment 4 Paul Wouters 2023-07-06 19:06:05 UTC
This package is dead since fedora 31. Please use python3-dns or python3-unbound


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