[libvirt] [PATCH 01/10] nwfilter: don't ignore child process failures

Laine Stump laine at laine.org
Fri Feb 21 11:20:11 UTC 2014


On 02/20/2014 07:13 AM, Eric Blake wrote:
> While auditing all callers of virCommandRun, I noticed that nwfilter
> code never paid attention to commands with a non-zero status.
> In the cases where status was captured, either the callers required
> that the status was 0, or they discarded any failures from
> virCommandRun.  Collecting status manually means that a non-zero
> child exit status is not logged, but I could not see the benefit
> in avoiding the logging in any command issued in the code.
> Therefore, it was simpler to just nuke the wasted effort of
> manually checking or ignoring non-zero status.

You need to be careful with this - for some of the external execs in
nwfilter (same with viriptables.c), a non-0 status *should* be ignored
and not reported. In particular, if a command that is attempting to
remove an iptables or ebtables rule fails, that is often because libvirt
is attempting to remove a rule that actually isn't there.

As a matter of fact, in all the cases where the 2nd argument to
ebiptablesExecCLI is non-NULL, that is exactly what's happening - the
code was written that way to avoid putting a bogus and misleading error
message in the logs; viriptables.c *does* log these errors, and that has
led to many bug reports that incorrectly list the error message about
failure to remove a rule as evidence that there is a bug. (I think there
may even be a BZ filed requesting that these error logs be removed
because they are misleading.)

Because of the experience with viriptables.c, I don't think we should
change the code to add back in the logging of these messages.

>
> While at it, I also noticed that ebiptablesRemoveRules would
> actually report success if the child process failed for a
> reason other than non-zero status, such as OOM.
>
> * src/nwfilter/nwfilter_ebiptables_driver.c (ebiptablesExecCLI):
> Drop parameter.
> (ebtablesApplyBasicRules, ebtablesApplyDHCPOnlyRules)
> (ebtablesApplyDropAllRules, ebtablesCleanAll)
> (ebiptablesApplyNewRules, ebiptablesTearNewRules)
> (ebiptablesTearOldRules, ebiptablesAllTeardown)
> (ebiptablesDriverInitWithFirewallD)
> (ebiptablesDriverTestCLITools, ebiptablesDriverProbeStateMatch):
> Adjust all clients.
> (ebiptablesRemoveRules): Likewise, and fix return value on failure.
>
> Signed-off-by: Eric Blake <eblake at redhat.com>
> ---
>  src/nwfilter/nwfilter_ebiptables_driver.c | 89 ++++++++++++-------------------
>  1 file changed, 35 insertions(+), 54 deletions(-)
>
> diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/nwfilter/nwfilter_ebiptables_driver.c
> index dc651a2..002a844 100644
> --- a/src/nwfilter/nwfilter_ebiptables_driver.c
> +++ b/src/nwfilter/nwfilter_ebiptables_driver.c
> @@ -1,7 +1,7 @@
>  /*
>   * nwfilter_ebiptables_driver.c: driver for ebtables/iptables on tap devices
>   *
> - * Copyright (C) 2011-2013 Red Hat, Inc.
> + * Copyright (C) 2011-2014 Red Hat, Inc.
>   * Copyright (C) 2010-2012 IBM Corp.
>   * Copyright (C) 2010-2012 Stefan Berger
>   *
> @@ -2799,8 +2799,6 @@ ebiptablesDisplayRuleInstance(void *_inst)
>   * ebiptablesExecCLI:
>   * @buf : pointer to virBuffer containing the string with the commands to
>   *        execute.
> - * @status: Pointer to an integer for returning the WEXITSTATUS of the
> - *        commands executed via the script the was run.
>   * @outbuf: Optional pointer to a string that will hold the buffer with
>   *          output of the executed command. The actual buffer holding
>   *          the message will be newly allocated by this function and
> @@ -2815,15 +2813,11 @@ ebiptablesDisplayRuleInstance(void *_inst)
>   * NULL, then the script must exit with status 0).
>   */
>  static int
> -ebiptablesExecCLI(virBufferPtr buf,
> -                  int *status, char **outbuf)
> +ebiptablesExecCLI(virBufferPtr buf, char **outbuf)
>  {
>      int rc = -1;
>      virCommandPtr cmd;
>
> -    if (status)
> -         *status = 0;
> -
>      if (!virBufferError(buf) && !virBufferUse(buf))
>          return 0;
>
> @@ -2837,7 +2831,7 @@ ebiptablesExecCLI(virBufferPtr buf,
>
>      virMutexLock(&execCLIMutex);
>
> -    rc = virCommandRun(cmd, status);
> +    rc = virCommandRun(cmd, NULL);
>
>      virMutexUnlock(&execCLIMutex);
>
> @@ -3293,7 +3287,7 @@ ebtablesApplyBasicRules(const char *ifname,
>      ebtablesLinkTmpRootChain(&buf, 1, ifname, 1);
>      ebtablesRenameTmpRootChain(&buf, 1, ifname);
>
> -    if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
> +    if (ebiptablesExecCLI(&buf, NULL) < 0)
>          goto tear_down_tmpebchains;
>
>      return 0;
> @@ -3441,7 +3435,7 @@ ebtablesApplyDHCPOnlyRules(const char *ifname,
>          ebtablesRenameTmpRootChain(&buf, 0, ifname);
>      }
>
> -    if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
> +    if (ebiptablesExecCLI(&buf, NULL) < 0)
>          goto tear_down_tmpebchains;
>
>      return 0;
> @@ -3511,7 +3505,7 @@ ebtablesApplyDropAllRules(const char *ifname)
>      ebtablesRenameTmpRootChain(&buf, 1, ifname);
>      ebtablesRenameTmpRootChain(&buf, 0, ifname);
>
> -    if (ebiptablesExecCLI(&buf, NULL, NULL) < 0)
> +    if (ebiptablesExecCLI(&buf, NULL) < 0)
>          goto tear_down_tmpebchains;
>
>      return 0;
> @@ -3537,7 +3531,6 @@ ebtablesRemoveBasicRules(const char *ifname)
>  static int ebtablesCleanAll(const char *ifname)
>  {
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
> -    int cli_status;
>
>      if (!ebtables_cmd_path)
>          return 0;
> @@ -3556,7 +3549,7 @@ static int ebtablesCleanAll(const char *ifname)
>      ebtablesRemoveTmpRootChain(&buf, 1, ifname);
>      ebtablesRemoveTmpRootChain(&buf, 0, ifname);
>
> -    ebiptablesExecCLI(&buf, &cli_status, NULL);
> +    ebiptablesExecCLI(&buf, NULL);
>      return 0;
>  }
>
> @@ -3704,7 +3697,6 @@ ebiptablesApplyNewRules(const char *ifname,
>                          void **_inst)
>  {
>      size_t i, j;
> -    int cli_status;
>      ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
>      virHashTablePtr chains_in_set  = virHashCreate(10, NULL);
> @@ -3752,7 +3744,7 @@ ebiptablesApplyNewRules(const char *ifname,
>          ebtablesRemoveTmpSubChains(&buf, ifname);
>          ebtablesRemoveTmpRootChain(&buf, 1, ifname);
>          ebtablesRemoveTmpRootChain(&buf, 0, ifname);
> -        ebiptablesExecCLI(&buf, &cli_status, NULL);
> +        ebiptablesExecCLI(&buf, NULL);
>      }
>
>      NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
> @@ -3771,7 +3763,7 @@ ebiptablesApplyNewRules(const char *ifname,
>          qsort(&ebtChains[0], nEbtChains, sizeof(ebtChains[0]),
>                ebiptablesRuleOrderSort);
>
> -    if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +    if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>          goto tear_down_tmpebchains;
>
>      NWFILTER_SET_EBTABLES_SHELLVAR(&buf);
> @@ -3807,7 +3799,7 @@ ebiptablesApplyNewRules(const char *ifname,
>                                ebtChains[j++].commandTemplate,
>                                'A', -1, 1);
>
> -    if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +    if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>          goto tear_down_tmpebchains;
>
>      if (haveIptables) {
> @@ -3818,21 +3810,21 @@ ebiptablesApplyNewRules(const char *ifname,
>
>          iptablesCreateBaseChains(&buf);
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>              goto tear_down_tmpebchains;
>
>          NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
>
>          iptablesCreateTmpRootChains(&buf, ifname);
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>             goto tear_down_tmpiptchains;
>
>          NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
>
>          iptablesLinkTmpRootChains(&buf, ifname);
>          iptablesSetupVirtInPost(&buf, ifname);
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>             goto tear_down_tmpiptchains;
>
>          NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
> @@ -3845,7 +3837,7 @@ ebiptablesApplyNewRules(const char *ifname,
>                                      'A', -1, 1);
>          }
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>             goto tear_down_tmpiptchains;
>
>          iptablesCheckBridgeNFCallEnabled(false);
> @@ -3859,21 +3851,21 @@ ebiptablesApplyNewRules(const char *ifname,
>
>          iptablesCreateBaseChains(&buf);
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>              goto tear_down_tmpiptchains;
>
>          NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
>
>          iptablesCreateTmpRootChains(&buf, ifname);
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>             goto tear_down_tmpip6tchains;
>
>          NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
>
>          iptablesLinkTmpRootChains(&buf, ifname);
>          iptablesSetupVirtInPost(&buf, ifname);
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>             goto tear_down_tmpip6tchains;
>
>          NWFILTER_SET_IP6TABLES_SHELLVAR(&buf);
> @@ -3885,7 +3877,7 @@ ebiptablesApplyNewRules(const char *ifname,
>                                      'A', -1, 1);
>          }
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>             goto tear_down_tmpip6tchains;
>
>          iptablesCheckBridgeNFCallEnabled(true);
> @@ -3898,7 +3890,7 @@ ebiptablesApplyNewRules(const char *ifname,
>      if (virHashSize(chains_out_set) != 0)
>          ebtablesLinkTmpRootChain(&buf, 0, ifname, 1);
>
> -    if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0)
> +    if (ebiptablesExecCLI(&buf, &errmsg) < 0)
>          goto tear_down_ebsubchains_and_unlink;
>
>      virHashFree(chains_in_set);
> @@ -3945,7 +3937,7 @@ tear_down_tmpebchains:
>          ebtablesRemoveTmpRootChain(&buf, 0, ifname);
>      }
>
> -    ebiptablesExecCLI(&buf, &cli_status, NULL);
> +    ebiptablesExecCLI(&buf, NULL);
>
>      virReportError(VIR_ERR_BUILD_FIREWALL,
>                     _("Some rules could not be created for "
> @@ -3971,7 +3963,6 @@ exit_free_sets:
>  static int
>  ebiptablesTearNewRules(const char *ifname)
>  {
> -    int cli_status;
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
>
>      if (iptables_cmd_path) {
> @@ -3999,7 +3990,7 @@ ebiptablesTearNewRules(const char *ifname)
>          ebtablesRemoveTmpRootChain(&buf, 0, ifname);
>      }
>
> -    ebiptablesExecCLI(&buf, &cli_status, NULL);
> +    ebiptablesExecCLI(&buf, NULL);
>
>      return 0;
>  }
> @@ -4008,7 +3999,6 @@ ebiptablesTearNewRules(const char *ifname)
>  static int
>  ebiptablesTearOldRules(const char *ifname)
>  {
> -    int cli_status;
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
>
>      /* switch to new iptables user defined chains */
> @@ -4019,7 +4009,7 @@ ebiptablesTearOldRules(const char *ifname)
>          iptablesRemoveRootChains(&buf, ifname);
>
>          iptablesRenameTmpRootChains(&buf, ifname);
> -        ebiptablesExecCLI(&buf, &cli_status, NULL);
> +        ebiptablesExecCLI(&buf, NULL);
>      }
>
>      if (ip6tables_cmd_path) {
> @@ -4029,7 +4019,7 @@ ebiptablesTearOldRules(const char *ifname)
>          iptablesRemoveRootChains(&buf, ifname);
>
>          iptablesRenameTmpRootChains(&buf, ifname);
> -        ebiptablesExecCLI(&buf, &cli_status, NULL);
> +        ebiptablesExecCLI(&buf, NULL);
>      }
>
>      if (ebtables_cmd_path) {
> @@ -4045,7 +4035,7 @@ ebiptablesTearOldRules(const char *ifname)
>
>          ebtablesRenameTmpSubAndRootChains(&buf, ifname);
>
> -        ebiptablesExecCLI(&buf, &cli_status, NULL);
> +        ebiptablesExecCLI(&buf, NULL);
>      }
>
>      return 0;
> @@ -4068,8 +4058,7 @@ ebiptablesRemoveRules(const char *ifname ATTRIBUTE_UNUSED,
>                        int nruleInstances,
>                        void **_inst)
>  {
> -    int rc = 0;
> -    int cli_status;
> +    int rc = -1;
>      size_t i;
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
>      ebiptablesRuleInstPtr *inst = (ebiptablesRuleInstPtr *)_inst;
> @@ -4082,17 +4071,12 @@ ebiptablesRemoveRules(const char *ifname ATTRIBUTE_UNUSED,
>                                'D', -1,
>                                0);
>
> -    if (ebiptablesExecCLI(&buf, &cli_status, NULL) < 0)
> -        goto err_exit;
> +    if (ebiptablesExecCLI(&buf, NULL) < 0)
> +        goto cleanup;
>
> -    if (cli_status) {
> -        virReportError(VIR_ERR_BUILD_FIREWALL,
> -                       "%s",
> -                       _("error while executing CLI commands"));
> -        rc = -1;
> -    }
> +    rc = 0;
>
> -err_exit:
> +cleanup:
>      return rc;
>  }
>
> @@ -4110,7 +4094,6 @@ static int
>  ebiptablesAllTeardown(const char *ifname)
>  {
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
> -    int cli_status;
>
>      if (iptables_cmd_path) {
>          NWFILTER_SET_IPTABLES_SHELLVAR(&buf);
> @@ -4139,7 +4122,7 @@ ebiptablesAllTeardown(const char *ifname)
>          ebtablesRemoveRootChain(&buf, 1, ifname);
>          ebtablesRemoveRootChain(&buf, 0, ifname);
>      }
> -    ebiptablesExecCLI(&buf, &cli_status, NULL);
> +    ebiptablesExecCLI(&buf, NULL);
>
>      return 0;
>  }
> @@ -4180,7 +4163,6 @@ ebiptablesDriverInitWithFirewallD(void)
>      virBuffer buf = VIR_BUFFER_INITIALIZER;
>      char *firewall_cmd_path;
>      char *output = NULL;
> -    int status;
>      int ret = -1;
>
>      if (!virNWFilterDriverIsWatchingFirewallD())
> @@ -4196,8 +4178,7 @@ ebiptablesDriverInitWithFirewallD(void)
>                            "%s",
>                            CMD_STOPONERR(1));
>
> -        if (ebiptablesExecCLI(&buf, &status, &output) < 0 ||
> -            status != 0) {
> +        if (ebiptablesExecCLI(&buf, &output) < 0) {
>              VIR_INFO("firewalld support disabled for nwfilter");
>          } else {
>              VIR_INFO("firewalld support enabled for nwfilter");
> @@ -4268,7 +4249,7 @@ ebiptablesDriverTestCLITools(void)
>                            "%s",
>                            CMD_STOPONERR(1));
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0) {
>              VIR_FREE(ebtables_cmd_path);
>              VIR_ERROR(_("Testing of ebtables command failed: %s"),
>                        errmsg);
> @@ -4285,7 +4266,7 @@ ebiptablesDriverTestCLITools(void)
>                            "%s",
>                            CMD_STOPONERR(1));
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0) {
>              VIR_FREE(iptables_cmd_path);
>              VIR_ERROR(_("Testing of iptables command failed: %s"),
>                        errmsg);
> @@ -4302,7 +4283,7 @@ ebiptablesDriverTestCLITools(void)
>                            "%s",
>                            CMD_STOPONERR(1));
>
> -        if (ebiptablesExecCLI(&buf, NULL, &errmsg) < 0) {
> +        if (ebiptablesExecCLI(&buf, &errmsg) < 0) {
>              VIR_FREE(ip6tables_cmd_path);
>              VIR_ERROR(_("Testing of ip6tables command failed: %s"),
>                        errmsg);
> @@ -4353,7 +4334,7 @@ ebiptablesDriverProbeStateMatch(void)
>      virBufferAsprintf(&buf,
>                        "$IPT --version");
>
> -    if (ebiptablesExecCLI(&buf, NULL, &cmdout) < 0) {
> +    if (ebiptablesExecCLI(&buf, &cmdout) < 0) {
>          VIR_ERROR(_("Testing of iptables command failed: %s"),
>                    cmdout);
>          return;




More information about the libvir-list mailing list