From: Wyatt Feng 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 clamp them to the per-netns range `[1, tcp_max_reordering]`. Apply the matching cross-check to `tcp_max_reordering` so the existing invariant `tcp_max_reordering >= tcp_reordering` is preserved. This keeps the fix at the sysctl boundary and avoids changing the TCP fast path. Fixes: 91cc17c0e5e5 ("[TCP]: MTUprobe: receiver window & data available checks fixed") Cc: stable@vger.kernel.org Reported-by: Yuan Tan Reported-by: Zhengchuan Liang Reported-by: Xin Liu Assisted-by: Codex:GPT-5.4 Signed-off-by: Wyatt Feng Signed-off-by: Ren Wei --- net/ipv4/sysctl_net_ipv4.c | 38 ++++++++++++++++++++++++++++++++++++-- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c index c0e85cc171ae..c44afb9c321d 100644 --- a/net/ipv4/sysctl_net_ipv4.c +++ b/net/ipv4/sysctl_net_ipv4.c @@ -215,6 +215,40 @@ static int ipv4_fwd_update_priority(const struct ctl_table *table, int write, return ret; } +static int proc_tcp_reordering(const struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table tmp = { + .data = table->data, + .maxlen = table->maxlen, + .mode = table->mode, + .extra1 = SYSCTL_ONE, + }; + struct net *net; + + net = container_of(table->data, struct net, ipv4.sysctl_tcp_reordering); + tmp.extra2 = &net->ipv4.sysctl_tcp_max_reordering; + + return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); +} + +static int proc_tcp_max_reordering(const struct ctl_table *table, int write, + void *buffer, size_t *lenp, loff_t *ppos) +{ + struct ctl_table tmp = { + .data = table->data, + .maxlen = table->maxlen, + .mode = table->mode, + }; + struct net *net; + + net = container_of(table->data, struct net, + ipv4.sysctl_tcp_max_reordering); + tmp.extra1 = &net->ipv4.sysctl_tcp_reordering; + + return proc_dointvec_minmax(&tmp, write, buffer, lenp, ppos); +} + static int proc_tcp_congestion_control(const struct ctl_table *ctl, int write, void *buffer, size_t *lenp, loff_t *ppos) { @@ -1058,7 +1092,7 @@ 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_tcp_reordering }, { .procname = "tcp_retries1", @@ -1293,7 +1327,7 @@ 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_tcp_max_reordering }, { .procname = "tcp_dsack", -- 2.47.3