From 1ac3f62f3d4475cbf4cb31f1bd39008e1b5314a4 Mon Sep 17 00:00:00 2001 From: CentOS Sources Date: Aug 09 2021 18:22:10 +0000 Subject: import firewalld-0.9.3-7.el8 --- diff --git a/SOURCES/0031-test-functions-FWD_GREP_LOG-allow-checking-error-cod.patch b/SOURCES/0031-test-functions-FWD_GREP_LOG-allow-checking-error-cod.patch new file mode 100644 index 0000000..787f4a4 --- /dev/null +++ b/SOURCES/0031-test-functions-FWD_GREP_LOG-allow-checking-error-cod.patch @@ -0,0 +1,28 @@ +From 8d8ec4530dea1a74254c6cc14ece4fa14f7f94fe Mon Sep 17 00:00:00 2001 +From: Eric Garver +Date: Thu, 3 Jun 2021 12:00:06 -0400 +Subject: [PATCH 31/36] test(functions): FWD_GREP_LOG: allow checking error + code + +(cherry picked from commit 748bcaee9a1d1151cf0e4bc9229f7b46774332ae) +(cherry picked from commit 69c6a91ca507bdf0e18784ce06d3d872a1c2e5ab) +--- + src/tests/functions.at | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/src/tests/functions.at b/src/tests/functions.at +index 54afcf14585a..4b298644d7e4 100644 +--- a/src/tests/functions.at ++++ b/src/tests/functions.at +@@ -328,7 +328,7 @@ m4_define([FWD_CHECK], [ + ]) + + m4_define([FWD_GREP_LOG], [ +- AT_CHECK([grep "$1" ./firewalld.log], 0, [ignore], [ignore]) ++ AT_CHECK([grep "$1" ./firewalld.log], $2, [ignore], [ignore]) + ]) + + m4_define([TRIM], [[sed -e 's/^[ \t]*//' -e 's/[ \t]*$//']]) +-- +2.27.0 + diff --git a/SOURCES/0032-test-functions-improve-checking-firewalld.log-for-er.patch b/SOURCES/0032-test-functions-improve-checking-firewalld.log-for-er.patch new file mode 100644 index 0000000..c68de27 --- /dev/null +++ b/SOURCES/0032-test-functions-improve-checking-firewalld.log-for-er.patch @@ -0,0 +1,41 @@ +From fd61eebac7618b1f9051497904d4392ac9b6f53b Mon Sep 17 00:00:00 2001 +From: Eric Garver +Date: Thu, 3 Jun 2021 12:12:03 -0400 +Subject: [PATCH 32/36] test(functions): improve checking firewalld.log for + errors + +Don't delete the errors/warnings from the log. Use sed/grep in a pipe +instead. + +(cherry picked from commit 23dc028083dbdbd291f022ab60bad0462e23d48e) +(cherry picked from commit 1bafb54763926f49f930038fb6ecd9ab3e05c796) +--- + src/tests/functions.at | 11 ++++------- + 1 file changed, 4 insertions(+), 7 deletions(-) + +diff --git a/src/tests/functions.at b/src/tests/functions.at +index 4b298644d7e4..03795bc3c132 100644 +--- a/src/tests/functions.at ++++ b/src/tests/functions.at +@@ -255,14 +255,11 @@ m4_define([FWD_START_TEST], [ + + m4_define([FWD_END_TEST], [ + m4_ifdef([TESTING_FIREWALL_OFFLINE_CMD], [], [ +- IF_HOST_SUPPORTS_IP6TABLES([], [ +- sed -i "/WARNING: ip6tables not usable, disabling IPv6 firewall/d" ./firewalld.log +- ]) + if test x"$1" != x"ignore"; then +- if test -n "$1"; then +- sed -i $1 ./firewalld.log +- fi +- AT_FAIL_IF([[grep '^[0-9-]*[ ]\+[0-9:]*[ ]\+\(ERROR\|WARNING\)' ./firewalld.log]]) ++ AT_FAIL_IF([cat ./firewalld.log | dnl ++ sed "/WARNING: ip6tables not usable, disabling IPv6 firewall/d" | dnl ++ m4_ifnblank([$1], [sed $1 |]) dnl ++ [grep '^[0-9-]*[ ]\+[0-9:]*[ ]\+\(ERROR\|WARNING\)']]) + fi + m4_undefine([CURRENT_DBUS_ADDRESS]) + m4_undefine([CURRENT_TEST_NS]) +-- +2.27.0 + diff --git a/SOURCES/0033-fix-policy-warn-instead-of-error-for-overlapping-por.patch b/SOURCES/0033-fix-policy-warn-instead-of-error-for-overlapping-por.patch new file mode 100644 index 0000000..341cdf1 --- /dev/null +++ b/SOURCES/0033-fix-policy-warn-instead-of-error-for-overlapping-por.patch @@ -0,0 +1,46 @@ +From a79321b79b0543cff0c99702c1ab9eeaab8bfe06 Mon Sep 17 00:00:00 2001 +From: Eric Garver +Date: Thu, 3 Jun 2021 11:42:58 -0400 +Subject: [PATCH 33/36] fix(policy): warn instead of error for overlapping + ports + +Fixes: rhbz 1914935 +(cherry picked from commit b71e532bc21fb6a06345b5ecfeb60683c7a194e9) +(cherry picked from commit 66ca4b0fd9588d60d31998ad792f04962053aaab) +--- + src/firewall/core/fw_policy.py | 16 ++++++++++++++-- + 1 file changed, 14 insertions(+), 2 deletions(-) + +diff --git a/src/firewall/core/fw_policy.py b/src/firewall/core/fw_policy.py +index 3f5dab808ff0..79a52d8d97c0 100644 +--- a/src/firewall/core/fw_policy.py ++++ b/src/firewall/core/fw_policy.py +@@ -98,11 +98,23 @@ class FirewallPolicy(object): + for args in obj.services: + self.add_service(policy, args) + for args in obj.ports: +- self.add_port(policy, *args) ++ try: ++ self.add_port(policy, *args) ++ except FirewallError as error: ++ if error.code in [errors.ALREADY_ENABLED]: ++ log.warning(error) ++ else: ++ raise error + for args in obj.protocols: + self.add_protocol(policy, args) + for args in obj.source_ports: +- self.add_source_port(policy, *args) ++ try: ++ self.add_source_port(policy, *args) ++ except FirewallError as error: ++ if error.code in [errors.ALREADY_ENABLED]: ++ log.warning(error) ++ else: ++ raise error + for args in obj.rules: + self.add_rule(policy, args) + if obj.masquerade: +-- +2.27.0 + diff --git a/SOURCES/0034-test-zone-verify-overlapping-ports-don-t-halt-zone-l.patch b/SOURCES/0034-test-zone-verify-overlapping-ports-don-t-halt-zone-l.patch new file mode 100644 index 0000000..83c1d99 --- /dev/null +++ b/SOURCES/0034-test-zone-verify-overlapping-ports-don-t-halt-zone-l.patch @@ -0,0 +1,99 @@ +From 7c1e62b4933f2b110dcedc411b4381c00abe799f Mon Sep 17 00:00:00 2001 +From: Eric Garver +Date: Thu, 3 Jun 2021 11:27:11 -0400 +Subject: [PATCH 34/36] test(zone): verify overlapping ports don't halt zone + loading + +We can warn about the overlapping ports, but don't completely error out. + +Coverage: rhbz 1914935 +(cherry picked from commit 012a87a343673c7699f48fa6af973c890be08671) +(cherry picked from commit 50e4c979283eee83bf0c707184cd0ca9bf112e85) +--- + src/tests/regression/regression.at | 1 + + src/tests/regression/rhbz1914935.at | 64 +++++++++++++++++++++++++++++ + 2 files changed, 65 insertions(+) + create mode 100644 src/tests/regression/rhbz1914935.at + +diff --git a/src/tests/regression/regression.at b/src/tests/regression/regression.at +index 2a5ad9ef995a..aadd948a459f 100644 +--- a/src/tests/regression/regression.at ++++ b/src/tests/regression/regression.at +@@ -41,3 +41,4 @@ m4_include([regression/gh703.at]) + m4_include([regression/ipset_netmask_allowed.at]) + m4_include([regression/rhbz1940928.at]) + m4_include([regression/rhbz1936896.at]) ++m4_include([regression/rhbz1914935.at]) +diff --git a/src/tests/regression/rhbz1914935.at b/src/tests/regression/rhbz1914935.at +new file mode 100644 +index 000000000000..5b110ea4cf4d +--- /dev/null ++++ b/src/tests/regression/rhbz1914935.at +@@ -0,0 +1,64 @@ ++FWD_START_TEST([zone overlapping ports]) ++AT_KEYWORDS(zone port rhbz1914935) ++ ++AT_CHECK([mkdir -p ./zones]) ++ ++AT_DATA([./zones/foobar.xml], [dnl ++ ++ ++ ++ ++ ++ ++]) ++FWD_RELOAD ++FWD_GREP_LOG([WARNING: ALREADY_ENABLED: '1234:tcp' already in 'foobar']) ++FWD_GREP_LOG([WARNING: ALREADY_ENABLED: '2000-3000:tcp' already in 'foobar']) ++FWD_CHECK([--zone foobar --list-ports], 0, [dnl ++1024-65535/tcp ++]) ++ ++AT_DATA([./zones/foobar.xml], [dnl ++ ++ ++ ++ ++ ++ ++]) ++FWD_RELOAD ++FWD_GREP_LOG([WARNING: ALREADY_ENABLED: '1234:tcp' already in 'foobar']) ++FWD_GREP_LOG([WARNING: ALREADY_ENABLED: '2000-3000:tcp' already in 'foobar']) ++FWD_CHECK([--zone foobar --list-source-ports], 0, [dnl ++1024-65535/tcp ++]) ++ ++dnl this one partially overlaps so it should not throw a warning. ++AT_DATA([./zones/foobar.xml], [dnl ++ ++ ++ ++ ++ ++]) ++FWD_RELOAD ++FWD_GREP_LOG([WARNING: ALREADY_ENABLED: '1500-2500:tcp' already in 'foobar'], 1) ++FWD_CHECK([--zone foobar --list-ports], 0, [dnl ++1024-2500/tcp ++]) ++ ++dnl this one partially overlaps so it should not throw a warning. ++AT_DATA([./zones/foobar.xml], [dnl ++ ++ ++ ++ ++ ++]) ++FWD_RELOAD ++FWD_GREP_LOG([WARNING: ALREADY_ENABLED: '1500-2500:tcp' already in 'foobar'], 1) ++FWD_CHECK([--zone foobar --list-source-ports], 0, [dnl ++1024-2500/tcp ++]) ++ ++FWD_END_TEST([-e '/WARNING: ALREADY_ENABLED:/d']) +-- +2.27.0 + diff --git a/SOURCES/v1.0.0-0035-fix-ipset-normalize-entries-in-CIDR-notation.patch b/SOURCES/v1.0.0-0035-fix-ipset-normalize-entries-in-CIDR-notation.patch new file mode 100644 index 0000000..3257fac --- /dev/null +++ b/SOURCES/v1.0.0-0035-fix-ipset-normalize-entries-in-CIDR-notation.patch @@ -0,0 +1,242 @@ +From e399840e91c766531923c017ffa00bbc01e7bbe6 Mon Sep 17 00:00:00 2001 +From: Eric Garver +Date: Fri, 12 Feb 2021 14:23:21 -0500 +Subject: [PATCH 35/36] fix(ipset): normalize entries in CIDR notation + +This will convert things like 10.0.1.0/22 to 10.0.0.0/22. Fix up test +cases in which the error code changed due to this. + +(cherry picked from commit e4dc44fcfd214b27c718eb4d99d3b137495b9626) +--- + src/firewall/client.py | 9 ++++++++- + src/firewall/core/fw_ipset.py | 11 ++++++++++- + src/firewall/core/ipset.py | 13 +++++++++++++ + src/firewall/server/config_ipset.py | 10 ++++++++-- + src/tests/regression/rhbz1601610.at | 19 +++++++++++++------ + 5 files changed, 52 insertions(+), 10 deletions(-) + +diff --git a/src/firewall/client.py b/src/firewall/client.py +index 51bf09c8fad6..aa6bd7cd282b 100644 +--- a/src/firewall/client.py ++++ b/src/firewall/client.py +@@ -34,6 +34,7 @@ from firewall.core.base import DEFAULT_ZONE_TARGET, DEFAULT_POLICY_TARGET, DEFAU + from firewall.dbus_utils import dbus_to_python + from firewall.functions import b2u + from firewall.core.rich import Rich_Rule ++from firewall.core.ipset import normalize_ipset_entry + from firewall import errors + from firewall.errors import FirewallError + +@@ -1616,12 +1617,16 @@ class FirewallClientIPSetSettings(object): + if "timeout" in self.settings[4] and \ + self.settings[4]["timeout"] != "0": + raise FirewallError(errors.IPSET_WITH_TIMEOUT) +- self.settings[5] = entries ++ _entries = set() ++ for _entry in dbus_to_python(entries, list): ++ _entries.add(normalize_ipset_entry(_entry)) ++ self.settings[5] = list(_entries) + @handle_exceptions + def addEntry(self, entry): + if "timeout" in self.settings[4] and \ + self.settings[4]["timeout"] != "0": + raise FirewallError(errors.IPSET_WITH_TIMEOUT) ++ entry = normalize_ipset_entry(entry) + if entry not in self.settings[5]: + self.settings[5].append(entry) + else: +@@ -1631,6 +1636,7 @@ class FirewallClientIPSetSettings(object): + if "timeout" in self.settings[4] and \ + self.settings[4]["timeout"] != "0": + raise FirewallError(errors.IPSET_WITH_TIMEOUT) ++ entry = normalize_ipset_entry(entry) + if entry in self.settings[5]: + self.settings[5].remove(entry) + else: +@@ -1640,6 +1646,7 @@ class FirewallClientIPSetSettings(object): + if "timeout" in self.settings[4] and \ + self.settings[4]["timeout"] != "0": + raise FirewallError(errors.IPSET_WITH_TIMEOUT) ++ entry = normalize_ipset_entry(entry) + return entry in self.settings[5] + + # ipset config +diff --git a/src/firewall/core/fw_ipset.py b/src/firewall/core/fw_ipset.py +index 6ebda2d56213..e5348949413c 100644 +--- a/src/firewall/core/fw_ipset.py ++++ b/src/firewall/core/fw_ipset.py +@@ -24,7 +24,8 @@ + __all__ = [ "FirewallIPSet" ] + + from firewall.core.logger import log +-from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts ++from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts, \ ++ normalize_ipset_entry + from firewall.core.io.ipset import IPSet + from firewall import errors + from firewall.errors import FirewallError +@@ -189,6 +190,7 @@ class FirewallIPSet(object): + + def add_entry(self, name, entry): + obj = self.get_ipset(name, applied=True) ++ entry = normalize_ipset_entry(entry) + + IPSet.check_entry(entry, obj.options, obj.type) + if entry in obj.entries: +@@ -208,6 +210,7 @@ class FirewallIPSet(object): + + def remove_entry(self, name, entry): + obj = self.get_ipset(name, applied=True) ++ entry = normalize_ipset_entry(entry) + + # no entry check for removal + if entry not in obj.entries: +@@ -226,6 +229,7 @@ class FirewallIPSet(object): + + def query_entry(self, name, entry): + obj = self.get_ipset(name, applied=True) ++ entry = normalize_ipset_entry(entry) + if "timeout" in obj.options and obj.options["timeout"] != "0": + # no entries visible for ipsets with timeout + raise FirewallError(errors.IPSET_WITH_TIMEOUT, name) +@@ -239,6 +243,11 @@ class FirewallIPSet(object): + def set_entries(self, name, entries): + obj = self.get_ipset(name, applied=True) + ++ _entries = set() ++ for _entry in entries: ++ _entries.add(normalize_ipset_entry(_entry)) ++ entries = list(_entries) ++ + for entry in entries: + IPSet.check_entry(entry, obj.options, obj.type) + if "timeout" not in obj.options or obj.options["timeout"] == "0": +diff --git a/src/firewall/core/ipset.py b/src/firewall/core/ipset.py +index 0d632143ce13..5bb21856f648 100644 +--- a/src/firewall/core/ipset.py ++++ b/src/firewall/core/ipset.py +@@ -24,6 +24,7 @@ + __all__ = [ "ipset", "check_ipset_name", "remove_default_create_options" ] + + import os.path ++import ipaddress + + from firewall import errors + from firewall.errors import FirewallError +@@ -289,3 +290,15 @@ def remove_default_create_options(options): + IPSET_DEFAULT_CREATE_OPTIONS[opt] == _options[opt]: + del _options[opt] + return _options ++ ++def normalize_ipset_entry(entry): ++ """ Normalize IP addresses in entry """ ++ _entry = [] ++ for _part in entry.split(","): ++ try: ++ _part.index("/") ++ _entry.append(str(ipaddress.ip_network(_part, strict=False))) ++ except ValueError: ++ _entry.append(_part) ++ ++ return ",".join(_entry) +diff --git a/src/firewall/server/config_ipset.py b/src/firewall/server/config_ipset.py +index 8c647bc29ab9..18ef5783de62 100644 +--- a/src/firewall/server/config_ipset.py ++++ b/src/firewall/server/config_ipset.py +@@ -33,7 +33,7 @@ from firewall.dbus_utils import dbus_to_python, \ + dbus_introspection_prepare_properties, \ + dbus_introspection_add_properties + from firewall.core.io.ipset import IPSet +-from firewall.core.ipset import IPSET_TYPES ++from firewall.core.ipset import IPSET_TYPES, normalize_ipset_entry + from firewall.core.logger import log + from firewall.server.decorators import handle_exceptions, \ + dbus_handle_exceptions, dbus_service_method +@@ -406,7 +406,10 @@ class FirewallDConfigIPSet(slip.dbus.service.Object): + in_signature='as') + @dbus_handle_exceptions + def setEntries(self, entries, sender=None): +- entries = dbus_to_python(entries, list) ++ _entries = set() ++ for _entry in dbus_to_python(entries, list): ++ _entries.add(normalize_ipset_entry(_entry)) ++ entries = list(_entries) + log.debug1("%s.setEntries('[%s]')", self._log_prefix, + ",".join(entries)) + self.parent.accessCheck(sender) +@@ -421,6 +424,7 @@ class FirewallDConfigIPSet(slip.dbus.service.Object): + @dbus_handle_exceptions + def addEntry(self, entry, sender=None): + entry = dbus_to_python(entry, str) ++ entry = normalize_ipset_entry(entry) + log.debug1("%s.addEntry('%s')", self._log_prefix, entry) + self.parent.accessCheck(sender) + settings = list(self.getSettings()) +@@ -436,6 +440,7 @@ class FirewallDConfigIPSet(slip.dbus.service.Object): + @dbus_handle_exceptions + def removeEntry(self, entry, sender=None): + entry = dbus_to_python(entry, str) ++ entry = normalize_ipset_entry(entry) + log.debug1("%s.removeEntry('%s')", self._log_prefix, entry) + self.parent.accessCheck(sender) + settings = list(self.getSettings()) +@@ -451,6 +456,7 @@ class FirewallDConfigIPSet(slip.dbus.service.Object): + @dbus_handle_exceptions + def queryEntry(self, entry, sender=None): # pylint: disable=W0613 + entry = dbus_to_python(entry, str) ++ entry = normalize_ipset_entry(entry) + log.debug1("%s.queryEntry('%s')", self._log_prefix, entry) + settings = list(self.getSettings()) + if "timeout" in settings[4] and settings[4]["timeout"] != "0": +diff --git a/src/tests/regression/rhbz1601610.at b/src/tests/regression/rhbz1601610.at +index ede2c45b88c1..a716539a8acf 100644 +--- a/src/tests/regression/rhbz1601610.at ++++ b/src/tests/regression/rhbz1601610.at +@@ -6,11 +6,14 @@ CHECK_IPSET + FWD_CHECK([-q --new-ipset=foobar --permanent --type=hash:net]) + FWD_RELOAD + +-FWD_CHECK([-q --ipset=foobar --add-entry=10.1.1.0/22]) +-FWD_CHECK([-q --ipset=foobar --add-entry=10.1.2.0/22], 13, ignore, ignore) +-FWD_CHECK([-q --ipset=foobar --add-entry=10.2.0.0/22]) ++FWD_CHECK([--ipset=foobar --add-entry=10.1.1.0/22], 0, [ignore]) ++FWD_CHECK([--ipset=foobar --query-entry 10.1.2.0/22], 0, [ignore]) ++FWD_CHECK([--ipset=foobar --add-entry=10.1.2.0/22], 0, [ignore], [dnl ++Warning: ALREADY_ENABLED: '10.1.0.0/22' already is in 'foobar' ++]) ++FWD_CHECK([--ipset=foobar --add-entry=10.2.0.0/22], 0, [ignore]) + FWD_CHECK([--ipset=foobar --get-entries], 0, [dnl +-10.1.1.0/22 ++10.1.0.0/22 + 10.2.0.0/22 + ]) + NFT_LIST_SET([foobar], 0, [dnl +@@ -31,6 +34,9 @@ Members: + ]) + + FWD_CHECK([-q --ipset=foobar --remove-entry=10.1.1.0/22]) ++FWD_CHECK([--ipset=foobar --query-entry 10.1.1.0/22], 1, [ignore]) ++FWD_CHECK([--ipset=foobar --query-entry 10.1.2.0/22], 1, [ignore]) ++FWD_CHECK([--ipset=foobar --query-entry 10.2.0.0/22], 0, [ignore]) + FWD_CHECK([--ipset=foobar --get-entries], 0, [dnl + 10.2.0.0/22 + ]) +@@ -52,7 +58,7 @@ Members: + + FWD_CHECK([-q --permanent --ipset=foobar --add-entry=10.1.1.0/22]) + FWD_CHECK([--permanent --ipset=foobar --get-entries], 0, [dnl +-10.1.1.0/22 ++10.1.0.0/22 + ]) + FWD_CHECK([-q --permanent --ipset=foobar --remove-entry=10.1.1.0/22]) + FWD_CHECK([--permanent --ipset=foobar --get-entries], 0, [ +@@ -101,4 +107,5 @@ Members: + + FWD_END_TEST([-e '/ERROR: COMMAND_FAILED:.*already added.*/d'dnl + -e '/ERROR: COMMAND_FAILED:.*element.*exists/d'dnl +- -e '/Kernel support protocol versions/d']) ++ -e '/Kernel support protocol versions/d'dnl ++ -e '/WARNING: ALREADY_ENABLED:/d']) +-- +2.27.0 + diff --git a/SOURCES/v1.0.0-0036-fix-ipset-disallow-overlapping-entries.patch b/SOURCES/v1.0.0-0036-fix-ipset-disallow-overlapping-entries.patch new file mode 100644 index 0000000..78681bb --- /dev/null +++ b/SOURCES/v1.0.0-0036-fix-ipset-disallow-overlapping-entries.patch @@ -0,0 +1,157 @@ +From 3d7ec2dabb164cbc2dce5aa8aa37ae156ebad275 Mon Sep 17 00:00:00 2001 +From: Eric Garver +Date: Tue, 23 Feb 2021 09:18:33 -0500 +Subject: [PATCH 36/36] fix(ipset): disallow overlapping entries + +These are already being blocked by the ipset backend, but we should +catch them higher up to avoid differences in the backends. + +(cherry picked from commit 5b4e8918715a1d2e4abf77ed4eb3252486a19109) +--- + src/firewall/client.py | 4 +++- + src/firewall/core/fw_ipset.py | 4 +++- + src/firewall/core/ipset.py | 13 +++++++++++++ + src/firewall/server/config_ipset.py | 5 ++++- + src/tests/regression/ipset_netmask_allowed.at | 14 ++++++++------ + 5 files changed, 31 insertions(+), 9 deletions(-) + +diff --git a/src/firewall/client.py b/src/firewall/client.py +index aa6bd7cd282b..3715ffd29316 100644 +--- a/src/firewall/client.py ++++ b/src/firewall/client.py +@@ -34,7 +34,7 @@ from firewall.core.base import DEFAULT_ZONE_TARGET, DEFAULT_POLICY_TARGET, DEFAU + from firewall.dbus_utils import dbus_to_python + from firewall.functions import b2u + from firewall.core.rich import Rich_Rule +-from firewall.core.ipset import normalize_ipset_entry ++from firewall.core.ipset import normalize_ipset_entry, check_entry_overlaps_existing + from firewall import errors + from firewall.errors import FirewallError + +@@ -1619,6 +1619,7 @@ class FirewallClientIPSetSettings(object): + raise FirewallError(errors.IPSET_WITH_TIMEOUT) + _entries = set() + for _entry in dbus_to_python(entries, list): ++ check_entry_overlaps_existing(_entry, _entries) + _entries.add(normalize_ipset_entry(_entry)) + self.settings[5] = list(_entries) + @handle_exceptions +@@ -1628,6 +1629,7 @@ class FirewallClientIPSetSettings(object): + raise FirewallError(errors.IPSET_WITH_TIMEOUT) + entry = normalize_ipset_entry(entry) + if entry not in self.settings[5]: ++ check_entry_overlaps_existing(entry, self.settings[5]) + self.settings[5].append(entry) + else: + raise FirewallError(errors.ALREADY_ENABLED, entry) +diff --git a/src/firewall/core/fw_ipset.py b/src/firewall/core/fw_ipset.py +index e5348949413c..a285fd4a4aab 100644 +--- a/src/firewall/core/fw_ipset.py ++++ b/src/firewall/core/fw_ipset.py +@@ -25,7 +25,7 @@ __all__ = [ "FirewallIPSet" ] + + from firewall.core.logger import log + from firewall.core.ipset import remove_default_create_options as rm_def_cr_opts, \ +- normalize_ipset_entry ++ normalize_ipset_entry, check_entry_overlaps_existing + from firewall.core.io.ipset import IPSet + from firewall import errors + from firewall.errors import FirewallError +@@ -196,6 +196,7 @@ class FirewallIPSet(object): + if entry in obj.entries: + raise FirewallError(errors.ALREADY_ENABLED, + "'%s' already is in '%s'" % (entry, name)) ++ check_entry_overlaps_existing(entry, obj.entries) + + try: + for backend in self.backends(): +@@ -245,6 +246,7 @@ class FirewallIPSet(object): + + _entries = set() + for _entry in entries: ++ check_entry_overlaps_existing(_entry, _entries) + _entries.add(normalize_ipset_entry(_entry)) + entries = list(_entries) + +diff --git a/src/firewall/core/ipset.py b/src/firewall/core/ipset.py +index 5bb21856f648..d6defa395241 100644 +--- a/src/firewall/core/ipset.py ++++ b/src/firewall/core/ipset.py +@@ -302,3 +302,16 @@ def normalize_ipset_entry(entry): + _entry.append(_part) + + return ",".join(_entry) ++ ++def check_entry_overlaps_existing(entry, entries): ++ """ Check if entry overlaps any entry in the list of entries """ ++ # Only check simple types ++ if len(entry.split(",")) > 1: ++ return ++ ++ for itr in entries: ++ try: ++ if ipaddress.ip_network(itr, strict=False).overlaps(ipaddress.ip_network(entry, strict=False)): ++ raise FirewallError(errors.INVALID_ENTRY, "Entry '{}' overlaps with existing entry '{}'".format(itr, entry)) ++ except ValueError: ++ pass +diff --git a/src/firewall/server/config_ipset.py b/src/firewall/server/config_ipset.py +index 18ef5783de62..f33c2a02926f 100644 +--- a/src/firewall/server/config_ipset.py ++++ b/src/firewall/server/config_ipset.py +@@ -33,7 +33,8 @@ from firewall.dbus_utils import dbus_to_python, \ + dbus_introspection_prepare_properties, \ + dbus_introspection_add_properties + from firewall.core.io.ipset import IPSet +-from firewall.core.ipset import IPSET_TYPES, normalize_ipset_entry ++from firewall.core.ipset import IPSET_TYPES, normalize_ipset_entry, \ ++ check_entry_overlaps_existing + from firewall.core.logger import log + from firewall.server.decorators import handle_exceptions, \ + dbus_handle_exceptions, dbus_service_method +@@ -408,6 +409,7 @@ class FirewallDConfigIPSet(slip.dbus.service.Object): + def setEntries(self, entries, sender=None): + _entries = set() + for _entry in dbus_to_python(entries, list): ++ check_entry_overlaps_existing(_entry, _entries) + _entries.add(normalize_ipset_entry(_entry)) + entries = list(_entries) + log.debug1("%s.setEntries('[%s]')", self._log_prefix, +@@ -432,6 +434,7 @@ class FirewallDConfigIPSet(slip.dbus.service.Object): + raise FirewallError(errors.IPSET_WITH_TIMEOUT) + if entry in settings[5]: + raise FirewallError(errors.ALREADY_ENABLED, entry) ++ check_entry_overlaps_existing(entry, settings[5]) + settings[5].append(entry) + self.update(settings) + +diff --git a/src/tests/regression/ipset_netmask_allowed.at b/src/tests/regression/ipset_netmask_allowed.at +index b5165d94b220..fd08afd3b57c 100644 +--- a/src/tests/regression/ipset_netmask_allowed.at ++++ b/src/tests/regression/ipset_netmask_allowed.at +@@ -9,15 +9,17 @@ dnl an add for the whole range. i.e. 1.2.3.4/24 --> 1.2.3.[0.255] (256 + dnl entries). + dnl + dnl In nftables, we allow this by using actual intervals. +-FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.0/24], 0, [ignore]) +-FWD_CHECK([ --ipset foobar --add-entry 1.2.3.0/24], 0, [ignore]) ++FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.4/24], 0, [ignore]) ++FWD_CHECK([ --ipset foobar --add-entry 1.2.3.4/24], 0, [ignore]) + + dnl check the edge case + FWD_CHECK([--permanent --ipset foobar --add-entry 4.3.2.1/32], 0, [ignore]) + FWD_CHECK([ --ipset foobar --add-entry 4.3.2.1/32], 0, [ignore]) + +-dnl overlaps should be denied by ipset +-FWD_CHECK([ --ipset foobar --add-entry 1.2.3.0/22], 13, [ignore], [ignore]) +-FWD_CHECK([ --ipset foobar --add-entry 1.2.3.0/30], 13, [ignore], [ignore]) ++dnl overlaps should be denied ++FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.0/22], 136, [ignore], [ignore]) ++FWD_CHECK([ --ipset foobar --add-entry 1.2.3.0/22], 136, [ignore], [ignore]) ++FWD_CHECK([--permanent --ipset foobar --add-entry 1.2.3.4/30], 136, [ignore], [ignore]) ++FWD_CHECK([ --ipset foobar --add-entry 1.2.3.4/30], 136, [ignore], [ignore]) + +-FWD_END_TEST([-e '/ERROR: COMMAND_FAILED:/d']) ++FWD_END_TEST([-e '/ERROR: INVALID_ENTRY:/d']) +-- +2.27.0 + diff --git a/SPECS/firewalld.spec b/SPECS/firewalld.spec index 715e981..675dd16 100644 --- a/SPECS/firewalld.spec +++ b/SPECS/firewalld.spec @@ -1,7 +1,7 @@ Summary: A firewall daemon with D-Bus interface providing a dynamic firewall Name: firewalld Version: 0.9.3 -Release: 5%{?dist} +Release: 7%{?dist} URL: http://www.firewalld.org License: GPLv2+ Source0: https://github.com/firewalld/firewalld/releases/download/v%{version}/firewalld-%{version}.tar.gz @@ -35,6 +35,12 @@ Patch27: 0027-fix-nm-reload-only-consider-NM-connections-with-a-re.patch Patch28: 0028-test-nm-reload-only-consider-NM-connections-with-a-r.patch Patch29: 0029-docs-conf-note-that-IPv6_rpfilter-has-a-performance-.patch Patch30: 0030-improvement-conf-note-that-IPv6_rpfilter-has-a-perfo.patch +Patch31: 0031-test-functions-FWD_GREP_LOG-allow-checking-error-cod.patch +Patch32: 0032-test-functions-improve-checking-firewalld.log-for-er.patch +Patch33: 0033-fix-policy-warn-instead-of-error-for-overlapping-por.patch +Patch34: 0034-test-zone-verify-overlapping-ports-don-t-halt-zone-l.patch +Patch35: v1.0.0-0035-fix-ipset-normalize-entries-in-CIDR-notation.patch +Patch36: v1.0.0-0036-fix-ipset-disallow-overlapping-entries.patch BuildArch: noarch BuildRequires: autoconf @@ -236,6 +242,12 @@ desktop-file-install --delete-original \ %{_mandir}/man1/firewall-config*.1* %changelog +* Tue Jul 13 2021 Eric Garver - 0.9.3-7 +- fix(ipset): disallow overlapping entries + +* Tue Jul 13 2021 Eric Garver - 0.9.3-6 +- fix(policy): warn instead of error for overlapping ports + * Wed May 19 2021 Eric Garver - 0.9.3-5 - docs(conf): note that IPv6_rpfilter has a performance penalty