git: e215460dae3a - stable/14 - netlink/route: fix nlattr_get_multipath() to check length

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Mon, 31 Mar 2025 17:31:40 UTC
The branch stable/14 has been updated by glebius:

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

commit e215460dae3a8ff00ed0e78f978425464da36a3e
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-01-29 18:22:46 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-03-31 17:31:21 +0000

    netlink/route: fix nlattr_get_multipath() to check length
    
    of supplied nexthop sub-attributes.  While here, use unsigned types for
    length calculations and improve style(9).
    
    PR:                     283860
    (cherry picked from commit 49a6e213416b5c0c9eccdff0af1c6b01f34c3693)
---
 sys/netlink/route/rt.c | 32 ++++++++++++++++++++++----------
 1 file changed, 22 insertions(+), 10 deletions(-)

diff --git a/sys/netlink/route/rt.c b/sys/netlink/route/rt.c
index 679260e54322..410b1b04b6fc 100644
--- a/sys/netlink/route/rt.c
+++ b/sys/netlink/route/rt.c
@@ -425,33 +425,45 @@ post_p_rtnh(void *_attrs, struct nl_pstate *npt __unused)
 NL_DECLARE_PARSER_EXT(mpath_parser, struct rtnexthop, NULL, nlf_p_rtnh, nla_p_rtnh, post_p_rtnh);
 
 struct rta_mpath {
-	int num_nhops;
+	u_int num_nhops;
 	struct rta_mpath_nh nhops[0];
 };
 
 static int
-nlattr_get_multipath(struct nlattr *nla, struct nl_pstate *npt, const void *arg, void *target)
+nlattr_get_multipath(struct nlattr *nla, struct nl_pstate *npt,
+    const void *arg, void *target)
 {
-	int data_len = nla->nla_len - sizeof(struct nlattr);
+	struct rta_mpath *mp;
 	struct rtnexthop *rtnh;
+	uint16_t data_len, len;
+	u_int max_nhops;
+	int error;
 
-	int max_nhops = data_len / sizeof(struct rtnexthop);
+	data_len = nla->nla_len - sizeof(struct nlattr);
+	max_nhops = data_len / sizeof(struct rtnexthop);
 
-	struct rta_mpath *mp = npt_alloc(npt, (max_nhops + 2) * sizeof(struct rta_mpath_nh));
+	mp = npt_alloc(npt, (max_nhops + 2) * sizeof(struct rta_mpath_nh));
 	mp->num_nhops = 0;
 
 	for (rtnh = (struct rtnexthop *)(nla + 1); data_len > 0; ) {
-		struct rta_mpath_nh *mpnh = &mp->nhops[mp->num_nhops++];
+		struct rta_mpath_nh *mpnh;
 
-		int error = nl_parse_header(rtnh, rtnh->rtnh_len, &mpath_parser,
+		if (__predict_false(rtnh->rtnh_len <= sizeof(*rtnh) ||
+		    rtnh->rtnh_len > data_len)) {
+			NLMSG_REPORT_ERR_MSG(npt, "%s: bad length %u",
+			    __func__, rtnh->rtnh_len);
+			return (EINVAL);
+		}
+		mpnh = &mp->nhops[mp->num_nhops++];
+		error = nl_parse_header(rtnh, rtnh->rtnh_len, &mpath_parser,
 		    npt, mpnh);
 		if (error != 0) {
-			NLMSG_REPORT_ERR_MSG(npt, "RTA_MULTIPATH: nexhop %d: parse failed",
+			NLMSG_REPORT_ERR_MSG(npt,
+			    "RTA_MULTIPATH: nexthop %u: parse failed",
 			    mp->num_nhops - 1);
 			return (error);
 		}
-
-		int len = NL_ITEM_ALIGN(rtnh->rtnh_len);
+		len = NL_ITEM_ALIGN(rtnh->rtnh_len);
 		data_len -= len;
 		rtnh = (struct rtnexthop *)((char *)rtnh + len);
 	}