Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,9 +274,23 @@ static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
return (void *)priv;
}


/**
* enum nft_iter_type - nftables set iterator type
*
* @NFT_ITER_READ: read-only iteration over set elements
* @NFT_ITER_UPDATE: iteration under mutex to update set element state
*/
enum nft_iter_type {
NFT_ITER_UNSPEC,
NFT_ITER_READ,
NFT_ITER_UPDATE,
};

struct nft_set;
struct nft_set_iter {
u8 genmask;
enum nft_iter_type type:8;
unsigned int count;
unsigned int skip;
int err;
Expand Down
49 changes: 45 additions & 4 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -591,6 +591,12 @@ static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
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);

return 0;
Expand All @@ -615,6 +621,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);
elem.priv = catchall->elem;
nft_setelem_data_deactivate(ctx->net, set, &elem);
break;
Expand All @@ -625,6 +632,7 @@ static void nft_map_deactivate(const struct nft_ctx *ctx, struct nft_set *set)
{
struct nft_set_iter iter = {
.genmask = nft_genmask_next(ctx->net),
.type = NFT_ITER_UPDATE,
.fn = nft_mapelem_deactivate,
};

Expand Down Expand Up @@ -3483,6 +3491,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 @@ -3506,19 +3517,21 @@ 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_elem elem;
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;

elem.priv = catchall->elem;
ret = nft_setelem_validate(ctx, set, NULL, &elem);
ret = nft_setelem_validate(ctx, set, &dummy_iter, &elem);
if (ret < 0)
return ret;
}
Expand Down Expand Up @@ -4995,6 +5008,11 @@ static int nf_tables_bind_check_setelem(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
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);
}

Expand Down Expand Up @@ -5041,6 +5059,7 @@ int nf_tables_bind_set(const struct nft_ctx *ctx, struct nft_set *set,
}

iter.genmask = nft_genmask_next(ctx->net);
iter.type = NFT_ITER_UPDATE;
iter.skip = 0;
iter.count = 0;
iter.err = 0;
Expand Down Expand Up @@ -5088,6 +5107,13 @@ static int nft_mapelem_activate(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
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);

return 0;
Expand All @@ -5106,6 +5132,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);
elem.priv = catchall->elem;
nft_setelem_data_activate(ctx->net, set, &elem);
break;
Expand All @@ -5116,6 +5143,7 @@ static void nft_map_activate(const struct nft_ctx *ctx, struct nft_set *set)
{
struct nft_set_iter iter = {
.genmask = nft_genmask_next(ctx->net),
.type = NFT_ITER_UPDATE,
.fn = nft_mapelem_activate,
};

Expand Down Expand Up @@ -5377,6 +5405,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 @@ -5473,6 +5504,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
args.cb = cb;
args.skb = skb;
args.iter.genmask = nft_genmask_cur(net);
args.iter.type = NFT_ITER_READ;
args.iter.skip = cb->args[0];
args.iter.count = 0;
args.iter.err = 0;
Expand Down Expand Up @@ -6109,7 +6141,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)) {
nft_set_elem_change_active(net, set, ext);
nft_clear(net, ext);
} else {
set->ops->activate(net, set, elem);
}
Expand Down Expand Up @@ -6783,8 +6815,12 @@ static int nft_setelem_flush(const struct nft_ctx *ctx,
const struct nft_set_iter *iter,
struct nft_set_elem *elem)
{
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 @@ -6848,6 +6884,7 @@ static int nft_set_flush(struct nft_ctx *ctx, struct nft_set *set, u8 genmask)
{
struct nft_set_iter iter = {
.genmask = genmask,
.type = NFT_ITER_UPDATE,
.fn = nft_setelem_flush,
};

Expand Down Expand Up @@ -10051,6 +10088,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 Expand Up @@ -10132,6 +10172,7 @@ static int nf_tables_check_loops(const struct nft_ctx *ctx,
continue;

iter.genmask = nft_genmask_next(ctx->net);
iter.type = NFT_ITER_UPDATE;
iter.skip = 0;
iter.count = 0;
iter.err = 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 @@ -217,6 +217,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 @@ -173,7 +173,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 @@ -224,8 +224,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;

elem.priv = &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 @@ -196,7 +196,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 @@ -283,8 +283,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;

elem.priv = &he->priv;

Expand Down Expand Up @@ -612,7 +610,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 @@ -666,8 +664,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;

elem.priv = &he->priv;

Expand Down
11 changes: 5 additions & 6 deletions net/netfilter/nft_set_pipapo.c
Original file line number Diff line number Diff line change
Expand Up @@ -1754,7 +1754,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 @@ -2021,13 +2021,15 @@ static void nft_pipapo_walk(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_set_iter *iter)
{
struct nft_pipapo *priv = nft_set_priv(set);
struct net *net = read_pnet(&set->net);
struct nft_pipapo_match *m;
struct nft_pipapo_field *f;
int i, r;

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

rcu_read_lock();
if (iter->genmask == nft_genmask_cur(net))
if (iter->type == NFT_ITER_READ)
m = rcu_dereference(priv->match);
else
m = priv->clone;
Expand All @@ -2050,9 +2052,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;

elem.priv = &e->priv;

iter->err = iter->fn(ctx, set, iter, &elem);
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 @@ -530,7 +530,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 @@ -596,8 +596,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;

elem.priv = &rbe->priv;

Expand Down