mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH net v2 0/5] net: fix misc signed overflows caused by bad sysctl values
@ 2026-10-27 10:45 Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 1/5] ipv6: restrict gc_elasticity to 31 Jiayuan Chen
                   ` (4 more replies)
  0 siblings, 5 replies; 8+ messages in thread
From: Jiayuan Chen @ 2026-10-27 10:45 UTC (permalink / raw)
  To: netdev
  Cc: Jiayuan Chen, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	Randy Dunlap, David Ahern, Ido Schimmel, Joel Granados,
	Thomas Gleixner, Petr Pavlu, Kuniyuki Iwashima,
	Fernando Fernandez Mancera, Willem de Bruijn, Maoyi Xie,
	Zhan Xusheng, Jiri Wiesner, Oleg Nesterov, Chia-Yu Chang,
	Yung Chih Su, Wyatt Feng, Flavio Leitner, Hannes Frederic Sowa,
	Petr Mladek, Paul E. McKenney, linux-doc, linux-kernel

Recently I have reviewed quite a few fixes for variable overflows caused
by config values, i.e. a value set from sysctl, module params or netlink
that is accepted as valid but later overflows when it is used in a
calculation. I believe there are more of these still out there, so I
used an LLM to dig through the code and it found the issues fixed in
this series.

All of them have been reproduced and verified in QEMU.

v2:
 - gc_elasticity, mld_qrv, igmp_qrv: store the sysctl as u8 and use
   proc_dou8vec_minmax(), as suggested by Kuniyuki
 - docs: add the missing "Maximum: 255" to the mld_qrv and igmp_qrv
   entries in ip-sysctl.rst
 - message_cost: add proc_dointvec_jiffies_minmax() instead of a local
   handler, as Joel suggested
 - redirect_load: reject negative values as well
 - kept Fernando's Reviewed-by on gc_elasticity, mld_qrv and igmp_qrv:
   v2 narrows the storage type to u8, the fix itself is the same
v1: https://lore.kernel.org/netdev/20261023091419.167088-1-jiayuan.chen@linux.dev/

Jiayuan Chen (5):
  ipv6: restrict gc_elasticity to 31
  ipv4: fix shift-out-of-bounds in ip_rt_send_redirect()
  ipv6: restrict mld_qrv to 255
  ipv4: restrict igmp_qrv to 255
  net: restrict message_cost and message_burst to non-negative values

 Documentation/networking/ip-sysctl.rst        |  4 ++
 .../net_cachelines/netns_ipv4_sysctl.rst      |  2 +-
 include/linux/jiffies.h                       |  2 +
 include/net/ipv6.h                            |  2 +-
 include/net/netns/ipv4.h                      |  2 +-
 include/net/netns/ipv6.h                      |  2 +-
 kernel/time/jiffies.c                         | 40 +++++++++++++++++++
 net/core/sysctl_net_core.c                    |  6 ++-
 net/ipv4/route.c                              | 10 +++--
 net/ipv4/sysctl_net_ipv4.c                    |  4 +-
 net/ipv6/mcast.c                              |  2 +-
 net/ipv6/route.c                              |  7 +++-
 net/ipv6/sysctl_net_ipv6.c                    |  4 +-
 13 files changed, 70 insertions(+), 17 deletions(-)

-- 
2.43.0


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

* [PATCH net v2 1/5] ipv6: restrict gc_elasticity to 31
  2026-10-27 10:45 [PATCH net v2 0/5] net: fix misc signed overflows caused by bad sysctl values Jiayuan Chen
@ 2026-10-27 10:45 ` Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 2/5] ipv4: fix shift-out-of-bounds in ip_rt_send_redirect() Jiayuan Chen
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 8+ messages in thread
From: Jiayuan Chen @ 2026-10-27 10:45 UTC (permalink / raw)
  To: netdev
  Cc: Jiayuan Chen, stable, Fernando Fernandez Mancera,
	Kuniyuki Iwashima, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	Randy Dunlap, David Ahern, Ido Schimmel, Joel Granados,
	Thomas Gleixner, Petr Pavlu, Willem de Bruijn, Maoyi Xie,
	Jiri Wiesner, Gerd Rausch, Zhan Xusheng, Oleg Nesterov,
	Chia-Yu Chang, Yung Chih Su, Wyatt Feng, Hannes Frederic Sowa,
	Flavio Leitner, Paul E. McKenney, Petr Mladek, linux-doc,
	linux-kernel

Every counted IPv6 dst allocation runs ip6_dst_gc() once the number of
live dst goes over gc_thresh (1024 by default). ip6_dst_gc() decays
ip6_rt_gc_expire by gc_elasticity: the smaller gc_elasticity is, the
smaller ip6_rt_gc_expire gets, i.e. the more aggressive the gc.

ip6_dst_gc() reads ip6_rt_gc_expire into a u32, but gc_elasticity has no
bounds at all, so writing >= 32 shifts a 32-bit value by >= 32 bits, and
a negative value gives a negative shift count. Both are UB:

	val = atomic_read(&net->ipv6.ip6_rt_gc_expire);
	atomic_set(&net->ipv6.ip6_rt_gc_expire, val - (val >> rt_elasticity));

  UBSAN: shift-out-of-bounds in net/ipv6/route.c:3369:53
  shift exponent 32 is too large for 32-bit type 'unsigned int'
  CPU: 2 UID: 0 PID: 615 Comm: ping6 Not tainted 7.3.0-rc7+ #364 PREEMPT
  Call Trace:
   <IRQ>
   dump_stack_lvl+0xc1/0xf0
   dump_stack+0x10/0x20
   __ubsan_handle_shift_out_of_bounds+0x1d1/0x390
   ip6_dst_gc.cold+0x15/0x1a
   dst_alloc+0x4e0/0x620
   ip6_rt_cache_alloc+0x189/0x7e0
   __ip6_rt_update_pmtu+0x68e/0x1160
   ip6_update_pmtu+0x30c/0x3a0
   icmpv6_err+0x1fa/0x330
   icmpv6_notify+0x303/0x770
   icmpv6_rcv+0xc12/0x1670
   ip6_protocol_deliver_rcu+0xb4a/0x1520
   ip6_input_finish+0x19c/0x400
   ip6_input+0xd4/0x240
   ipv6_rcv+0x1fd/0x330
   __netif_receive_skb_one_core+0x118/0x1c0
   __netif_receive_skb+0x21/0x150
   process_backlog+0x37e/0x1200
   __napi_poll.constprop.0+0xa5/0x5e0
   net_rx_action+0x4c0/0xf70
   handle_softirqs+0x204/0x9b0
   __do_softirq+0x10/0x18

Make it a u8 and reject writes outside 0..31 with proc_dou8vec_minmax().

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
Reviewed-by: Kuniyuki Iwashima <kuniyu@google.com>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
v2: switched to u8 and proc_dou8vec_minmax(), as suggested by Kuniyuki
Iwashima.
---
 include/net/netns/ipv6.h | 2 +-
 net/ipv6/route.c         | 7 +++++--
 2 files changed, 6 insertions(+), 3 deletions(-)

diff --git a/include/net/netns/ipv6.h b/include/net/netns/ipv6.h
index ffda15318be59..aefce37c04a4f 100644
--- a/include/net/netns/ipv6.h
+++ b/include/net/netns/ipv6.h
@@ -25,11 +25,11 @@ struct netns_sysctl_ipv6 {
 	int ip6_rt_gc_min_interval;
 	int ip6_rt_gc_timeout;
 	int ip6_rt_gc_interval;
-	int ip6_rt_gc_elasticity;
 	int ip6_rt_mtu_expires;
 	int ip6_rt_min_advmss;
 	u32 multipath_hash_fields;
 	u8 multipath_hash_policy;
+	u8 ip6_rt_gc_elasticity;
 
 	__cacheline_group_begin(sysctl_ipv6_flowlabel);
 	u8 flowlabel_consistency;
diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 94e5ef1c4f83e..abc8b811cd423 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -6579,6 +6579,8 @@ static int ipv6_sysctl_rtcache_flush(const struct ctl_table *ctl, int write,
 	return 0;
 }
 
+static int ip6_rt_gc_elasticity_max = 31;
+
 static const struct ctl_table ipv6_route_table_template[] = {
 	{
 		.procname	=	"max_size",
@@ -6625,9 +6627,10 @@ static const struct ctl_table ipv6_route_table_template[] = {
 	{
 		.procname	=	"gc_elasticity",
 		.data		=	&init_net.ipv6.sysctl.ip6_rt_gc_elasticity,
-		.maxlen		=	sizeof(int),
+		.maxlen		=	sizeof(u8),
 		.mode		=	0644,
-		.proc_handler	=	proc_dointvec,
+		.proc_handler	=	proc_dou8vec_minmax,
+		.extra2		=	&ip6_rt_gc_elasticity_max,
 	},
 	{
 		.procname	=	"mtu_expires",
-- 
2.43.0


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

* [PATCH net v2 2/5] ipv4: fix shift-out-of-bounds in ip_rt_send_redirect()
  2026-10-27 10:45 [PATCH net v2 0/5] net: fix misc signed overflows caused by bad sysctl values Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 1/5] ipv6: restrict gc_elasticity to 31 Jiayuan Chen
@ 2026-10-27 10:45 ` Jiayuan Chen
  2026-10-27 11:54   ` Fernando Fernandez Mancera
  2026-10-27 10:45 ` [PATCH net v2 3/5] ipv6: restrict mld_qrv to 255 Jiayuan Chen
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 8+ messages in thread
From: Jiayuan Chen @ 2026-10-27 10:45 UTC (permalink / raw)
  To: netdev
  Cc: Jiayuan Chen, stable, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
	Shuah Khan, Randy Dunlap, David Ahern, Ido Schimmel,
	Thomas Gleixner, Joel Granados, Petr Pavlu, Kuniyuki Iwashima,
	Fernando Fernandez Mancera, Willem de Bruijn, Maoyi Xie,
	Daniel J Blueman, Jiri Wiesner, Gerd Rausch, Oleg Nesterov,
	Chia-Yu Chang, Wyatt Feng, Yung Chih Su, Hannes Frederic Sowa,
	Flavio Leitner, Petr Mladek, Paul E. McKenney, linux-doc,
	linux-kernel

ip_rt_redirect_number is the max number of ICMP Redirects we send to one
endpoint; once we hit it we stop. Before that, ip_rt_redirect_load gives
the redirects an exponential backoff:

	if (peer->n_redirects == 0 ||
	    time_after(jiffies,
		       (peer->rate_last +
			(ip_rt_redirect_load << peer->n_redirects)))) {

n_redirects grows until it reaches ip_rt_redirect_number, and both
redirect_number and redirect_load are plain proc_dointvec sysctls with
no upper bound. Set redirect_number past 32 and n_redirects climbs past
31, so "ip_rt_redirect_load << peer->n_redirects" shifts a 32-bit int by
>= 32 bits, which is UB:

  UBSAN: shift-out-of-bounds in net/ipv4/route.c:949:6
  shift exponent 32 is too large for 32-bit type 'int'
  CPU: 1 UID: 0 PID: 1845 Comm: ping Not tainted 7.3.0-rc7+ #364 PREEMPT
  Call Trace:
   <IRQ>
   dump_stack_lvl+0xc1/0xf0
   dump_stack+0x10/0x20
   __ubsan_handle_shift_out_of_bounds+0x1d1/0x390
   ip_rt_send_redirect.cold+0x2c/0x146
   ip_forward+0x1ddc/0x2430
   ip_rcv+0x2b1/0x320
   __netif_receive_skb_one_core+0x16b/0x1c0
   __netif_receive_skb+0x21/0x150
   process_backlog+0x37e/0x1200
   __napi_poll.constprop.0+0xa5/0x5e0
   net_rx_action+0x4c0/0xf70

Bounding redirect_number instead is not an option: 0 disables redirects
and -1 removes the cap. Compute the backoff in u64 with the shift count
capped at 31, which cannot overflow once ip_rt_redirect_load is
non-negative, and clamp the result to MAX_JIFFY_OFFSET: on 32-bit a
backoff of 2^31 or more is read by time_after() as already expired. This
keeps redirect_number as the limit on how many ICMP redirects are sent,
and the shift can no longer go out of bounds.

redirect_load on the other hand gets a lower bound of 0. A negative
backoff never meant anything, the old code only happened to treat it as
no backoff, and once converted to u64 it would turn into the maximum
backoff instead.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
 net/ipv4/route.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/net/ipv4/route.c b/net/ipv4/route.c
index 595a3b7f17830..f2c899f4cf8ca 100644
--- a/net/ipv4/route.c
+++ b/net/ipv4/route.c
@@ -907,6 +907,7 @@ void ip_rt_send_redirect(struct sk_buff *skb)
 	struct inet_peer *peer;
 	int log_martians;
 	struct net *net;
+	u64 backoff;
 	int vif;
 
 	rcu_read_lock();
@@ -945,10 +946,10 @@ void ip_rt_send_redirect(struct sk_buff *skb)
 	/* Check for load limit; set rate_last to the latest sent
 	 * redirect.
 	 */
+	backoff = (u64)ip_rt_redirect_load << min(peer->n_redirects, 31U);
+	backoff = min_t(u64, backoff, MAX_JIFFY_OFFSET);
 	if (peer->n_redirects == 0 ||
-	    time_after(jiffies,
-		       (peer->rate_last +
-			(ip_rt_redirect_load << peer->n_redirects)))) {
+	    time_after(jiffies, peer->rate_last + (unsigned long)backoff)) {
 		__be32 gw = rt_nexthop(rt, ip_hdr(skb)->daddr);
 
 		icmp_send(skb, ICMP_REDIRECT, ICMP_REDIR_HOST, gw);
@@ -3573,7 +3574,8 @@ static struct ctl_table ipv4_route_table[] = {
 		.data		= &ip_rt_redirect_load,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= SYSCTL_ZERO,
 	},
 	{
 		.procname	= "redirect_number",
-- 
2.43.0


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

* [PATCH net v2 3/5] ipv6: restrict mld_qrv to 255
  2026-10-27 10:45 [PATCH net v2 0/5] net: fix misc signed overflows caused by bad sysctl values Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 1/5] ipv6: restrict gc_elasticity to 31 Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 2/5] ipv4: fix shift-out-of-bounds in ip_rt_send_redirect() Jiayuan Chen
@ 2026-10-27 10:45 ` Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 4/5] ipv4: restrict igmp_qrv " Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 5/5] net: restrict message_cost and message_burst to non-negative values Jiayuan Chen
  4 siblings, 0 replies; 8+ messages in thread
From: Jiayuan Chen @ 2026-10-27 10:45 UTC (permalink / raw)
  To: netdev
  Cc: Jiayuan Chen, stable, Fernando Fernandez Mancera,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	David Ahern, Ido Schimmel, Joel Granados, Thomas Gleixner,
	Petr Pavlu, Kuniyuki Iwashima, Willem de Bruijn, Maoyi Xie,
	Daniel J Blueman, Oleg Nesterov, Chia-Yu Chang, Yung Chih Su,
	Wyatt Feng, Hannes Frederic Sowa, Flavio Leitner,
	Paul E. McKenney, Petr Mladek, linux-doc, linux-kernel

net.ipv6.mld_qrv only has a lower bound, but ipv6_mc_reset() stores it
into the u8 inet6_dev::mc_qrv, so 256 wraps to 0 and the first MLDv2
Query received on the interface trips the WARN_ON() in mld_update_qrv():

	WARN_ON(idev->mc_qrv == 0);

  WARNING: net/ipv6/mcast.c:1327 at mld_query_work+0x1fd2/0x2cb0, CPU#3: kworker/3:1/2688
  Workqueue: mld mld_query_work
  RIP: 0010:mld_query_work+0x1fd2/0x2cb0
  Call Trace:
   <TASK>
   process_one_work+0x93a/0x1b20
   worker_thread+0x6d0/0x11d0
   kthread+0x358/0x470
   ret_from_fork+0x5b3/0x820
   ret_from_fork_asm+0x1a/0x30
   </TASK>

Make the sysctl a u8 like mc_qrv and switch to proc_dou8vec_minmax(),
which rejects anything above 255, and document it.

Fixes: 2f711939d2ea ("ipv6: add sysctl_mld_qrv to configure query robustness variable")
Cc: stable@vger.kernel.org
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
v2: switched to u8 and proc_dou8vec_minmax(), as suggested by Kuniyuki
Iwashima.
---
 Documentation/networking/ip-sysctl.rst | 2 ++
 include/net/ipv6.h                     | 2 +-
 net/ipv6/mcast.c                       | 2 +-
 net/ipv6/sysctl_net_ipv6.c             | 4 ++--
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index 4b19c8d3efda7..71f334f27004e 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -2515,6 +2515,8 @@ mld_qrv - INTEGER
 
 	Minimum: 1 (as specified by RFC6636 4.5)
 
+	Maximum: 255
+
 max_dst_opts_number - INTEGER
 	Maximum number of non-padding TLVs allowed in a Destination
 	options extension header. If this value is less than zero
diff --git a/include/net/ipv6.h b/include/net/ipv6.h
index 3de07e738538f..4901a92066e61 100644
--- a/include/net/ipv6.h
+++ b/include/net/ipv6.h
@@ -205,7 +205,7 @@ struct sk_buff *ip6_frag_next(struct sk_buff *skb,
 
 /* sysctls */
 extern int sysctl_mld_max_msf;
-extern int sysctl_mld_qrv;
+extern u8 sysctl_mld_qrv;
 
 #define _DEVINC(net, statname, mod, idev, field)			\
 ({									\
diff --git a/net/ipv6/mcast.c b/net/ipv6/mcast.c
index ecef55f261890..13f31132e0f97 100644
--- a/net/ipv6/mcast.c
+++ b/net/ipv6/mcast.c
@@ -106,7 +106,7 @@ static int __ipv6_dev_mc_inc(struct net_device *dev,
 #define IPV6_MLD_MAX_MSF	64
 
 int sysctl_mld_max_msf __read_mostly = IPV6_MLD_MAX_MSF;
-int sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
+u8 sysctl_mld_qrv __read_mostly = MLD_QRV_DEFAULT;
 
 #define mc_assert_locked(idev)			\
 	lockdep_assert_held(&(idev)->mc_lock)
diff --git a/net/ipv6/sysctl_net_ipv6.c b/net/ipv6/sysctl_net_ipv6.c
index 1a0a36dcdabc1..f3ac04dbc71d0 100644
--- a/net/ipv6/sysctl_net_ipv6.c
+++ b/net/ipv6/sysctl_net_ipv6.c
@@ -226,9 +226,9 @@ static struct ctl_table ipv6_rotable[] = {
 	{
 		.procname	= "mld_qrv",
 		.data		= &sysctl_mld_qrv,
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(u8),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec_minmax,
+		.proc_handler	= proc_dou8vec_minmax,
 		.extra1		= SYSCTL_ONE
 	},
 #ifdef CONFIG_NETLABEL
-- 
2.43.0


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

* [PATCH net v2 4/5] ipv4: restrict igmp_qrv to 255
  2026-10-27 10:45 [PATCH net v2 0/5] net: fix misc signed overflows caused by bad sysctl values Jiayuan Chen
                   ` (2 preceding siblings ...)
  2026-10-27 10:45 ` [PATCH net v2 3/5] ipv6: restrict mld_qrv to 255 Jiayuan Chen
@ 2026-10-27 10:45 ` Jiayuan Chen
  2026-10-27 10:45 ` [PATCH net v2 5/5] net: restrict message_cost and message_burst to non-negative values Jiayuan Chen
  4 siblings, 0 replies; 8+ messages in thread
From: Jiayuan Chen @ 2026-10-27 10:45 UTC (permalink / raw)
  To: netdev
  Cc: Jiayuan Chen, stable, Fernando Fernandez Mancera,
	David S. Miller, Eric Dumazet, Jakub Kicinski, Paolo Abeni,
	Simon Horman, Jonathan Corbet, Shuah Khan, Randy Dunlap,
	David Ahern, Ido Schimmel, Joel Granados, Thomas Gleixner,
	Petr Pavlu, Kuniyuki Iwashima, Willem de Bruijn, Maoyi Xie,
	Daniel J Blueman, Oleg Nesterov, Chia-Yu Chang, Wyatt Feng,
	Yung Chih Su, Flavio Leitner, Hannes Frederic Sowa, Petr Mladek,
	Paul E. McKenney, linux-doc, linux-kernel

net.ipv4.igmp_qrv only has a lower bound, but ip_mc_reset() stores it
into the u8 in_device::mr_qrv, and the IGMPv3 retransmit counters filled
from it (crcount, sf_crcount) are u8 as well. Anything above 255
silently wraps. With 256, mr_qrv becomes 0, every
"in_dev->mr_qrv ?: sysctl_igmp_qrv" falls back to 256, which truncates
to 0 again in crcount, and igmpv3_send_cr() never puts the state change
records for the group into a report. The older version querier present
timeout (mr_qrv * mr_qi + mr_qri) also collapses to just mr_qri.

Make the sysctl a u8 like mr_qrv and switch to proc_dou8vec_minmax(),
which rejects anything above 255, and document it.

Fixes: a9fe8e29945d ("ipv4: implement igmp_qrv sysctl to tune igmp robustness variable")
Cc: stable@vger.kernel.org
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
For AI review: drivers/net/amt.c writing sysctl_igmp_qrv into the 3-bit
qrv wire fields is pre-existing and out of scope for this patch.

v2: switched to u8 and proc_dou8vec_minmax(), as suggested by Kuniyuki
Iwashima.
---
 Documentation/networking/ip-sysctl.rst                        | 2 ++
 Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst | 2 +-
 include/net/netns/ipv4.h                                      | 2 +-
 net/ipv4/sysctl_net_ipv4.c                                    | 4 ++--
 4 files changed, 6 insertions(+), 4 deletions(-)

diff --git a/Documentation/networking/ip-sysctl.rst b/Documentation/networking/ip-sysctl.rst
index 71f334f27004e..9e282fb046904 100644
--- a/Documentation/networking/ip-sysctl.rst
+++ b/Documentation/networking/ip-sysctl.rst
@@ -1906,6 +1906,8 @@ igmp_qrv - INTEGER
 
 	Minimum: 1 (as specified by RFC6636 4.5)
 
+	Maximum: 255
+
 force_igmp_version - INTEGER
 	- 0 - (default) No enforcement of a IGMP version, IGMPv1/v2 fallback
 	  allowed. Will back to IGMPv3 mode again if all IGMPv1/v2 Querier
diff --git a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst
index 3dc03bff739e4..2833ce6cba1d4 100644
--- a/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst
+++ b/Documentation/networking/net_cachelines/netns_ipv4_sysctl.rst
@@ -143,9 +143,9 @@ int                             sysctl_udp_rmem_min
 u8                              sysctl_fib_notify_on_flag_change
 u8                              sysctl_udp_l3mdev_accept
 u8                              sysctl_igmp_llm_reports
+u8                              sysctl_igmp_qrv
 int                             sysctl_igmp_max_memberships
 int                             sysctl_igmp_max_msf
-int                             sysctl_igmp_qrv
 struct_ping_group_range         ping_group_range
 atomic_t                        dev_addr_genid
 unsigned_int                    sysctl_udp_child_hash_entries
diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h
index cb7f8bf15671c..3efbc7f4b4f7d 100644
--- a/include/net/netns/ipv4.h
+++ b/include/net/netns/ipv4.h
@@ -258,9 +258,9 @@ struct netns_ipv4 {
 #endif
 
 	u8 sysctl_igmp_llm_reports;
+	u8 sysctl_igmp_qrv;
 	int sysctl_igmp_max_memberships;
 	int sysctl_igmp_max_msf;
-	int sysctl_igmp_qrv;
 
 	struct ping_group_range ping_group_range;
 	u16			ping_port_rover;
diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c
index e3760daa34706..09f7fc6771456 100644
--- a/net/ipv4/sysctl_net_ipv4.c
+++ b/net/ipv4/sysctl_net_ipv4.c
@@ -975,9 +975,9 @@ static const struct ctl_table ipv4_net_table[] = {
 	{
 		.procname	= "igmp_qrv",
 		.data		= &init_net.ipv4.sysctl_igmp_qrv,
-		.maxlen		= sizeof(int),
+		.maxlen		= sizeof(u8),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec_minmax,
+		.proc_handler	= proc_dou8vec_minmax,
 		.extra1		= SYSCTL_ONE
 	},
 #endif
-- 
2.43.0


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

* [PATCH net v2 5/5] net: restrict message_cost and message_burst to non-negative values
  2026-10-27 10:45 [PATCH net v2 0/5] net: fix misc signed overflows caused by bad sysctl values Jiayuan Chen
                   ` (3 preceding siblings ...)
  2026-10-27 10:45 ` [PATCH net v2 4/5] ipv4: restrict igmp_qrv " Jiayuan Chen
@ 2026-10-27 10:45 ` Jiayuan Chen
  2026-10-27 11:56   ` Fernando Fernandez Mancera
  4 siblings, 1 reply; 8+ messages in thread
From: Jiayuan Chen @ 2026-10-27 10:45 UTC (permalink / raw)
  To: netdev
  Cc: Jiayuan Chen, stable, Joel Granados, David S. Miller,
	Eric Dumazet, Jakub Kicinski, Paolo Abeni, Simon Horman,
	Jonathan Corbet, Shuah Khan, Randy Dunlap, David Ahern,
	Ido Schimmel, Thomas Gleixner, Petr Pavlu, Kuniyuki Iwashima,
	Fernando Fernandez Mancera, Willem de Bruijn, Maoyi Xie,
	Gerd Rausch, Zhan Xusheng, Oleg Nesterov, Chia-Yu Chang,
	Yung Chih Su, Wyatt Feng, Hannes Frederic Sowa, Flavio Leitner,
	Petr Mladek, Paul E. McKenney, linux-doc, linux-kernel

net.core.message_cost and net.core.message_burst feed the interval and
burst of net_ratelimit_state, but neither rejects negative values:
message_burst uses plain proc_dointvec, and message_cost uses
proc_dointvec_jiffies, which happily stores -1 second as -HZ jiffies.

Since commit a940d145cc38 ("ratelimit: Warn if ->interval or ->burst are
negative"), ___ratelimit() splats on such values, so the next
net_ratelimit() caller warns, e.g. a martian source log:

  Negative interval (-250) or burst (10): Uninitialized ratelimit_state structure?
  WARNING: lib/ratelimit.c:43 at ___ratelimit+0x56e/0x960, CPU#1: ping/3218
  RIP: 0010:___ratelimit+0x578/0x960
  Call Trace:
   <IRQ>
   net_ratelimit+0x1c/0x30
   ip_handle_martian_source+0x1bb/0x340
   ip_route_input_slow+0x1057/0x3650
   ip_route_input_noref+0x104/0x260
   arp_process+0x109b/0x2510
   arp_rcv+0x381/0x460
   __netif_receive_skb_one_core+0x173/0x1c0
   __netif_receive_skb+0x21/0x150
   process_backlog+0x37e/0x1200
   __napi_poll.constprop.0+0xa5/0x5e0
   net_rx_action+0x4c0/0xf70
   handle_softirqs+0x204/0x9b0
   __do_softirq+0x10/0x18
   do_softirq.part.0+0x49/0xd0
   </IRQ>

Negative values never meant anything here: 0 already expresses both
"no limit" (interval) and "suppress everything" (burst).

Reject them at write time. message_burst can simply use
proc_dointvec_minmax with extra1 = 0. proc_dointvec_jiffies has no
minmax variant, so add proc_dointvec_jiffies_minmax(), mirroring
proc_dointvec_ms_jiffies_minmax(), and use it for message_cost with
extra1 = 0. Note that like the ms variant, extra1/extra2 are compared
against the converted jiffies value.

Fixes: a940d145cc38 ("ratelimit: Warn if ->interval or ->burst are negative")
Cc: stable@vger.kernel.org
Suggested-by: Joel Granados <joel.granados@kernel.org>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
 include/linux/jiffies.h    |  2 ++
 kernel/time/jiffies.c      | 40 ++++++++++++++++++++++++++++++++++++++
 net/core/sysctl_net_core.c |  6 ++++--
 3 files changed, 46 insertions(+), 2 deletions(-)

diff --git a/include/linux/jiffies.h b/include/linux/jiffies.h
index bbd57061802cd..de12920f8e94b 100644
--- a/include/linux/jiffies.h
+++ b/include/linux/jiffies.h
@@ -646,6 +646,8 @@ extern unsigned long nsecs_to_jiffies(u64 n);
 struct ctl_table;
 int proc_dointvec_jiffies(const struct ctl_table *table, int dir, void *buffer,
 			  size_t *lenp, loff_t *ppos);
+int proc_dointvec_jiffies_minmax(const struct ctl_table *table, int dir,
+				 void *buffer, size_t *lenp, loff_t *ppos);
 int proc_dointvec_ms_jiffies_minmax(const struct ctl_table *table, int dir,
 				    void *buffer, size_t *lenp, loff_t *ppos);
 int proc_dointvec_userhz_jiffies(const struct ctl_table *table, int dir,
diff --git a/kernel/time/jiffies.c b/kernel/time/jiffies.c
index 9b3487d40cd6a..22a70caa58bc1 100644
--- a/kernel/time/jiffies.c
+++ b/kernel/time/jiffies.c
@@ -165,6 +165,14 @@ static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr,
 			     sysctl_u2k_int_conv_hz, sysctl_k2u_int_conv_hz);
 }
 
+static int do_proc_int_conv_jiffies_minmax(bool *negp, ulong *u_ptr,
+					   int *k_ptr, int dir,
+					   const struct ctl_table *tbl)
+{
+	return proc_int_conv(negp, u_ptr, k_ptr, dir, tbl, true,
+			     sysctl_u2k_int_conv_hz, sysctl_k2u_int_conv_hz);
+}
+
 static int do_proc_int_conv_userhz_jiffies(bool *negp, ulong *u_ptr,
 					   int *k_ptr, int dir,
 					   const struct ctl_table *tbl)
@@ -213,6 +221,13 @@ static int do_proc_int_conv_jiffies(bool *negp, ulong *u_ptr, int *k_ptr,
 	return -ENOSYS;
 }
 
+static int do_proc_int_conv_jiffies_minmax(bool *negp, ulong *u_ptr,
+					   int *k_ptr, int dir,
+					   const struct ctl_table *tbl)
+{
+	return -ENOSYS;
+}
+
 static int do_proc_int_conv_userhz_jiffies(bool *negp, ulong *u_ptr,
 					   int *k_ptr, int dir,
 					   const struct ctl_table *tbl)
@@ -263,6 +278,31 @@ int proc_dointvec_jiffies(const struct ctl_table *table, int dir,
 }
 EXPORT_SYMBOL(proc_dointvec_jiffies);
 
+/**
+ * proc_dointvec_jiffies_minmax - read a vector of integers as seconds with min/max values
+ * @table: the sysctl table
+ * @dir: %TRUE if this is a write to the sysctl file
+ * @buffer: the user buffer
+ * @lenp: the size of the user buffer
+ * @ppos: file position
+ *
+ * Reads/writes up to table->maxlen/sizeof(unsigned int) integer
+ * values from/to the user buffer, treated as an ASCII string.
+ * The values read are assumed to be in seconds, and are converted into
+ * jiffies. The converted values are checked against the optional
+ * table->extra1 (min) and table->extra2 (max) bounds, in jiffies;
+ * a value outside the range is rejected with -EINVAL.
+ *
+ * Returns 0 on success.
+ */
+int proc_dointvec_jiffies_minmax(const struct ctl_table *table, int dir,
+				 void *buffer, size_t *lenp, loff_t *ppos)
+{
+	return proc_dointvec_conv(table, dir, buffer, lenp, ppos,
+				  do_proc_int_conv_jiffies_minmax);
+}
+EXPORT_SYMBOL(proc_dointvec_jiffies_minmax);
+
 /**
  * proc_dointvec_userhz_jiffies - read a vector of integers as 1/USER_HZ seconds
  * @table: the sysctl table
diff --git a/net/core/sysctl_net_core.c b/net/core/sysctl_net_core.c
index 473c162736d69..9226b96f2e89b 100644
--- a/net/core/sysctl_net_core.c
+++ b/net/core/sysctl_net_core.c
@@ -544,14 +544,16 @@ static struct ctl_table net_core_table[] = {
 		.data		= &net_ratelimit_state.interval,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec_jiffies,
+		.proc_handler	= proc_dointvec_jiffies_minmax,
+		.extra1		= SYSCTL_ZERO,
 	},
 	{
 		.procname	= "message_burst",
 		.data		= &net_ratelimit_state.burst,
 		.maxlen		= sizeof(int),
 		.mode		= 0644,
-		.proc_handler	= proc_dointvec,
+		.proc_handler	= proc_dointvec_minmax,
+		.extra1		= SYSCTL_ZERO,
 	},
 #ifdef CONFIG_RPS
 	{
-- 
2.43.0


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

* Re: [PATCH net v2 2/5] ipv4: fix shift-out-of-bounds in ip_rt_send_redirect()
  2026-10-27 10:45 ` [PATCH net v2 2/5] ipv4: fix shift-out-of-bounds in ip_rt_send_redirect() Jiayuan Chen
@ 2026-10-27 11:54   ` Fernando Fernandez Mancera
  0 siblings, 0 replies; 8+ messages in thread
From: Fernando Fernandez Mancera @ 2026-10-27 11:54 UTC (permalink / raw)
  To: Jiayuan Chen, netdev
  Cc: stable, David S. Miller, Eric Dumazet, Jakub Kicinski,
	Paolo Abeni, Simon Horman, Jonathan Corbet, Shuah Khan,
	Randy Dunlap, David Ahern, Ido Schimmel, Thomas Gleixner,
	Joel Granados, Petr Pavlu, Kuniyuki Iwashima, Willem de Bruijn,
	Maoyi Xie, Daniel J Blueman, Jiri Wiesner, Gerd Rausch,
	Oleg Nesterov, Chia-Yu Chang, Wyatt Feng, Yung Chih Su,
	Hannes Frederic Sowa, Flavio Leitner, Petr Mladek,
	Paul E. McKenney, linux-doc, linux-kernel

On 10/27/26 11:45 AM, Jiayuan Chen wrote:
> ip_rt_redirect_number is the max number of ICMP Redirects we send to one
> endpoint; once we hit it we stop. Before that, ip_rt_redirect_load gives
> the redirects an exponential backoff:
> 
> 	if (peer->n_redirects == 0 ||
> 	    time_after(jiffies,
> 		       (peer->rate_last +
> 			(ip_rt_redirect_load << peer->n_redirects)))) {
> 
> n_redirects grows until it reaches ip_rt_redirect_number, and both
> redirect_number and redirect_load are plain proc_dointvec sysctls with
> no upper bound. Set redirect_number past 32 and n_redirects climbs past
> 31, so "ip_rt_redirect_load << peer->n_redirects" shifts a 32-bit int by
>> = 32 bits, which is UB:
> 
>    UBSAN: shift-out-of-bounds in net/ipv4/route.c:949:6
>    shift exponent 32 is too large for 32-bit type 'int'
>    CPU: 1 UID: 0 PID: 1845 Comm: ping Not tainted 7.3.0-rc7+ #364 PREEMPT
>    Call Trace:
>     <IRQ>
>     dump_stack_lvl+0xc1/0xf0
>     dump_stack+0x10/0x20
>     __ubsan_handle_shift_out_of_bounds+0x1d1/0x390
>     ip_rt_send_redirect.cold+0x2c/0x146
>     ip_forward+0x1ddc/0x2430
>     ip_rcv+0x2b1/0x320
>     __netif_receive_skb_one_core+0x16b/0x1c0
>     __netif_receive_skb+0x21/0x150
>     process_backlog+0x37e/0x1200
>     __napi_poll.constprop.0+0xa5/0x5e0
>     net_rx_action+0x4c0/0xf70
> 
> Bounding redirect_number instead is not an option: 0 disables redirects
> and -1 removes the cap. Compute the backoff in u64 with the shift count
> capped at 31, which cannot overflow once ip_rt_redirect_load is
> non-negative, and clamp the result to MAX_JIFFY_OFFSET: on 32-bit a
> backoff of 2^31 or more is read by time_after() as already expired. This
> keeps redirect_number as the limit on how many ICMP redirects are sent,
> and the shift can no longer go out of bounds.
> 
> redirect_load on the other hand gets a lower bound of 0. A negative
> backoff never meant anything, the old code only happened to treat it as
> no backoff, and once converted to u64 it would turn into the maximum
> backoff instead.
> 
> Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
> Cc: stable@vger.kernel.org
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>

Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>

Thanks!

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

* Re: [PATCH net v2 5/5] net: restrict message_cost and message_burst to non-negative values
  2026-10-27 10:45 ` [PATCH net v2 5/5] net: restrict message_cost and message_burst to non-negative values Jiayuan Chen
@ 2026-10-27 11:56   ` Fernando Fernandez Mancera
  0 siblings, 0 replies; 8+ messages in thread
From: Fernando Fernandez Mancera @ 2026-10-27 11:56 UTC (permalink / raw)
  To: Jiayuan Chen, netdev
  Cc: stable, Joel Granados, David S. Miller, Eric Dumazet,
	Jakub Kicinski, Paolo Abeni, Simon Horman, Jonathan Corbet,
	Shuah Khan, Randy Dunlap, David Ahern, Ido Schimmel,
	Thomas Gleixner, Petr Pavlu, Kuniyuki Iwashima, Willem de Bruijn,
	Maoyi Xie, Gerd Rausch, Zhan Xusheng, Oleg Nesterov,
	Chia-Yu Chang, Yung Chih Su, Wyatt Feng, Hannes Frederic Sowa,
	Flavio Leitner, Petr Mladek, Paul E. McKenney, linux-doc,
	linux-kernel

On 10/27/26 11:45 AM, Jiayuan Chen wrote:
> net.core.message_cost and net.core.message_burst feed the interval and
> burst of net_ratelimit_state, but neither rejects negative values:
> message_burst uses plain proc_dointvec, and message_cost uses
> proc_dointvec_jiffies, which happily stores -1 second as -HZ jiffies.
> 
> Since commit a940d145cc38 ("ratelimit: Warn if ->interval or ->burst are
> negative"), ___ratelimit() splats on such values, so the next
> net_ratelimit() caller warns, e.g. a martian source log:
> 
>    Negative interval (-250) or burst (10): Uninitialized ratelimit_state structure?
>    WARNING: lib/ratelimit.c:43 at ___ratelimit+0x56e/0x960, CPU#1: ping/3218
>    RIP: 0010:___ratelimit+0x578/0x960
>    Call Trace:
>     <IRQ>
>     net_ratelimit+0x1c/0x30
>     ip_handle_martian_source+0x1bb/0x340
>     ip_route_input_slow+0x1057/0x3650
>     ip_route_input_noref+0x104/0x260
>     arp_process+0x109b/0x2510
>     arp_rcv+0x381/0x460
>     __netif_receive_skb_one_core+0x173/0x1c0
>     __netif_receive_skb+0x21/0x150
>     process_backlog+0x37e/0x1200
>     __napi_poll.constprop.0+0xa5/0x5e0
>     net_rx_action+0x4c0/0xf70
>     handle_softirqs+0x204/0x9b0
>     __do_softirq+0x10/0x18
>     do_softirq.part.0+0x49/0xd0
>     </IRQ>
> 
> Negative values never meant anything here: 0 already expresses both
> "no limit" (interval) and "suppress everything" (burst).
> 
> Reject them at write time. message_burst can simply use
> proc_dointvec_minmax with extra1 = 0. proc_dointvec_jiffies has no
> minmax variant, so add proc_dointvec_jiffies_minmax(), mirroring
> proc_dointvec_ms_jiffies_minmax(), and use it for message_cost with
> extra1 = 0. Note that like the ms variant, extra1/extra2 are compared
> against the converted jiffies value.
> 
> Fixes: a940d145cc38 ("ratelimit: Warn if ->interval or ->burst are negative")
> Cc: stable@vger.kernel.org
> Suggested-by: Joel Granados <joel.granados@kernel.org>
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
Reviewed-by: Fernando Fernandez Mancera <fmancera@suse.de>

Thanks!

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

end of thread, other threads:[~2026-10-27 11:58 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-10-27 10:45 [PATCH net v2 0/5] net: fix misc signed overflows caused by bad sysctl values Jiayuan Chen
2026-10-27 10:45 ` [PATCH net v2 1/5] ipv6: restrict gc_elasticity to 31 Jiayuan Chen
2026-10-27 10:45 ` [PATCH net v2 2/5] ipv4: fix shift-out-of-bounds in ip_rt_send_redirect() Jiayuan Chen
2026-10-27 11:54   ` Fernando Fernandez Mancera
2026-10-27 10:45 ` [PATCH net v2 3/5] ipv6: restrict mld_qrv to 255 Jiayuan Chen
2026-10-27 10:45 ` [PATCH net v2 4/5] ipv4: restrict igmp_qrv " Jiayuan Chen
2026-10-27 10:45 ` [PATCH net v2 5/5] net: restrict message_cost and message_burst to non-negative values Jiayuan Chen
2026-10-27 11:56   ` Fernando Fernandez Mancera

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

all inboxes | Powered by JetHome®