Skip to content

Commit 123b996

Browse files
committed
netfilter: nf_tables: honor set timeout and garbage collection updates
Set timeout and garbage collection interval updates are ignored on updates. Add transaction to update global set element timeout and garbage collection interval. Fixes: 9651851 ("netfilter: add nftables") Suggested-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent f6594c3 commit 123b996

File tree

2 files changed

+57
-19
lines changed

2 files changed

+57
-19
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -597,7 +597,9 @@ void *nft_set_catchall_gc(const struct nft_set *set);
597597

598598
static inline unsigned long nft_set_gc_interval(const struct nft_set *set)
599599
{
600-
return set->gc_int ? msecs_to_jiffies(set->gc_int) : HZ;
600+
u32 gc_int = READ_ONCE(set->gc_int);
601+
602+
return gc_int ? msecs_to_jiffies(gc_int) : HZ;
601603
}
602604

603605
/**
@@ -1570,6 +1572,9 @@ struct nft_trans_rule {
15701572
struct nft_trans_set {
15711573
struct nft_set *set;
15721574
u32 set_id;
1575+
u32 gc_int;
1576+
u64 timeout;
1577+
bool update;
15731578
bool bound;
15741579
};
15751580

@@ -1579,6 +1584,12 @@ struct nft_trans_set {
15791584
(((struct nft_trans_set *)trans->data)->set_id)
15801585
#define nft_trans_set_bound(trans) \
15811586
(((struct nft_trans_set *)trans->data)->bound)
1587+
#define nft_trans_set_update(trans) \
1588+
(((struct nft_trans_set *)trans->data)->update)
1589+
#define nft_trans_set_timeout(trans) \
1590+
(((struct nft_trans_set *)trans->data)->timeout)
1591+
#define nft_trans_set_gc_int(trans) \
1592+
(((struct nft_trans_set *)trans->data)->gc_int)
15821593

15831594
struct nft_trans_chain {
15841595
bool update;

net/netfilter/nf_tables_api.c

Lines changed: 45 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -465,26 +465,38 @@ static int nft_delrule_by_chain(struct nft_ctx *ctx)
465465
return 0;
466466
}
467467

468-
static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
469-
struct nft_set *set)
468+
static int __nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
469+
struct nft_set *set,
470+
const struct nft_set_desc *desc)
470471
{
471472
struct nft_trans *trans;
472473

473474
trans = nft_trans_alloc(ctx, msg_type, sizeof(struct nft_trans_set));
474475
if (trans == NULL)
475476
return -ENOMEM;
476477

477-
if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] != NULL) {
478+
if (msg_type == NFT_MSG_NEWSET && ctx->nla[NFTA_SET_ID] && !desc) {
478479
nft_trans_set_id(trans) =
479480
ntohl(nla_get_be32(ctx->nla[NFTA_SET_ID]));
480481
nft_activate_next(ctx->net, set);
481482
}
482483
nft_trans_set(trans) = set;
484+
if (desc) {
485+
nft_trans_set_update(trans) = true;
486+
nft_trans_set_gc_int(trans) = desc->gc_int;
487+
nft_trans_set_timeout(trans) = desc->timeout;
488+
}
483489
nft_trans_commit_list_add_tail(ctx->net, trans);
484490

485491
return 0;
486492
}
487493

494+
static int nft_trans_set_add(const struct nft_ctx *ctx, int msg_type,
495+
struct nft_set *set)
496+
{
497+
return __nft_trans_set_add(ctx, msg_type, set, NULL);
498+
}
499+
488500
static int nft_delset(const struct nft_ctx *ctx, struct nft_set *set)
489501
{
490502
int err;
@@ -4044,8 +4056,10 @@ static int nf_tables_fill_set_concat(struct sk_buff *skb,
40444056
static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
40454057
const struct nft_set *set, u16 event, u16 flags)
40464058
{
4047-
struct nlmsghdr *nlh;
4059+
u64 timeout = READ_ONCE(set->timeout);
4060+
u32 gc_int = READ_ONCE(set->gc_int);
40484061
u32 portid = ctx->portid;
4062+
struct nlmsghdr *nlh;
40494063
struct nlattr *nest;
40504064
u32 seq = ctx->seq;
40514065
int i;
@@ -4081,13 +4095,13 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
40814095
nla_put_be32(skb, NFTA_SET_OBJ_TYPE, htonl(set->objtype)))
40824096
goto nla_put_failure;
40834097

4084-
if (set->timeout &&
4098+
if (timeout &&
40854099
nla_put_be64(skb, NFTA_SET_TIMEOUT,
4086-
nf_jiffies64_to_msecs(set->timeout),
4100+
nf_jiffies64_to_msecs(timeout),
40874101
NFTA_SET_PAD))
40884102
goto nla_put_failure;
4089-
if (set->gc_int &&
4090-
nla_put_be32(skb, NFTA_SET_GC_INTERVAL, htonl(set->gc_int)))
4103+
if (gc_int &&
4104+
nla_put_be32(skb, NFTA_SET_GC_INTERVAL, htonl(gc_int)))
40914105
goto nla_put_failure;
40924106

40934107
if (set->policy != NFT_SET_POL_PERFORMANCE) {
@@ -4632,7 +4646,10 @@ static int nf_tables_newset(struct sk_buff *skb, const struct nfnl_info *info,
46324646
for (i = 0; i < num_exprs; i++)
46334647
nft_expr_destroy(&ctx, exprs[i]);
46344648

4635-
return err;
4649+
if (err < 0)
4650+
return err;
4651+
4652+
return __nft_trans_set_add(&ctx, NFT_MSG_NEWSET, set, &desc);
46364653
}
46374654

46384655
if (!(info->nlh->nlmsg_flags & NLM_F_CREATE))
@@ -6070,7 +6087,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
60706087
return err;
60716088
} else if (set->flags & NFT_SET_TIMEOUT &&
60726089
!(flags & NFT_SET_ELEM_INTERVAL_END)) {
6073-
timeout = set->timeout;
6090+
timeout = READ_ONCE(set->timeout);
60746091
}
60756092

60766093
expiration = 0;
@@ -6171,7 +6188,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
61716188
if (err < 0)
61726189
goto err_parse_key_end;
61736190

6174-
if (timeout != set->timeout) {
6191+
if (timeout != READ_ONCE(set->timeout)) {
61756192
err = nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
61766193
if (err < 0)
61776194
goto err_parse_key_end;
@@ -9093,14 +9110,20 @@ static int nf_tables_commit(struct net *net, struct sk_buff *skb)
90939110
nft_flow_rule_destroy(nft_trans_flow_rule(trans));
90949111
break;
90959112
case NFT_MSG_NEWSET:
9096-
nft_clear(net, nft_trans_set(trans));
9097-
/* This avoids hitting -EBUSY when deleting the table
9098-
* from the transaction.
9099-
*/
9100-
if (nft_set_is_anonymous(nft_trans_set(trans)) &&
9101-
!list_empty(&nft_trans_set(trans)->bindings))
9102-
trans->ctx.table->use--;
9113+
if (nft_trans_set_update(trans)) {
9114+
struct nft_set *set = nft_trans_set(trans);
91039115

9116+
WRITE_ONCE(set->timeout, nft_trans_set_timeout(trans));
9117+
WRITE_ONCE(set->gc_int, nft_trans_set_gc_int(trans));
9118+
} else {
9119+
nft_clear(net, nft_trans_set(trans));
9120+
/* This avoids hitting -EBUSY when deleting the table
9121+
* from the transaction.
9122+
*/
9123+
if (nft_set_is_anonymous(nft_trans_set(trans)) &&
9124+
!list_empty(&nft_trans_set(trans)->bindings))
9125+
trans->ctx.table->use--;
9126+
}
91049127
nf_tables_set_notify(&trans->ctx, nft_trans_set(trans),
91059128
NFT_MSG_NEWSET, GFP_KERNEL);
91069129
nft_trans_destroy(trans);
@@ -9322,6 +9345,10 @@ static int __nf_tables_abort(struct net *net, enum nfnl_abort_action action)
93229345
nft_trans_destroy(trans);
93239346
break;
93249347
case NFT_MSG_NEWSET:
9348+
if (nft_trans_set_update(trans)) {
9349+
nft_trans_destroy(trans);
9350+
break;
9351+
}
93259352
trans->ctx.table->use--;
93269353
if (nft_trans_set_bound(trans)) {
93279354
nft_trans_destroy(trans);

0 commit comments

Comments
 (0)