]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: ensure SCM_TXTIME delivery time is no older than system boot
authorWillem de Bruijn <willemb@google.com>
Thu, 4 Jun 2026 19:41:03 +0000 (15:41 -0400)
committerJakub Kicinski <kuba@kernel.org>
Mon, 8 Jun 2026 23:00:05 +0000 (16:00 -0700)
Limit input to sane values to avoid having to add tests later in the
kernel hot path, e.g., in FQ.

SCM_TXTIME timestamps are converted to signed ktime_t when assigned to
skb->tstamp. Avoid having negative values overflow into large positive
ones when again used as u64, e.g., in FQ time_to_send.

For CLOCK_MONOTONIC, only allow positive values.

For CLOCK_REALTIME and CLOCK_TAI, allow equivalent values, i.e., no
older than the boot of the machine.

skb->tstamp zero is a special case signaling feature off. This is not
converted between clockids.

Handle the special case where the realtime clock is set so small that
real - mono is negative, however unlikely in practice.

Ideally we would also set a sane upper bound, but that would require
reading the clock, which is an expensive operation. Continue to defer
that validation to users of the data. FQ already does this.

Bound rather than return error on older timestamps. This is the
existing policy e.g., in FQ.

Signed-off-by: Willem de Bruijn <willemb@google.com>
----

Changes
  v1 -> v2
    - remove spurious semicolon at end of switch
    - remove Fixes tag

Link: https://patch.msgid.link/20260604194221.3319080-2-willemdebruijn.kernel@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/core/sock.c

index 4315409c22dba5828b478fbfb46778a0c816af9b..4a8a16793e16e31b613c7cccb41154c0d311e474 100644 (file)
@@ -3045,12 +3045,42 @@ int __sock_cmsg_send(struct sock *sk, struct cmsghdr *cmsg,
                sockc->tsflags |= tsflags;
                break;
        case SCM_TXTIME:
+       {
+               ktime_t tmin;
+               u64 txtime;
+
                if (!sock_flag(sk, SOCK_TXTIME))
                        return -EINVAL;
                if (cmsg->cmsg_len != CMSG_LEN(sizeof(u64)))
                        return -EINVAL;
-               sockc->transmit_time = get_unaligned((u64 *)CMSG_DATA(cmsg));
+
+               txtime = get_unaligned((u64 *)CMSG_DATA(cmsg));
+
+               /* Allow sending without a delivery time: zero special case */
+               if (!txtime) {
+                       sockc->transmit_time = 0;
+                       break;
+               }
+
+               switch (sk->sk_clockid) {
+               case CLOCK_MONOTONIC:
+                       tmin = 1;
+                       break;
+               case CLOCK_REALTIME:
+                       tmin = max(ktime_mono_to_real(0), 1);
+                       break;
+               case CLOCK_TAI:
+                       tmin = max(ktime_mono_to_any(0, TK_OFFS_TAI), 1);
+                       break;
+               default:
+                       tmin = 1;
+                       WARN_ON_ONCE(1);
+                       break;
+               }
+
+               sockc->transmit_time = max_t(ktime_t, txtime, tmin);
                break;
+       }
        case SCM_TS_OPT_ID:
                if (sk_is_tcp(sk))
                        return -EINVAL;