ea8ea4
From eeb2b58b84e6a61d5c212e78e2cf1a44846d5301 Mon Sep 17 00:00:00 2001
4f7c03
From: Eric Garver <eric@garver.life>
4f7c03
Date: Sun, 19 Jan 2020 14:13:36 -0500
ea8ea4
Subject: [PATCH 139/146] feat: AllowZoneDrifting config option
4f7c03
4f7c03
Older versions of firewalld had undocumented behavior known as "zone
4f7c03
drifting". This allowed packets to ingress multiple zones - this is a
4f7c03
violation of zone based firewalls. However, some users rely on this
4f7c03
behavior to have a "catch-all" zone, e.g. the default zone. You can
4f7c03
enable this if you desire such behavior. It's disabled by default for
4f7c03
security reasons.
4f7c03
4f7c03
Note: If "yes" packets will only drift from source based zones to
4f7c03
interface based zones (including the default zone). Packets never drift
4f7c03
from interface based zones to other interfaces based zones (including
4f7c03
the default zone).
4f7c03
4f7c03
(cherry picked from commit afadd377b09dc62b340d24bcf891d31f040d1a18)
4f7c03
(cherry picked from commit 3bbd15a5317b59e175e2a060d1a6ecf4c2129b32)
4f7c03
---
4f7c03
 config/firewalld.conf                  | 12 ++++++++++++
4f7c03
 doc/xml/firewalld.conf.xml             | 19 +++++++++++++++++++
4f7c03
 doc/xml/firewalld.dbus.xml             | 16 ++++++++++++++++
4f7c03
 src/firewall/config/__init__.py.in     |  1 +
4f7c03
 src/firewall/core/fw.py                | 14 ++++++++++++++
4f7c03
 src/firewall/core/io/firewalld_conf.py | 13 +++++++++++--
4f7c03
 src/firewall/server/config.py          | 20 +++++++++++++++++---
4f7c03
 src/tests/dbus/firewalld.conf.at       |  3 +++
4f7c03
 8 files changed, 93 insertions(+), 5 deletions(-)
4f7c03
4f7c03
diff --git a/config/firewalld.conf b/config/firewalld.conf
4f7c03
index 63df409bf567..02be07b9b892 100644
4f7c03
--- a/config/firewalld.conf
4f7c03
+++ b/config/firewalld.conf
4f7c03
@@ -55,3 +55,15 @@ LogDenied=off
4f7c03
 # will be used. Possible values are: yes, no and system.
4f7c03
 # Default: system
4f7c03
 AutomaticHelpers=system
4f7c03
+
4f7c03
+# AllowZoneDrifting
4f7c03
+# Older versions of firewalld had undocumented behavior known as "zone
4f7c03
+# drifting". This allowed packets to ingress multiple zones - this is a
4f7c03
+# violation of zone based firewalls. However, some users rely on this behavior
4f7c03
+# to have a "catch-all" zone, e.g. the default zone. You can enable this if you
4f7c03
+# desire such behavior. It's disabled by default for security reasons.
4f7c03
+# Note: If "yes" packets will only drift from source based zones to interface
4f7c03
+# based zones (including the default zone). Packets never drift from interface
4f7c03
+# based zones to other interfaces based zones (including the default zone).
4f7c03
+# Possible values; "yes", "no". Defaults to "no".
4f7c03
+AllowZoneDrifting=no
4f7c03
diff --git a/doc/xml/firewalld.conf.xml b/doc/xml/firewalld.conf.xml
4f7c03
index afb94b90937f..9d8017df3112 100644
4f7c03
--- a/doc/xml/firewalld.conf.xml
4f7c03
+++ b/doc/xml/firewalld.conf.xml
4f7c03
@@ -144,6 +144,25 @@
4f7c03
 	</listitem>
4f7c03
       </varlistentry>
4f7c03
 
4f7c03
+        <varlistentry>
4f7c03
+            <term><option>AllowZoneDrifting</option></term>
4f7c03
+            <listitem>
4f7c03
+                <para>
4f7c03
+                Older versions of firewalld had undocumented behavior known
4f7c03
+                as "zone drifting". This allowed packets to ingress multiple
4f7c03
+                zones - this is a violation of zone based firewalls. However,
4f7c03
+                some users rely on this behavior to have a "catch-all" zone,
4f7c03
+                e.g. the default zone. You can enable this if you desire such
4f7c03
+                behavior. It's disabled by default for security reasons.
4f7c03
+                Note: If "yes" packets will only drift from source based zones
4f7c03
+                to interface based zones (including the default zone). Packets
4f7c03
+                never drift from interface based zones to other interfaces
4f7c03
+                based zones (including the default zone).
4f7c03
+                Valid values; "yes", "no". Defaults to "no".
4f7c03
+                </para>
4f7c03
+            </listitem>
4f7c03
+        </varlistentry>
4f7c03
+
4f7c03
     </variablelist>
4f7c03
 
4f7c03
   </refsect1>
4f7c03
diff --git a/doc/xml/firewalld.dbus.xml b/doc/xml/firewalld.dbus.xml
4f7c03
index ec82d4cad077..ea0be9cefd1c 100644
4f7c03
--- a/doc/xml/firewalld.dbus.xml
4f7c03
+++ b/doc/xml/firewalld.dbus.xml
4f7c03
@@ -2558,6 +2558,22 @@
4f7c03
       <refsect3 id="FirewallD1.config.Properties">
4f7c03
         <title>Properties</title>
4f7c03
         <variablelist>
4f7c03
+          <varlistentry id="FirewallD1.config.Properties.AllowZoneDrifting">
4f7c03
+            <term><parameter>AllowZoneDrifting</parameter> - s - (rw)</term>
4f7c03
+            <listitem><para>
4f7c03
+                Older versions of firewalld had undocumented behavior known
4f7c03
+                as "zone drifting". This allowed packets to ingress multiple
4f7c03
+                zones - this is a violation of zone based firewalls. However,
4f7c03
+                some users rely on this behavior to have a "catch-all" zone,
4f7c03
+                e.g. the default zone. You can enable this if you desire such
4f7c03
+                behavior. It's disabled by default for security reasons.
4f7c03
+                Note: If "yes" packets will only drift from source based zones
4f7c03
+                to interface based zones (including the default zone). Packets
4f7c03
+                never drift from interface based zones to other interfaces
4f7c03
+                based zones (including the default zone).
4f7c03
+                Valid values; "yes", "no". Defaults to "no".
4f7c03
+            </para></listitem>
4f7c03
+          </varlistentry>
4f7c03
           <varlistentry id="FirewallD1.config.Properties.AutomaticHelpers">
4f7c03
             <term>AutomaticHelpers - s - (rw)</term>
4f7c03
             <listitem>
4f7c03
diff --git a/src/firewall/config/__init__.py.in b/src/firewall/config/__init__.py.in
4f7c03
index 1b2168bde44d..3926c8fdb3a3 100644
4f7c03
--- a/src/firewall/config/__init__.py.in
4f7c03
+++ b/src/firewall/config/__init__.py.in
4f7c03
@@ -128,3 +128,4 @@ FALLBACK_INDIVIDUAL_CALLS = False
4f7c03
 FALLBACK_LOG_DENIED = "off"
4f7c03
 FALLBACK_AUTOMATIC_HELPERS = "system"
4f7c03
 FALLBACK_FIREWALL_BACKEND = "iptables"
4f7c03
+FALLBACK_ALLOW_ZONE_DRIFTING = False
4f7c03
diff --git a/src/firewall/core/fw.py b/src/firewall/core/fw.py
4f7c03
index b1643a1ebff4..5d3cf6e6ce44 100644
4f7c03
--- a/src/firewall/core/fw.py
4f7c03
+++ b/src/firewall/core/fw.py
4f7c03
@@ -114,6 +114,7 @@ class Firewall(object):
4f7c03
         self._automatic_helpers = config.FALLBACK_AUTOMATIC_HELPERS
4f7c03
         self._firewall_backend = config.FALLBACK_FIREWALL_BACKEND
4f7c03
         self.nf_conntrack_helper_setting = 0
4f7c03
+        self._allow_zone_drifting = config.FALLBACK_ALLOW_ZONE_DRIFTING
4f7c03
 
4f7c03
     def individual_calls(self):
4f7c03
         return self._individual_calls
4f7c03
@@ -269,6 +270,19 @@ class Firewall(object):
4f7c03
                     log.debug1("AutomaticHelpers is set to '%s'",
4f7c03
                                self._automatic_helpers)
4f7c03
 
4f7c03
+            if self._firewalld_conf.get("AllowZoneDrifting"):
4f7c03
+                value = self._firewalld_conf.get("AllowZoneDrifting")
4f7c03
+                if value.lower() in [ "no", "false" ]:
4f7c03
+                    self._allow_zone_drifting = False
4f7c03
+                else:
4f7c03
+                    self._allow_zone_drifting = True
4f7c03
+                    log.warning("AllowZoneDrifting is enabled. This is considered "
4f7c03
+                                "an insecure configuration option. It will be "
4f7c03
+                                "removed in a future release. Please consider "
4f7c03
+                                "disabling it now.")
4f7c03
+                log.debug1("AllowZoneDrifting is set to '%s'",
4f7c03
+                           self._allow_zone_drifting)
4f7c03
+
4f7c03
         self.config.set_firewalld_conf(copy.deepcopy(self._firewalld_conf))
4f7c03
 
4f7c03
         self._select_firewall_backend(self._firewall_backend)
4f7c03
diff --git a/src/firewall/core/io/firewalld_conf.py b/src/firewall/core/io/firewalld_conf.py
4f7c03
index 9aee2dc6f9b7..a640d8e2f201 100644
4f7c03
--- a/src/firewall/core/io/firewalld_conf.py
4f7c03
+++ b/src/firewall/core/io/firewalld_conf.py
4f7c03
@@ -28,9 +28,9 @@ from firewall import config
4f7c03
 from firewall.core.logger import log
4f7c03
 from firewall.functions import b2u, u2b, PY2
4f7c03
 
4f7c03
-valid_keys = [ "DefaultZone", "MinimalMark", "CleanupOnExit", "Lockdown", 
4f7c03
+valid_keys = [ "DefaultZone", "MinimalMark", "CleanupOnExit", "Lockdown",
4f7c03
                "IPv6_rpfilter", "IndividualCalls", "LogDenied",
4f7c03
-               "AutomaticHelpers" ]
4f7c03
+               "AutomaticHelpers", "AllowZoneDrifting" ]
4f7c03
 
4f7c03
 class firewalld_conf(object):
4f7c03
     def __init__(self, filename):
4f7c03
@@ -79,6 +79,7 @@ class firewalld_conf(object):
4f7c03
             self.set("IndividualCalls", "yes" if config.FALLBACK_INDIVIDUAL_CALLS else "no")
4f7c03
             self.set("LogDenied", config.FALLBACK_LOG_DENIED)
4f7c03
             self.set("AutomaticHelpers", config.FALLBACK_AUTOMATIC_HELPERS)
4f7c03
+            self.set("AllowZoneDrifting", "yes" if config.FALLBACK_ALLOW_ZONE_DRIFTING else "no")
4f7c03
             raise
4f7c03
 
4f7c03
         for line in f:
4f7c03
@@ -174,6 +175,14 @@ class firewalld_conf(object):
4f7c03
                             config.FALLBACK_AUTOMATIC_HELPERS)
4f7c03
             self.set("AutomaticHelpers", str(config.FALLBACK_AUTOMATIC_HELPERS))
4f7c03
 
4f7c03
+        value = self.get("AllowZoneDrifting")
4f7c03
+        if not value or value.lower() not in [ "yes", "true", "no", "false" ]:
4f7c03
+            if value is not None:
4f7c03
+                log.warning("AllowZoneDrifting '%s' is not valid, using default "
4f7c03
+                            "value %s", value if value else '',
4f7c03
+                            config.FALLBACK_ALLOW_ZONE_DRIFTING)
4f7c03
+            self.set("AllowZoneDrifting", str(config.FALLBACK_ALLOW_ZONE_DRIFTING))
4f7c03
+
4f7c03
     # save to self.filename if there are key/value changes
4f7c03
     def write(self):
4f7c03
         if len(self._config) < 1:
4f7c03
diff --git a/src/firewall/server/config.py b/src/firewall/server/config.py
4f7c03
index cd640ba881ca..86b4e4428748 100644
4f7c03
--- a/src/firewall/server/config.py
4f7c03
+++ b/src/firewall/server/config.py
4f7c03
@@ -105,6 +105,7 @@ class FirewallDConfig(slip.dbus.service.Object):
4f7c03
                                                 "IndividualCalls": "readwrite",
4f7c03
                                                 "LogDenied": "readwrite",
4f7c03
                                                 "AutomaticHelpers": "readwrite",
4f7c03
+                                                "AllowZoneDrifting": "readwrite",
4f7c03
                                               })
4f7c03
 
4f7c03
     @handle_exceptions
4f7c03
@@ -484,7 +485,7 @@ class FirewallDConfig(slip.dbus.service.Object):
4f7c03
     def _get_property(self, prop):
4f7c03
         if prop not in [ "DefaultZone", "MinimalMark", "CleanupOnExit",
4f7c03
                          "Lockdown", "IPv6_rpfilter", "IndividualCalls",
4f7c03
-                         "LogDenied", "AutomaticHelpers" ]:
4f7c03
+                         "LogDenied", "AutomaticHelpers", "AllowZoneDrifting"]:
4f7c03
             raise dbus.exceptions.DBusException(
4f7c03
                 "org.freedesktop.DBus.Error.InvalidArgs: "
4f7c03
                 "Property '%s' does not exist" % prop)
4f7c03
@@ -525,6 +526,10 @@ class FirewallDConfig(slip.dbus.service.Object):
4f7c03
             if value is None:
4f7c03
                 value = config.FALLBACK_AUTOMATIC_HELPERS
4f7c03
             return dbus.String(value)
4f7c03
+        elif prop == "AllowZoneDrifting":
4f7c03
+            if value is None:
4f7c03
+                value = "yes" if config.FALLBACK_ALLOW_ZONE_DRIFTING else "no"
4f7c03
+            return dbus.String(value)
4f7c03
 
4f7c03
     @dbus_handle_exceptions
4f7c03
     def _get_dbus_property(self, prop):
4f7c03
@@ -544,6 +549,8 @@ class FirewallDConfig(slip.dbus.service.Object):
4f7c03
             return dbus.String(self._get_property(prop))
4f7c03
         elif prop == "AutomaticHelpers":
4f7c03
             return dbus.String(self._get_property(prop))
4f7c03
+        elif prop == "AllowZoneDrifting":
4f7c03
+            return dbus.String(self._get_property(prop))
4f7c03
         else:
4f7c03
             raise dbus.exceptions.DBusException(
4f7c03
                 "org.freedesktop.DBus.Error.InvalidArgs: "
4f7c03
@@ -583,7 +590,7 @@ class FirewallDConfig(slip.dbus.service.Object):
4f7c03
         if interface_name == config.dbus.DBUS_INTERFACE_CONFIG:
4f7c03
             for x in [ "DefaultZone", "MinimalMark", "CleanupOnExit",
4f7c03
                        "Lockdown", "IPv6_rpfilter", "IndividualCalls",
4f7c03
-                       "LogDenied", "AutomaticHelpers" ]:
4f7c03
+                       "LogDenied", "AutomaticHelpers", "AllowZoneDrifting" ]:
4f7c03
                 ret[x] = self._get_property(x)
4f7c03
         elif interface_name in [ config.dbus.DBUS_INTERFACE_CONFIG_DIRECT,
4f7c03
                                  config.dbus.DBUS_INTERFACE_CONFIG_POLICIES ]:
4f7c03
@@ -609,7 +616,8 @@ class FirewallDConfig(slip.dbus.service.Object):
4f7c03
         if interface_name == config.dbus.DBUS_INTERFACE_CONFIG:
4f7c03
             if property_name in [ "MinimalMark", "CleanupOnExit", "Lockdown",
4f7c03
                                   "IPv6_rpfilter", "IndividualCalls",
4f7c03
-                                  "LogDenied", "AutomaticHelpers" ]:
4f7c03
+                                  "LogDenied", "AutomaticHelpers",
4f7c03
+                                  "AllowZoneDrifting" ]:
4f7c03
                 if property_name == "MinimalMark":
4f7c03
                     try:
4f7c03
                         int(new_value)
4f7c03
@@ -638,6 +646,12 @@ class FirewallDConfig(slip.dbus.service.Object):
4f7c03
                         raise FirewallError(errors.INVALID_VALUE,
4f7c03
                                             "'%s' for %s" % \
4f7c03
                                             (new_value, property_name))
4f7c03
+                if property_name == "AllowZoneDrifting":
4f7c03
+                    if new_value.lower() not in ["yes", "true", "no", "false"]:
4f7c03
+                        raise FirewallError(errors.INVALID_VALUE,
4f7c03
+                                            "'%s' for %s" % \
4f7c03
+                                            (new_value, property_name))
4f7c03
+
4f7c03
                 self.config.get_firewalld_conf().set(property_name, new_value)
4f7c03
                 self.config.get_firewalld_conf().write()
4f7c03
                 self.PropertiesChanged(interface_name,
4f7c03
diff --git a/src/tests/dbus/firewalld.conf.at b/src/tests/dbus/firewalld.conf.at
4f7c03
index 05eb3dd5f650..0884e21b6368 100644
4f7c03
--- a/src/tests/dbus/firewalld.conf.at
4f7c03
+++ b/src/tests/dbus/firewalld.conf.at
4f7c03
@@ -3,6 +3,7 @@ FWD_START_TEST([firewalld.conf])
4f7c03
 dnl Verify defaults over dbus. Should be inline with default firewalld.conf.
4f7c03
 IF_HOST_SUPPORTS_NFT_FIB([
4f7c03
 DBUS_GETALL([config], [config], 0, [dnl
4f7c03
+string "AllowZoneDrifting" : variant string "no"
4f7c03
 string "AutomaticHelpers" : variant string "system"
4f7c03
 string "CleanupOnExit" : variant string "no"
4f7c03
 string "DefaultZone" : variant string "public"
4f7c03
@@ -13,6 +14,7 @@ string "LogDenied" : variant string "off"
4f7c03
 string "MinimalMark" : variant int32 100
4f7c03
 ])], [
4f7c03
 DBUS_GETALL([config], [config], 0, [dnl
4f7c03
+string "AllowZoneDrifting" : variant string "no"
4f7c03
 string "AutomaticHelpers" : variant string "system"
4f7c03
 string "CleanupOnExit" : variant string "no"
4f7c03
 string "DefaultZone" : variant string "public"
4f7c03
@@ -39,6 +41,7 @@ _helper([LogDenied], [string:"all"], [variant string "all"])
4f7c03
 _helper([IPv6_rpfilter], [string:"yes"], [variant string "yes"])
4f7c03
 _helper([IndividualCalls], [string:"yes"], [variant string "yes"])
4f7c03
 _helper([CleanupOnExit], [string:"yes"], [variant string "yes"])
4f7c03
+_helper([AllowZoneDrifting], [string:"yes"], [variant string "yes"])
4f7c03
 dnl Note: DefaultZone is RO
4f7c03
 m4_undefine([_helper])
4f7c03
 
4f7c03
-- 
4f7c03
2.23.0
4f7c03