diff mbox series

[next] netfilter: nf_tables: Fix dereference of null pointer flow

Message ID 20210624195718.170796-1-colin.king@canonical.com
State New
Headers show
Series [next] netfilter: nf_tables: Fix dereference of null pointer flow | expand

Commit Message

Colin King June 24, 2021, 7:57 p.m. UTC
From: Colin Ian King <colin.king@canonical.com>

In the case where chain->flags & NFT_CHAIN_HW_OFFLOAD is false then
nft_flow_rule_create is not called and flow is NULL. The subsequent
error handling execution via label err_destroy_flow_rule will lead
to a null pointer dereference on flow when calling nft_flow_rule_destroy.
Since the error path to err_destroy_flow_rule has to cater for null
and non-null flows, only call nft_flow_rule_destroy if flow is non-null
to fix this issue.

Addresses-Coverity: ("Explicity null dereference")
Fixes: 3c5e44622011 ("netfilter: nf_tables: memleak in hw offload abort path")
Signed-off-by: Colin Ian King <colin.king@canonical.com>
---
 net/netfilter/nf_tables_api.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

Comments

Dan Carpenter June 25, 2021, 9:59 a.m. UTC | #1
Btw, why is there no clean up if nft_table_validate() fails?

net/netfilter/nf_tables_api.c
  3432                                  list_add_tail_rcu(&rule->list, &old_rule->list);
  3433                          else
  3434                                  list_add_rcu(&rule->list, &chain->rules);
  3435                  }
  3436          }
  3437          kvfree(expr_info);
  3438          chain->use++;
  3439  
  3440          if (flow)
  3441                  nft_trans_flow_rule(trans) = flow;
  3442  
  3443          if (nft_net->validate_state == NFT_VALIDATE_DO)
  3444                  return nft_table_validate(net, table);
                        ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
The cleanup for this would be quite involved unfortunately...  Not
necessarily something to attempt without being able to test the code.

  3445  
  3446          return 0;
  3447  
  3448  err_destroy_flow_rule:
  3449          nft_flow_rule_destroy(flow);
  3450  err_release_rule:
  3451          nf_tables_rule_release(&ctx, rule);
  3452  err_release_expr:
  3453          for (i = 0; i < n; i++) {
  3454                  if (expr_info[i].ops) {
  3455                          module_put(expr_info[i].ops->type->owner);
  3456                          if (expr_info[i].ops->type->release_ops)
  3457                                  expr_info[i].ops->type->release_ops(expr_info[i].ops);
  3458                  }
  3459          }
  3460          kvfree(expr_info);
  3461  
  3462          return err;
  3463  }

regards,
dan carpenter
Pablo Neira Ayuso June 25, 2021, 10:20 a.m. UTC | #2
Hi,

On Fri, Jun 25, 2021 at 12:59:01PM +0300, Dan Carpenter wrote:
> Btw, why is there no clean up if nft_table_validate() fails?


See below.

> net/netfilter/nf_tables_api.c

>   3432                                  list_add_tail_rcu(&rule->list, &old_rule->list);

>   3433                          else

>   3434                                  list_add_rcu(&rule->list, &chain->rules);

>   3435                  }

>   3436          }

>   3437          kvfree(expr_info);

>   3438          chain->use++;

>   3439  

>   3440          if (flow)

>   3441                  nft_trans_flow_rule(trans) = flow;

>   3442  

>   3443          if (nft_net->validate_state == NFT_VALIDATE_DO)

>   3444                  return nft_table_validate(net, table);

>                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> The cleanup for this would be quite involved unfortunately...  Not

> necessarily something to attempt without being able to test the code.


At this stage, the transaction has been already registered in the
list, and the nf_tables_abort() path takes care of undoing what has
been updated in the preparation phase.

Having said this, Colin patch is correct, it's fixing up the error
path.
Pablo Neira Ayuso June 25, 2021, 10:21 a.m. UTC | #3
On Fri, Jun 25, 2021 at 10:06:26AM +0000, Walter Harms wrote:
> hi Colin,

> most free_something_functions accept NULL

> these days, perhaps it would be more efficient

> to add a check in nft_flow_rule_destroy().

> There is a chance that this will catch the same

> mistake in future  also.


I'm fine with Colin patch.

Thanks.
Dan Carpenter June 25, 2021, 10:33 a.m. UTC | #4
On Fri, Jun 25, 2021 at 12:20:21PM +0200, Pablo Neira Ayuso wrote:
> Hi,

> 

> On Fri, Jun 25, 2021 at 12:59:01PM +0300, Dan Carpenter wrote:

> > Btw, why is there no clean up if nft_table_validate() fails?

> 

> See below.

> 

> > net/netfilter/nf_tables_api.c

> >   3432                                  list_add_tail_rcu(&rule->list, &old_rule->list);

> >   3433                          else

> >   3434                                  list_add_rcu(&rule->list, &chain->rules);

> >   3435                  }

> >   3436          }

> >   3437          kvfree(expr_info);

> >   3438          chain->use++;

> >   3439  

> >   3440          if (flow)

> >   3441                  nft_trans_flow_rule(trans) = flow;

> >   3442  

> >   3443          if (nft_net->validate_state == NFT_VALIDATE_DO)

> >   3444                  return nft_table_validate(net, table);

> >                         ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

> > The cleanup for this would be quite involved unfortunately...  Not

> > necessarily something to attempt without being able to test the code.

> 

> At this stage, the transaction has been already registered in the

> list, and the nf_tables_abort() path takes care of undoing what has

> been updated in the preparation phase.

> 


Ah...  Thanks.

regards,
dan carpenter
Pablo Neira Ayuso July 2, 2021, 12:56 a.m. UTC | #5
On Thu, Jun 24, 2021 at 08:57:18PM +0100, Colin King wrote:
> From: Colin Ian King <colin.king@canonical.com>

> 

> In the case where chain->flags & NFT_CHAIN_HW_OFFLOAD is false then

> nft_flow_rule_create is not called and flow is NULL. The subsequent

> error handling execution via label err_destroy_flow_rule will lead

> to a null pointer dereference on flow when calling nft_flow_rule_destroy.

> Since the error path to err_destroy_flow_rule has to cater for null

> and non-null flows, only call nft_flow_rule_destroy if flow is non-null

> to fix this issue.


Applied, thanks.
diff mbox series

Patch

diff --git a/net/netfilter/nf_tables_api.c b/net/netfilter/nf_tables_api.c
index 390d4466567f..de182d1f7c4e 100644
--- a/net/netfilter/nf_tables_api.c
+++ b/net/netfilter/nf_tables_api.c
@@ -3446,7 +3446,8 @@  static int nf_tables_newrule(struct sk_buff *skb, const struct nfnl_info *info,
 	return 0;
 
 err_destroy_flow_rule:
-	nft_flow_rule_destroy(flow);
+	if (flow)
+		nft_flow_rule_destroy(flow);
 err_release_rule:
 	nf_tables_rule_release(&ctx, rule);
 err_release_expr: