CVE-2021-23270 (Other, published 2021-04-12T19:15Z)
Description: 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.
Severity: MEDIUM (CVSS v3 base score: 7.5)
Weakness: CWE-834 \u2014 Excessive Iteration
The product performs an iteration or loop without sufficiently limiting the number of times that the loop is executed.
Repository: https://github.com/ericpaulbishop/gargoyle
Files changed:
patches-generic/601-odhcp6c-CNVD-C-2021-04732.patch
patches-generic/602-netifd-CNVD-C-2021-04732.patch
Commit message: Fix IPv6 routing loops


Vulnerable code:

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
+