Re: [PATCH net] tcp: make probe0 timer handle expired user timeout

From: Altan Hacigumus

Date: Tue Apr 21 2026 - 23:32:07 EST


On Mon, Apr 20, 2026 at 9:58 PM Eric Dumazet <edumazet@xxxxxxxxxx> wrote:
>
> On Mon, Apr 13, 2026 at 6:36 PM Altan Hacigumus <ahacigu.linux@xxxxxxxxx> 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@xxxxxxxxx>
> > ---
> > 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