From: Owen Hilyard Date: Wed, 23 Jun 2021 15:17:29 +0000 (-0400) Subject: rib: fix max depth IPv6 lookup X-Git-Url: http://git.droids-corp.org/?a=commitdiff_plain;h=03b8372a9a73;p=dpdk.git rib: fix max depth IPv6 lookup ASAN found a stack buffer overflow in lib/rib/rte_rib6.c:get_dir. The fix for the stack buffer overflow was to make sure depth was always < 128, since when depth = 128 it caused the index into the ip address to be 16, which read off the end of the array. While trying to solve the buffer overflow, I noticed that a few changes could be made to remove the for loop entirely. Fixes: f7e861e21c46 ("rib: support IPv6") Cc: stable@dpdk.org Signed-off-by: Owen Hilyard Acked-by: Vladimir Medvedkin --- diff --git a/lib/rib/rte_rib6.c b/lib/rib/rte_rib6.c index f6c55ee454..96424e9c9f 100644 --- a/lib/rib/rte_rib6.c +++ b/lib/rib/rte_rib6.c @@ -79,20 +79,33 @@ is_covered(const uint8_t ip1[RTE_RIB6_IPV6_ADDR_SIZE], static inline int get_dir(const uint8_t ip[RTE_RIB6_IPV6_ADDR_SIZE], uint8_t depth) { - int i = 0; - uint8_t p_depth, msk; - - for (p_depth = depth; p_depth >= 8; p_depth -= 8) - i++; - - msk = 1 << (7 - p_depth); - return (ip[i] & msk) != 0; + uint8_t index, msk; + + /* + * depth & 127 clamps depth to values that will not + * read off the end of ip. + * depth is the number of bits deep into ip to traverse, and + * is incremented in blocks of 8 (1 byte). This means the last + * 3 bits are irrelevant to what the index of ip should be. + */ + index = (depth & (UINT8_MAX - 1)) / CHAR_BIT; + + /* + * msk is the bitmask used to extract the bit used to decide the + * direction of the next step of the binary search. + */ + msk = 1 << (7 - (depth & 7)); + + return (ip[index] & msk) != 0; } static inline struct rte_rib6_node * get_nxt_node(struct rte_rib6_node *node, const uint8_t ip[RTE_RIB6_IPV6_ADDR_SIZE]) { + if (node->depth == RIB6_MAXDEPTH) + return NULL; + return (get_dir(ip, node->depth)) ? node->right : node->left; }