Skip to content

Commit cf5000a

Browse files
author
Florian Westphal
committed
netfilter: nf_tables: fix memleak when more than 255 elements expired
When more than 255 elements expired we're supposed to switch to a new gc container structure. This never happens: u8 type will wrap before reaching the boundary and nft_trans_gc_space() always returns true. This means we recycle the initial gc container structure and lose track of the elements that came before. While at it, don't deref 'gc' after we've passed it to call_rcu. Fixes: 5f68718 ("netfilter: nf_tables: GC transaction API to avoid race with control plane") Reported-by: Pablo Neira Ayuso <pablo@netfilter.org> Signed-off-by: Florian Westphal <fw@strlen.de>
1 parent c9bd265 commit cf5000a

File tree

2 files changed

+9
-3
lines changed

2 files changed

+9
-3
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1682,7 +1682,7 @@ struct nft_trans_gc {
16821682
struct net *net;
16831683
struct nft_set *set;
16841684
u32 seq;
1685-
u8 count;
1685+
u16 count;
16861686
void *priv[NFT_TRANS_GC_BATCHCOUNT];
16871687
struct rcu_head rcu;
16881688
};

net/netfilter/nf_tables_api.c

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9579,12 +9579,15 @@ static int nft_trans_gc_space(struct nft_trans_gc *trans)
95799579
struct nft_trans_gc *nft_trans_gc_queue_async(struct nft_trans_gc *gc,
95809580
unsigned int gc_seq, gfp_t gfp)
95819581
{
9582+
struct nft_set *set;
9583+
95829584
if (nft_trans_gc_space(gc))
95839585
return gc;
95849586

9587+
set = gc->set;
95859588
nft_trans_gc_queue_work(gc);
95869589

9587-
return nft_trans_gc_alloc(gc->set, gc_seq, gfp);
9590+
return nft_trans_gc_alloc(set, gc_seq, gfp);
95889591
}
95899592

95909593
void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)
@@ -9599,15 +9602,18 @@ void nft_trans_gc_queue_async_done(struct nft_trans_gc *trans)
95999602

96009603
struct nft_trans_gc *nft_trans_gc_queue_sync(struct nft_trans_gc *gc, gfp_t gfp)
96019604
{
9605+
struct nft_set *set;
9606+
96029607
if (WARN_ON_ONCE(!lockdep_commit_lock_is_held(gc->net)))
96039608
return NULL;
96049609

96059610
if (nft_trans_gc_space(gc))
96069611
return gc;
96079612

9613+
set = gc->set;
96089614
call_rcu(&gc->rcu, nft_trans_gc_trans_free);
96099615

9610-
return nft_trans_gc_alloc(gc->set, 0, gfp);
9616+
return nft_trans_gc_alloc(set, 0, gfp);
96119617
}
96129618

96139619
void nft_trans_gc_queue_sync_done(struct nft_trans_gc *trans)

0 commit comments

Comments
 (0)