Skip to content

Commit 8e1102d

Browse files
Florian Westphalummakynes
authored andcommitted
netfilter: nf_tables: support timeouts larger than 23 days
Marco De Benedetto says: I would like to use a timeout of 30 days for elements in a set but it seems there is a some kind of problem above 24d20h31m23s. Fix this by using 'jiffies64' for timeout handling to get same behaviour on 32 and 64bit systems. nftables passes timeouts as u64 in milliseconds to the kernel, but on kernel side we used a mixture of 'long' and jiffies conversions rather than u64 and jiffies64. Bugzilla: https://bugzilla.netfilter.org/show_bug.cgi?id=1237 Signed-off-by: Florian Westphal <[email protected]> Signed-off-by: Pablo Neira Ayuso <[email protected]>
1 parent dc3c09d commit 8e1102d

File tree

2 files changed

+39
-15
lines changed

2 files changed

+39
-15
lines changed

include/net/netfilter/nf_tables.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -585,7 +585,7 @@ static inline u64 *nft_set_ext_timeout(const struct nft_set_ext *ext)
585585
return nft_set_ext(ext, NFT_SET_EXT_TIMEOUT);
586586
}
587587

588-
static inline unsigned long *nft_set_ext_expiration(const struct nft_set_ext *ext)
588+
static inline u64 *nft_set_ext_expiration(const struct nft_set_ext *ext)
589589
{
590590
return nft_set_ext(ext, NFT_SET_EXT_EXPIRATION);
591591
}
@@ -603,7 +603,7 @@ static inline struct nft_expr *nft_set_ext_expr(const struct nft_set_ext *ext)
603603
static inline bool nft_set_elem_expired(const struct nft_set_ext *ext)
604604
{
605605
return nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION) &&
606-
time_is_before_eq_jiffies(*nft_set_ext_expiration(ext));
606+
time_is_before_eq_jiffies64(*nft_set_ext_expiration(ext));
607607
}
608608

609609
static inline struct nft_set_ext *nft_set_elem_ext(const struct nft_set *set,

net/netfilter/nf_tables_api.c

Lines changed: 37 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2779,6 +2779,27 @@ static int nf_tables_set_alloc_name(struct nft_ctx *ctx, struct nft_set *set,
27792779
return 0;
27802780
}
27812781

2782+
static int nf_msecs_to_jiffies64(const struct nlattr *nla, u64 *result)
2783+
{
2784+
u64 ms = be64_to_cpu(nla_get_be64(nla));
2785+
u64 max = (u64)(~((u64)0));
2786+
2787+
max = div_u64(max, NSEC_PER_MSEC);
2788+
if (ms >= max)
2789+
return -ERANGE;
2790+
2791+
ms *= NSEC_PER_MSEC;
2792+
*result = nsecs_to_jiffies64(ms);
2793+
return 0;
2794+
}
2795+
2796+
static u64 nf_jiffies64_to_msecs(u64 input)
2797+
{
2798+
u64 ms = jiffies64_to_nsecs(input);
2799+
2800+
return cpu_to_be64(div_u64(ms, NSEC_PER_MSEC));
2801+
}
2802+
27822803
static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
27832804
const struct nft_set *set, u16 event, u16 flags)
27842805
{
@@ -2826,7 +2847,7 @@ static int nf_tables_fill_set(struct sk_buff *skb, const struct nft_ctx *ctx,
28262847

28272848
if (set->timeout &&
28282849
nla_put_be64(skb, NFTA_SET_TIMEOUT,
2829-
cpu_to_be64(jiffies_to_msecs(set->timeout)),
2850+
nf_jiffies64_to_msecs(set->timeout),
28302851
NFTA_SET_PAD))
28312852
goto nla_put_failure;
28322853
if (set->gc_int &&
@@ -3122,8 +3143,10 @@ static int nf_tables_newset(struct net *net, struct sock *nlsk,
31223143
if (nla[NFTA_SET_TIMEOUT] != NULL) {
31233144
if (!(flags & NFT_SET_TIMEOUT))
31243145
return -EINVAL;
3125-
timeout = msecs_to_jiffies(be64_to_cpu(nla_get_be64(
3126-
nla[NFTA_SET_TIMEOUT])));
3146+
3147+
err = nf_msecs_to_jiffies64(nla[NFTA_SET_TIMEOUT], &timeout);
3148+
if (err)
3149+
return err;
31273150
}
31283151
gc_int = 0;
31293152
if (nla[NFTA_SET_GC_INTERVAL] != NULL) {
@@ -3387,8 +3410,8 @@ const struct nft_set_ext_type nft_set_ext_types[] = {
33873410
.align = __alignof__(u64),
33883411
},
33893412
[NFT_SET_EXT_EXPIRATION] = {
3390-
.len = sizeof(unsigned long),
3391-
.align = __alignof__(unsigned long),
3413+
.len = sizeof(u64),
3414+
.align = __alignof__(u64),
33923415
},
33933416
[NFT_SET_EXT_USERDATA] = {
33943417
.len = sizeof(struct nft_userdata),
@@ -3481,22 +3504,21 @@ static int nf_tables_fill_setelem(struct sk_buff *skb,
34813504

34823505
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT) &&
34833506
nla_put_be64(skb, NFTA_SET_ELEM_TIMEOUT,
3484-
cpu_to_be64(jiffies_to_msecs(
3485-
*nft_set_ext_timeout(ext))),
3507+
nf_jiffies64_to_msecs(*nft_set_ext_timeout(ext)),
34863508
NFTA_SET_ELEM_PAD))
34873509
goto nla_put_failure;
34883510

34893511
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION)) {
3490-
unsigned long expires, now = jiffies;
3512+
u64 expires, now = get_jiffies_64();
34913513

34923514
expires = *nft_set_ext_expiration(ext);
3493-
if (time_before(now, expires))
3515+
if (time_before64(now, expires))
34943516
expires -= now;
34953517
else
34963518
expires = 0;
34973519

34983520
if (nla_put_be64(skb, NFTA_SET_ELEM_EXPIRATION,
3499-
cpu_to_be64(jiffies_to_msecs(expires)),
3521+
nf_jiffies64_to_msecs(expires),
35003522
NFTA_SET_ELEM_PAD))
35013523
goto nla_put_failure;
35023524
}
@@ -3871,7 +3893,7 @@ void *nft_set_elem_init(const struct nft_set *set,
38713893
memcpy(nft_set_ext_data(ext), data, set->dlen);
38723894
if (nft_set_ext_exists(ext, NFT_SET_EXT_EXPIRATION))
38733895
*nft_set_ext_expiration(ext) =
3874-
jiffies + timeout;
3896+
get_jiffies_64() + timeout;
38753897
if (nft_set_ext_exists(ext, NFT_SET_EXT_TIMEOUT))
38763898
*nft_set_ext_timeout(ext) = timeout;
38773899

@@ -3958,8 +3980,10 @@ static int nft_add_set_elem(struct nft_ctx *ctx, struct nft_set *set,
39583980
if (nla[NFTA_SET_ELEM_TIMEOUT] != NULL) {
39593981
if (!(set->flags & NFT_SET_TIMEOUT))
39603982
return -EINVAL;
3961-
timeout = msecs_to_jiffies(be64_to_cpu(nla_get_be64(
3962-
nla[NFTA_SET_ELEM_TIMEOUT])));
3983+
err = nf_msecs_to_jiffies64(nla[NFTA_SET_ELEM_TIMEOUT],
3984+
&timeout);
3985+
if (err)
3986+
return err;
39633987
} else if (set->flags & NFT_SET_TIMEOUT) {
39643988
timeout = set->timeout;
39653989
}

0 commit comments

Comments
 (0)