Re: [PATCH] network: introduce a "none" firewall backend type

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



  Daniel P. Berrangé wrote:

> There are two scenarios identified after the recent firewall backend
> selection was introduced, which result in libvirtd failing to startup
> due to an inability to find either iptables/nftables
> 
>  - On Linux if running unprivileged with $PATH lacking the dir
>    containing iptables/nftables
>  - On non-Linux where iptables/nftables never existed
> 
> In the former case, it is preferrable to restore the behaviour whereby
> the driver starts successfully. Users will get an error reported when
> attempting to start any virtual network, due to the lack of permissions
> needed to create bridge devices. This makes the missing firewall backend
> irrelevant.
> 
> In the latter case, the network driver calls the 'nop' platform
> implementation which does not attempt to implement any firewall logic,
> just allowing the network to start without firewall rules.
> 
> To solve this are number of changes are required
> 
>  * Introduce VIR_FIREWALL_BACKEND_NONE, which does nothing except
>    report a fatal error from virFirewallApply(). This code path
>    is unreachable, since we'll never create a virFirewall
>    object with with VIR_FIREWALL_BACKEND_NONE, so the error reporting
>    is just a sanity check.
> 
>  * Ignore the compile time backend defaults and assume use of
>    the 'none' backend if running unprivileged.
> 
>    This fixes the first regression, avoiding the failure to start
>    libvirtd on Linux in unprivileged context, instead allowing use
>    of the driver and expecting a permission denied when creating a
>    bridge.
> 
>  * Reject the use of compile time backend defaults no non-Linux
>    and hardcode the 'none' backend. The non-Linux platforms have
>    no firewall implementation at all currently, so there's no
>    reason to permit the use of 'firewall_backend_priority'
>    meson option.
> 
>    This fixes the second regression, avoiding the failure to start
>    libvirtd on non-Linux hosts due to non-existant Linux binaries.
> 
>  * Change the Linux platform backend to raise an error if the
>    firewall backend is 'none'. Again this code path is unreachable
>    by default since we'll fail to create the bridge before getting
>    here, but if someone modified network.conf to request the 'none'
>    backend, this will stop further progress.
> 
>  * Change the nop platform backend to raise an error if the
>    firewall backend is 'iptables' or 'nftables'. Again this code
>    path is unreachable, since we should already have failed to
>    find the iptables/nftables binaries on non-Linux hosts, so
>    this is just a sanity check.
> 
>  * 'none' is not permited as a value in 'firewall_backend_priority'
>    meson option, since it is conceptually meaningless to ask for
>    that on Linux.

Thanks for the quick fix! You were faster than me.

Minor fixups:

--- a/src/network/bridge_driver_nop.c
+++ b/src/network/bridge_driver_nop.c
@@ -19,6 +19,8 @@
 
 #include <config.h>
 
+#define VIR_FROM_THIS VIR_FROM_NETWORK
+
 void networkPreReloadFirewallRules(virNetworkDriverState *driver G_GNUC_UNUSED,
                                    bool startup G_GNUC_UNUSED,
                                    bool force G_GNUC_UNUSED)
@@ -45,10 +47,10 @@ int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED,
      * ought to fail to find the required binaries when loading,
      * so this is just a sanity check
      */
-    if (firewallBackend != VIR_FIREWALL_NONE) {
-        virReportError(VIR_ERR_NO_SUPPORT, "%s",
+    if (firewallBackend != VIR_FIREWALL_BACKEND_NONE) {
+        virReportError(VIR_ERR_NO_SUPPORT,
                        _("Firewall backend '%s' not available on this platform"),
-                       virFirewallBackendTypeToSTring(firewallBackend));
+                       virFirewallBackendTypeToString(firewallBackend));
         return -1;
     }
     return 0;

I briefly run-time tested that and it works for me.

> Signed-off-by: Daniel P. Berrangé <berrange@xxxxxxxxxx>
> ---
>  meson.build                       | 26 +++++++++++++++++++-------
>  meson_options.txt                 |  2 +-
>  src/network/bridge_driver_conf.c  | 19 ++++++++++++++-----
>  src/network/bridge_driver_linux.c | 10 ++++++++++
>  src/network/bridge_driver_nop.c   | 13 ++++++++++++-
>  src/util/virfirewall.c            |  6 ++++++
>  src/util/virfirewall.h            |  1 +
>  7 files changed, 63 insertions(+), 14 deletions(-)
> 
> diff --git a/meson.build b/meson.build
> index 5c7cd7ec2e..2e8b87280d 100644
> --- a/meson.build
> +++ b/meson.build
> @@ -1647,15 +1647,27 @@ if not get_option('driver_network').disabled() and conf.has('WITH_LIBVIRTD')
>    conf.set('WITH_NETWORK', 1)
>  
>    firewall_backend_priority = get_option('firewall_backend_priority')
> -  if (not firewall_backend_priority.contains('nftables') or
> -      not firewall_backend_priority.contains('iptables') or
> -      firewall_backend_priority.length() != 2)
> -    error('invalid value for firewall_backend_priority option')
> +  if firewall_backend_priority.length() == 0
> +      if host_machine.system() == 'linux'
> +          firewall_backend_priority = ['nftables', 'iptables']
> +      else
> +          # No firewall impl on non-Linux so far, so force 'none'
> +          # as placeholder
> +          firewall_backend_priority = ['none']
> +      endif
> +  else
> +      if host_machine.system() != 'linux'
> +          error('firewall backend priority only supported on linux hosts')
> +      endif
>    endif
>  
> -  conf.set('FIREWALL_BACKEND_PRIORITY_0', 'VIR_FIREWALL_BACKEND_' + firewall_backend_priority[0].to_upper())
> -  conf.set('FIREWALL_BACKEND_PRIORITY_1', 'VIR_FIREWALL_BACKEND_' + firewall_backend_priority[1].to_upper())
> -  conf.set('FIREWALL_BACKEND_PRIORITY_NUM', firewall_backend_priority.length())
> +  backends = []
> +  foreach backend: firewall_backend_priority
> +      backend = 'VIR_FIREWALL_BACKEND_' + backend.to_upper()
> +      backends += backend
> +  endforeach
> +
> +  conf.set('FIREWALL_BACKENDS', ', '.join(backends))
>  elif get_option('driver_network').enabled()
>    error('libvirtd must be enabled to build the network driver')
>  endif
> diff --git a/meson_options.txt b/meson_options.txt
> index 50d71427cb..2d440c63d8 100644
> --- a/meson_options.txt
> +++ b/meson_options.txt
> @@ -117,7 +117,7 @@ option('dtrace', type: 'feature', value: 'auto', description: 'use dtrace for st
>  option('firewalld', type: 'feature', value: 'auto', description: 'firewalld support')
>  # dep:firewalld
>  option('firewalld_zone', type: 'feature', value: 'auto', description: 'whether to install firewalld libvirt zone')
> -option('firewall_backend_priority', type: 'array', choices: ['nftables', 'iptables'], description: 'order in which to try firewall backends')
> +option('firewall_backend_priority', type: 'array', choices: ['nftables', 'iptables'], value: [], description: 'order in which to try firewall backends')
>  option('host_validate', type: 'feature', value: 'auto', description: 'build virt-host-validate')
>  option('init_script', type: 'combo', choices: ['systemd', 'openrc', 'check', 'none'], value: 'check', description: 'Style of init script to install')
>  option('loader_nvram', type: 'string', value: '', description: 'Pass list of pairs of <loader>:<nvram> paths. Both pairs and list items are separated by a colon.')
> diff --git a/src/network/bridge_driver_conf.c b/src/network/bridge_driver_conf.c
> index e2f3613a41..9da5e790b7 100644
> --- a/src/network/bridge_driver_conf.c
> +++ b/src/network/bridge_driver_conf.c
> @@ -61,6 +61,7 @@ networkGetDnsmasqCaps(virNetworkDriverState *driver)
>  
>  static int
>  virNetworkLoadDriverConfig(virNetworkDriverConfig *cfg G_GNUC_UNUSED,
> +                           bool privileged,
>                             const char *filename)
>  {
>      g_autoptr(virConf) conf = NULL;
> @@ -68,13 +69,17 @@ virNetworkLoadDriverConfig(virNetworkDriverConfig *cfg G_GNUC_UNUSED,
>      bool fwBackendSelected = false;
>      size_t i;
>      int fwBackends[] = {
> -        FIREWALL_BACKEND_PRIORITY_0,
> -        FIREWALL_BACKEND_PRIORITY_1,
> +        FIREWALL_BACKENDS
>      };
> -    G_STATIC_ASSERT(G_N_ELEMENTS(fwBackends) == VIR_FIREWALL_BACKEND_LAST);
> -    G_STATIC_ASSERT(G_N_ELEMENTS(fwBackends) == FIREWALL_BACKEND_PRIORITY_NUM);
> +    G_STATIC_ASSERT(G_N_ELEMENTS(fwBackends) > 0 &&
> +                    G_N_ELEMENTS(fwBackends) <= VIR_FIREWALL_BACKEND_LAST);
>      int nFwBackends = G_N_ELEMENTS(fwBackends);
>  
> +    if (!privileged) {
> +        fwBackends[0] = VIR_FIREWALL_BACKEND_NONE;
> +        nFwBackends = 1;
> +    }
> +
>      if (access(filename, R_OK) == 0) {
>  
>          conf = virConfReadFile(filename, 0);
> @@ -104,6 +109,10 @@ virNetworkLoadDriverConfig(virNetworkDriverConfig *cfg G_GNUC_UNUSED,
>      for (i = 0; i < nFwBackends && !fwBackendSelected; i++) {
>  
>          switch ((virFirewallBackend)fwBackends[i]) {
> +        case VIR_FIREWALL_BACKEND_NONE:
> +            fwBackendSelected = true;
> +            break;
> +
>          case VIR_FIREWALL_BACKEND_IPTABLES: {
>              g_autofree char *iptablesInPath = virFindFileInPath(IPTABLES);
>  
> @@ -187,7 +196,7 @@ virNetworkDriverConfigNew(bool privileged)
>  
>      configfile = g_strconcat(configdir, "/network.conf", NULL);
>  
> -    if (virNetworkLoadDriverConfig(cfg, configfile) < 0)
> +    if (virNetworkLoadDriverConfig(cfg, privileged, configfile) < 0)
>          return NULL;
>  
>      if (g_mkdir_with_parents(cfg->stateDir, 0777) < 0) {
> diff --git a/src/network/bridge_driver_linux.c b/src/network/bridge_driver_linux.c
> index 35e6bd1154..fe7c6e193c 100644
> --- a/src/network/bridge_driver_linux.c
> +++ b/src/network/bridge_driver_linux.c
> @@ -47,6 +47,11 @@ networkFirewallSetupPrivateChains(virFirewallBackend backend,
>                                    virFirewallLayer layer)
>  {
>      switch (backend) {
> +    case VIR_FIREWALL_BACKEND_NONE:
> +        virReportError(VIR_ERR_NO_SUPPORT, "%s",
> +                       _("No firewall backend is available"));
> +        return -1;
> +
>      case VIR_FIREWALL_BACKEND_IPTABLES:
>          return iptablesSetupPrivateChains(layer);
>  
> @@ -417,6 +422,11 @@ networkAddFirewallRules(virNetworkDef *def,
>      }
>  
>      switch (firewallBackend) {
> +    case VIR_FIREWALL_BACKEND_NONE:
> +        virReportError(VIR_ERR_NO_SUPPORT, "%s",
> +                       _("No firewall backend is available"));
> +        return -1;
> +
>      case VIR_FIREWALL_BACKEND_IPTABLES:
>          return iptablesAddFirewallRules(def, fwRemoval);
>  
> diff --git a/src/network/bridge_driver_nop.c b/src/network/bridge_driver_nop.c
> index 537b9234f8..7797be1ba8 100644
> --- a/src/network/bridge_driver_nop.c
> +++ b/src/network/bridge_driver_nop.c
> @@ -37,9 +37,20 @@ int networkCheckRouteCollision(virNetworkDef *def G_GNUC_UNUSED)
>  }
>  
>  int networkAddFirewallRules(virNetworkDef *def G_GNUC_UNUSED,
> -                            virFirewallBackend firewallBackend G_GNUC_UNUSED,
> +                            virFirewallBackend firewallBackend,
>                              virFirewall **fwRemoval G_GNUC_UNUSED)
>  {
> +    /*
> +     * Shouldn't be possible, since virNetworkLoadDriverConfig
> +     * ought to fail to find the required binaries when loading,
> +     * so this is just a sanity check
> +     */
> +    if (firewallBackend != VIR_FIREWALL_NONE) {
> +        virReportError(VIR_ERR_NO_SUPPORT, "%s",
> +                       _("Firewall backend '%s' not available on this platform"),
> +                       virFirewallBackendTypeToSTring(firewallBackend));
> +        return -1;
> +    }
>      return 0;
>  }
>  
> diff --git a/src/util/virfirewall.c b/src/util/virfirewall.c
> index 2219506b18..d374f54b64 100644
> --- a/src/util/virfirewall.c
> +++ b/src/util/virfirewall.c
> @@ -37,6 +37,7 @@ VIR_LOG_INIT("util.firewall");
>  
>  VIR_ENUM_IMPL(virFirewallBackend,
>                VIR_FIREWALL_BACKEND_LAST,
> +              "none",
>                "iptables",
>                "nftables");
>  
> @@ -815,6 +816,11 @@ virFirewallApplyCmd(virFirewall *firewall,
>      }
>  
>      switch (virFirewallGetBackend(firewall)) {
> +    case VIR_FIREWALL_BACKEND_NONE:
> +        virReportError(VIR_ERR_NO_SUPPORT,
> +                       _("Firewall backend is not implemented"));
> +        return -1;
> +
>      case VIR_FIREWALL_BACKEND_IPTABLES:
>          if (virFirewallCmdIptablesApply(firewall, fwCmd, &output) < 0)
>              return -1;
> diff --git a/src/util/virfirewall.h b/src/util/virfirewall.h
> index 302a6a4e5b..bce51259d2 100644
> --- a/src/util/virfirewall.h
> +++ b/src/util/virfirewall.h
> @@ -44,6 +44,7 @@ typedef enum {
>  } virFirewallLayer;
>  
>  typedef enum {
> +    VIR_FIREWALL_BACKEND_NONE, /* Always fails */
>      VIR_FIREWALL_BACKEND_IPTABLES,
>      VIR_FIREWALL_BACKEND_NFTABLES,
>  
> -- 
> 2.45.1




[Index of Archives]     [Virt Tools]     [Libvirt Users]     [Lib OS Info]     [Fedora Users]     [Fedora Desktop]     [Fedora SELinux]     [Big List of Linux Books]     [Yosemite News]     [KDE Users]     [Fedora Tools]

  Powered by Linux