Skip to content

Commit

Permalink
Merge tag 'nf-24-04-18' of git://git.kernel.org/pub/scm/linux/kernel/…
Browse files Browse the repository at this point in the history
…git/netfilter/nf

Pablo Neira Ayuso says:

====================
Netfilter fixes for net

The following patchset contains Netfilter fixes for net:

Patch #1 amends a missing spot where the set iterator type is unset.
	 This is fixing a issue in the previous pull request.

Patch #2 fixes the delete set command abort path by restoring state
         of the elements. Reverse logic for the activate (abort) case
	 otherwise element state is not restored, this requires to move
	 the check for active/inactive elements to the set iterator
	 callback. From the deactivate path, toggle the next generation
	 bit and from the activate (abort) path, clear the next generation
	 bitmask.

Patch #3 skips elements already restored by delete set command from the
	 abort path in case there is a previous delete element command in
	 the batch. Check for the next generation bit just like it is done
	 via set iteration to restore maps.

netfilter pull request 24-04-18

* tag 'nf-24-04-18' of git://git.kernel.org/pub/scm/linux/kernel/git/netfilter/nf:
  netfilter: nf_tables: fix memleak in map from abort path
  netfilter: nf_tables: restore set elements when delete set fails
  netfilter: nf_tables: missing iterator type in lookup walk
====================

Link: https://lore.kernel.org/r/20240418010948.3332346-1-pablo@netfilter.org
Signed-off-by: Paolo Abeni <pabeni@redhat.com>
  • Loading branch information
Paolo Abeni committed Apr 18, 2024
2 parents d10a7f5 + 86a1471 commit ac1a21d
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 23 deletions.
60 changes: 54 additions & 6 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -594,6 +594,12 @@ static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_elem_priv *elem_priv)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);

if (!nft_set_elem_active(ext, iter->genmask))
return 0;

nft_set_elem_change_active(ctx->net, set, ext);
nft_setelem_data_deactivate(ctx->net, set, elem_priv);

return 0;
Expand All @@ -617,6 +623,7 @@ static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
if (!nft_set_elem_active(ext, genmask))
continue;

nft_set_elem_change_active(ctx->net, set, ext);
nft_setelem_data_deactivate(ctx->net, set, catchall->elem);
break;
}
Expand Down Expand Up @@ -3880,6 +3887,9 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
const struct nft_data *data;
int err;

if (!nft_set_elem_active(ext, iter->genmask))
return 0;

if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
return 0;
Expand All @@ -3903,17 +3913,20 @@ int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,

int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set)
{
u8 genmask = nft_genmask_next(ctx->net);
struct nft_set_iter dummy_iter = {
.genmask = nft_genmask_next(ctx->net),
};
struct nft_set_elem_catchall *catchall;

struct nft_set_ext *ext;
int ret = 0;

list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
ext = nft_set_elem_ext(set, catchall->elem);
if (!nft_set_elem_active(ext, genmask))
if (!nft_set_elem_active(ext, dummy_iter.genmask))
continue;

ret = nft_setelem_validate(ctx, set, NULL, catchall->elem);
ret = nft_setelem_validate(ctx, set, &dummy_iter, catchall->elem);
if (ret < 0)
return ret;
}
Expand Down Expand Up @@ -5402,6 +5415,11 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_elem_priv *elem_priv)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);

if (!nft_set_elem_active(ext, iter->genmask))
return 0;

return nft_setelem_data_validate(ctx, set, elem_priv);
}

Expand Down Expand Up @@ -5494,6 +5512,13 @@ static int nft_mapelem_activate(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_elem_priv *elem_priv)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);

/* called from abort path, reverse check to undo changes. */
if (nft_set_elem_active(ext, iter->genmask))
return 0;

nft_clear(ctx->net, ext);
nft_setelem_data_activate(ctx->net, set, elem_priv);

return 0;
Expand All @@ -5511,6 +5536,7 @@ static void nft_map_catchall_activate(const struct nft_ctx *ctx,
if (!nft_set_elem_active(ext, genmask))
continue;

nft_clear(ctx->net, ext);
nft_setelem_data_activate(ctx->net, set, catchall->elem);
break;
}
Expand Down Expand Up @@ -5785,6 +5811,9 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
struct nft_set_dump_args *args;

if (!nft_set_elem_active(ext, iter->genmask))
return 0;

if (nft_set_elem_expired(ext) || nft_set_elem_is_dead(ext))
return 0;

Expand Down Expand Up @@ -6635,7 +6664,7 @@ static void nft_setelem_activate(struct net *net, struct nft_set *set,
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);

if (nft_setelem_is_catchall(set, elem_priv)) {
nft_set_elem_change_active(net, set, ext);
nft_clear(net, ext);
} else {
set->ops->activate(net, set, elem_priv);
}
Expand Down Expand Up @@ -7194,6 +7223,16 @@ void nft_data_hold(const struct nft_data *data, enum nft_data_types type)
}
}

static int nft_setelem_active_next(const struct net *net,
const struct nft_set *set,
struct nft_elem_priv *elem_priv)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
u8 genmask = nft_genmask_next(net);

return nft_set_elem_active(ext, genmask);
}

static void nft_setelem_data_activate(const struct net *net,
const struct nft_set *set,
struct nft_elem_priv *elem_priv)
Expand Down Expand Up @@ -7317,8 +7356,12 @@ static int nft_setelem_flush(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_elem_priv *elem_priv)
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
struct nft_trans *trans;

if (!nft_set_elem_active(ext, iter->genmask))
return 0;

trans = nft_trans_alloc_gfp(ctx, NFT_MSG_DELSETELEM,
sizeof(struct nft_trans_elem), GFP_ATOMIC);
if (!trans)
Expand Down Expand Up @@ -10611,8 +10654,10 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
case NFT_MSG_DESTROYSETELEM:
te = (struct nft_trans_elem *)trans->data;

nft_setelem_data_activate(net, te->set, te->elem_priv);
nft_setelem_activate(net, te->set, te->elem_priv);
if (!nft_setelem_active_next(net, te->set, te->elem_priv)) {
nft_setelem_data_activate(net, te->set, te->elem_priv);
nft_setelem_activate(net, te->set, te->elem_priv);
}
if (!nft_setelem_is_catchall(te->set, te->elem_priv))
te->set->ndeact--;

Expand Down Expand Up @@ -10800,6 +10845,9 @@ static int nf_tables_loop_check_setelem(const struct nft_ctx *ctx,
{
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);

if (!nft_set_elem_active(ext, iter->genmask))
return 0;

if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
return 0;
Expand Down
1 change: 1 addition & 0 deletions net/netfilter/nft_lookup.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,7 @@ static int nft_lookup_validate(const struct nft_ctx *ctx,
return 0;

iter.genmask = nft_genmask_next(ctx->net);
iter.type = NFT_ITER_UPDATE;
iter.skip = 0;
iter.count = 0;
iter.err = 0;
Expand Down
4 changes: 1 addition & 3 deletions net/netfilter/nft_set_bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ static void nft_bitmap_activate(const struct net *net,
nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
/* Enter 11 state. */
priv->bitmap[idx] |= (genmask << off);
nft_set_elem_change_active(net, set, &be->ext);
nft_clear(net, &be->ext);
}

static void nft_bitmap_flush(const struct net *net,
Expand Down Expand Up @@ -222,8 +222,6 @@ static void nft_bitmap_walk(const struct nft_ctx *ctx,
list_for_each_entry_rcu(be, &priv->list, head) {
if (iter->count < iter->skip)
goto cont;
if (!nft_set_elem_active(&be->ext, iter->genmask))
goto cont;

iter->err = iter->fn(ctx, set, iter, &be->priv);

Expand Down
8 changes: 2 additions & 6 deletions net/netfilter/nft_set_hash.c
Original file line number Diff line number Diff line change
Expand Up @@ -199,7 +199,7 @@ static void nft_rhash_activate(const struct net *net, const struct nft_set *set,
{
struct nft_rhash_elem *he = nft_elem_priv_cast(elem_priv);

nft_set_elem_change_active(net, set, &he->ext);
nft_clear(net, &he->ext);
}

static void nft_rhash_flush(const struct net *net,
Expand Down Expand Up @@ -286,8 +286,6 @@ static void nft_rhash_walk(const struct nft_ctx *ctx, struct nft_set *set,

if (iter->count < iter->skip)
goto cont;
if (!nft_set_elem_active(&he->ext, iter->genmask))
goto cont;

iter->err = iter->fn(ctx, set, iter, &he->priv);
if (iter->err < 0)
Expand Down Expand Up @@ -599,7 +597,7 @@ static void nft_hash_activate(const struct net *net, const struct nft_set *set,
{
struct nft_hash_elem *he = nft_elem_priv_cast(elem_priv);

nft_set_elem_change_active(net, set, &he->ext);
nft_clear(net, &he->ext);
}

static void nft_hash_flush(const struct net *net,
Expand Down Expand Up @@ -652,8 +650,6 @@ static void nft_hash_walk(const struct nft_ctx *ctx, struct nft_set *set,
hlist_for_each_entry_rcu(he, &priv->table[i], node) {
if (iter->count < iter->skip)
goto cont;
if (!nft_set_elem_active(&he->ext, iter->genmask))
goto cont;

iter->err = iter->fn(ctx, set, iter, &he->priv);
if (iter->err < 0)
Expand Down
8 changes: 3 additions & 5 deletions net/netfilter/nft_set_pipapo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1847,7 +1847,7 @@ static void nft_pipapo_activate(const struct net *net,
{
struct nft_pipapo_elem *e = nft_elem_priv_cast(elem_priv);

nft_set_elem_change_active(net, set, &e->ext);
nft_clear(net, &e->ext);
}

/**
Expand Down Expand Up @@ -2123,7 +2123,8 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
const struct nft_pipapo_field *f;
unsigned int i, r;

WARN_ON_ONCE(iter->type == NFT_ITER_UNSPEC);
WARN_ON_ONCE(iter->type != NFT_ITER_READ &&
iter->type != NFT_ITER_UPDATE);

rcu_read_lock();
if (iter->type == NFT_ITER_READ)
Expand All @@ -2148,9 +2149,6 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,

e = f->mt[r].e;

if (!nft_set_elem_active(&e->ext, iter->genmask))
goto cont;

iter->err = iter->fn(ctx, set, iter, &e->priv);
if (iter->err < 0)
goto out;
Expand Down
4 changes: 1 addition & 3 deletions net/netfilter/nft_set_rbtree.c
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,7 @@ static void nft_rbtree_activate(const struct net *net,
{
struct nft_rbtree_elem *rbe = nft_elem_priv_cast(elem_priv);

nft_set_elem_change_active(net, set, &rbe->ext);
nft_clear(net, &rbe->ext);
}

static void nft_rbtree_flush(const struct net *net,
Expand Down Expand Up @@ -600,8 +600,6 @@ static void nft_rbtree_walk(const struct nft_ctx *ctx,

if (iter->count < iter->skip)
goto cont;
if (!nft_set_elem_active(&rbe->ext, iter->genmask))
goto cont;

iter->err = iter->fn(ctx, set, iter, &rbe->priv);
if (iter->err < 0) {
Expand Down

0 comments on commit ac1a21d

Please sign in to comment.