Skip to content

Commit a35dbfa

Browse files
fw-strlenpvts-mat
authored andcommitted
netfilter: nf_tables: expose opaque set element as struct nft_elem_priv
jira VULN-430 cve CVE-2023-4244 commit-author Pablo Neira Ayuso <pablo@netfilter.org> commit 9dad402 upstream-diff Context conflict with the cve fix 5d4bb57 (wrong application order). 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 <fw@strlen.de> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> (cherry picked from commit 9dad402) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent f21727c commit a35dbfa

File tree

8 files changed

+173
-121
lines changed

8 files changed

+173
-121
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 25 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -243,6 +243,9 @@ struct nft_userdata {
243243
unsigned char data[];
244244
};
245245

246+
/* placeholder structure for opaque set element backend representation. */
247+
struct nft_elem_priv { };
248+
246249
/**
247250
* struct nft_set_elem - generic representation of set elements
248251
*
@@ -263,9 +266,14 @@ struct nft_set_elem {
263266
u32 buf[NFT_DATA_VALUE_MAXLEN / sizeof(u32)];
264267
struct nft_data val;
265268
} data;
266-
void *priv;
269+
struct nft_elem_priv *priv;
267270
};
268271

272+
static inline void *nft_elem_priv_cast(const struct nft_elem_priv *priv)
273+
{
274+
return (void *)priv;
275+
}
276+
269277
struct nft_set;
270278
struct nft_set_iter {
271279
u8 genmask;
@@ -393,7 +401,8 @@ struct nft_set_ops {
393401
const struct nft_set_ext **ext);
394402
bool (*update)(struct nft_set *set,
395403
const u32 *key,
396-
void *(*new)(struct nft_set *,
404+
struct nft_elem_priv *
405+
(*new)(struct nft_set *,
397406
const struct nft_expr *,
398407
struct nft_regs *),
399408
const struct nft_expr *expr,
@@ -409,19 +418,19 @@ struct nft_set_ops {
409418
void (*activate)(const struct net *net,
410419
const struct nft_set *set,
411420
const struct nft_set_elem *elem);
412-
void * (*deactivate)(const struct net *net,
421+
struct nft_elem_priv * (*deactivate)(const struct net *net,
413422
const struct nft_set *set,
414423
const struct nft_set_elem *elem);
415424
void (*flush)(const struct net *net,
416425
const struct nft_set *set,
417-
void *priv);
426+
struct nft_elem_priv *priv);
418427
void (*remove)(const struct net *net,
419428
const struct nft_set *set,
420429
const struct nft_set_elem *elem);
421430
void (*walk)(const struct nft_ctx *ctx,
422431
struct nft_set *set,
423432
struct nft_set_iter *iter);
424-
void * (*get)(const struct net *net,
433+
struct nft_elem_priv * (*get)(const struct net *net,
425434
const struct nft_set *set,
426435
const struct nft_set_elem *elem,
427436
unsigned int flags);
@@ -759,9 +768,9 @@ static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
759768
}
760769

761770
static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,
762-
void *elem)
771+
const struct nft_elem_priv *elem_priv)
763772
{
764-
return elem + set->ops->elemsize;
773+
return (void *)elem_priv + set->ops->elemsize;
765774
}
766775

767776
static inline struct nft_object **nft_set_ext_obj(const struct nft_set_ext *ext)
@@ -773,16 +782,19 @@ struct nft_expr *nft_set_elem_expr_alloc(const struct nft_ctx *ctx,
773782
const struct nft_set *set,
774783
const struct nlattr *attr);
775784

776-
void *nft_set_elem_init(const struct nft_set *set,
777-
const struct nft_set_ext_tmpl *tmpl,
778-
const u32 *key, const u32 *key_end, const u32 *data,
779-
u64 timeout, u64 expiration, gfp_t gfp);
785+
struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
786+
const struct nft_set_ext_tmpl *tmpl,
787+
const u32 *key, const u32 *key_end,
788+
const u32 *data,
789+
u64 timeout, u64 expiration, gfp_t gfp);
780790
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,
781791
struct nft_expr *expr_array[]);
782-
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
792+
void nft_set_elem_destroy(const struct nft_set *set,
793+
const struct nft_elem_priv *elem_priv,
783794
bool destroy_expr);
784795
void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
785-
const struct nft_set *set, void *elem);
796+
const struct nft_set *set,
797+
const struct nft_elem_priv *elem_priv);
786798

787799
struct nft_expr_ops;
788800
/**

net/netfilter/nf_tables_api.c

Lines changed: 15 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ static int nft_mapelem_deactivate(const struct nft_ctx *ctx,
601601
struct nft_set_elem_catchall {
602602
struct list_head list;
603603
struct rcu_head rcu;
604-
void *elem;
604+
struct nft_elem_priv *elem;
605605
};
606606

607607
static void nft_map_catchall_deactivate(const struct nft_ctx *ctx,
@@ -5910,10 +5910,11 @@ static int nft_set_ext_memcpy(const struct nft_set_ext_tmpl *tmpl, u8 id,
59105910
return 0;
59115911
}
59125912

5913-
void *nft_set_elem_init(const struct nft_set *set,
5914-
const struct nft_set_ext_tmpl *tmpl,
5915-
const u32 *key, const u32 *key_end,
5916-
const u32 *data, u64 timeout, u64 expiration, gfp_t gfp)
5913+
struct nft_elem_priv *nft_set_elem_init(const struct nft_set *set,
5914+
const struct nft_set_ext_tmpl *tmpl,
5915+
const u32 *key, const u32 *key_end,
5916+
const u32 *data,
5917+
u64 timeout, u64 expiration, gfp_t gfp)
59175918
{
59185919
struct nft_set_ext *ext;
59195920
void *elem;
@@ -5978,10 +5979,11 @@ static void nft_set_elem_expr_destroy(const struct nft_ctx *ctx,
59785979
}
59795980

59805981
/* Drop references and destroy. Called from gc, dynset and abort path. */
5981-
void nft_set_elem_destroy(const struct nft_set *set, void *elem,
5982+
void nft_set_elem_destroy(const struct nft_set *set,
5983+
const struct nft_elem_priv *elem_priv,
59825984
bool destroy_expr)
59835985
{
5984-
struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
5986+
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
59855987
struct nft_ctx ctx = {
59865988
.net = read_pnet(&set->net),
59875989
.family = set->table->family,
@@ -5992,25 +5994,26 @@ void nft_set_elem_destroy(const struct nft_set *set, void *elem,
59925994
nft_data_release(nft_set_ext_data(ext), set->dtype);
59935995
if (destroy_expr && nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
59945996
nft_set_elem_expr_destroy(&ctx, nft_set_ext_expr(ext));
5995-
59965997
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF))
59975998
nft_use_dec(&(*nft_set_ext_obj(ext))->use);
5998-
kfree(elem);
5999+
6000+
kfree(elem_priv);
59996001
}
60006002
EXPORT_SYMBOL_GPL(nft_set_elem_destroy);
60016003

60026004
/* Destroy element. References have been already dropped in the preparation
60036005
* path via nft_setelem_data_deactivate().
60046006
*/
60056007
void nf_tables_set_elem_destroy(const struct nft_ctx *ctx,
6006-
const struct nft_set *set, void *elem)
6008+
const struct nft_set *set,
6009+
const struct nft_elem_priv *elem_priv)
60076010
{
6008-
struct nft_set_ext *ext = nft_set_elem_ext(set, elem);
6011+
struct nft_set_ext *ext = nft_set_elem_ext(set, elem_priv);
60096012

60106013
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS))
60116014
nft_set_elem_expr_destroy(ctx, nft_set_ext_expr(ext));
60126015

6013-
kfree(elem);
6016+
kfree(elem_priv);
60146017
}
60156018

60166019
int nft_set_elem_expr_clone(const struct nft_ctx *ctx, struct nft_set *set,

net/netfilter/nft_dynset.c

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -44,33 +44,34 @@ static int nft_dynset_expr_setup(const struct nft_dynset *priv,
4444
return 0;
4545
}
4646

47-
static void *nft_dynset_new(struct nft_set *set, const struct nft_expr *expr,
48-
struct nft_regs *regs)
47+
static struct nft_elem_priv *nft_dynset_new(struct nft_set *set,
48+
const struct nft_expr *expr,
49+
struct nft_regs *regs)
4950
{
5051
const struct nft_dynset *priv = nft_expr_priv(expr);
5152
struct nft_set_ext *ext;
53+
void *elem_priv;
5254
u64 timeout;
53-
void *elem;
5455

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

5859
timeout = priv->timeout ? : set->timeout;
59-
elem = nft_set_elem_init(set, &priv->tmpl,
60-
&regs->data[priv->sreg_key], NULL,
61-
&regs->data[priv->sreg_data],
62-
timeout, 0, GFP_ATOMIC);
63-
if (IS_ERR(elem))
60+
elem_priv = nft_set_elem_init(set, &priv->tmpl,
61+
&regs->data[priv->sreg_key], NULL,
62+
&regs->data[priv->sreg_data],
63+
timeout, 0, GFP_ATOMIC);
64+
if (IS_ERR(elem_priv))
6465
goto err1;
6566

66-
ext = nft_set_elem_ext(set, elem);
67+
ext = nft_set_elem_ext(set, elem_priv);
6768
if (priv->num_exprs && nft_dynset_expr_setup(priv, ext) < 0)
6869
goto err2;
6970

70-
return elem;
71+
return elem_priv;
7172

7273
err2:
73-
nft_set_elem_destroy(set, elem, false);
74+
nft_set_elem_destroy(set, elem_priv, false);
7475
err1:
7576
if (set->size)
7677
atomic_dec(&set->nelems);

net/netfilter/nft_set_bitmap.c

Lines changed: 20 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include <net/netfilter/nf_tables_core.h>
1414

1515
struct nft_bitmap_elem {
16+
struct nft_elem_priv priv;
1617
struct list_head head;
1718
struct nft_set_ext ext;
1819
};
@@ -104,8 +105,9 @@ nft_bitmap_elem_find(const struct nft_set *set, struct nft_bitmap_elem *this,
104105
return NULL;
105106
}
106107

107-
static void *nft_bitmap_get(const struct net *net, const struct nft_set *set,
108-
const struct nft_set_elem *elem, unsigned int flags)
108+
static struct nft_elem_priv *
109+
nft_bitmap_get(const struct net *net, const struct nft_set *set,
110+
const struct nft_set_elem *elem, unsigned int flags)
109111
{
110112
const struct nft_bitmap *priv = nft_set_priv(set);
111113
u8 genmask = nft_genmask_cur(net);
@@ -116,7 +118,7 @@ static void *nft_bitmap_get(const struct net *net, const struct nft_set *set,
116118
!nft_set_elem_active(&be->ext, genmask))
117119
continue;
118120

119-
return be;
121+
return &be->priv;
120122
}
121123
return ERR_PTR(-ENOENT);
122124
}
@@ -125,8 +127,8 @@ static int nft_bitmap_insert(const struct net *net, const struct nft_set *set,
125127
const struct nft_set_elem *elem,
126128
struct nft_set_ext **ext)
127129
{
130+
struct nft_bitmap_elem *new = nft_elem_priv_cast(elem->priv), *be;
128131
struct nft_bitmap *priv = nft_set_priv(set);
129-
struct nft_bitmap_elem *new = elem->priv, *be;
130132
u8 genmask = nft_genmask_next(net);
131133
u32 idx, off;
132134

@@ -148,8 +150,8 @@ static void nft_bitmap_remove(const struct net *net,
148150
const struct nft_set *set,
149151
const struct nft_set_elem *elem)
150152
{
153+
struct nft_bitmap_elem *be = nft_elem_priv_cast(elem->priv);
151154
struct nft_bitmap *priv = nft_set_priv(set);
152-
struct nft_bitmap_elem *be = elem->priv;
153155
u8 genmask = nft_genmask_next(net);
154156
u32 idx, off;
155157

@@ -163,8 +165,8 @@ static void nft_bitmap_activate(const struct net *net,
163165
const struct nft_set *set,
164166
const struct nft_set_elem *elem)
165167
{
168+
struct nft_bitmap_elem *be = nft_elem_priv_cast(elem->priv);
166169
struct nft_bitmap *priv = nft_set_priv(set);
167-
struct nft_bitmap_elem *be = elem->priv;
168170
u8 genmask = nft_genmask_next(net);
169171
u32 idx, off;
170172

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

177179
static void nft_bitmap_flush(const struct net *net,
178-
const struct nft_set *set, void *_be)
180+
const struct nft_set *set,
181+
struct nft_elem_priv *elem_priv)
179182
{
183+
struct nft_bitmap_elem *be = nft_elem_priv_cast(elem_priv);
180184
struct nft_bitmap *priv = nft_set_priv(set);
181185
u8 genmask = nft_genmask_next(net);
182-
struct nft_bitmap_elem *be = _be;
183186
u32 idx, off;
184187

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

191-
static void *nft_bitmap_deactivate(const struct net *net,
192-
const struct nft_set *set,
193-
const struct nft_set_elem *elem)
194+
static struct nft_elem_priv *
195+
nft_bitmap_deactivate(const struct net *net, const struct nft_set *set,
196+
const struct nft_set_elem *elem)
194197
{
198+
struct nft_bitmap_elem *this = nft_elem_priv_cast(elem->priv), *be;
195199
struct nft_bitmap *priv = nft_set_priv(set);
196-
struct nft_bitmap_elem *this = elem->priv, *be;
197200
u8 genmask = nft_genmask_next(net);
198201
u32 idx, off;
199202

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

210-
return be;
213+
return &be->priv;
211214
}
212215

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

227-
elem.priv = be;
230+
elem.priv = &be->priv;
228231

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

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

269+
BUILD_BUG_ON(offsetof(struct nft_bitmap_elem, priv) != 0);
270+
266271
INIT_LIST_HEAD(&priv->list);
267272
priv->bitmap_size = nft_bitmap_size(set->klen);
268273

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

278283
list_for_each_entry_safe(be, n, &priv->list, head)
279-
nf_tables_set_elem_destroy(ctx, set, be);
284+
nf_tables_set_elem_destroy(ctx, set, &be->priv);
280285
}
281286

282287
static bool nft_bitmap_estimate(const struct nft_set_desc *desc, u32 features,

0 commit comments

Comments
 (0)