Skip to content

Commit 8bfb74a

Browse files
committed
netfilter: nf_tables: zero timeout means element never times out
This patch uses zero as timeout marker for those elements that never expire when the element is created. If userspace provides no timeout for an element, then the default set timeout applies. However, if no default set timeout is specified and timeout flag is set on, then timeout extension is allocated and timeout is set to zero to allow for future updates. Use of zero a never timeout marker has been suggested by Phil Sutter. Note that, in older kernels, it is already possible to define elements that never expire by declaring a set with the set timeout flag set on and no global set timeout, in this case, new element with no explicit timeout never expire do not allocate the timeout extension, hence, they never expire. This approach makes it complicated to accomodate element timeout update, because element extensions do not support reallocations. Therefore, allocate the timeout extension and use the new marker for this case, but do not expose it to userspace to retain backward compatibility in the set listing. Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent 4c5daea commit 8bfb74a

File tree

4 files changed

+31
-20
lines changed

4 files changed

+31
-20
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -832,8 +832,11 @@ static inline struct nft_set_elem_expr *nft_set_ext_expr(const struct nft_set_ex
832832
static inline bool __nft_set_elem_expired(const struct nft_set_ext *ext,
833833
u64 tstamp)
834834
{
835-
return nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
836-
time_after_eq64(tstamp, READ_ONCE(nft_set_ext_timeout(ext)->expiration));
835+
if (!nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) ||
836+
nft_set_ext_timeout(ext)->timeout == 0)
837+
return false;
838+
839+
return time_after_eq64(tstamp, READ_ONCE(nft_set_ext_timeout(ext)->expiration));
837840
}
838841

839842
static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -436,7 +436,7 @@ enum nft_set_elem_flags {
436436
* @NFTA_SET_ELEM_KEY: key value (NLA_NESTED: nft_data)
437437
* @NFTA_SET_ELEM_DATA: data value of mapping (NLA_NESTED: nft_data_attributes)
438438
* @NFTA_SET_ELEM_FLAGS: bitmask of nft_set_elem_flags (NLA_U32)
439-
* @NFTA_SET_ELEM_TIMEOUT: timeout value (NLA_U64)
439+
* @NFTA_SET_ELEM_TIMEOUT: timeout value, zero means never times out (NLA_U64)
440440
* @NFTA_SET_ELEM_EXPIRATION: expiration time (NLA_U64)
441441
* @NFTA_SET_ELEM_USERDATA: user data (NLA_BINARY)
442442
* @NFTA_SET_ELEM_EXPR: expression (NLA_NESTED: nft_expr_attributes)

net/netfilter/nf_tables_api.c

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -5815,24 +5815,31 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
58155815
goto nla_put_failure;
58165816

58175817
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
5818-
u64 expires, now = get_jiffies_64();
5818+
u64 timeout = nft_set_ext_timeout(ext)->timeout;
5819+
u64 set_timeout = READ_ONCE(set->timeout);
5820+
__be64 msecs = 0;
5821+
5822+
if (set_timeout != timeout) {
5823+
msecs = nf_jiffies64_to_msecs(timeout);
5824+
if (nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT, msecs,
5825+
NFTA_SET_ELEM_PAD))
5826+
goto nla_put_failure;
5827+
}
58195828

5820-
if (nft_set_ext_timeout(ext)->timeout != READ_ONCE(set->timeout) &&
5821-
nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
5822-
nf_jiffies64_to_msecs(nft_set_ext_timeout(ext)->timeout),
5823-
NFTA_SET_ELEM_PAD))
5824-
goto nla_put_failure;
5829+
if (timeout > 0) {
5830+
u64 expires, now = get_jiffies_64();
58255831

5826-
expires = READ_ONCE(nft_set_ext_timeout(ext)->expiration);
5827-
if (time_before64(now, expires))
5828-
expires -= now;
5829-
else
5830-
expires = 0;
5832+
expires = READ_ONCE(nft_set_ext_timeout(ext)->expiration);
5833+
if (time_before64(now, expires))
5834+
expires -= now;
5835+
else
5836+
expires = 0;
58315837

5832-
if (nla_put_be64(skb, NFTA_SET_ELEM_EXPIRATION,
5833-
nf_jiffies64_to_msecs(expires),
5834-
NFTA_SET_ELEM_PAD))
5835-
goto nla_put_failure;
5838+
if (nla_put_be64(skb, NFTA_SET_ELEM_EXPIRATION,
5839+
nf_jiffies64_to_msecs(expires),
5840+
NFTA_SET_ELEM_PAD))
5841+
goto nla_put_failure;
5842+
}
58365843
}
58375844

58385845
if (nft_set_ext_exists(ext, NFT_SET_EXT_USERDATA)) {
@@ -7015,7 +7022,7 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
70157022
goto err_parse_key_end;
70167023
}
70177024

7018-
if (timeout > 0) {
7025+
if (set->flags & NFT_SET_TIMEOUT) {
70197026
err = nft_set_ext_add(&tmpl, NFT_SET_EXT_TIMEOUT);
70207027
if (err < 0)
70217028
goto err_parse_key_end;

net/netfilter/nft_dynset.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,8 @@ void nft_dynset_eval(const struct nft_expr *expr,
9494
if (set->ops->update(set, &regs->data[priv->sreg_key], nft_dynset_new,
9595
expr, regs, &ext)) {
9696
if (priv->op == NFT_DYNSET_OP_UPDATE &&
97-
nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT)) {
97+
nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
98+
nft_set_ext_timeout(ext)->timeout != 0) {
9899
timeout = priv->timeout ? : READ_ONCE(set->timeout);
99100
WRITE_ONCE(nft_set_ext_timeout(ext)->expiration, get_jiffies_64() + timeout);
100101
}

0 commit comments

Comments
 (0)