From: Robert Sanford <[email protected]>

When a prefix whose range ends at the top of the address space
(ffff:ffff:...:ffff) is added, deleted, or has its next hop changed,
modify_dp() walks the more-specific routes under it and installs the
next hop into the gaps. If the last of those routes starts exactly at
the current left edge and ends at the top of the address space, the
equal-edges branch advances ledge past it with get_nxt_net(), and
ledge wraps to ::. That branch has no wraparound check, so the loop
continues. With no more routes, the final branch computes redge,
which also wraps to ::. Its exception for an unspecified ledge, which
exists for a default route added as the first route, lets the call
through, and install_to_dp() with both edges at :: overwrites the
entire table. The call returns 0, so the corruption is silent.

For example, with ::/0, ::/1 and 8000::/1 installed, deleting ::/0
makes every lookup miss. With 2001:db8::/32 and two /121 routes at
ffff:...:ff00 and ffff:...:ff80 installed, adding their covering /120
makes every address, including 2001:db8::1, return the /120's next
hop.

The same commit added a wraparound check to the other branch only.
Add the same check to the equal-edges branch.

Fixes: fd66617c5774 ("fib6: fix adding default route as first route")
Cc: [email protected]

Signed-off-by: Robert Sanford <[email protected]>
---
 lib/fib/trie.c | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/lib/fib/trie.c b/lib/fib/trie.c
index 187360d1c8..59f043ce0e 100644
--- a/lib/fib/trie.c
+++ b/lib/fib/trie.c
@@ -506,6 +506,12 @@ modify_dp(struct rte_trie_tbl *dp, struct rte_rib6 *rib,
                        rte_rib6_get_ip(tmp, &redge);
                        if (rte_ipv6_addr_eq(&ledge, &redge)) {
                                get_nxt_net(&ledge, tmp_depth);
+                               /*
+                                * we got to the end of address space
+                                * and wrapped around
+                                */
+                               if (rte_ipv6_addr_is_unspec(&ledge))
+                                       break;
                                continue;
                        }
                        ret = install_to_dp(dp, &ledge, &redge, next_hop);
-- 
2.34.1

Reply via email to