ip6_route_lookup() can return an error-free route whose rt6i_idev is NULL. For example, lowering an external nexthop device's MTU below IPV6_MIN_MTU tears down its inet6_dev while fib6_ifdown() leaves routes using nexthop objects in the FIB. rpfilter_lookup_reverse6() dereferences rt6i_idev before evaluating its loose-mode condition. This lets an unprivileged user with a private user and network namespace trigger a NULL pointer dereference: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000000 KASAN: null-ptr-deref in range [0x0000000000000000-0x0000000000000007] RIP: rpfilter_mt ip6t_do_table nf_hook_slow ipv6_rcv process_backlog net_rx_action handle_softirqs Evaluate loose mode first because route existence is sufficient there. In strict mode, compare devices only when the route has an inet6_dev. Fixes: e26f9a480fb6 ("netfilter: add ipv6 reverse path filter match") Reported-by: co+459f67f4d8af8ce6@bugs.sh Closes: https://lore.kernel.org/all/VtWUkE8QzJt5CroTj2V2v3ZQ0gwbXZ7nq7I3@bugs.sh/ Assisted-by: Claude:gpt-5 Signed-off-by: Weiming Shi --- net/ipv6/netfilter/ip6t_rpfilter.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/net/ipv6/netfilter/ip6t_rpfilter.c b/net/ipv6/netfilter/ip6t_rpfilter.c index 67c87a88cde4f..2bcc96f9385cb 100644 --- a/net/ipv6/netfilter/ip6t_rpfilter.c +++ b/net/ipv6/netfilter/ip6t_rpfilter.c @@ -72,9 +72,11 @@ static bool rpfilter_lookup_reverse6(struct net *net, const struct sk_buff *skb, goto out; } - if (rt->rt6i_idev->dev == dev || - l3mdev_master_ifindex_rcu(rt->rt6i_idev->dev) == dev->ifindex || - (flags & XT_RPFILTER_LOOSE)) + if (flags & XT_RPFILTER_LOOSE) + ret = true; + else if (rt->rt6i_idev && + (rt->rt6i_idev->dev == dev || + l3mdev_master_ifindex_rcu(rt->rt6i_idev->dev) == dev->ifindex)) ret = true; out: ip6_rt_put(rt); -- 2.55.0