public inbox for netdev@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH net] tcp: make probe0 timer handle expired user timeout
@ 2026-04-14  1:36 Altan Hacigumus
  2026-04-20 18:33 ` Jakub Kicinski
                   ` (2 more replies)
  0 siblings, 3 replies; 8+ messages in thread
From: Altan Hacigumus @ 2026-04-14  1:36 UTC (permalink / raw)
  To: Eric Dumazet, Neal Cardwell, Kuniyuki Iwashima, David S . Miller,
	David Ahern, Jakub Kicinski, Paolo Abeni, Simon Horman
  Cc: netdev, linux-kernel, Enke Chen, Altan Hacigumus

tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
using subtraction with an unsigned lvalue.  If elapsed probing time
already exceeds the configured TCP_USER_TIMEOUT, the subtraction
underflows and yields a large value.

Handle this expiration case similarly to tcp_clamp_rto_to_user_timeout().

Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>
---
 net/ipv4/tcp_timer.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 5a14a53a3c9e..4a43356a4e06 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
 u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
-	u32 remaining, user_timeout;
+	u32 user_timeout;
+	s32 remaining;
 	s32 elapsed;
 
 	user_timeout = READ_ONCE(icsk->icsk_user_timeout);
@@ -61,6 +62,8 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
 	if (unlikely(elapsed < 0))
 		elapsed = 0;
 	remaining = msecs_to_jiffies(user_timeout) - elapsed;
+	if (remaining <= 0)
+		return 1;
 	remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
 
 	return min_t(u32, remaining, when);
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

* Re: [PATCH net] tcp: make probe0 timer handle expired user timeout
  2026-04-14  1:36 [PATCH net] tcp: make probe0 timer handle expired user timeout Altan Hacigumus
@ 2026-04-20 18:33 ` Jakub Kicinski
  2026-04-20 18:45   ` Eric Dumazet
  2026-04-21  4:57 ` Eric Dumazet
  2026-04-24  1:46 ` [PATCH net v2] " Altan Hacigumus
  2 siblings, 1 reply; 8+ messages in thread
From: Jakub Kicinski @ 2026-04-20 18:33 UTC (permalink / raw)
  To: Eric Dumazet, Neal Cardwell
  Cc: Altan Hacigumus, Kuniyuki Iwashima, David S . Miller, David Ahern,
	Paolo Abeni, Simon Horman, netdev, Enke Chen

On Mon, 13 Apr 2026 18:36:34 -0700 Altan Hacigumus wrote:
> tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
> using subtraction with an unsigned lvalue.  If elapsed probing time
> already exceeds the configured TCP_USER_TIMEOUT, the subtraction
> underflows and yields a large value.
> 
> Handle this expiration case similarly to tcp_clamp_rto_to_user_timeout().
> 
> Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
> Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>

Hi Eric, Neal, does this makes sense?

> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index 5a14a53a3c9e..4a43356a4e06 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
>  u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
>  {
>  	const struct inet_connection_sock *icsk = inet_csk(sk);
> -	u32 remaining, user_timeout;
> +	u32 user_timeout;
> +	s32 remaining;
>  	s32 elapsed;
>  
>  	user_timeout = READ_ONCE(icsk->icsk_user_timeout);
> @@ -61,6 +62,8 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
>  	if (unlikely(elapsed < 0))
>  		elapsed = 0;
>  	remaining = msecs_to_jiffies(user_timeout) - elapsed;
> +	if (remaining <= 0)
> +		return 1;
>  	remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
>  
>  	return min_t(u32, remaining, when);


^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net] tcp: make probe0 timer handle expired user timeout
  2026-04-20 18:33 ` Jakub Kicinski
@ 2026-04-20 18:45   ` Eric Dumazet
  0 siblings, 0 replies; 8+ messages in thread
From: Eric Dumazet @ 2026-04-20 18:45 UTC (permalink / raw)
  To: Jakub Kicinski
  Cc: Neal Cardwell, Altan Hacigumus, Kuniyuki Iwashima,
	David S . Miller, David Ahern, Paolo Abeni, Simon Horman, netdev,
	Enke Chen

On Mon, Apr 20, 2026 at 11:33 AM Jakub Kicinski <kuba@kernel.org> wrote:
>
> On Mon, 13 Apr 2026 18:36:34 -0700 Altan Hacigumus wrote:
> > tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
> > using subtraction with an unsigned lvalue.  If elapsed probing time
> > already exceeds the configured TCP_USER_TIMEOUT, the subtraction
> > underflows and yields a large value.
> >
> > Handle this expiration case similarly to tcp_clamp_rto_to_user_timeout().
> >
> > Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
> > Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>
>
> Hi Eric, Neal, does this makes sense?
>

I missed this patch. I will take a look asap.
Thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net] tcp: make probe0 timer handle expired user timeout
  2026-04-14  1:36 [PATCH net] tcp: make probe0 timer handle expired user timeout Altan Hacigumus
  2026-04-20 18:33 ` Jakub Kicinski
@ 2026-04-21  4:57 ` Eric Dumazet
  2026-04-22  3:31   ` Altan Hacigumus
  2026-04-24  1:46 ` [PATCH net v2] " Altan Hacigumus
  2 siblings, 1 reply; 8+ messages in thread
From: Eric Dumazet @ 2026-04-21  4:57 UTC (permalink / raw)
  To: Altan Hacigumus
  Cc: Neal Cardwell, Kuniyuki Iwashima, David S . Miller, David Ahern,
	Jakub Kicinski, Paolo Abeni, Simon Horman, netdev, linux-kernel,
	Enke Chen

On Mon, Apr 13, 2026 at 6:36 PM Altan Hacigumus <ahacigu.linux@gmail.com> wrote:
>
> tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
> using subtraction with an unsigned lvalue.  If elapsed probing time
> already exceeds the configured TCP_USER_TIMEOUT, the subtraction
> underflows and yields a large value.
>
> Handle this expiration case similarly to tcp_clamp_rto_to_user_timeout().
>
> Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
> Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>
> ---
>  net/ipv4/tcp_timer.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> index 5a14a53a3c9e..4a43356a4e06 100644
> --- a/net/ipv4/tcp_timer.c
> +++ b/net/ipv4/tcp_timer.c
> @@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
>  u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
>  {
>         const struct inet_connection_sock *icsk = inet_csk(sk);
> -       u32 remaining, user_timeout;
> +       u32 user_timeout;
> +       s32 remaining;
>         s32 elapsed;
>
>         user_timeout = READ_ONCE(icsk->icsk_user_timeout);
> @@ -61,6 +62,8 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
>         if (unlikely(elapsed < 0))
>                 elapsed = 0;
>         remaining = msecs_to_jiffies(user_timeout) - elapsed;
> +       if (remaining <= 0)
> +               return 1;

I do not think this chunk is needed ?
If @remaining is signed, then perhaps change the following line to:

remaining = max_t(int, remaining, TCP_TIMEOUT_MIN);

Also, it would be great to have a  new packetdrill test.

>         remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
>
>         return min_t(u32, remaining, when);
> --
> 2.43.0
>

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net] tcp: make probe0 timer handle expired user timeout
  2026-04-21  4:57 ` Eric Dumazet
@ 2026-04-22  3:31   ` Altan Hacigumus
  2026-04-22  7:39     ` Eric Dumazet
  0 siblings, 1 reply; 8+ messages in thread
From: Altan Hacigumus @ 2026-04-22  3:31 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Neal Cardwell, Kuniyuki Iwashima, David S . Miller, David Ahern,
	Jakub Kicinski, Paolo Abeni, Simon Horman, netdev, linux-kernel,
	Enke Chen

On Mon, Apr 20, 2026 at 9:58 PM Eric Dumazet <edumazet@google.com> wrote:
>
> On Mon, Apr 13, 2026 at 6:36 PM Altan Hacigumus <ahacigu.linux@gmail.com> wrote:
> >
> > tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
> > using subtraction with an unsigned lvalue.  If elapsed probing time
> > already exceeds the configured TCP_USER_TIMEOUT, the subtraction
> > underflows and yields a large value.
> >
> > Handle this expiration case similarly to tcp_clamp_rto_to_user_timeout().
> >
> > Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
> > Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>
> > ---
> >  net/ipv4/tcp_timer.c | 5 ++++-
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> > index 5a14a53a3c9e..4a43356a4e06 100644
> > --- a/net/ipv4/tcp_timer.c
> > +++ b/net/ipv4/tcp_timer.c
> > @@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
> >  u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
> >  {
> >         const struct inet_connection_sock *icsk = inet_csk(sk);
> > -       u32 remaining, user_timeout;
> > +       u32 user_timeout;
> > +       s32 remaining;
> >         s32 elapsed;
> >
> >         user_timeout = READ_ONCE(icsk->icsk_user_timeout);
> > @@ -61,6 +62,8 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
> >         if (unlikely(elapsed < 0))
> >                 elapsed = 0;
> >         remaining = msecs_to_jiffies(user_timeout) - elapsed;
> > +       if (remaining <= 0)
> > +               return 1;
>
> I do not think this chunk is needed ?
> If @remaining is signed, then perhaps change the following line to:
>
> remaining = max_t(int, remaining, TCP_TIMEOUT_MIN);
>

The if (remaining <= 0) return 1 handles the already-expired case and
mirrors the logic in tcp_clamp_rto_to_user_timeout().

max_t(s32, remaining, TCP_TIMEOUT_MIN) with remaining changed to s32
also fixes the underflow; I used the explicit early return for symmetry
with the RTO helper, but I can switch that in v2 if you prefer.

> Also, it would be great to have a  new packetdrill test.
>

With packetdrill, AFAICS it would require a late ACK to be processed
after TCP_USER_TIMEOUT has elapsed but before tcp_probe_timer() runs the
abort check - i.e. a race between the RX softirq path and the timer.
This is not purely an event/packet ordering problem, so it is not clear
to me how a deterministic behavior can be simulated with packetdrill
without tying it to exact probe timing.

> >         remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
> >
> >         return min_t(u32, remaining, when);
> > --
> > 2.43.0
> >

Thanks

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net] tcp: make probe0 timer handle expired user timeout
  2026-04-22  3:31   ` Altan Hacigumus
@ 2026-04-22  7:39     ` Eric Dumazet
  2026-04-23  3:02       ` Altan Hacigumus
  0 siblings, 1 reply; 8+ messages in thread
From: Eric Dumazet @ 2026-04-22  7:39 UTC (permalink / raw)
  To: Altan Hacigumus
  Cc: Neal Cardwell, Kuniyuki Iwashima, David S . Miller, David Ahern,
	Jakub Kicinski, Paolo Abeni, Simon Horman, netdev, linux-kernel,
	Enke Chen

On Tue, Apr 21, 2026 at 8:31 PM Altan Hacigumus <ahacigu.linux@gmail.com> wrote:
>
> On Mon, Apr 20, 2026 at 9:58 PM Eric Dumazet <edumazet@google.com> wrote:
> >
> > On Mon, Apr 13, 2026 at 6:36 PM Altan Hacigumus <ahacigu.linux@gmail.com> wrote:
> > >
> > > tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
> > > using subtraction with an unsigned lvalue.  If elapsed probing time
> > > already exceeds the configured TCP_USER_TIMEOUT, the subtraction
> > > underflows and yields a large value.
> > >
> > > Handle this expiration case similarly to tcp_clamp_rto_to_user_timeout().
> > >
> > > Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
> > > Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>
> > > ---
> > >  net/ipv4/tcp_timer.c | 5 ++++-
> > >  1 file changed, 4 insertions(+), 1 deletion(-)
> > >
> > > diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> > > index 5a14a53a3c9e..4a43356a4e06 100644
> > > --- a/net/ipv4/tcp_timer.c
> > > +++ b/net/ipv4/tcp_timer.c
> > > @@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
> > >  u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
> > >  {
> > >         const struct inet_connection_sock *icsk = inet_csk(sk);
> > > -       u32 remaining, user_timeout;
> > > +       u32 user_timeout;
> > > +       s32 remaining;
> > >         s32 elapsed;
> > >
> > >         user_timeout = READ_ONCE(icsk->icsk_user_timeout);
> > > @@ -61,6 +62,8 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
> > >         if (unlikely(elapsed < 0))
> > >                 elapsed = 0;
> > >         remaining = msecs_to_jiffies(user_timeout) - elapsed;
> > > +       if (remaining <= 0)
> > > +               return 1;
> >
> > I do not think this chunk is needed ?
> > If @remaining is signed, then perhaps change the following line to:
> >
> > remaining = max_t(int, remaining, TCP_TIMEOUT_MIN);
> >
>
> The if (remaining <= 0) return 1 handles the already-expired case and
> mirrors the logic in tcp_clamp_rto_to_user_timeout().

tcp_clamp_rto_to_user_timeout() has two conditionals.

if (remaining <= 0)
   return 1;
return min_t(u32, icsk->icsk_rto, msecs_to_jiffies(remaining));

First one was to avoid to call msecs_to_jiffies() with a negative number.

tcp_clamp_probe0_to_user_timeout() has 3 tests already, you want to
add a fourth one...
I would prefer something less obscure.
We do not care if we return 1 or 2 (TCP_TIMEOUT_MIN) jiffies

>
> max_t(s32, remaining, TCP_TIMEOUT_MIN) with remaining changed to s32
> also fixes the underflow; I used the explicit early return for symmetry
> with the RTO helper, but I can switch that in v2 if you prefer.
>
> > Also, it would be great to have a  new packetdrill test.
> >
>
> With packetdrill, AFAICS it would require a late ACK to be processed
> after TCP_USER_TIMEOUT has elapsed but before tcp_probe_timer() runs the
> abort check - i.e. a race between the RX softirq path and the timer.
> This is not purely an event/packet ordering problem, so it is not clear
> to me how a deterministic behavior can be simulated with packetdrill
> without tying it to exact probe timing.

I was trying to sense if the bug was serious or not, considering last
tcp_clamp_probe0_to_user_timeout()
statement is:

return min_t(u32, remaining, when);

Perhaps you should give more details in the changelog. What were the
symptoms of this bug, for TCP_USER_TIMEOUT users.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* Re: [PATCH net] tcp: make probe0 timer handle expired user timeout
  2026-04-22  7:39     ` Eric Dumazet
@ 2026-04-23  3:02       ` Altan Hacigumus
  0 siblings, 0 replies; 8+ messages in thread
From: Altan Hacigumus @ 2026-04-23  3:02 UTC (permalink / raw)
  To: Eric Dumazet
  Cc: Neal Cardwell, Kuniyuki Iwashima, David S . Miller, David Ahern,
	Jakub Kicinski, Paolo Abeni, Simon Horman, netdev, linux-kernel,
	Enke Chen

On Wed, Apr 22, 2026 at 12:39 AM Eric Dumazet <edumazet@google.com> wrote:
>
> On Tue, Apr 21, 2026 at 8:31 PM Altan Hacigumus <ahacigu.linux@gmail.com> wrote:
> >
> > On Mon, Apr 20, 2026 at 9:58 PM Eric Dumazet <edumazet@google.com> wrote:
> > >
> > > On Mon, Apr 13, 2026 at 6:36 PM Altan Hacigumus <ahacigu.linux@gmail.com> wrote:
> > > >
> > > > tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
> > > > using subtraction with an unsigned lvalue.  If elapsed probing time
> > > > already exceeds the configured TCP_USER_TIMEOUT, the subtraction
> > > > underflows and yields a large value.
> > > >
> > > > Handle this expiration case similarly to tcp_clamp_rto_to_user_timeout().
> > > >
> > > > Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
> > > > Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>
> > > > ---
> > > >  net/ipv4/tcp_timer.c | 5 ++++-
> > > >  1 file changed, 4 insertions(+), 1 deletion(-)
> > > >
> > > > diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
> > > > index 5a14a53a3c9e..4a43356a4e06 100644
> > > > --- a/net/ipv4/tcp_timer.c
> > > > +++ b/net/ipv4/tcp_timer.c
> > > > @@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
> > > >  u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
> > > >  {
> > > >         const struct inet_connection_sock *icsk = inet_csk(sk);
> > > > -       u32 remaining, user_timeout;
> > > > +       u32 user_timeout;
> > > > +       s32 remaining;
> > > >         s32 elapsed;
> > > >
> > > >         user_timeout = READ_ONCE(icsk->icsk_user_timeout);
> > > > @@ -61,6 +62,8 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
> > > >         if (unlikely(elapsed < 0))
> > > >                 elapsed = 0;
> > > >         remaining = msecs_to_jiffies(user_timeout) - elapsed;
> > > > +       if (remaining <= 0)
> > > > +               return 1;
> > >
> > > I do not think this chunk is needed ?
> > > If @remaining is signed, then perhaps change the following line to:
> > >
> > > remaining = max_t(int, remaining, TCP_TIMEOUT_MIN);
> > >
> >
> > The if (remaining <= 0) return 1 handles the already-expired case and
> > mirrors the logic in tcp_clamp_rto_to_user_timeout().
>
> tcp_clamp_rto_to_user_timeout() has two conditionals.
>
> if (remaining <= 0)
>    return 1;
> return min_t(u32, icsk->icsk_rto, msecs_to_jiffies(remaining));
>
> First one was to avoid to call msecs_to_jiffies() with a negative number.
>
> tcp_clamp_probe0_to_user_timeout() has 3 tests already, you want to
> add a fourth one...
> I would prefer something less obscure.
> We do not care if we return 1 or 2 (TCP_TIMEOUT_MIN) jiffies
>

okay

> >
> > max_t(s32, remaining, TCP_TIMEOUT_MIN) with remaining changed to s32
> > also fixes the underflow; I used the explicit early return for symmetry
> > with the RTO helper, but I can switch that in v2 if you prefer.
> >
> > > Also, it would be great to have a  new packetdrill test.
> > >
> >
> > With packetdrill, AFAICS it would require a late ACK to be processed
> > after TCP_USER_TIMEOUT has elapsed but before tcp_probe_timer() runs the
> > abort check - i.e. a race between the RX softirq path and the timer.
> > This is not purely an event/packet ordering problem, so it is not clear
> > to me how a deterministic behavior can be simulated with packetdrill
> > without tying it to exact probe timing.
>
> I was trying to sense if the bug was serious or not, considering last
> tcp_clamp_probe0_to_user_timeout()
> statement is:
>
> return min_t(u32, remaining, when);
>
> Perhaps you should give more details in the changelog. What were the
> symptoms of this bug, for TCP_USER_TIMEOUT users.

Yes, it at least clamps to @when, but still caused connection teardowns
to be intermittently delayed beyond the user's explicit timeout sockopt.

Will send a v2 accordingly.

Thanks.

^ permalink raw reply	[flat|nested] 8+ messages in thread

* [PATCH net v2] tcp: make probe0 timer handle expired user timeout
  2026-04-14  1:36 [PATCH net] tcp: make probe0 timer handle expired user timeout Altan Hacigumus
  2026-04-20 18:33 ` Jakub Kicinski
  2026-04-21  4:57 ` Eric Dumazet
@ 2026-04-24  1:46 ` Altan Hacigumus
  2 siblings, 0 replies; 8+ messages in thread
From: Altan Hacigumus @ 2026-04-24  1:46 UTC (permalink / raw)
  To: Eric Dumazet, Neal Cardwell, Kuniyuki Iwashima, David S . Miller,
	David Ahern, Jakub Kicinski, Paolo Abeni, Simon Horman
  Cc: netdev, linux-kernel, Enke Chen

tcp_clamp_probe0_to_user_timeout() computes remaining time in jiffies
using subtraction with an unsigned lvalue.  If elapsed probing time
exceeds the configured TCP_USER_TIMEOUT, the underflow yields a large
value.

This ends up re-arming the probe timer for a full backoff interval
instead of expiring immediately, delaying connection teardown beyond
the configured timeout.

Fix this by preventing underflow so user-set timeout expiration is
handled correctly without extending the probe timer.

Fixes: 344db93ae3ee ("tcp: make TCP_USER_TIMEOUT accurate for zero window probes")
Link: https://lore.kernel.org/r/20260414013634.43997-1-ahacigu.linux@gmail.com
Signed-off-by: Altan Hacigumus <ahacigu.linux@gmail.com>
---
v2:
- Use the existing TCP_TIMEOUT_MIN clamping along with signed @remaining
---
 net/ipv4/tcp_timer.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/net/ipv4/tcp_timer.c b/net/ipv4/tcp_timer.c
index 8d791a954cd6..322db13333c7 100644
--- a/net/ipv4/tcp_timer.c
+++ b/net/ipv4/tcp_timer.c
@@ -50,7 +50,8 @@ static u32 tcp_clamp_rto_to_user_timeout(const struct sock *sk)
 u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
 {
 	const struct inet_connection_sock *icsk = inet_csk(sk);
-	u32 remaining, user_timeout;
+	u32 user_timeout;
+	s32 remaining;
 	s32 elapsed;
 
 	user_timeout = READ_ONCE(icsk->icsk_user_timeout);
@@ -61,7 +62,7 @@ u32 tcp_clamp_probe0_to_user_timeout(const struct sock *sk, u32 when)
 	if (unlikely(elapsed < 0))
 		elapsed = 0;
 	remaining = msecs_to_jiffies(user_timeout) - elapsed;
-	remaining = max_t(u32, remaining, TCP_TIMEOUT_MIN);
+	remaining = max_t(int, remaining, TCP_TIMEOUT_MIN);
 
 	return min_t(u32, remaining, when);
 }
-- 
2.43.0


^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2026-04-24  1:46 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-14  1:36 [PATCH net] tcp: make probe0 timer handle expired user timeout Altan Hacigumus
2026-04-20 18:33 ` Jakub Kicinski
2026-04-20 18:45   ` Eric Dumazet
2026-04-21  4:57 ` Eric Dumazet
2026-04-22  3:31   ` Altan Hacigumus
2026-04-22  7:39     ` Eric Dumazet
2026-04-23  3:02       ` Altan Hacigumus
2026-04-24  1:46 ` [PATCH net v2] " Altan Hacigumus

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox