From 1228a65963956300bd0466437530b975e0eaeec5 Mon Sep 17 00:00:00 2001
From: Thomas Haller <thaller@redhat.com>
Date: Mon, 6 Nov 2017 15:04:14 +0100
Subject: [PATCH 08/76] route: fix handling old_nh in rtnl_route_parse() and
 avoid leak

The previous code would miss to release old_nh in the error
path.

Also, it relied on the present netlink attributes to have old_nh
initialized. Don't do that.

Also, fixup error codes by using "goto errout_nomem" where appropriate
and keep @err as returned from rtnl_route_set_metric().
---
 lib/route/route_obj.c | 28 ++++++++++++++++++++--------
 1 file changed, 20 insertions(+), 8 deletions(-)

diff --git a/lib/route/route_obj.c b/lib/route/route_obj.c
index 8ae6b89..bc62408 100644
--- a/lib/route/route_obj.c
+++ b/lib/route/route_obj.c
@@ -1125,10 +1125,8 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 	int err, family;
 
 	route = rtnl_route_alloc();
-	if (!route) {
-		err = -NLE_NOMEM;
-		goto errout;
-	}
+	if (!route)
+		goto errout_nomem;
 
 	route->ce_msgtype = nlh->nlmsg_type;
 
@@ -1213,7 +1211,9 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 		for (i = 1; i <= RTAX_MAX; i++) {
 			if (mtb[i] && nla_len(mtb[i]) >= sizeof(uint32_t)) {
 				uint32_t m = nla_get_u32(mtb[i]);
-				if (rtnl_route_set_metric(route, i, m) < 0)
+
+				err = rtnl_route_set_metric(route, i, m);
+				if (err < 0)
 					goto errout;
 			}
 		}
@@ -1231,14 +1231,14 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 
 	if (tb[RTA_OIF]) {
 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
-			goto errout;
+			goto errout_nomem;
 
 		rtnl_route_nh_set_ifindex(old_nh, nla_get_u32(tb[RTA_OIF]));
 	}
 
 	if (tb[RTA_GATEWAY]) {
 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
-			goto errout;
+			goto errout_nomem;
 
 		if (!(addr = nl_addr_alloc_attr(tb[RTA_GATEWAY], family)))
 			goto errout_nomem;
@@ -1249,7 +1249,7 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 
 	if (tb[RTA_FLOW]) {
 		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
-			goto errout;
+			goto errout_nomem;
 
 		rtnl_route_nh_set_realms(old_nh, nla_get_u32(tb[RTA_FLOW]));
 	}
@@ -1257,6 +1257,9 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 	if (tb[RTA_NEWDST]) {
 		struct nl_addr *addr;
 
+		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+			goto errout_nomem;
+
 		addr = nl_addr_alloc_attr(tb[RTA_NEWDST], route->rt_family);
 		if (!addr)
 			goto errout_nomem;
@@ -1271,6 +1274,9 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 		int alen = nla_len(tb[RTA_VIA]) - offsetof(struct rtvia, rtvia_addr);
 		struct rtvia *via = nla_data(tb[RTA_VIA]);
 
+		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+			goto errout_nomem;
+
 		addr = nl_addr_build(via->rtvia_family, via->rtvia_addr, alen);
 		if (!addr)
 			goto errout_nomem;
@@ -1287,6 +1293,9 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 	}
 
 	if (tb[RTA_ENCAP] && tb[RTA_ENCAP_TYPE]) {
+		if (!old_nh && !(old_nh = rtnl_route_nh_alloc()))
+			goto errout_nomem;
+
 		err = nh_encap_parse_msg(tb[RTA_ENCAP],
 					 tb[RTA_ENCAP_TYPE], old_nh);
 		if (err)
@@ -1319,12 +1328,15 @@ int rtnl_route_parse(struct nlmsghdr *nlh, struct rtnl_route **result)
 
 			rtnl_route_nh_free(old_nh);
 		}
+		old_nh = NULL;
 	}
 
 	*result = route;
 	return 0;
 
 errout:
+	if (old_nh)
+		rtnl_route_nh_free(old_nh);
 	rtnl_route_put(route);
 	return err;
 
-- 
1.8.3.1

