Blame SOURCES/v1.0.0-0036-fix-ipset-disallow-overlapping-entries.patch

1ac3f6
From 3d7ec2dabb164cbc2dce5aa8aa37ae156ebad275 Mon Sep 17 00:00:00 2001
1ac3f6
From: Eric Garver <eric@garver.life>
1ac3f6
Date: Tue, 23 Feb 2021 09:18:33 -0500
1ac3f6
Subject: [PATCH 36/36] fix(ipset): disallow overlapping entries
1ac3f6
1ac3f6
These are already being blocked by the ipset backend, but we should
1ac3f6
catch them higher up to avoid differences in the backends.
1ac3f6
1ac3f6
(cherry picked from commit 5b4e8918715a1d2e4abf77ed4eb3252486a19109)
1ac3f6
---
1ac3f6
 src/firewall/client.py                        |  4 +++-
1ac3f6
 src/firewall/core/fw_ipset.py                 |  4 +++-
1ac3f6
 src/firewall/core/ipset.py                    | 13 +++++++++++++
1ac3f6
 src/firewall/server/config_ipset.py           |  5 ++++-
1ac3f6
 src/tests/regression/ipset_netmask_allowed.at | 14 ++++++++------
1ac3f6
 5 files changed, 31 insertions(+), 9 deletions(-)
1ac3f6
1ac3f6
diff --git a/src/firewall/client.py b/src/firewall/client.py
1ac3f6
index aa6bd7cd282b..3715ffd29316 100644
1ac3f6
--- a/src/firewall/client.py
1ac3f6
+++ b/src/firewall/client.py
1ac3f6
@@ -34,7 +34,7 @@ from firewall.core.base import DEFAULT_ZONE_TARGET, DEFAULT_POLICY_TARGET, DEFAU
1ac3f6
 from firewall.dbus_utils import dbus_to_python
1ac3f6
 from firewall.functions import b2u
1ac3f6
 from firewall.core.rich import Rich_Rule
1ac3f6
-from firewall.core.ipset import normalize_ipset_entry
1ac3f6
+from firewall.core.ipset import normalize_ipset_entry, check_entry_overlaps_existing
1ac3f6
 from firewall import errors
1ac3f6
 from firewall.errors import FirewallError
1ac3f6
 
1ac3f6
@@ -1619,6 +1619,7 @@ class FirewallClientIPSetSettings(object):
1ac3f6
             raise FirewallError(errors.IPSET_WITH_TIMEOUT)
1ac3f6
         _entries = set()
1ac3f6
         for _entry in dbus_to_python(entries, list):
1ac3f6
+            check_entry_overlaps_existing(_entry, _entries)
1ac3f6
             _entries.add(normalize_ipset_entry(_entry))
1ac3f6
         self.settings[5] = list(_entries)
1ac3f6
     @handle_exceptions
1ac3f6
@@ -1628,6 +1629,7 @@ class FirewallClientIPSetSettings(object):
1ac3f6
             raise FirewallError(errors.IPSET_WITH_TIMEOUT)
1ac3f6
         entry = normalize_ipset_entry(entry)
1ac3f6
         if entry not in self.settings[5]:
1ac3f6
+            check_entry_overlaps_existing(entry, self.settings[5])
1ac3f6
             self.settings[5].append(entry)
1ac3f6
         else:
1ac3f6
             raise FirewallError(errors.ALREADY_ENABLED, entry)
1ac3f6
diff --git a/src/firewall/core/fw_ipset.py b/src/firewall/core/fw_ipset.py
1ac3f6
index e5348949413c..a285fd4a4aab 100644
1ac3f6
--- a/src/firewall/core/fw_ipset.py
1ac3f6
+++ b/src/firewall/core/fw_ipset.py
1ac3f6
@@ -25,7 +25,7 @@ __all__ = [ "FirewallIPSet" ]
1ac3f6
 
1ac3f6
 from firewall.core.logger import log
1ac3f6
 from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts, \
1ac3f6
-                                normalize_ipset_entry
1ac3f6
+                                normalize_ipset_entry, check_entry_overlaps_existing
1ac3f6
 from firewall.core.io.ipset import IPSet
1ac3f6
 from firewall import errors
1ac3f6
 from firewall.errors import FirewallError
1ac3f6
@@ -196,6 +196,7 @@ class FirewallIPSet(object):
1ac3f6
         if entry in obj.entries:
1ac3f6
             raise FirewallError(errors.ALREADY_ENABLED,
1ac3f6
                                 "'%s' already is in '%s'" % (entry, name))
1ac3f6
+        check_entry_overlaps_existing(entry, obj.entries)
1ac3f6
 
1ac3f6
         try:
1ac3f6
             for backend in self.backends():
1ac3f6
@@ -245,6 +246,7 @@ class FirewallIPSet(object):
1ac3f6
 
1ac3f6
         _entries = set()
1ac3f6
         for _entry in entries:
1ac3f6
+            check_entry_overlaps_existing(_entry, _entries)
1ac3f6
             _entries.add(normalize_ipset_entry(_entry))
1ac3f6
         entries = list(_entries)
1ac3f6
 
1ac3f6
diff --git a/src/firewall/core/ipset.py b/src/firewall/core/ipset.py
1ac3f6
index 5bb21856f648..d6defa395241 100644
1ac3f6
--- a/src/firewall/core/ipset.py
1ac3f6
+++ b/src/firewall/core/ipset.py
1ac3f6
@@ -302,3 +302,16 @@ def normalize_ipset_entry(entry):
1ac3f6
             _entry.append(_part)
1ac3f6
 
1ac3f6
     return ",".join(_entry)
1ac3f6
+
1ac3f6
+def check_entry_overlaps_existing(entry, entries):
1ac3f6
+    """ Check if entry overlaps any entry in the list of entries """
1ac3f6
+    # Only check simple types
1ac3f6
+    if len(entry.split(",")) > 1:
1ac3f6
+        return
1ac3f6
+
1ac3f6
+    for itr in entries:
1ac3f6
+        try:
1ac3f6
+            if ipaddress.ip_network(itr, strict=False).overlaps(ipaddress.ip_network(entry, strict=False)):
1ac3f6
+                raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps with existing entry '{}'".format(itr, entry))
1ac3f6
+        except ValueError:
1ac3f6
+            pass
1ac3f6
diff --git a/src/firewall/server/config_ipset.py b/src/firewall/server/config_ipset.py
1ac3f6
index 18ef5783de62..f33c2a02926f 100644
1ac3f6
--- a/src/firewall/server/config_ipset.py
1ac3f6
+++ b/src/firewall/server/config_ipset.py
1ac3f6
@@ -33,7 +33,8 @@ from firewall.dbus_utils import dbus_to_python, \
1ac3f6
     dbus_introspection_prepare_properties, \
1ac3f6
     dbus_introspection_add_properties
1ac3f6
 from firewall.core.io.ipset import IPSet
1ac3f6
-from firewall.core.ipset import IPSET_TYPES, normalize_ipset_entry
1ac3f6
+from firewall.core.ipset import IPSET_TYPES, normalize_ipset_entry, \
1ac3f6
+                                check_entry_overlaps_existing
1ac3f6
 from firewall.core.logger import log
1ac3f6
 from firewall.server.decorators import handle_exceptions, \
1ac3f6
     dbus_handle_exceptions, dbus_service_method
1ac3f6
@@ -408,6 +409,7 @@ class FirewallDConfigIPSet(slip.dbus.service.Object):
1ac3f6
     def setEntries(self, entries, sender=None):
1ac3f6
         _entries = set()
1ac3f6
         for _entry in dbus_to_python(entries, list):
1ac3f6
+            check_entry_overlaps_existing(_entry, _entries)
1ac3f6
             _entries.add(normalize_ipset_entry(_entry))
1ac3f6
         entries = list(_entries)
1ac3f6
         log.debug1("%s.setEntries('[%s]')", self._log_prefix,
1ac3f6
@@ -432,6 +434,7 @@ class FirewallDConfigIPSet(slip.dbus.service.Object):
1ac3f6
             raise FirewallError(errors.IPSET_WITH_TIMEOUT)
1ac3f6
         if entry in settings[5]:
1ac3f6
             raise FirewallError(errors.ALREADY_ENABLED, entry)
1ac3f6
+        check_entry_overlaps_existing(entry, settings[5])
1ac3f6
         settings[5].append(entry)
1ac3f6
         self.update(settings)
1ac3f6
 
1ac3f6
diff --git a/src/tests/regression/ipset_netmask_allowed.at b/src/tests/regression/ipset_netmask_allowed.at
1ac3f6
index b5165d94b220..fd08afd3b57c 100644
1ac3f6
--- a/src/tests/regression/ipset_netmask_allowed.at
1ac3f6
+++ b/src/tests/regression/ipset_netmask_allowed.at
1ac3f6
@@ -9,15 +9,17 @@ dnl an add for the whole range. i.e. 1.2.3.4/24  --> 1.2.3.[0.255] (256
1ac3f6
 dnl entries).
1ac3f6
 dnl
1ac3f6
 dnl In nftables, we allow this by using actual intervals.
1ac3f6
-FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.0/24], 0, [ignore])
1ac3f6
-FWD_CHECK([            --ipset foobar --add-entry 1.2.3.0/24], 0, [ignore])
1ac3f6
+FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.4/24], 0, [ignore])
1ac3f6
+FWD_CHECK([            --ipset foobar --add-entry 1.2.3.4/24], 0, [ignore])
1ac3f6
 
1ac3f6
 dnl check the edge case
1ac3f6
 FWD_CHECK([--permanent --ipset foobar --add-entry 4.3.2.1/32], 0, [ignore])
1ac3f6
 FWD_CHECK([            --ipset foobar --add-entry 4.3.2.1/32], 0, [ignore])
1ac3f6
 
1ac3f6
-dnl overlaps should be denied by ipset
1ac3f6
-FWD_CHECK([            --ipset foobar --add-entry 1.2.3.0/22], 13, [ignore], [ignore])
1ac3f6
-FWD_CHECK([            --ipset foobar --add-entry 1.2.3.0/30], 13, [ignore], [ignore])
1ac3f6
+dnl overlaps should be denied
1ac3f6
+FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.0/22], 136, [ignore], [ignore])
1ac3f6
+FWD_CHECK([            --ipset foobar --add-entry 1.2.3.0/22], 136, [ignore], [ignore])
1ac3f6
+FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.4/30], 136, [ignore], [ignore])
1ac3f6
+FWD_CHECK([            --ipset foobar --add-entry 1.2.3.4/30], 136, [ignore], [ignore])
1ac3f6
 
1ac3f6
-FWD_END_TEST([-e '/ERROR: COMMAND_FAILED:/d'])
1ac3f6
+FWD_END_TEST([-e '/ERROR: INVALID_ENTRY:/d'])
1ac3f6
-- 
1ac3f6
2.27.0
1ac3f6