Skip to content

Commit

Permalink
netfilter: nf_tables: expose opaque set element as struct nft_elem_priv
Browse files Browse the repository at this point in the history
Add placeholder structure and place it at the beginning of each struct
nft_*_elem for each existing set backend, instead of exposing elements
as void type to the frontend which defeats compiler type checks. Use
this pointer to this new type to replace void *.

This patch updates the following set backend API to use this new struct
nft_elem_priv placeholder structure:

- update
- deactivate
- flush
- get

as well as the following helper functions:

- nft_set_elem_ext()
- nft_set_elem_init()
- nft_set_elem_destroy()
- nf_tables_set_elem_destroy()

This patch adds nft_elem_priv_cast() to cast struct nft_elem_priv to
native element representation from the corresponding set backend.
BUILD_BUG_ON() makes sure this .priv placeholder is always at the top
of the opaque set element representation.

Suggested-by: Florian Westphal <[email protected]>
Signed-off-by: Pablo Neira Ayuso <[email protected]>
  • Loading branch information
ummakynes committed Oct 24, 2023
1 parent 6509a2e commit 9dad402
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 121 deletions.
38 changes: 25 additions & 13 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -274,6 +274,9 @@ struct nft_userdata {
unsigned char data[];
};

/* placeholder structure for opaque set element backend representation. */
struct nft_elem_priv { };

/**
* struct nft_set_elem - generic representation of set elements
*
Expand All @@ -294,9 +297,14 @@ struct nft_set_elem {
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
struct nft_data val;
} data;
void *priv;
struct nft_elem_priv *priv;
};

static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
{
return (void *)priv;
}

struct nft_set;
struct nft_set_iter {
u8 genmask;
Expand Down Expand Up @@ -430,7 +438,8 @@ struct nft_set_ops {
const struct nft_set_ext **ext);
bool (*update)(struct nft_set *set,
const u32 *key,
void *(*new)(struct nft_set *,
struct nft_elem_priv *
(*new)(struct nft_set *,
const struct nft_expr *,
struct nft_regs *),
const struct nft_expr *expr,
Expand All @@ -446,19 +455,19 @@ struct nft_set_ops {
void (*activate)(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem);
void * (*deactivate)(const struct net *net,
struct nft_elem_priv * (*deactivate)(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem);
void (*flush)(const struct net *net,
const struct nft_set *set,
void *priv);
struct nft_elem_priv *priv);
void (*remove)(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem);
void (*walk)(const struct nft_ctx *ctx,
struct nft_set *set,
struct nft_set_iter *iter);
void * (*get)(const struct net *net,
struct nft_elem_priv * (*get)(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem,
unsigned int flags);
Expand Down Expand Up @@ -796,9 +805,9 @@ static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
}

static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
void *elem)
const struct nft_elem_priv *elem_priv)
{
return elem + set->ops->elemsize;
return (void *)elem_priv + set->ops->elemsize;
}

static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
Expand All @@ -810,16 +819,19 @@ struct nft_expr *nft_set_elem_expr_alloc(const struct nft_ctx *ctx,
const struct nft_set *set,
const struct nlattr *attr);

void *nft_set_elem_init(const struct nft_set *set,
const struct nft_set_ext_tmpl *tmpl,
const u32 *key, const u32 *key_end, const u32 *data,
u64 timeout, u64 expiration, gfp_t gfp);
struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
const struct nft_set_ext_tmpl *tmpl,
const u32 *key, const u32 *key_end,
const u32 *data,
u64 timeout, u64 expiration, gfp_t gfp);
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
struct nft_expr *expr_array[]);
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
void nft_set_elem_destroy(const struct nft_set *set,
const struct nft_elem_priv *elem_priv,
bool destroy_expr);
void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
const struct nft_set *set, void *elem);
const struct nft_set *set,
const struct nft_elem_priv *elem_priv);

struct nft_expr_ops;
/**
Expand Down
27 changes: 15 additions & 12 deletions net/netfilter/nf_tables_api.c
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
struct nft_set_elem_catchall {
struct list_head list;
struct rcu_head rcu;
void *elem;
struct nft_elem_priv *elem;
};

static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
Expand Down Expand Up @@ -6218,10 +6218,11 @@ static int nft_set_ext_memcpy(const struct nft_set_ext_tmpl *tmpl, u8 id,
return 0;
}

void *nft_set_elem_init(const struct nft_set *set,
const struct nft_set_ext_tmpl *tmpl,
const u32 *key, const u32 *key_end,
const u32 *data, u64 timeout, u64 expiration, gfp_t gfp)
struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
const struct nft_set_ext_tmpl *tmpl,
const u32 *key, const u32 *key_end,
const u32 *data,
u64 timeout, u64 expiration, gfp_t gfp)
{
struct nft_set_ext *ext;
void *elem;
Expand Down Expand Up @@ -6286,10 +6287,11 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
}

/* Drop references and destroy. Called from gc, dynset and abort path. */
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
void nft_set_elem_destroy(const struct nft_set *set,
const struct nft_elem_priv *elem_priv,
bool destroy_expr)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
struct nft_ctx ctx = {
.net = read_pnet(&set->net),
.family = set->table->family,
Expand All @@ -6300,25 +6302,26 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
nft_data_release(nft_set_ext_data(ext), set->dtype);
if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));

if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
nft_use_dec(&(*nft_set_ext_obj(ext))->use);
kfree(elem);

kfree(elem_priv);
}
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);

/* Destroy element. References have been already dropped in the preparation
* path via nft_setelem_data_deactivate().
*/
void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
const struct nft_set *set, void *elem)
const struct nft_set *set,
const struct nft_elem_priv *elem_priv)
{
struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);

if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));

kfree(elem);
kfree(elem_priv);
}

int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
Expand Down
23 changes: 12 additions & 11 deletions net/netfilter/nft_dynset.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,33 +44,34 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
return 0;
}

static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
struct nft_regs *regs)
static struct nft_elem_priv *nft_dynset_new(struct nft_set *set,
const struct nft_expr *expr,
struct nft_regs *regs)
{
const struct nft_dynset *priv = nft_expr_priv(expr);
struct nft_set_ext *ext;
void *elem_priv;
u64 timeout;
void *elem;

if (!atomic_add_unless(&set->nelems, 1, set->size))
return NULL;

timeout = priv->timeout ? : set->timeout;
elem = nft_set_elem_init(set, &priv->tmpl,
&regs->data[priv->sreg_key], NULL,
&regs->data[priv->sreg_data],
timeout, 0, GFP_ATOMIC);
if (IS_ERR(elem))
elem_priv = nft_set_elem_init(set, &priv->tmpl,
&regs->data[priv->sreg_key], NULL,
&regs->data[priv->sreg_data],
timeout, 0, GFP_ATOMIC);
if (IS_ERR(elem_priv))
goto err1;

ext = nft_set_elem_ext(set, elem);
ext = nft_set_elem_ext(set, elem_priv);
if (priv->num_exprs && nft_dynset_expr_setup(priv, ext) < 0)
goto err2;

return elem;
return elem_priv;

err2:
nft_set_elem_destroy(set, elem, false);
nft_set_elem_destroy(set, elem_priv, false);
err1:
if (set->size)
atomic_dec(&set->nelems);
Expand Down
35 changes: 20 additions & 15 deletions net/netfilter/nft_set_bitmap.c
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
#include <net/netfilter/nf_tables_core.h>

struct nft_bitmap_elem {
struct nft_elem_priv priv;
struct list_head head;
struct nft_set_ext ext;
};
Expand Down Expand Up @@ -104,8 +105,9 @@ nft_bitmap_elem_find(const struct nft_set *set, struct nft_bitmap_elem *this,
return NULL;
}

static void *nft_bitmap_get(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem, unsigned int flags)
static struct nft_elem_priv *
nft_bitmap_get(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem, unsigned int flags)
{
const struct nft_bitmap *priv = nft_set_priv(set);
u8 genmask = nft_genmask_cur(net);
Expand All @@ -116,7 +118,7 @@ static void *nft_bitmap_get(const struct net *net, const struct nft_set *set,
!nft_set_elem_active(&be->ext, genmask))
continue;

return be;
return &be->priv;
}
return ERR_PTR(-ENOENT);
}
Expand All @@ -125,8 +127,8 @@ static int nft_bitmap_insert(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem,
struct nft_set_ext **ext)
{
struct nft_bitmap_elem *new = nft_elem_priv_cast(elem->priv), *be;
struct nft_bitmap *priv = nft_set_priv(set);
struct nft_bitmap_elem *new = elem->priv, *be;
u8 genmask = nft_genmask_next(net);
u32 idx, off;

Expand All @@ -148,8 +150,8 @@ static void nft_bitmap_remove(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_bitmap_elem *be = nft_elem_priv_cast(elem->priv);
struct nft_bitmap *priv = nft_set_priv(set);
struct nft_bitmap_elem *be = elem->priv;
u8 genmask = nft_genmask_next(net);
u32 idx, off;

Expand All @@ -163,8 +165,8 @@ static void nft_bitmap_activate(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_bitmap_elem *be = nft_elem_priv_cast(elem->priv);
struct nft_bitmap *priv = nft_set_priv(set);
struct nft_bitmap_elem *be = elem->priv;
u8 genmask = nft_genmask_next(net);
u32 idx, off;

Expand All @@ -175,11 +177,12 @@ static void nft_bitmap_activate(const struct net *net,
}

static void nft_bitmap_flush(const struct net *net,
const struct nft_set *set, void *_be)
const struct nft_set *set,
struct nft_elem_priv *elem_priv)
{
struct nft_bitmap_elem *be = nft_elem_priv_cast(elem_priv);
struct nft_bitmap *priv = nft_set_priv(set);
u8 genmask = nft_genmask_next(net);
struct nft_bitmap_elem *be = _be;
u32 idx, off;

nft_bitmap_location(set, nft_set_ext_key(&be->ext), &idx, &off);
Expand All @@ -188,12 +191,12 @@ static void nft_bitmap_flush(const struct net *net,
nft_set_elem_change_active(net, set, &be->ext);
}

static void *nft_bitmap_deactivate(const struct net *net,
const struct nft_set *set,
const struct nft_set_elem *elem)
static struct nft_elem_priv *
nft_bitmap_deactivate(const struct net *net, const struct nft_set *set,
const struct nft_set_elem *elem)
{
struct nft_bitmap_elem *this = nft_elem_priv_cast(elem->priv), *be;
struct nft_bitmap *priv = nft_set_priv(set);
struct nft_bitmap_elem *this = elem->priv, *be;
u8 genmask = nft_genmask_next(net);
u32 idx, off;

Expand All @@ -207,7 +210,7 @@ static void *nft_bitmap_deactivate(const struct net *net,
priv->bitmap[idx] &= ~(genmask << off);
nft_set_elem_change_active(net, set, &be->ext);

return be;
return &be->priv;
}

static void nft_bitmap_walk(const struct nft_ctx *ctx,
Expand All @@ -224,7 +227,7 @@ static void nft_bitmap_walk(const struct nft_ctx *ctx,
if (!nft_set_elem_active(&be->ext, iter->genmask))
goto cont;

elem.priv = be;
elem.priv = &be->priv;

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

Expand Down Expand Up @@ -263,6 +266,8 @@ static int nft_bitmap_init(const struct nft_set *set,
{
struct nft_bitmap *priv = nft_set_priv(set);

BUILD_BUG_ON(offsetof(struct nft_bitmap_elem, priv) != 0);

INIT_LIST_HEAD(&priv->list);
priv->bitmap_size = nft_bitmap_size(set->klen);

Expand All @@ -276,7 +281,7 @@ static void nft_bitmap_destroy(const struct nft_ctx *ctx,
struct nft_bitmap_elem *be, *n;

list_for_each_entry_safe(be, n, &priv->list, head)
nf_tables_set_elem_destroy(ctx, set, be);
nf_tables_set_elem_destroy(ctx, set, &be->priv);
}

static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,
Expand Down
Loading

0 comments on commit 9dad402

Please sign in to comment.