[PATCH net 1/2] netfilter: conntrack: avoid secs-to-jiffies overflow in SIP helper

From: luoqing

Date: Wed Nov 04 2026 - 04:04:19 EST


From: Qing Luo <luoqing@xxxxxxxxxx>

refresh_signalling_expectation() converts the expiry from a SIP
REGISTER 2xx response with "expires * HZ" in 32-bit arithmetic and
stores it in a u32. sip_strtouint() only rejects values above
UINT_MAX, so the answering registrar controls the input.

Expectations are reaped with "(__s32)(exp->timeout - nfct_time_stamp)
<= 0". At HZ=1000 an expiry of 2147484 seconds (24.9 days) crosses
2^31 and the expectation is born expired, while 4294968 seconds wraps
to 704 jiffies. Registration refreshes break, or a signalling
expectation stays pinned for days.

Add nf_ct_secs_to_jiffies(), which multiplies in u64 and saturates at
INT_MAX so the signed expiry test stays positive, and use it for the
SIP expectation refresh.

Sweeping all 2^32-1 inputs at HZ=1000, the helper never wraps, never
yields a value that reads as expired, and matches the old expression
up to INT_MAX / HZ.

Fixes: 0f32a40fc91a ("[NETFILTER]: nf_conntrack_sip: create signalling expectations")
Cc: stable@xxxxxxxxxxxxxxx
Signed-off-by: Qing Luo <luoqing@xxxxxxxxxx>
---
include/net/netfilter/nf_conntrack.h | 10 ++++++++++
net/netfilter/nf_conntrack_sip.c | 3 ++-
2 files changed, 12 insertions(+), 1 deletion(-)

diff --git a/include/net/netfilter/nf_conntrack.h b/include/net/netfilter/nf_conntrack.h
index c39425e54d87..b32716084ea8 100644
--- a/include/net/netfilter/nf_conntrack.h
+++ b/include/net/netfilter/nf_conntrack.h
@@ -210,6 +210,16 @@ bool nf_ct_get_tuplepr(const struct sk_buff *skb, unsigned int nhoff,
void __nf_ct_refresh_acct(struct nf_conn *ct, enum ip_conntrack_info ctinfo,
u32 extra_jiffies, unsigned int bytes);

+/* Convert a timeout in seconds to jiffies, saturating at INT_MAX instead of
+ * wrapping the "secs * HZ" product in u32.
+ */
+static inline u32 nf_ct_secs_to_jiffies(u32 secs)
+{
+ u64 delta = (u64)secs * HZ;
+
+ return delta > INT_MAX ? INT_MAX : (u32)delta;
+}
+
/* Refresh conntrack for this many jiffies and do accounting */
static inline void nf_ct_refresh_acct(struct nf_conn *ct,
enum ip_conntrack_info ctinfo,
diff --git a/net/netfilter/nf_conntrack_sip.c b/net/netfilter/nf_conntrack_sip.c
index 64bc440b1181..e2fd97f53386 100644
--- a/net/netfilter/nf_conntrack_sip.c
+++ b/net/netfilter/nf_conntrack_sip.c
@@ -891,7 +891,8 @@ static int refresh_signalling_expectation(struct nf_conn *ct,
exp->tuple.dst.protonum != proto ||
exp->tuple.dst.u.udp.port != port)
continue;
- WRITE_ONCE(exp->timeout, nfct_time_stamp + (expires * HZ));
+ WRITE_ONCE(exp->timeout,
+ nfct_time_stamp + nf_ct_secs_to_jiffies(expires));
WRITE_ONCE(exp->flags, exp->flags & ~NF_CT_EXPECT_INACTIVE);
found = 1;
break;
--
2.25.1