[PATCH net-next v2 2/2] ipv6: preserve ip6mr_get_route() error in rt6_fill_node()

From: Wenbo Sun

Date: Thu Nov 12 2026 - 04:52:22 EST


In rt6_fill_node(), when ip6mr_get_route() fails with a negative error
(for example -ENODEV, -ENOENT, -ENOMEM, or -ENOBUFS), the error path
currently jumps to nla_put_failure and unconditionally returns -EMSGSIZE
("RTNETLINK answers: Message too long").

Among all callers of rt6_fill_node(), only inet6_rtm_getroute() passes
a non-zero iif and propagates negative errors back to userspace. Keeping
-EMSGSIZE as the default return value for attribute put failures while
preserving the negative error returned by ip6mr_get_route() lets
userspace see the actual failure reason when multicast forwarding is
enabled.

This issue was pointed out during code review of rt6_fill_node() by
Hangbin Liu, confirmed on a UML kernel with MRT6_INIT enabled (where
"ip -6 route get ff0e::1 from 2001:db8::3 iif d0" reported "Message too
long" despite the failure in ip6mr_get_route() being -ENODEV), and
verified after the patch that it returns -ENODEV ("No such device")
instead while other rt6_fill_node() paths behave unchanged.

Built with W=1 on UML, x86_64 allmodconfig, and x86_64 allyesconfig with
zero new warnings or errors.

Suggested-by: Hangbin Liu <liuhangbin@xxxxxxxxxx>
Signed-off-by: Wenbo Sun <sunwenbo@xxxxxxxxxxxxxxxxxxxx>
---
net/ipv6/route.c | 11 +++++++----
1 file changed, 7 insertions(+), 4 deletions(-)

diff --git a/net/ipv6/route.c b/net/ipv6/route.c
index 6dd4a70f6490..11ce0db66484 100644
--- a/net/ipv6/route.c
+++ b/net/ipv6/route.c
@@ -5808,6 +5808,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
struct nlmsghdr *nlh;
struct rtmsg *rtm;
long expires = 0;
+ int err = -EMSGSIZE;

nlh = nlmsg_put(skb, portid, seq, type, sizeof(*rtm), flags);
if (!nlh)
@@ -5864,12 +5865,14 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,
#ifdef CONFIG_IPV6_MROUTE
if (ipv6_addr_is_multicast(&rt6_dst->addr) &&
atomic_read(&net->ipv6.devconf_all->mc_forwarding)) {
- int err = ip6mr_get_route(net, skb, rtm, portid);
+ int ret = ip6mr_get_route(net, skb, rtm, portid);

- if (err == 0)
+ if (ret == 0)
return 0;
- if (err < 0)
+ if (ret < 0) {
+ err = ret;
goto nla_put_failure;
+ }
} else
#endif
if (nla_put_u32(skb, RTA_IIF, iif))
@@ -5992,7 +5995,7 @@ static int rt6_fill_node(struct net *net, struct sk_buff *skb,

nla_put_failure:
nlmsg_cancel(skb, nlh);
- return -EMSGSIZE;
+ return err;
}

static int fib6_info_nh_uses_dev(struct fib6_nh *nh, void *arg)
--
2.33.0