CVE-2021-23270: Excessive Iteration (CWE-834)
value: In Gargoyle OS 1.12.0, when IPv6 is used, a routing loop can occur that generates excessive network traffic between an affected device and its upstream ISP's router. This occurs when a link prefix route points to a point-to-point link, a destination IPv6 address belongs to the prefix and is not a local IPv6 address, and a router advertisement is received with at least one global unique IPv6 prefix for which the on-link flag is set.
CWE description: The product performs an iteration or loop without sufficiently limiting the number of times that the loop is executed.
CVSS v3 base score: 7.5
Published: 2021-04-12T19:15Z
Repository: https://github.com/ericpaulbishop/gargoyle
Language: Other
Files changed: patches-generic/601-odhcp6c-CNVD-C-2021-04732.patch, patches-generic/602-netifd-CNVD-C-2021-04732.patch
Commit date: 2021-01-20 18:05:51 +1100
Commit message: Fix IPv6 routing loops

Diff: diff --git a/patches-generic/601-odhcp6c-CNVD-C-2021-04732.patch b/patches-generic/601-odhcp6c-CNVD-C-2021-04732.patch
new file mode 100644
index 00000000..73552010
--- /dev/null
+++ b/patches-generic/601-odhcp6c-CNVD-C-2021-04732.patch
@@ -0,0 +1,118 @@
+--- /dev/null
++++ b/package/network/ipv6/odhcp6c/patches/001-ra-align-ifindex-resolving.patch
+@@ -0,0 +1,52 @@
++From 2b6959dfe2095402e004b63d9aca9900c074abb6 Mon Sep 17 00:00:00 2001
++From: Hans Dedecker <dedeckeh@gmail.com>
++Date: Wed, 6 Jan 2021 21:15:49 +0100
++Subject: [PATCH] ra: align ifindex resolving
++
++Use ioctl SIOCGIFINDEX to resolve ifindex similar as in init_dhcpv6
++
++Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
++---
++ src/ra.c | 10 +++++++---
++ 1 file changed, 7 insertions(+), 3 deletions(-)
++
++diff --git a/src/ra.c b/src/ra.c
++index 337c0bd..32a3097 100644
++--- a/src/ra.c
+++++ b/src/ra.c
++@@ -27,6 +27,7 @@
++ 
++ #include <net/if.h>
++ #include <arpa/inet.h>
+++#include <sys/ioctl.h>
++ #include <sys/socket.h>
++ #include <sys/types.h>
++ #include <netinet/in.h>
++@@ -76,6 +77,8 @@ static void ra_send_rs(int signal __attribute__((unused)));
++ int ra_init(const char *ifname, const struct in6_addr *ifid,
++ 		unsigned int options, unsigned int holdoff_interval)
++ {
+++	struct ifreq ifr;
+++
++ 	ra_options = options;
++ 	ra_holdoff_interval = holdoff_interval;
++ 
++@@ -84,11 +87,12 @@ int ra_init(const char *ifname, const struct in6_addr *ifid,
++ 	if (sock < 0)
++ 		goto failure;
++ 
++-	if_index = if_nametoindex(ifname);
++-	if (!if_index)
+++	memset(&ifr, 0, sizeof(ifr));
+++	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+++	if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
++ 		goto failure;
++ 
++-	strncpy(if_name, ifname, sizeof(if_name) - 1);
+++	if_index = ifr.ifr_ifindex;
++ 	lladdr = *ifid;
++ 
++ 	rtnl = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
++-- 
++2.20.1
++
+--- /dev/null
++++ b/package/network/ipv6/odhcp6c/patches/002-ra-fix-routing-loop-ppp-links.patch
+@@ -0,0 +1,60 @@
++From 53f07e90b7f1da6977143a488dd5cb73a33b233b Mon Sep 17 00:00:00 2001
++From: Hans Dedecker <dedeckeh@gmail.com>
++Date: Sat, 9 Jan 2021 21:17:48 +0100
++Subject: [PATCH] ra: fix routing loop on point to point links
++
++For point-to-point links (e.g. PPP) don't create a link prefix route
++when receiving a prefix information option with the on-link flag set.
++Point-to-point links are non shared media and as such a destination
++IPv6 address cannot be on-link.
++If a link prefix route points to a point-to-point link it can trigger
++a routing loop if the destination IPv6 address belongs to the prefix.
++If such a packet is received and not directed to a local IPv6 address
++it will be routed to the point-to-point link due to the link prefix route;
++the upstream ISP router will route the IPv6 packet back due to the assigned
++prefix route creating a "ping pong" effect
++
++Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
++---
++ src/ra.c | 11 ++++++++++-
++ 1 file changed, 10 insertions(+), 1 deletion(-)
++
++diff --git a/src/ra.c b/src/ra.c
++index 32a3097..4e6dd64 100644
++--- a/src/ra.c
+++++ b/src/ra.c
++@@ -51,6 +51,7 @@
++ #include "ra.h"
++ 
++ static bool nocarrier = false;
+++static bool ptp_link = false;
++ 
++ static int sock = -1, rtnl = -1;
++ static int if_index = 0;
++@@ -87,6 +88,13 @@ int ra_init(const char *ifname, const struct in6_addr *ifid,
++ 	if (sock < 0)
++ 		goto failure;
++ 
+++	memset(&ifr, 0, sizeof(ifr));
+++	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+++	if (ioctl(sock, SIOCGIFFLAGS, &ifr) < 0)
+++		goto failure;
+++
+++	ptp_link = !!(ifr.ifr_flags & IFF_POINTOPOINT);
+++
++ 	memset(&ifr, 0, sizeof(ifr));
++ 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
++ 	if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
++@@ -488,7 +496,8 @@ bool ra_process(void)
++ 						|| entry->valid < entry->preferred)
++ 					continue;
++ 
++-				if (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
+++				if ((pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK) &&
+++				    !ptp_link)
++ 					changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
++ 									7200, ra_holdoff_interval);
++ 
++-- 
++2.20.1
++
diff --git a/patches-generic/602-netifd-CNVD-C-2021-04732.patch b/patches-generic/602-netifd-CNVD-C-2021-04732.patch
new file mode 100644
index 00000000..3fa169d2
--- /dev/null
+++ b/patches-generic/602-netifd-CNVD-C-2021-04732.patch
@@ -0,0 +1,131 @@
+--- /dev/null
++++ b/package/network/config/netifd/patches/001-interface_ip-add-unreachable-route-offlink-address.patch
+@@ -0,0 +1,128 @@
++From c00c8335d6188daa326ecfe5a62da15a9b9987e1 Mon Sep 17 00:00:00 2001
++From: Hans Dedecker <dedeckeh@gmail.com>
++Date: Sat, 9 Jan 2021 21:18:45 +0100
++Subject: [PATCH] interface-ip: add unreachable route if address is offlink
++
++In order to avoid a routing loop add an unreachable route for the
++address prefix is the offlink flag is set for an address.
++This fixes a routing loop which is currently present on point-to-point
++links (e.g PPP) when the wan interface is assigned a globally unique
++prefix (e.g. 2001:db8:1:0::/64) from which an IPv6 address is picked
++and installed on the wan interface
++(e.g. 2001:db8:1:0:5054:ff:feab:d87c/64)
++
++The prefix route 2001:db8:1::/64 would be present in the routing table
++which will route any packet with as destination 2001:db8:1::/64 to the wan
++interface and would be routed back by the upstream router due to the
++wan interface due to the assigned global unique prefix.
++Besides not installing the prefix route 2001:db8:1::/64 on point-to-point links
++adding an unreachable route is required to avoid the routing loop.
++
++Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
++---
++ interface-ip.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++
++ 1 file changed, 69 insertions(+)
++
++diff --git a/interface-ip.c b/interface-ip.c
++index 3768000..1444fbf 100644
++--- a/interface-ip.c
+++++ b/interface-ip.c
++@@ -684,6 +684,22 @@ interface_update_proto_addr(struct vlist_tree *tree,
++ 			if (!(a_old->flags & DEVADDR_EXTERNAL)) {
++ 				interface_handle_subnet_route(iface, a_old, false);
++ 				system_del_address(dev, a_old);
+++
+++				if ((a_old->flags & DEVADDR_OFFLINK) && (a_old->mask < (v6 ? 128 : 32))) {
+++					struct device_route route;
+++
+++					memset(&route, 0, sizeof(route));
+++					route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
+++					route.metric = INT32_MAX;
+++					route.mask = a_old->mask;
+++					route.addr = a_old->addr;
+++
+++					clear_if_addr(&route.addr, route.mask);
+++
+++					/* Delete null-route */
+++					system_del_route(NULL, &route);
+++				}
+++
++ 			}
++ 		}
++ 		free(a_old->pclass);
++@@ -708,6 +724,26 @@ interface_update_proto_addr(struct vlist_tree *tree,
++ 			}
++ 
++ 			if (!keep) {
+++				if (!(a_new->flags & DEVADDR_EXTERNAL) &&
+++				    (a_new->flags & DEVADDR_OFFLINK) &&
+++				    (a_new->mask < (v6 ? 128 : 32))) {
+++					struct device_route route;
+++
+++					memset(&route, 0, sizeof(route));
+++					route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
+++					route.metric = INT32_MAX;
+++					route.mask = a_new->mask;
+++					route.addr = a_new->addr;
+++
+++					clear_if_addr(&route.addr, route.mask);
+++
+++					/*
+++					 * In case off link is specifed as address property
+++					 * add null-route to avoid routing loops
+++					 */
+++					system_add_route(NULL, &route);
+++				}
+++
++ 				if (a_new->policy_table)
++ 					interface_add_addr_rules(a_new, true);
++ 			}
++@@ -1578,12 +1614,45 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
++ 			if (iface->metric || addr->policy_table)
++ 				interface_handle_subnet_route(iface, addr, true);
++ 
+++			if ((addr->flags & DEVADDR_OFFLINK) && (addr->mask < (v6 ? 128 : 32))) {
+++				struct device_route route;
+++
+++				memset(&route, 0, sizeof(route));
+++				route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
+++				route.metric = INT32_MAX;
+++				route.mask = addr->mask;
+++				route.addr = addr->addr;
+++
+++				clear_if_addr(&route.addr, route.mask);
+++
+++				/*
+++				 * In case off link is specifed as address property
+++				 * add null-route to avoid routing loops
+++				 */
+++				system_add_route(NULL, &route);
+++			}
+++
++ 			if (addr->policy_table)
++ 				interface_add_addr_rules(addr, true);
++ 		} else {
++ 			interface_handle_subnet_route(iface, addr, false);
++ 			system_del_address(dev, addr);
++ 
+++			if ((addr->flags & DEVADDR_OFFLINK) && (addr->mask < (v6 ? 128 : 32))) {
+++				struct device_route route;
+++
+++				memset(&route, 0, sizeof(route));
+++				route.flags = v6 ? DEVADDR_INET6 : DEVADDR_INET4;
+++				route.metric = INT32_MAX;
+++				route.mask = addr->mask;
+++				route.addr = addr->addr;
+++
+++				clear_if_addr(&route.addr, route.mask);
+++
+++				/* Delete null-route */
+++				system_del_route(NULL, &route);
+++			}
+++
++ 			if (addr->policy_table)
++ 				interface_add_addr_rules(addr, false);
++ 		}
++-- 
++2.20.1
++

Fixed code: --- /dev/null
@@ -0,0 +1,52 @@
+From 2b6959dfe2095402e004b63d9aca9900c074abb6 Mon Sep 17 00:00:00 2001
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Wed, 6 Jan 2021 21:15:49 +0100
+Subject: [PATCH] ra: align ifindex resolving
+
+Use ioctl SIOCGIFINDEX to resolve ifindex similar as in init_dhcpv6
+
+Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+---
+ src/ra.c | 10 +++++++---
+ 1 file changed, 7 insertions(+), 3 deletions(-)
+
+diff --git a/src/ra.c b/src/ra.c
+index 337c0bd..32a3097 100644
+--- a/src/ra.c
+@@ -27,6 +27,7 @@
+ 
+ #include <net/if.h>
+ #include <arpa/inet.h>
+ #include <sys/socket.h>
+ #include <sys/types.h>
+ #include <netinet/in.h>
+@@ -76,6 +77,8 @@ static void ra_send_rs(int signal __attribute__((unused)));
+ int ra_init(const char *ifname, const struct in6_addr *ifid,
+ 		unsigned int options, unsigned int holdoff_interval)
+ {
+ 	ra_options = options;
+ 	ra_holdoff_interval = holdoff_interval;
+ 
+@@ -84,11 +87,12 @@ int ra_init(const char *ifname, const struct in6_addr *ifid,
+ 	if (sock < 0)
+ 		goto failure;
+ 
+-	if_index = if_nametoindex(ifname);
+-	if (!if_index)
+ 		goto failure;
+ 
+-	strncpy(if_name, ifname, sizeof(if_name) - 1);
+ 	lladdr = *ifid;
+ 
+ 	rtnl = socket(AF_NETLINK, SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
+-- 
+2.20.1
+
--- /dev/null
@@ -0,0 +1,60 @@
+From 53f07e90b7f1da6977143a488dd5cb73a33b233b Mon Sep 17 00:00:00 2001
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Sat, 9 Jan 2021 21:17:48 +0100
+Subject: [PATCH] ra: fix routing loop on point to point links
+
+For point-to-point links (e.g. PPP) don't create a link prefix route
+when receiving a prefix information option with the on-link flag set.
+Point-to-point links are non shared media and as such a destination
+IPv6 address cannot be on-link.
+If a link prefix route points to a point-to-point link it can trigger
+a routing loop if the destination IPv6 address belongs to the prefix.
+If such a packet is received and not directed to a local IPv6 address
+it will be routed to the point-to-point link due to the link prefix route;
+the upstream ISP router will route the IPv6 packet back due to the assigned
+prefix route creating a "ping pong" effect
+
+Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+---
+ src/ra.c | 11 ++++++++++-
+ 1 file changed, 10 insertions(+), 1 deletion(-)
+
+diff --git a/src/ra.c b/src/ra.c
+index 32a3097..4e6dd64 100644
+--- a/src/ra.c
+@@ -51,6 +51,7 @@
+ #include "ra.h"
+ 
+ static bool nocarrier = false;
+ 
+ static int sock = -1, rtnl = -1;
+ static int if_index = 0;
+@@ -87,6 +88,13 @@ int ra_init(const char *ifname, const struct in6_addr *ifid,
+ 	if (sock < 0)
+ 		goto failure;
+ 
+ 	memset(&ifr, 0, sizeof(ifr));
+ 	strncpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name) - 1);
+ 	if (ioctl(sock, SIOCGIFINDEX, &ifr) < 0)
+@@ -488,7 +496,8 @@ bool ra_process(void)
+ 						|| entry->valid < entry->preferred)
+ 					continue;
+ 
+-				if (pinfo->nd_opt_pi_flags_reserved & ND_OPT_PI_FLAG_ONLINK)
+ 					changed |= odhcp6c_update_entry(STATE_RA_ROUTE, entry,
+ 									7200, ra_holdoff_interval);
+ 
+-- 
+2.20.1
+
--- /dev/null
@@ -0,0 +1,128 @@
+From c00c8335d6188daa326ecfe5a62da15a9b9987e1 Mon Sep 17 00:00:00 2001
+From: Hans Dedecker <dedeckeh@gmail.com>
+Date: Sat, 9 Jan 2021 21:18:45 +0100
+Subject: [PATCH] interface-ip: add unreachable route if address is offlink
+
+In order to avoid a routing loop add an unreachable route for the
+address prefix is the offlink flag is set for an address.
+This fixes a routing loop which is currently present on point-to-point
+links (e.g PPP) when the wan interface is assigned a globally unique
+prefix (e.g. 2001:db8:1:0::/64) from which an IPv6 address is picked
+and installed on the wan interface
+(e.g. 2001:db8:1:0:5054:ff:feab:d87c/64)
+
+The prefix route 2001:db8:1::/64 would be present in the routing table
+which will route any packet with as destination 2001:db8:1::/64 to the wan
+interface and would be routed back by the upstream router due to the
+wan interface due to the assigned global unique prefix.
+Besides not installing the prefix route 2001:db8:1::/64 on point-to-point links
+adding an unreachable route is required to avoid the routing loop.
+
+Signed-off-by: Hans Dedecker <dedeckeh@gmail.com>
+---
+ interface-ip.c | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 69 insertions(+)
+
+diff --git a/interface-ip.c b/interface-ip.c
+index 3768000..1444fbf 100644
+--- a/interface-ip.c
+@@ -684,6 +684,22 @@ interface_update_proto_addr(struct vlist_tree *tree,
+ 			if (!(a_old->flags & DEVADDR_EXTERNAL)) {
+ 				interface_handle_subnet_route(iface, a_old, false);
+ 				system_del_address(dev, a_old);
+ 			}
+ 		}
+ 		free(a_old->pclass);
+@@ -708,6 +724,26 @@ interface_update_proto_addr(struct vlist_tree *tree,
+ 			}
+ 
+ 			if (!keep) {
+ 				if (a_new->policy_table)
+ 					interface_add_addr_rules(a_new, true);
+ 			}
+@@ -1578,12 +1614,45 @@ void interface_ip_set_enabled(struct interface_ip_settings *ip, bool enabled)
+ 			if (iface->metric || addr->policy_table)
+ 				interface_handle_subnet_route(iface, addr, true);
+ 
+ 			if (addr->policy_table)
+ 				interface_add_addr_rules(addr, true);
+ 		} else {
+ 			interface_handle_subnet_route(iface, addr, false);
+ 			system_del_address(dev, addr);
+ 
+ 			if (addr->policy_table)
+ 				interface_add_addr_rules(addr, false);
+ 		}
+-- 
+2.20.1
+