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

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