naccyde / rpms / iproute

Forked from rpms/iproute 5 months ago
Clone

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

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