]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
net: ipv4: bound TCP reordering sysctl writes and MTU probe sizes
authorWyatt Feng <bronzed_45_vested@icloud.com>
Mon, 15 Jun 2026 10:31:18 +0000 (18:31 +0800)
committerJakub Kicinski <kuba@kernel.org>
Wed, 17 Jun 2026 23:35:13 +0000 (16:35 -0700)
Reject invalid `net.ipv4.tcp_reordering` values before they reach TCP
socket state. The sysctl is stored as an `int` but copied into the
`u32` `tp->reordering` field for new sockets, so negative writes wrap
to large values.

With `tcp_mtu_probing=2`, the wrapped value can overflow the
`tcp_mtu_probe()` size calculation and drive the MTU probing path into
an out-of-bounds read. Route `tcp_reordering` writes through
`proc_dointvec_minmax()` and require it to be at least 1. Also require
`tcp_max_reordering` to be at least 1 so the configured maximum cannot
become negative either.

When registering the table for a non-init network namespace, relocate
`extra2` pointers that refer into `init_net.ipv4` so the
`tcp_reordering` upper bound follows that namespace's
`tcp_max_reordering`.

Harden `tcp_mtu_probe()` itself by computing `size_needed` as `u64`.
This keeps the send queue and window checks from being bypassed through
signed integer overflow.

Fixes: 91cc17c0e5e5 ("[TCP]: MTUprobe: receiver window & data available checks fixed")
Cc: stable@vger.kernel.org
Reported-by: Yuan Tan <yuantan098@gmail.com>
Reported-by: Zhengchuan Liang <zcliangcn@gmail.com>
Reported-by: Xin Liu <bird@lzu.edu.cn>
Suggested-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: Wyatt Feng <bronzed_45_vested@icloud.com>
Signed-off-by: Ren Wei <n05ec@lzu.edu.cn>
Reviewed-by: Eric Dumazet <edumazet@google.com>
Link: https://patch.msgid.link/1a5b7e1ef4d70fbad8c8ee0b82d8405f3c964a3d.1781395200.git.bronzed_45_vested@icloud.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_output.c

index c0e85cc171aec099fd5d4897b1a623dd27eaee08..ca1180dba1dea9ce72028ba49b7f953da343336b 100644 (file)
@@ -1058,7 +1058,9 @@ static struct ctl_table ipv4_net_table[] = {
                .data           = &init_net.ipv4.sysctl_tcp_reordering,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = SYSCTL_ONE,
+               .extra2         = &init_net.ipv4.sysctl_tcp_max_reordering,
        },
        {
                .procname       = "tcp_retries1",
@@ -1293,7 +1295,8 @@ static struct ctl_table ipv4_net_table[] = {
                .data           = &init_net.ipv4.sysctl_tcp_max_reordering,
                .maxlen         = sizeof(int),
                .mode           = 0644,
-               .proc_handler   = proc_dointvec
+               .proc_handler   = proc_dointvec_minmax,
+               .extra1         = SYSCTL_ONE,
        },
        {
                .procname       = "tcp_dsack",
@@ -1676,6 +1679,9 @@ static __net_init int ipv4_sysctl_init_net(struct net *net)
                                 */
                                table[i].mode &= ~0222;
                        }
+                       if (table[i].extra2 >= (void *)&init_net.ipv4 &&
+                           table[i].extra2 < (void *)(&init_net.ipv4 + 1))
+                               table[i].extra2 += (void *)net - (void *)&init_net;
                }
        }
 
index 26dd751ec72abfc2803b771fbe7a7bc44ed8247b..00ec4b5900f27571df24d3aad37567bf47de222c 100644 (file)
@@ -2688,7 +2688,7 @@ static int tcp_mtu_probe(struct sock *sk)
        struct sk_buff *skb, *nskb, *next;
        struct net *net = sock_net(sk);
        int probe_size;
-       int size_needed;
+       u64 size_needed;
        int copy, len;
        int mss_now;
        int interval;
@@ -2712,7 +2712,7 @@ static int tcp_mtu_probe(struct sock *sk)
        mss_now = tcp_current_mss(sk);
        probe_size = tcp_mtu_to_mss(sk, (icsk->icsk_mtup.search_high +
                                    icsk->icsk_mtup.search_low) >> 1);
-       size_needed = probe_size + (tp->reordering + 1) * tp->mss_cache;
+       size_needed = probe_size + (tp->reordering + 1) * (u64)tp->mss_cache;
        interval = icsk->icsk_mtup.search_high - icsk->icsk_mtup.search_low;
        /* When misfortune happens, we are reprobing actively,
         * and then reprobe timer has expired. We stick with current