<br><tt><font size=2>Jim Meyering <jim@meyering.net> wrote on 03/29/2010
02:26:47 PM:<br>
<br>
Jim,</font></tt>
<br>
<br><tt><font size=2>  either of the patches below is fine with me...
with a comment on the assert to 'keep static analyzer quiet'?</font></tt>
<br>
<br><tt><font size=2>Regards,</font></tt>
<br><tt><font size=2>   Stefan</font></tt>
<br>
<br>
<br><tt><font size=2>> <br>
> Stefan Berger wrote:<br>
> ...<br>
> >> > ACK that your patch is the minimal fix to avoid a segfault,
but we<br>
> >> > should probably get Stefan's input on whether returning
success on an<br>
> >> > empty input is the best course of behavior.<br>
> >><br>
> >> Ok.  I've Cc'd him.<br>
> ><br>
> > Actually the inst[n] accesses are protected by nInstances having
<br>
> to be > 0 for<br>
> > code to try to read a inst[n]. So it should be fine the way it
is.nInstances<br>
> > and inst belong together and nInstances indicates the number
of <br>
> members in that<br>
> > array. No member of inst[] is expected to be NULL.<br>
> <br>
> I noticed that, of course.<br>
> However, static analyzers can't always deduce such intended invariants.<br>
> In this case, it's guaranteed to be true (but not at all easy to see)<br>
> only because a prior initialization of that pointer to NULL ensures<br>
> that it's defined even when the number of rules is 0.<br>
> <br>
> Since static analyzers like clang are very handy, I'd like a way<br>
> to tell it that these uses of inst[i] are valid.<br>
> <br>
> One way is the first patch below.<br>
> That has an unpleasant side effect of adding code that we would<br>
> then have to maintain, and that would probably raise eyebrows<br>
> of anyone reviewing it. (or increase their WTF/m rate ;-)<br>
> <br>
> Another way to give clang the info it needs is to add<br>
> an "assert (inst);" on the first line of each loop in question.<br>
> That has the added benefit of helping to document the code.<br>
> They would never be triggered (assuming no one violates the invariant).<br>
> But if someone violates an invariant like that, they might as well
add<br>
> code like this: v = NULL; use (*v);<br>
> <br>
> <br>
> From 84c8cc5425f79f4892b15ae131a721d0a7a1e175 Mon Sep 17 00:00:00
2001<br>
> From: Jim Meyering <meyering@redhat.com><br>
> Date: Mon, 29 Mar 2010 18:27:26 +0200<br>
> Subject: [PATCH] nwfilter_ebiptables_driver.c: avoid NULL dereference<br>
> <br>
> * src/nwfilter/nwfilter_ebiptables_driver.c (ebiptablesApplyNewRules):<br>
> Don't dereference a NULL or uninitialized pointer when given<br>
> an empty list of rules.  Guard each use of "inst[i]",
in case<br>
> inst is NULL in spite of nruleInstances larger than zero.<br>
> ---<br>
>  src/nwfilter/nwfilter_ebiptables_driver.c |   11 +++++------<br>
>  1 files changed, 5 insertions(+), 6 deletions(-)<br>
> <br>
> diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/<br>
> nwfilter/nwfilter_ebiptables_driver.c<br>
> index 7871926..f29d0c0 100644<br>
> --- a/src/nwfilter/nwfilter_ebiptables_driver.c<br>
> +++ b/src/nwfilter/nwfilter_ebiptables_driver.c<br>
> @@ -2389,11 +2389,10 @@ ebiptablesApplyNewRules(virConnectPtr conn,<br>
>      virBuffer buf = VIR_BUFFER_INITIALIZER;<br>
>      int haveIptables = 0;<br>
> <br>
> -    if (inst)<br>
> -        qsort(inst, nruleInstances, sizeof(inst[0]),<br>
> -              ebiptablesRuleOrderSort);<br>
> +    if (nruleInstances > 1 && inst)<br>
> +        qsort(inst, nruleInstances, sizeof(inst[0]),
<br>
> ebiptablesRuleOrderSort);<br>
> <br>
> -    for (i = 0; i < nruleInstances; i++) {<br>
> +    for (i = 0; i < nruleInstances && inst;
i++) {<br>
>          if (inst[i]->ruleType == RT_EBTABLES)
{<br>
>              if (inst[i]->chainprefix
== CHAINPREFIX_HOST_IN_TEMP)<br>
>                  chains_in
 |= (1 << inst[i]->neededProtocolChain);<br>
> @@ -2433,7 +2432,7 @@ ebiptablesApplyNewRules(virConnectPtr conn,<br>
>      if (ebiptablesExecCLI(conn, &buf, &cli_status)
|| cli_status != 0)<br>
>          goto tear_down_tmpebchains;<br>
> <br>
> -    for (i = 0; i < nruleInstances; i++)<br>
> +    for (i = 0; i < nruleInstances && inst;
i++)<br>
>          switch (inst[i]->ruleType) {<br>
>          case RT_EBTABLES:<br>
>              ebiptablesInstCommand(conn,
&buf,<br>
> @@ -2469,7 +2468,7 @@ ebiptablesApplyNewRules(virConnectPtr conn,<br>
>          if (ebiptablesExecCLI(conn, &buf,
&cli_status) || cli_status != 0)<br>
>             goto tear_down_tmpiptchains;<br>
> <br>
> -        for (i = 0; i < nruleInstances; i++)
{<br>
> +        for (i = 0; i < nruleInstances &&
inst; i++) {<br>
>              if (inst[i]->ruleType
== RT_IPTABLES)<br>
>                  iptablesInstCommand(conn,
&buf,<br>
>                    
                 inst[i]->commandTemplate,<br>
> --<br>
> 1.7.0.3.448.g82eeb<br>
> <br>
> <br>
> Here's the alternative patch:<br>
> <br>
> From 27367f86dbb0b9c33a77a75388a584e625bf4440 Mon Sep 17 00:00:00
2001<br>
> From: Jim Meyering <meyering@redhat.com><br>
> Date: Mon, 29 Mar 2010 18:27:26 +0200<br>
> Subject: [PATCH] nwfilter_ebiptables_driver.c: avoid NULL dereference<br>
> <br>
> * src/nwfilter/nwfilter_ebiptables_driver.c (ebiptablesApplyNewRules):<br>
> Don't dereference a NULL or uninitialized pointer when given<br>
> an empty list of rules.  Add an assert(inst) in each loop to<br>
> tell clang that the uses of "inst[i]" are valid.<br>
> ---<br>
>  src/nwfilter/nwfilter_ebiptables_driver.c |    9 ++++++---<br>
>  1 files changed, 6 insertions(+), 3 deletions(-)<br>
> <br>
> diff --git a/src/nwfilter/nwfilter_ebiptables_driver.c b/src/<br>
> nwfilter/nwfilter_ebiptables_driver.c<br>
> index 7871926..05d1339 100644<br>
> --- a/src/nwfilter/nwfilter_ebiptables_driver.c<br>
> +++ b/src/nwfilter/nwfilter_ebiptables_driver.c<br>
> @@ -24,6 +24,7 @@<br>
>  #include <config.h><br>
> <br>
>  #include <sys/stat.h><br>
> +#include <assert.h><br>
> <br>
>  #include "internal.h"<br>
> <br>
> @@ -2389,11 +2390,11 @@ ebiptablesApplyNewRules(virConnectPtr conn,<br>
>      virBuffer buf = VIR_BUFFER_INITIALIZER;<br>
>      int haveIptables = 0;<br>
> <br>
> -    if (inst)<br>
> -        qsort(inst, nruleInstances, sizeof(inst[0]),<br>
> -              ebiptablesRuleOrderSort);<br>
> +    if (nruleInstances > 1 && inst)<br>
> +        qsort(inst, nruleInstances, sizeof(inst[0]),
<br>
> ebiptablesRuleOrderSort);<br>
> <br>
>      for (i = 0; i < nruleInstances; i++) {<br>
> +        assert (inst);<br>
>          if (inst[i]->ruleType == RT_EBTABLES)
{<br>
>              if (inst[i]->chainprefix
== CHAINPREFIX_HOST_IN_TEMP)<br>
>                  chains_in
 |= (1 << inst[i]->neededProtocolChain);<br>
> @@ -2434,6 +2435,7 @@ ebiptablesApplyNewRules(virConnectPtr conn,<br>
>          goto tear_down_tmpebchains;<br>
> <br>
>      for (i = 0; i < nruleInstances; i++)<br>
> +        assert (inst);<br>
>          switch (inst[i]->ruleType) {<br>
>          case RT_EBTABLES:<br>
>              ebiptablesInstCommand(conn,
&buf,<br>
> @@ -2470,6 +2472,7 @@ ebiptablesApplyNewRules(virConnectPtr conn,<br>
>             goto tear_down_tmpiptchains;<br>
> <br>
>          for (i = 0; i < nruleInstances;
i++) {<br>
> +            assert (inst);<br>
>              if (inst[i]->ruleType
== RT_IPTABLES)<br>
>                  iptablesInstCommand(conn,
&buf,<br>
>                    
                 inst[i]->commandTemplate,<br>
> --<br>
> 1.7.0.3.448.g82eeb<br>
</font></tt>