git: 188631e43a1a - main - rtnetlink: Check for allocation failure in nlattr_get_multipath()

From: Pouria Mousavizadeh Tehrani <pouria_at_FreeBSD.org>
Date: Wed, 13 May 2026 11:26:32 UTC
The branch main has been updated by pouria:

URL: https://cgit.FreeBSD.org/src/commit/?id=188631e43a1a5d2985156141c2e244a925670683

commit 188631e43a1a5d2985156141c2e244a925670683
Author:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
AuthorDate: 2026-05-11 19:53:21 +0000
Commit:     Pouria Mousavizadeh Tehrani <pouria@FreeBSD.org>
CommitDate: 2026-05-13 09:44:19 +0000

    rtnetlink: Check for allocation failure in nlattr_get_multipath()
    
    Check for alloction failure on `npt_alloc()` for RTA_MULTIPATH
    attributes in `nlattr_get_multipath()`.
    Also, add tests for maximum number of rtnexthop in rtnetlink.
    
    Reported by:    Joshua Rogers of AISLE Research Team
    Reviewed by:    markj
    MFC after:      3 days
    Differential Revision: https://reviews.freebsd.org/D56954
---
 sys/netlink/route/rt.c              |  4 +++
 tests/sys/netlink/test_rtnl_route.c | 55 +++++++++++++++++++++++++++++++++++++
 2 files changed, 59 insertions(+)

diff --git a/sys/netlink/route/rt.c b/sys/netlink/route/rt.c
index cb2d737f34e3..4d7b0a3e1fa3 100644
--- a/sys/netlink/route/rt.c
+++ b/sys/netlink/route/rt.c
@@ -470,6 +470,10 @@ nlattr_get_multipath(struct nlattr *nla, struct nl_pstate *npt,
 	max_nhops = data_len / sizeof(struct rtnexthop);
 
 	mp = npt_alloc(npt, (max_nhops + 2) * sizeof(struct rta_mpath_nh));
+	if (mp == NULL) {
+		NLMSG_REPORT_ERR_MSG(npt, "%s: too many RTA_MULTIPATH", __func__);
+		return (ENOMEM);
+	}
 	mp->num_nhops = 0;
 
 	for (rtnh = (struct rtnexthop *)(nla + 1); data_len > 0; ) {
diff --git a/tests/sys/netlink/test_rtnl_route.c b/tests/sys/netlink/test_rtnl_route.c
index 84d73db11cc7..334d1fea9fe9 100644
--- a/tests/sys/netlink/test_rtnl_route.c
+++ b/tests/sys/netlink/test_rtnl_route.c
@@ -18,6 +18,7 @@
 #include <netlink/netlink_snl_route_compat.h>
 #include <netlink/netlink_snl_route_parsers.h>
 
+#include <errno.h>
 #include <unistd.h>
 #include <time.h>
 
@@ -310,12 +311,66 @@ ATF_TC_BODY(rtnl_nhgrp_expire, tc)
 	cleanup_route_by_dst(&ss, &nw, "203.0.113.0");
 }
 
+ATF_TC(rtnl_nhgrp_big_nhops);
+ATF_TC_HEAD(rtnl_nhgrp_big_nhops, tc)
+{
+	atf_tc_set_md_var(tc, "descr", "test RTA_MULTIPATH with too many nhops using netlink");
+	atf_tc_set_md_var(tc, "require.user", "root");
+	atf_tc_set_md_var(tc, "require.kmods", "netlink");
+}
+
+ATF_TC_BODY(rtnl_nhgrp_big_nhops, tc)
+{
+	struct snl_state ss;
+	struct snl_writer nw;
+	struct nlmsghdr *hdr, *rx_hdr;
+	struct in_addr gw;
+	struct snl_errmsg_data e = {};
+	struct snl_parsed_route r = { .rtax_weight = RT_DEFAULT_WEIGHT };
+	struct rtmsg *rtm;
+	struct rtnexthop *rtnh;
+	int nhop, max_nhop, off, off2;
+
+	max_nhop = 25;
+	ATF_REQUIRE_MSG(snl_init(&ss, NETLINK_ROUTE), "snl_init() failed");
+
+	inet_pton(AF_INET, "127.0.2.1", &gw);
+
+	/* create new multipath route */
+	snl_init_writer(&ss, &nw);
+	ATF_REQUIRE((hdr = snl_create_msg_request(&nw, RTM_NEWROUTE)) != NULL);
+	hdr->nlmsg_flags |= NLM_F_CREATE;
+	ATF_REQUIRE((rtm = prepare_rtm_by_dst(&nw, "203.0.113.0")) != NULL);
+
+	off = snl_add_msg_attr_nested(&nw, RTA_MULTIPATH);
+	for (nhop = 0; nhop < max_nhop; nhop++) {
+		off2 = snl_get_msg_offset(&nw);
+		rtnh = snl_reserve_msg_object(&nw, struct rtnexthop);
+		rtnh->rtnh_flags = 0;
+		rtnh->rtnh_hops = nhop + 1;
+		rtnh->rtnh_ifindex = 0;
+		snl_add_msg_attr_ip4(&nw, RTA_GATEWAY, &gw);
+		rtnh = snl_restore_msg_offset(&nw, off2, struct rtnexthop);
+		rtnh->rtnh_len = snl_get_msg_offset(&nw) - off2;
+	}
+	snl_end_attr_nested(&nw, off);
+
+	ATF_REQUIRE((hdr = snl_finalize_msg(&nw)) != NULL);
+	ATF_REQUIRE(snl_send_message(&ss, hdr));
+	ATF_REQUIRE((rx_hdr = snl_read_reply(&ss, hdr->nlmsg_seq)) != NULL);
+	ATF_REQUIRE(snl_parse_errmsg(&ss, rx_hdr, &e));
+	ATF_REQUIRE_INTEQ(e.error, ENOMEM);
+
+	cleanup_route_by_dst(&ss, &nw, "203.0.113.0");
+}
+
 
 ATF_TP_ADD_TCS(tp)
 {
 	ATF_TP_ADD_TC(tp, rtnl_nhgrp);
 	ATF_TP_ADD_TC(tp, rtnl_nhgrp_expire);
 	ATF_TP_ADD_TC(tp, rtnl_nhop_merge);
+	ATF_TP_ADD_TC(tp, rtnl_nhgrp_big_nhops);
 
 	return (atf_no_error());
 }