All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH nf v2 0/1] netfilter: ip6t_rt: fix zero-address non-strict match out-of-bounds read
@ 2026-09-06 13:29 Ren Wei
  2026-09-06 13:29 ` [PATCH nf v2 1/1] " Ren Wei
  0 siblings, 1 reply; 2+ messages in thread
From: Ren Wei @ 2026-09-06 13:29 UTC (permalink / raw)
  To: netfilter-devel, fw; +Cc: pablo, phil, vega, rakukuip, weir

From: Luxiao Xu <rakukuip@gmail.com>

Hi Florian, netfilter maintainers,

This patch fixes an out-of-bounds read in net/ipv6/netfilter/ip6t_rt.c
reachable by unprivileged users with CAP_NET_ADMIN in user/net namespaces
when configuring non-strict routing match rules with addrnr == 0.

v1 -> v2:
 - Move the loop termination check (i < rtinfo->addrnr) into the for-loop
   header condition in rt_mt6() and remove the backwards break check at
   the bottom of the loop body (suggested by Florian Westphal).
 - v1 Link: https://lore.kernel.org/all/cover.1788337633.git.rakukuip@gmail.com/

Thanks,
Ren Wei
Luxiao Xu

Luxiao Xu (1):
  netfilter: ip6t_rt: fix zero-address non-strict match  out-of-bounds
    read

 net/ipv6/netfilter/ip6t_rt.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

-- 
2.43.0

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

* [PATCH nf v2 1/1] netfilter: ip6t_rt: fix zero-address non-strict match  out-of-bounds read
  2026-09-06 13:29 [PATCH nf v2 0/1] netfilter: ip6t_rt: fix zero-address non-strict match out-of-bounds read Ren Wei
@ 2026-09-06 13:29 ` Ren Wei
  0 siblings, 0 replies; 2+ messages in thread
From: Ren Wei @ 2026-09-06 13:29 UTC (permalink / raw)
  To: netfilter-devel, fw; +Cc: pablo, phil, vega, rakukuip, weir

From: Luxiao Xu <rakukuip@gmail.com>

rt_mt6_check() permits rules to be configured with rtinfo->addrnr == 0
even when address matching (IP6T_RT_FST_MASK) is requested.

In the IP6T_RT_FST_NSTRICT path, rt_mt6() evaluates packet routing
addresses against rtinfo->addrs[i] and terminates backwards at the bottom
of the loop:

    if (ipv6_addr_equal(ap, &rtinfo->addrs[i])) {
        i++;
    }
    if (i == rtinfo->addrnr)
        break;

When addrnr is 0, if the first packet address matches rtinfo->addrs[0],
i is incremented to 1. Because i is now strictly greater than addrnr (0),
the loop termination condition (i == rtinfo->addrnr) is bypassed and will
never be satisfied.

If a crafted IPv6 packet contains matching routing addresses, i will
advance past IP6T_RT_HOPS (16). The subsequent call to ipv6_addr_equal()
reads beyond struct ip6t_rt, triggering UBSAN/KASAN out-of-bounds warnings
or kernel panics.

Fix this by:
1. Rejecting rules in rt_mt6_check() where IP6T_RT_FST_MASK is set but
   rtinfo->addrnr is zero.
2. In rt_mt6(), moving the termination condition (i < rtinfo->addrnr)
   into the for-loop header condition and removing the backwards break
   at the end of the loop body.

Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2")
Cc: stable@vger.kernel.org
Reported-by: Vega <vega@nebusec.ai>
Suggested-by: Florian Westphal <fw@strlen.de>
Assisted-by: LLM
Signed-off-by: Luxiao Xu <rakukuip@gmail.com>
Signed-off-by: Ren Wei <weir@nebusec.ai>
---
v1 -> v2:
 - In rt_mt6(), check i < rtinfo->addrnr in the for-loop header and
   drop the backwards loop termination break at the end of the loop
   body (Florian Westphal).
 - v1 Link: https://lore.kernel.org/all/cover.1788337633.git.rakukuip@gmail.com/
---
 net/ipv6/netfilter/ip6t_rt.c | 11 ++++++++---
 1 file changed, 8 insertions(+), 3 deletions(-)

diff --git a/net/ipv6/netfilter/ip6t_rt.c b/net/ipv6/netfilter/ip6t_rt.c
index 8051425213dd..9880faf3cc7d 100644
--- a/net/ipv6/netfilter/ip6t_rt.c
+++ b/net/ipv6/netfilter/ip6t_rt.c
@@ -96,7 +96,8 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 			unsigned int i = 0;
 
 			for (temp = 0;
-			     temp < (unsigned int)((hdrlen - 8) / 16);
+			     temp < (unsigned int)((hdrlen - 8) / 16) &&
+			     i < rtinfo->addrnr;
 			     temp++) {
 				ap = skb_header_pointer(skb,
 							ptr
@@ -112,8 +113,6 @@ static bool rt_mt6(const struct sk_buff *skb, struct xt_action_param *par)
 
 				if (ipv6_addr_equal(ap, &rtinfo->addrs[i]))
 					i++;
-				if (i == rtinfo->addrnr)
-					break;
 			}
 			if (i == rtinfo->addrnr)
 				return ret;
@@ -162,6 +161,12 @@ static int rt_mt6_check(const struct xt_mtchk_param *par)
 		pr_info_ratelimited("too many addresses specified\n");
 		return -EINVAL;
 	}
+
+	if ((rtinfo->flags & IP6T_RT_FST_MASK) && !rtinfo->addrnr) {
+		pr_info_ratelimited("address list match requested but addrnr is 0\n");
+		return -EINVAL;
+	}
+
 	if ((rtinfo->flags & (IP6T_RT_RES | IP6T_RT_FST_MASK)) &&
 	    (!(rtinfo->flags & IP6T_RT_TYP) ||
 	     (rtinfo->rt_type != 0) ||
-- 
2.43.0

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

end of thread, other threads:[~2026-09-06 13:30 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-06 13:29 [PATCH nf v2 0/1] netfilter: ip6t_rt: fix zero-address non-strict match out-of-bounds read Ren Wei
2026-09-06 13:29 ` [PATCH nf v2 1/1] " Ren Wei

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.