Skip to content

Commit 492891d

Browse files
committed
netfilter: nf_tables: validate catch-all set elements
jira LE-1907 cve CVE-2023-3390 Rebuild_History Non-Buildable kernel-5.14.0-284.30.1.el9_2 commit-author Pablo Neira Ayuso <pablo@netfilter.org> commit d46fc89 catch-all set element might jump/goto to chain that uses expressions that require validation. Fixes: aaa3104 ("netfilter: nftables: add catch-all set element support") Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> (cherry picked from commit d46fc89) Signed-off-by: Jonathan Maple <jmaple@ciq.com>
1 parent 8e1579a commit 492891d

File tree

3 files changed

+66
-38
lines changed

3 files changed

+66
-38
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1029,6 +1029,10 @@ struct nft_chain {
10291029
};
10301030

10311031
int nft_chain_validate(const struct nft_ctx *ctx, const struct nft_chain *chain);
1032+
int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
1033+
const struct nft_set_iter *iter,
1034+
struct nft_set_elem *elem);
1035+
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set);
10321036

10331037
enum nft_chain_types {
10341038
NFT_CHAIN_T_DEFAULT = 0,

net/netfilter/nf_tables_api.c

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3294,6 +3294,64 @@ static int nft_table_validate(struct net *net, const struct nft_table *table)
32943294
return 0;
32953295
}
32963296

3297+
int nft_setelem_validate(const struct nft_ctx *ctx, struct nft_set *set,
3298+
const struct nft_set_iter *iter,
3299+
struct nft_set_elem *elem)
3300+
{
3301+
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
3302+
struct nft_ctx *pctx = (struct nft_ctx *)ctx;
3303+
const struct nft_data *data;
3304+
int err;
3305+
3306+
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
3307+
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
3308+
return 0;
3309+
3310+
data = nft_set_ext_data(ext);
3311+
switch (data->verdict.code) {
3312+
case NFT_JUMP:
3313+
case NFT_GOTO:
3314+
pctx->level++;
3315+
err = nft_chain_validate(ctx, data->verdict.chain);
3316+
if (err < 0)
3317+
return err;
3318+
pctx->level--;
3319+
break;
3320+
default:
3321+
break;
3322+
}
3323+
3324+
return 0;
3325+
}
3326+
3327+
struct nft_set_elem_catchall {
3328+
struct list_head list;
3329+
struct rcu_head rcu;
3330+
void *elem;
3331+
};
3332+
3333+
int nft_set_catchall_validate(const struct nft_ctx *ctx, struct nft_set *set)
3334+
{
3335+
u8 genmask = nft_genmask_next(ctx->net);
3336+
struct nft_set_elem_catchall *catchall;
3337+
struct nft_set_elem elem;
3338+
struct nft_set_ext *ext;
3339+
int ret = 0;
3340+
3341+
list_for_each_entry_rcu(catchall, &set->catchall_list, list) {
3342+
ext = nft_set_elem_ext(set, catchall->elem);
3343+
if (!nft_set_elem_active(ext, genmask))
3344+
continue;
3345+
3346+
elem.priv = catchall->elem;
3347+
ret = nft_setelem_validate(ctx, set, NULL, &elem);
3348+
if (ret < 0)
3349+
return ret;
3350+
}
3351+
3352+
return ret;
3353+
}
3354+
32973355
static struct nft_rule *nft_rule_lookup_byid(const struct net *net,
32983356
const struct nft_chain *chain,
32993357
const struct nlattr *nla);
@@ -4598,12 +4656,6 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
45984656
return err;
45994657
}
46004658

4601-
struct nft_set_elem_catchall {
4602-
struct list_head list;
4603-
struct rcu_head rcu;
4604-
void *elem;
4605-
};
4606-
46074659
static void nft_set_catchall_destroy(const struct nft_ctx *ctx,
46084660
struct nft_set *set)
46094661
{

net/netfilter/nft_lookup.c

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -198,37 +198,6 @@ static int nft_lookup_dump(struct sk_buff *skb, const struct nft_expr *expr)
198198
return -1;
199199
}
200200

201-
static int nft_lookup_validate_setelem(const struct nft_ctx *ctx,
202-
struct nft_set *set,
203-
const struct nft_set_iter *iter,
204-
struct nft_set_elem *elem)
205-
{
206-
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
207-
struct nft_ctx *pctx = (struct nft_ctx *)ctx;
208-
const struct nft_data *data;
209-
int err;
210-
211-
if (nft_set_ext_exists(ext, NFT_SET_EXT_FLAGS) &&
212-
*nft_set_ext_flags(ext) & NFT_SET_ELEM_INTERVAL_END)
213-
return 0;
214-
215-
data = nft_set_ext_data(ext);
216-
switch (data->verdict.code) {
217-
case NFT_JUMP:
218-
case NFT_GOTO:
219-
pctx->level++;
220-
err = nft_chain_validate(ctx, data->verdict.chain);
221-
if (err < 0)
222-
return err;
223-
pctx->level--;
224-
break;
225-
default:
226-
break;
227-
}
228-
229-
return 0;
230-
}
231-
232201
static int nft_lookup_validate(const struct nft_ctx *ctx,
233202
const struct nft_expr *expr,
234203
const struct nft_data **d)
@@ -244,9 +213,12 @@ static int nft_lookup_validate(const struct nft_ctx *ctx,
244213
iter.skip = 0;
245214
iter.count = 0;
246215
iter.err = 0;
247-
iter.fn = nft_lookup_validate_setelem;
216+
iter.fn = nft_setelem_validate;
248217

249218
priv->set->ops->walk(ctx, priv->set, &iter);
219+
if (!iter.err)
220+
iter.err = nft_set_catchall_validate(ctx, priv->set);
221+
250222
if (iter.err < 0)
251223
return iter.err;
252224

0 commit comments

Comments
 (0)