Skip to content

Commit b39b3ba

Browse files
committed
netfilter: nf_tables: Introduce NFT_MSG_GETSETELEM_RESET
jira VULN-430 cve-pre CVE-2023-4244 commit-author Phil Sutter <phil@nwl.cc> commit 079cd63 Analogous to NFT_MSG_GETOBJ_RESET, but for set elements with a timeout or attached stateful expressions like counters or quotas - reset them all at once. Respect a per element timeout value if present to reset the 'expires' value to. Signed-off-by: Phil Sutter <phil@nwl.cc> Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org> (cherry picked from commit 079cd63) Signed-off-by: Marcin Wcisło <marcin.wcislo@conclusive.pl>
1 parent 75be230 commit b39b3ba

File tree

2 files changed

+50
-20
lines changed

2 files changed

+50
-20
lines changed

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ enum nft_verdicts {
105105
* @NFT_MSG_DESTROYSETELEM: destroy a set element (enum nft_set_elem_attributes)
106106
* @NFT_MSG_DESTROYOBJ: destroy a stateful object (enum nft_object_attributes)
107107
* @NFT_MSG_DESTROYFLOWTABLE: destroy flow table (enum nft_flowtable_attributes)
108+
* @NFT_MSG_GETSETELEM_RESET: get set elements and reset attached stateful expressions (enum nft_set_elem_attributes)
108109
*/
109110
enum nf_tables_msg_types {
110111
NFT_MSG_NEWTABLE,
@@ -140,6 +141,7 @@ enum nf_tables_msg_types {
140141
NFT_MSG_DESTROYSETELEM,
141142
NFT_MSG_DESTROYOBJ,
142143
NFT_MSG_DESTROYFLOWTABLE,
144+
NFT_MSG_GETSETELEM_RESET,
143145
NFT_MSG_MAX,
144146
};
145147

net/netfilter/nf_tables_api.c

Lines changed: 48 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -5080,7 +5080,8 @@ static const struct nla_policy nft_set_elem_list_policy[NFTA_SET_ELEM_LIST_MAX +
50805080

50815081
static int nft_set_elem_expr_dump(struct sk_buff *skb,
50825082
const struct nft_set *set,
5083-
const struct nft_set_ext *ext)
5083+
const struct nft_set_ext *ext,
5084+
bool reset)
50845085
{
50855086
struct nft_set_elem_expr *elem_expr;
50865087
u32 size, num_exprs = 0;
@@ -5093,7 +5094,7 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb,
50935094

50945095
if (num_exprs == 1) {
50955096
expr = nft_setelem_expr_at(elem_expr, 0);
5096-
if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr, false) < 0)
5097+
if (nft_expr_dump(skb, NFTA_SET_ELEM_EXPR, expr, reset) < 0)
50975098
return -1;
50985099

50995100
return 0;
@@ -5104,7 +5105,7 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb,
51045105

51055106
nft_setelem_expr_foreach(expr, elem_expr, size) {
51065107
expr = nft_setelem_expr_at(elem_expr, size);
5107-
if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr, false) < 0)
5108+
if (nft_expr_dump(skb, NFTA_LIST_ELEM, expr, reset) < 0)
51085109
goto nla_put_failure;
51095110
}
51105111
nla_nest_end(skb, nest);
@@ -5117,11 +5118,13 @@ static int nft_set_elem_expr_dump(struct sk_buff *skb,
51175118

51185119
static int nf_tables_fill_setelem(struct sk_buff *skb,
51195120
const struct nft_set *set,
5120-
const struct nft_set_elem *elem)
5121+
const struct nft_set_elem *elem,
5122+
bool reset)
51215123
{
51225124
const struct nft_set_ext *ext = nft_set_elem_ext(set, elem->priv);
51235125
unsigned char *b = skb_tail_pointer(skb);
51245126
struct nlattr *nest;
5127+
u64 timeout = 0;
51255128

51265129
nest = nla_nest_start_noflag(skb, NFTA_LIST_ELEM);
51275130
if (nest == NULL)
@@ -5144,7 +5147,7 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
51445147
goto nla_put_failure;
51455148

51465149
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPRESSIONS) &&
5147-
nft_set_elem_expr_dump(skb, set, ext))
5150+
nft_set_elem_expr_dump(skb, set, ext, reset))
51485151
goto nla_put_failure;
51495152

51505153
if (nft_set_ext_exists(ext, NFT_SET_EXT_OBJREF) &&
@@ -5157,11 +5160,15 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
51575160
htonl(*nft_set_ext_flags(ext))))
51585161
goto nla_put_failure;
51595162

5160-
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
5161-
nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
5162-
nf_jiffies64_to_msecs(*nft_set_ext_timeout(ext)),
5163-
NFTA_SET_ELEM_PAD))
5164-
goto nla_put_failure;
5163+
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
5164+
timeout = *nft_set_ext_timeout(ext);
5165+
if (nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
5166+
nf_jiffies64_to_msecs(timeout),
5167+
NFTA_SET_ELEM_PAD))
5168+
goto nla_put_failure;
5169+
} else if (set->flags & NFT_SET_TIMEOUT) {
5170+
timeout = READ_ONCE(set->timeout);
5171+
}
51655172

51665173
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
51675174
u64 expires, now = get_jiffies_64();
@@ -5176,6 +5183,9 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
51765183
nf_jiffies64_to_msecs(expires),
51775184
NFTA_SET_ELEM_PAD))
51785185
goto nla_put_failure;
5186+
5187+
if (reset)
5188+
*nft_set_ext_expiration(ext) = now + timeout;
51795189
}
51805190

51815191
if (nft_set_ext_exists(ext, NFT_SET_EXT_USERDATA)) {
@@ -5199,6 +5209,7 @@ struct nft_set_dump_args {
51995209
const struct netlink_callback *cb;
52005210
struct nft_set_iter iter;
52015211
struct sk_buff *skb;
5212+
bool reset;
52025213
};
52035214

52045215
static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
@@ -5209,7 +5220,7 @@ static int nf_tables_dump_setelem(const struct nft_ctx *ctx,
52095220
struct nft_set_dump_args *args;
52105221

52115222
args = container_of(iter, struct nft_set_dump_args, iter);
5212-
return nf_tables_fill_setelem(args->skb, set, elem);
5223+
return nf_tables_fill_setelem(args->skb, set, elem, args->reset);
52135224
}
52145225

52155226
struct nft_set_dump_ctx {
@@ -5218,7 +5229,7 @@ struct nft_set_dump_ctx {
52185229
};
52195230

52205231
static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
5221-
const struct nft_set *set)
5232+
const struct nft_set *set, bool reset)
52225233
{
52235234
struct nft_set_elem_catchall *catchall;
52245235
u8 genmask = nft_genmask_cur(net);
@@ -5233,7 +5244,7 @@ static int nft_set_catchall_dump(struct net *net, struct sk_buff *skb,
52335244
continue;
52345245

52355246
elem.priv = catchall->elem;
5236-
ret = nf_tables_fill_setelem(skb, set, &elem);
5247+
ret = nf_tables_fill_setelem(skb, set, &elem, reset);
52375248
break;
52385249
}
52395250

@@ -5251,6 +5262,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
52515262
bool set_found = false;
52525263
struct nlmsghdr *nlh;
52535264
struct nlattr *nest;
5265+
bool reset = false;
52545266
u32 portid, seq;
52555267
int event;
52565268

@@ -5298,8 +5310,12 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
52985310
if (nest == NULL)
52995311
goto nla_put_failure;
53005312

5313+
if (NFNL_MSG_TYPE(cb->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET)
5314+
reset = true;
5315+
53015316
args.cb = cb;
53025317
args.skb = skb;
5318+
args.reset = reset;
53035319
args.iter.genmask = nft_genmask_cur(net);
53045320
args.iter.skip = cb->args[0];
53055321
args.iter.count = 0;
@@ -5308,7 +5324,7 @@ static int nf_tables_dump_set(struct sk_buff *skb, struct netlink_callback *cb)
53085324
set->ops->walk(&dump_ctx->ctx, set, &args.iter);
53095325

53105326
if (!args.iter.err && args.iter.count == cb->args[0])
5311-
args.iter.err = nft_set_catchall_dump(net, skb, set);
5327+
args.iter.err = nft_set_catchall_dump(net, skb, set, reset);
53125328
rcu_read_unlock();
53135329

53145330
nla_nest_end(skb, nest);
@@ -5346,7 +5362,8 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb,
53465362
const struct nft_ctx *ctx, u32 seq,
53475363
u32 portid, int event, u16 flags,
53485364
const struct nft_set *set,
5349-
const struct nft_set_elem *elem)
5365+
const struct nft_set_elem *elem,
5366+
bool reset)
53505367
{
53515368
struct nlmsghdr *nlh;
53525369
struct nlattr *nest;
@@ -5367,7 +5384,7 @@ static int nf_tables_fill_setelem_info(struct sk_buff *skb,
53675384
if (nest == NULL)
53685385
goto nla_put_failure;
53695386

5370-
err = nf_tables_fill_setelem(skb, set, elem);
5387+
err = nf_tables_fill_setelem(skb, set, elem, reset);
53715388
if (err < 0)
53725389
goto nla_put_failure;
53735390

@@ -5487,7 +5504,7 @@ static int nft_setelem_get(struct nft_ctx *ctx, struct nft_set *set,
54875504
}
54885505

54895506
static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
5490-
const struct nlattr *attr)
5507+
const struct nlattr *attr, bool reset)
54915508
{
54925509
struct nlattr *nla[NFTA_SET_ELEM_MAX + 1];
54935510
struct nft_set_elem elem;
@@ -5531,7 +5548,8 @@ static int nft_get_set_elem(struct nft_ctx *ctx, struct nft_set *set,
55315548
return err;
55325549

55335550
err = nf_tables_fill_setelem_info(skb, ctx, ctx->seq, ctx->portid,
5534-
NFT_MSG_NEWSETELEM, 0, set, &elem);
5551+
NFT_MSG_NEWSETELEM, 0, set, &elem,
5552+
reset);
55355553
if (err < 0)
55365554
goto err_fill_setelem;
55375555

@@ -5555,6 +5573,7 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
55555573
struct nft_set *set;
55565574
struct nlattr *attr;
55575575
struct nft_ctx ctx;
5576+
bool reset = false;
55585577
int rem, err = 0;
55595578

55605579
table = nft_table_lookup(net, nla[NFTA_SET_ELEM_LIST_TABLE], family,
@@ -5589,8 +5608,11 @@ static int nf_tables_getsetelem(struct sk_buff *skb,
55895608
if (!nla[NFTA_SET_ELEM_LIST_ELEMENTS])
55905609
return -EINVAL;
55915610

5611+
if (NFNL_MSG_TYPE(info->nlh->nlmsg_type) == NFT_MSG_GETSETELEM_RESET)
5612+
reset = true;
5613+
55925614
nla_for_each_nested(attr, nla[NFTA_SET_ELEM_LIST_ELEMENTS], rem) {
5593-
err = nft_get_set_elem(&ctx, set, attr);
5615+
err = nft_get_set_elem(&ctx, set, attr, reset);
55945616
if (err < 0) {
55955617
NL_SET_BAD_ATTR(extack, attr);
55965618
break;
@@ -5623,7 +5645,7 @@ static void nf_tables_setelem_notify(const struct nft_ctx *ctx,
56235645
flags |= ctx->flags & (NLM_F_CREATE | NLM_F_EXCL);
56245646

56255647
err = nf_tables_fill_setelem_info(skb, ctx, 0, portid, event, flags,
5626-
set, elem);
5648+
set, elem, false);
56275649
if (err < 0) {
56285650
kfree_skb(skb);
56295651
goto err;
@@ -8490,6 +8512,12 @@ static const struct nfnl_callback nf_tables_cb[NFT_MSG_MAX] = {
84908512
.attr_count = NFTA_SET_ELEM_LIST_MAX,
84918513
.policy = nft_set_elem_list_policy,
84928514
},
8515+
[NFT_MSG_GETSETELEM_RESET] = {
8516+
.call = nf_tables_getsetelem,
8517+
.type = NFNL_CB_RCU,
8518+
.attr_count = NFTA_SET_ELEM_LIST_MAX,
8519+
.policy = nft_set_elem_list_policy,
8520+
},
84938521
[NFT_MSG_DELSETELEM] = {
84948522
.call = nf_tables_delsetelem,
84958523
.type = NFNL_CB_BATCH,

0 commit comments

Comments
 (0)