Blame SOURCES/0015-ip-route-Fix-segfault-with-many-nexthops.patch

930fb9
From 4620f13fc0f0e344421c0b9a0b8747734d3caf00 Mon Sep 17 00:00:00 2001
930fb9
From: Phil Sutter <psutter@redhat.com>
930fb9
Date: Wed, 19 Sep 2018 19:59:54 +0200
930fb9
Subject: [PATCH] ip-route: Fix segfault with many nexthops
930fb9
930fb9
Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=1625358
930fb9
Upstream Status: iproute2.git commit bd59e5b1517b0
930fb9
930fb9
commit bd59e5b1517b09b6f26d59f38fe6077d953c2396
930fb9
Author: Phil Sutter <phil@nwl.cc>
930fb9
Date:   Thu Sep 6 15:31:51 2018 +0200
930fb9
930fb9
    ip-route: Fix segfault with many nexthops
930fb9
930fb9
    It was possible to crash ip-route by adding an IPv6 route with 37
930fb9
    nexthop statements. A simple reproducer is:
930fb9
930fb9
    | for i in `seq 37`; do
930fb9
    |       nhs="nexthop via 1111::$i "$nhs
930fb9
    | done
930fb9
    | ip -6 route add 3333::/64 $nhs
930fb9
930fb9
    The related code was broken in multiple ways:
930fb9
930fb9
    * parse_one_nh() assumed that rta points to 4kB of storage but caller
930fb9
      provided just 1kB. Fixed by passing 'len' parameter with the correct
930fb9
      value.
930fb9
930fb9
    * Error checking of rta_addattr*() calls in parse_one_nh() and called
930fb9
      functions was completely absent, so with above fix in place output
930fb9
      flood would occur due to parser looping forever.
930fb9
930fb9
    While being at it, increase message buffer sizes to 4k. This allows for
930fb9
    at most 144 nexthops.
930fb9
930fb9
    Signed-off-by: Phil Sutter <phil@nwl.cc>
930fb9
    Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
930fb9
---
930fb9
 ip/iproute.c          |  43 ++++++++++++--------
930fb9
 ip/iproute_lwtunnel.c | 108 ++++++++++++++++++++++++++++++--------------------
930fb9
 2 files changed, 91 insertions(+), 60 deletions(-)
930fb9
930fb9
diff --git a/ip/iproute.c b/ip/iproute.c
930fb9
index 3083341..398322f 100644
930fb9
--- a/ip/iproute.c
930fb9
+++ b/ip/iproute.c
930fb9
@@ -941,7 +941,7 @@ int print_route(const struct sockaddr_nl *who, struct nlmsghdr *n, void *arg)
930fb9
 }
930fb9
 
930fb9
 static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
930fb9
-			struct rtattr *rta, struct rtnexthop *rtnh,
930fb9
+			struct rtattr *rta, size_t len, struct rtnexthop *rtnh,
930fb9
 			int *argcp, char ***argvp)
930fb9
 {
930fb9
 	int argc = *argcp;
930fb9
@@ -962,11 +962,16 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
930fb9
 			if (r->rtm_family == AF_UNSPEC)
930fb9
 				r->rtm_family = addr.family;
930fb9
 			if (addr.family == r->rtm_family) {
930fb9
-				rta_addattr_l(rta, 4096, RTA_GATEWAY, &addr.data, addr.bytelen);
930fb9
-				rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
930fb9
+				if (rta_addattr_l(rta, len, RTA_GATEWAY,
930fb9
+						  &addr.data, addr.bytelen))
930fb9
+					return -1;
930fb9
+				rtnh->rtnh_len += sizeof(struct rtattr)
930fb9
+						  + addr.bytelen;
930fb9
 			} else {
930fb9
-				rta_addattr_l(rta, 4096, RTA_VIA, &addr.family, addr.bytelen+2);
930fb9
-				rtnh->rtnh_len += RTA_SPACE(addr.bytelen+2);
930fb9
+				if (rta_addattr_l(rta, len, RTA_VIA,
930fb9
+						  &addr.family, addr.bytelen + 2))
930fb9
+					return -1;
930fb9
+				rtnh->rtnh_len += RTA_SPACE(addr.bytelen + 2);
930fb9
 			}
930fb9
 		} else if (strcmp(*argv, "dev") == 0) {
930fb9
 			NEXT_ARG();
930fb9
@@ -988,13 +993,15 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
930fb9
 			NEXT_ARG();
930fb9
 			if (get_rt_realms_or_raw(&realm, *argv))
930fb9
 				invarg("\"realm\" value is invalid\n", *argv);
930fb9
-			rta_addattr32(rta, 4096, RTA_FLOW, realm);
930fb9
+			if (rta_addattr32(rta, len, RTA_FLOW, realm))
930fb9
+				return -1;
930fb9
 			rtnh->rtnh_len += sizeof(struct rtattr) + 4;
930fb9
 		} else if (strcmp(*argv, "encap") == 0) {
930fb9
-			int len = rta->rta_len;
930fb9
+			int old_len = rta->rta_len;
930fb9
 
930fb9
-			lwt_parse_encap(rta, 4096, &argc, &argv);
930fb9
-			rtnh->rtnh_len += rta->rta_len - len;
930fb9
+			if (lwt_parse_encap(rta, len, &argc, &argv))
930fb9
+				return -1;
930fb9
+			rtnh->rtnh_len += rta->rta_len - old_len;
930fb9
 		} else if (strcmp(*argv, "as") == 0) {
930fb9
 			inet_prefix addr;
930fb9
 
930fb9
@@ -1002,8 +1009,9 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
930fb9
 			if (strcmp(*argv, "to") == 0)
930fb9
 				NEXT_ARG();
930fb9
 			get_addr(&addr, *argv, r->rtm_family);
930fb9
-			rta_addattr_l(rta, 4096, RTA_NEWDST, &addr.data,
930fb9
-				      addr.bytelen);
930fb9
+			if (rta_addattr_l(rta, len, RTA_NEWDST,
930fb9
+					  &addr.data, addr.bytelen))
930fb9
+				return -1;
930fb9
 			rtnh->rtnh_len += sizeof(struct rtattr) + addr.bytelen;
930fb9
 		} else
930fb9
 			break;
930fb9
@@ -1016,7 +1024,7 @@ static int parse_one_nh(struct nlmsghdr *n, struct rtmsg *r,
930fb9
 static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
930fb9
 			  int argc, char **argv)
930fb9
 {
930fb9
-	char buf[1024];
930fb9
+	char buf[4096];
930fb9
 	struct rtattr *rta = (void *)buf;
930fb9
 	struct rtnexthop *rtnh;
930fb9
 
930fb9
@@ -1036,7 +1044,7 @@ static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
930fb9
 		memset(rtnh, 0, sizeof(*rtnh));
930fb9
 		rtnh->rtnh_len = sizeof(*rtnh);
930fb9
 		rta->rta_len += rtnh->rtnh_len;
930fb9
-		if (parse_one_nh(n, r, rta, rtnh, &argc, &argv)) {
930fb9
+		if (parse_one_nh(n, r, rta, 4096, rtnh, &argc, &argv)) {
930fb9
 			fprintf(stderr, "Error: cannot parse nexthop\n");
930fb9
 			exit(-1);
930fb9
 		}
930fb9
@@ -1044,7 +1052,8 @@ static int parse_nexthops(struct nlmsghdr *n, struct rtmsg *r,
930fb9
 	}
930fb9
 
930fb9
 	if (rta->rta_len > RTA_LENGTH(0))
930fb9
-		addattr_l(n, 1024, RTA_MULTIPATH, RTA_DATA(rta), RTA_PAYLOAD(rta));
930fb9
+		return addattr_l(n, 4096, RTA_MULTIPATH,
930fb9
+				 RTA_DATA(rta), RTA_PAYLOAD(rta));
930fb9
 	return 0;
930fb9
 }
930fb9
 
930fb9
@@ -1053,7 +1062,7 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
930fb9
 	struct {
930fb9
 		struct nlmsghdr	n;
930fb9
 		struct rtmsg		r;
930fb9
-		char			buf[1024];
930fb9
+		char			buf[4096];
930fb9
 	} req = {
930fb9
 		.n.nlmsg_len = NLMSG_LENGTH(sizeof(struct rtmsg)),
930fb9
 		.n.nlmsg_flags = NLM_F_REQUEST | flags,
930fb9
@@ -1484,8 +1493,8 @@ static int iproute_modify(int cmd, unsigned int flags, int argc, char **argv)
930fb9
 		addattr_l(&req.n, sizeof(req), RTA_METRICS, RTA_DATA(mxrta), RTA_PAYLOAD(mxrta));
930fb9
 	}
930fb9
 
930fb9
-	if (nhs_ok)
930fb9
-		parse_nexthops(&req.n, &req.r, argc, argv);
930fb9
+	if (nhs_ok && parse_nexthops(&req.n, &req.r, argc, argv))
930fb9
+		return -1;
930fb9
 
930fb9
 	if (req.r.rtm_family == AF_UNSPEC)
930fb9
 		req.r.rtm_family = AF_INET;
930fb9
diff --git a/ip/iproute_lwtunnel.c b/ip/iproute_lwtunnel.c
930fb9
index e604481..969a476 100644
930fb9
--- a/ip/iproute_lwtunnel.c
930fb9
+++ b/ip/iproute_lwtunnel.c
930fb9
@@ -538,8 +538,9 @@ static int parse_encap_seg6(struct rtattr *rta, size_t len, int *argcp,
930fb9
 
930fb9
 	memcpy(tuninfo->srh, srh, srhlen);
930fb9
 
930fb9
-	rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
930fb9
-		      sizeof(*tuninfo) + srhlen);
930fb9
+	if (rta_addattr_l(rta, len, SEG6_IPTUNNEL_SRH, tuninfo,
930fb9
+			  sizeof(*tuninfo) + srhlen))
930fb9
+		return -1;
930fb9
 
930fb9
 	free(tuninfo);
930fb9
 	free(srh);
930fb9
@@ -611,6 +612,7 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
930fb9
 	char segbuf[1024];
930fb9
 	inet_prefix addr;
930fb9
 	__u32 hmac = 0;
930fb9
+	int ret = 0;
930fb9
 
930fb9
 	while (argc > 0) {
930fb9
 		if (strcmp(*argv, "action") == 0) {
930fb9
@@ -620,27 +622,28 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
930fb9
 			action = read_action_type(*argv);
930fb9
 			if (!action)
930fb9
 				invarg("\"action\" value is invalid\n", *argv);
930fb9
-			rta_addattr32(rta, len, SEG6_LOCAL_ACTION, action);
930fb9
+			ret = rta_addattr32(rta, len, SEG6_LOCAL_ACTION,
930fb9
+					    action);
930fb9
 		} else if (strcmp(*argv, "table") == 0) {
930fb9
 			NEXT_ARG();
930fb9
 			if (table_ok++)
930fb9
 				duparg2("table", *argv);
930fb9
 			get_u32(&table, *argv, 0);
930fb9
-			rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
930fb9
+			ret = rta_addattr32(rta, len, SEG6_LOCAL_TABLE, table);
930fb9
 		} else if (strcmp(*argv, "nh4") == 0) {
930fb9
 			NEXT_ARG();
930fb9
 			if (nh4_ok++)
930fb9
 				duparg2("nh4", *argv);
930fb9
 			get_addr(&addr, *argv, AF_INET);
930fb9
-			rta_addattr_l(rta, len, SEG6_LOCAL_NH4, &addr.data,
930fb9
-				      addr.bytelen);
930fb9
+			ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH4,
930fb9
+					    &addr.data, addr.bytelen);
930fb9
 		} else if (strcmp(*argv, "nh6") == 0) {
930fb9
 			NEXT_ARG();
930fb9
 			if (nh6_ok++)
930fb9
 				duparg2("nh6", *argv);
930fb9
 			get_addr(&addr, *argv, AF_INET6);
930fb9
-			rta_addattr_l(rta, len, SEG6_LOCAL_NH6, &addr.data,
930fb9
-				      addr.bytelen);
930fb9
+			ret = rta_addattr_l(rta, len, SEG6_LOCAL_NH6,
930fb9
+					    &addr.data, addr.bytelen);
930fb9
 		} else if (strcmp(*argv, "iif") == 0) {
930fb9
 			NEXT_ARG();
930fb9
 			if (iif_ok++)
930fb9
@@ -648,7 +651,7 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
930fb9
 			iif = ll_name_to_index(*argv);
930fb9
 			if (!iif)
930fb9
 				exit(nodev(*argv));
930fb9
-			rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
930fb9
+			ret = rta_addattr32(rta, len, SEG6_LOCAL_IIF, iif);
930fb9
 		} else if (strcmp(*argv, "oif") == 0) {
930fb9
 			NEXT_ARG();
930fb9
 			if (oif_ok++)
930fb9
@@ -656,7 +659,7 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
930fb9
 			oif = ll_name_to_index(*argv);
930fb9
 			if (!oif)
930fb9
 				exit(nodev(*argv));
930fb9
-			rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
930fb9
+			ret = rta_addattr32(rta, len, SEG6_LOCAL_OIF, oif);
930fb9
 		} else if (strcmp(*argv, "srh") == 0) {
930fb9
 			NEXT_ARG();
930fb9
 			if (srh_ok++)
930fb9
@@ -691,6 +694,8 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
930fb9
 		} else {
930fb9
 			break;
930fb9
 		}
930fb9
+		if (ret)
930fb9
+			return ret;
930fb9
 		argc--; argv++;
930fb9
 	}
930fb9
 
930fb9
@@ -705,14 +710,14 @@ static int parse_encap_seg6local(struct rtattr *rta, size_t len, int *argcp,
930fb9
 		srh = parse_srh(segbuf, hmac,
930fb9
 				action == SEG6_LOCAL_ACTION_END_B6_ENCAP);
930fb9
 		srhlen = (srh->hdrlen + 1) << 3;
930fb9
-		rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
930fb9
+		ret = rta_addattr_l(rta, len, SEG6_LOCAL_SRH, srh, srhlen);
930fb9
 		free(srh);
930fb9
 	}
930fb9
 
930fb9
 	*argcp = argc + 1;
930fb9
 	*argvp = argv - 1;
930fb9
 
930fb9
-	return 0;
930fb9
+	return ret;
930fb9
 }
930fb9
 
930fb9
 static int parse_encap_mpls(struct rtattr *rta, size_t len,
930fb9
@@ -730,8 +735,9 @@ static int parse_encap_mpls(struct rtattr *rta, size_t len,
930fb9
 		exit(1);
930fb9
 	}
930fb9
 
930fb9
-	rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST, &addr.data,
930fb9
-		      addr.bytelen);
930fb9
+	if (rta_addattr_l(rta, len, MPLS_IPTUNNEL_DST,
930fb9
+			  &addr.data, addr.bytelen))
930fb9
+		return -1;
930fb9
 
930fb9
 	argc--;
930fb9
 	argv++;
930fb9
@@ -745,7 +751,8 @@ static int parse_encap_mpls(struct rtattr *rta, size_t len,
930fb9
 				duparg2("ttl", *argv);
930fb9
 			if (get_u8(&ttl, *argv, 0))
930fb9
 				invarg("\"ttl\" value is invalid\n", *argv);
930fb9
-			rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl);
930fb9
+			if (rta_addattr8(rta, len, MPLS_IPTUNNEL_TTL, ttl))
930fb9
+				return -1;
930fb9
 		} else {
930fb9
 			break;
930fb9
 		}
930fb9
@@ -768,6 +775,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
930fb9
 	int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
930fb9
 	char **argv = *argvp;
930fb9
 	int argc = *argcp;
930fb9
+	int ret = 0;
930fb9
 
930fb9
 	while (argc > 0) {
930fb9
 		if (strcmp(*argv, "id") == 0) {
930fb9
@@ -778,7 +786,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
930fb9
 				duparg2("id", *argv);
930fb9
 			if (get_be64(&id, *argv, 0))
930fb9
 				invarg("\"id\" value is invalid\n", *argv);
930fb9
-			rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
930fb9
+			ret = rta_addattr64(rta, len, LWTUNNEL_IP_ID, id);
930fb9
 		} else if (strcmp(*argv, "dst") == 0) {
930fb9
 			inet_prefix addr;
930fb9
 
930fb9
@@ -786,8 +794,8 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
930fb9
 			if (dst_ok++)
930fb9
 				duparg2("dst", *argv);
930fb9
 			get_addr(&addr, *argv, AF_INET);
930fb9
-			rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
930fb9
-				      &addr.data, addr.bytelen);
930fb9
+			ret = rta_addattr_l(rta, len, LWTUNNEL_IP_DST,
930fb9
+					    &addr.data, addr.bytelen);
930fb9
 		} else if (strcmp(*argv, "tos") == 0) {
930fb9
 			__u32 tos;
930fb9
 
930fb9
@@ -796,7 +804,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
930fb9
 				duparg2("tos", *argv);
930fb9
 			if (rtnl_dsfield_a2n(&tos, *argv))
930fb9
 				invarg("\"tos\" value is invalid\n", *argv);
930fb9
-			rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
930fb9
+			ret = rta_addattr8(rta, len, LWTUNNEL_IP_TOS, tos);
930fb9
 		} else if (strcmp(*argv, "ttl") == 0) {
930fb9
 			__u8 ttl;
930fb9
 
930fb9
@@ -805,10 +813,12 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
930fb9
 				duparg2("ttl", *argv);
930fb9
 			if (get_u8(&ttl, *argv, 0))
930fb9
 				invarg("\"ttl\" value is invalid\n", *argv);
930fb9
-			rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
930fb9
+			ret = rta_addattr8(rta, len, LWTUNNEL_IP_TTL, ttl);
930fb9
 		} else {
930fb9
 			break;
930fb9
 		}
930fb9
+		if (ret)
930fb9
+			break;
930fb9
 		argc--; argv++;
930fb9
 	}
930fb9
 
930fb9
@@ -819,7 +829,7 @@ static int parse_encap_ip(struct rtattr *rta, size_t len,
930fb9
 	*argcp = argc + 1;
930fb9
 	*argvp = argv - 1;
930fb9
 
930fb9
-	return 0;
930fb9
+	return ret;
930fb9
 }
930fb9
 
930fb9
 static int parse_encap_ila(struct rtattr *rta, size_t len,
930fb9
@@ -828,6 +838,7 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
930fb9
 	__u64 locator;
930fb9
 	int argc = *argcp;
930fb9
 	char **argv = *argvp;
930fb9
+	int ret = 0;
930fb9
 
930fb9
 	if (get_addr64(&locator, *argv) < 0) {
930fb9
 		fprintf(stderr, "Bad locator: %s\n", *argv);
930fb9
@@ -836,7 +847,8 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
930fb9
 
930fb9
 	argc--; argv++;
930fb9
 
930fb9
-	rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator);
930fb9
+	if (rta_addattr64(rta, 1024, ILA_ATTR_LOCATOR, locator))
930fb9
+		return -1;
930fb9
 
930fb9
 	while (argc > 0) {
930fb9
 		if (strcmp(*argv, "csum-mode") == 0) {
930fb9
@@ -849,8 +861,8 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
930fb9
 				invarg("\"csum-mode\" value is invalid\n",
930fb9
 				       *argv);
930fb9
 
930fb9
-			rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
930fb9
-				     (__u8)csum_mode);
930fb9
+			ret = rta_addattr8(rta, 1024, ILA_ATTR_CSUM_MODE,
930fb9
+					   (__u8)csum_mode);
930fb9
 
930fb9
 			argc--; argv++;
930fb9
 		} else if (strcmp(*argv, "ident-type") == 0) {
930fb9
@@ -863,8 +875,8 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
930fb9
 				invarg("\"ident-type\" value is invalid\n",
930fb9
 				       *argv);
930fb9
 
930fb9
-			rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
930fb9
-				     (__u8)ident_type);
930fb9
+			ret = rta_addattr8(rta, 1024, ILA_ATTR_IDENT_TYPE,
930fb9
+					   (__u8)ident_type);
930fb9
 
930fb9
 			argc--; argv++;
930fb9
 		} else if (strcmp(*argv, "hook-type") == 0) {
930fb9
@@ -877,13 +889,15 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
930fb9
 				invarg("\"hook-type\" value is invalid\n",
930fb9
 				       *argv);
930fb9
 
930fb9
-			rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
930fb9
-				     (__u8)hook_type);
930fb9
+			ret = rta_addattr8(rta, 1024, ILA_ATTR_HOOK_TYPE,
930fb9
+					   (__u8)hook_type);
930fb9
 
930fb9
 			argc--; argv++;
930fb9
 		} else {
930fb9
 			break;
930fb9
 		}
930fb9
+		if (ret)
930fb9
+			break;
930fb9
 	}
930fb9
 
930fb9
 	/* argv is currently the first unparsed argument,
930fb9
@@ -893,7 +907,7 @@ static int parse_encap_ila(struct rtattr *rta, size_t len,
930fb9
 	*argcp = argc + 1;
930fb9
 	*argvp = argv - 1;
930fb9
 
930fb9
-	return 0;
930fb9
+	return ret;
930fb9
 }
930fb9
 
930fb9
 static int parse_encap_ip6(struct rtattr *rta, size_t len,
930fb9
@@ -902,6 +916,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
930fb9
 	int id_ok = 0, dst_ok = 0, tos_ok = 0, ttl_ok = 0;
930fb9
 	char **argv = *argvp;
930fb9
 	int argc = *argcp;
930fb9
+	int ret = 0;
930fb9
 
930fb9
 	while (argc > 0) {
930fb9
 		if (strcmp(*argv, "id") == 0) {
930fb9
@@ -912,7 +927,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
930fb9
 				duparg2("id", *argv);
930fb9
 			if (get_be64(&id, *argv, 0))
930fb9
 				invarg("\"id\" value is invalid\n", *argv);
930fb9
-			rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
930fb9
+			ret = rta_addattr64(rta, len, LWTUNNEL_IP6_ID, id);
930fb9
 		} else if (strcmp(*argv, "dst") == 0) {
930fb9
 			inet_prefix addr;
930fb9
 
930fb9
@@ -920,8 +935,8 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
930fb9
 			if (dst_ok++)
930fb9
 				duparg2("dst", *argv);
930fb9
 			get_addr(&addr, *argv, AF_INET6);
930fb9
-			rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
930fb9
-				      &addr.data, addr.bytelen);
930fb9
+			ret = rta_addattr_l(rta, len, LWTUNNEL_IP6_DST,
930fb9
+					    &addr.data, addr.bytelen);
930fb9
 		} else if (strcmp(*argv, "tc") == 0) {
930fb9
 			__u32 tc;
930fb9
 
930fb9
@@ -930,7 +945,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
930fb9
 				duparg2("tc", *argv);
930fb9
 			if (rtnl_dsfield_a2n(&tc, *argv))
930fb9
 				invarg("\"tc\" value is invalid\n", *argv);
930fb9
-			rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
930fb9
+			ret = rta_addattr8(rta, len, LWTUNNEL_IP6_TC, tc);
930fb9
 		} else if (strcmp(*argv, "hoplimit") == 0) {
930fb9
 			__u8 hoplimit;
930fb9
 
930fb9
@@ -940,10 +955,13 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
930fb9
 			if (get_u8(&hoplimit, *argv, 0))
930fb9
 				invarg("\"hoplimit\" value is invalid\n",
930fb9
 				       *argv);
930fb9
-			rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT, hoplimit);
930fb9
+			ret = rta_addattr8(rta, len, LWTUNNEL_IP6_HOPLIMIT,
930fb9
+					   hoplimit);
930fb9
 		} else {
930fb9
 			break;
930fb9
 		}
930fb9
+		if (ret)
930fb9
+			break;
930fb9
 		argc--; argv++;
930fb9
 	}
930fb9
 
930fb9
@@ -954,7 +972,7 @@ static int parse_encap_ip6(struct rtattr *rta, size_t len,
930fb9
 	*argcp = argc + 1;
930fb9
 	*argvp = argv - 1;
930fb9
 
930fb9
-	return 0;
930fb9
+	return ret;
930fb9
 }
930fb9
 
930fb9
 static void lwt_bpf_usage(void)
930fb9
@@ -1021,6 +1039,7 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
930fb9
 	int argc = *argcp;
930fb9
 	char **argv = *argvp;
930fb9
 	__u16 type;
930fb9
+	int ret = 0;
930fb9
 
930fb9
 	NEXT_ARG();
930fb9
 	type = read_encap_type(*argv);
930fb9
@@ -1037,37 +1056,40 @@ int lwt_parse_encap(struct rtattr *rta, size_t len, int *argcp, char ***argvp)
930fb9
 	nest = rta_nest(rta, 1024, RTA_ENCAP);
930fb9
 	switch (type) {
930fb9
 	case LWTUNNEL_ENCAP_MPLS:
930fb9
-		parse_encap_mpls(rta, len, &argc, &argv);
930fb9
+		ret = parse_encap_mpls(rta, len, &argc, &argv);
930fb9
 		break;
930fb9
 	case LWTUNNEL_ENCAP_IP:
930fb9
-		parse_encap_ip(rta, len, &argc, &argv);
930fb9
+		ret = parse_encap_ip(rta, len, &argc, &argv);
930fb9
 		break;
930fb9
 	case LWTUNNEL_ENCAP_ILA:
930fb9
-		parse_encap_ila(rta, len, &argc, &argv);
930fb9
+		ret = parse_encap_ila(rta, len, &argc, &argv);
930fb9
 		break;
930fb9
 	case LWTUNNEL_ENCAP_IP6:
930fb9
-		parse_encap_ip6(rta, len, &argc, &argv);
930fb9
+		ret = parse_encap_ip6(rta, len, &argc, &argv);
930fb9
 		break;
930fb9
 	case LWTUNNEL_ENCAP_BPF:
930fb9
 		if (parse_encap_bpf(rta, len, &argc, &argv) < 0)
930fb9
 			exit(-1);
930fb9
 		break;
930fb9
 	case LWTUNNEL_ENCAP_SEG6:
930fb9
-		parse_encap_seg6(rta, len, &argc, &argv);
930fb9
+		ret = parse_encap_seg6(rta, len, &argc, &argv);
930fb9
 		break;
930fb9
 	case LWTUNNEL_ENCAP_SEG6_LOCAL:
930fb9
-		parse_encap_seg6local(rta, len, &argc, &argv);
930fb9
+		ret = parse_encap_seg6local(rta, len, &argc, &argv);
930fb9
 		break;
930fb9
 	default:
930fb9
 		fprintf(stderr, "Error: unsupported encap type\n");
930fb9
 		break;
930fb9
 	}
930fb9
+	if (ret)
930fb9
+		return ret;
930fb9
+
930fb9
 	rta_nest_end(rta, nest);
930fb9
 
930fb9
-	rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
930fb9
+	ret = rta_addattr16(rta, 1024, RTA_ENCAP_TYPE, type);
930fb9
 
930fb9
 	*argcp = argc;
930fb9
 	*argvp = argv;
930fb9
 
930fb9
-	return 0;
930fb9
+	return ret;
930fb9
 }
930fb9
-- 
930fb9
1.8.3.1
930fb9