From 108217f4bb1afb8b25fc705c2722b3e328b1ad78 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jo=C3=A3o=20Valverde?= Date: Sat, 16 Sep 2023 06:59:12 +0100 Subject: [PATCH] addr_resolv: Fix a heap buffer overflow Make sure we always pass at least 6 bytes to ws_manuf_lookup_str(). Fixes #19344. --- epan/addr_resolv.c | 29 +++++++++++++++++++++-------- epan/addr_resolv.h | 4 ++-- epan/address_types.c | 4 ++-- 3 files changed, 25 insertions(+), 12 deletions(-) diff --git a/epan/addr_resolv.c b/epan/addr_resolv.c index 3e0cc6d..4a6be03 100644 --- a/epan/addr_resolv.c +++ b/epan/addr_resolv.c @@ -1607,12 +1607,16 @@ add_manuf_name(const guint8 *addr, unsigned int mask, gchar *name, gchar *longna } /* add_manuf_name */ static hashmanuf_t * -manuf_name_lookup(const guint8 *addr) +manuf_name_lookup(const guint8 *addr, size_t size) { guint32 manuf_key; guint8 oct; hashmanuf_t *manuf_value; + if (size < 6) { + return NULL; + } + /* manuf needs only the 3 most significant octets of the ethernet address */ manuf_key = addr[0]; manuf_key = manuf_key<<8; @@ -1773,6 +1777,7 @@ eth_addr_resolve(hashether_t *tp) { ether_t *eth; hashmanuf_t *manuf_value; const guint8 *addr = tp->addr; + size_t addr_size = sizeof(tp->addr); if ( (eth = get_ethbyaddr(addr)) != NULL) { (void) g_strlcpy(tp->resolved_name, eth->name, MAXNAMELEN); @@ -1819,7 +1824,7 @@ eth_addr_resolve(hashether_t *tp) { } while (mask--); /* Now try looking in the manufacturer table. */ - manuf_value = manuf_name_lookup(addr); + manuf_value = manuf_name_lookup(addr, addr_size); if ((manuf_value != NULL) && (manuf_value->status != HASHETHER_STATUS_UNRESOLVED)) { g_snprintf(tp->resolved_name, MAXNAMELEN, "%s_%02x:%02x:%02x", manuf_value->resolved_name, addr[3], addr[4], addr[5]); @@ -3378,11 +3383,11 @@ get_vlan_name(wmem_allocator_t *allocator, const guint16 id) } /* get_vlan_name */ const gchar * -get_manuf_name(const guint8 *addr) +get_manuf_name(const guint8 *addr, size_t size) { hashmanuf_t *manuf_value; - manuf_value = manuf_name_lookup(addr); + manuf_value = manuf_name_lookup(addr, size); if (gbl_resolv_flags.mac_name && manuf_value->status != HASHETHER_STATUS_UNRESOLVED) return manuf_value->resolved_name; @@ -3393,16 +3398,22 @@ get_manuf_name(const guint8 *addr) const gchar * tvb_get_manuf_name(tvbuff_t *tvb, gint offset) { - return get_manuf_name(tvb_get_ptr(tvb, offset, 3)); + guint8 buf[6] = { 0 }; + tvb_memcpy(tvb, buf, offset, 3); + return get_manuf_name(buf, sizeof(buf)); } const gchar * -get_manuf_name_if_known(const guint8 *addr) +get_manuf_name_if_known(const guint8 *addr, size_t size) { hashmanuf_t *manuf_value; guint manuf_key; guint8 oct; + if (size != 6) { + return NULL; + } + /* manuf needs only the 3 most significant octets of the ethernet address */ manuf_key = addr[0]; manuf_key = manuf_key<<8; @@ -3437,7 +3448,9 @@ uint_get_manuf_name_if_known(const guint manuf_key) const gchar * tvb_get_manuf_name_if_known(tvbuff_t *tvb, gint offset) { - return get_manuf_name_if_known(tvb_get_ptr(tvb, offset, 3)); + guint8 buf[6] = { 0 }; + tvb_memcpy(tvb, buf, offset, 3); + return get_manuf_name_if_known(buf, sizeof(buf)); } char* get_hash_manuf_resolved_name(hashmanuf_t* manuf) @@ -3455,7 +3468,7 @@ eui64_to_display(wmem_allocator_t *allocator, const guint64 addr_eui64) /* Copy and convert the address to network byte order. */ *(guint64 *)(void *)(addr) = pntoh64(&(addr_eui64)); - manuf_value = manuf_name_lookup(addr); + manuf_value = manuf_name_lookup(addr, 8); if (!gbl_resolv_flags.mac_name || (manuf_value->status == HASHETHER_STATUS_UNRESOLVED)) { ret = wmem_strdup_printf(allocator, "%02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x", addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]); } else { diff --git a/epan/addr_resolv.h b/epan/addr_resolv.h index 313e8f9..362682c 100644 --- a/epan/addr_resolv.h +++ b/epan/addr_resolv.h @@ -223,13 +223,13 @@ const gchar *get_ether_name_if_known(const guint8 *addr); * Given a sequence of 3 octets containing an OID, get_manuf_name() * returns the vendor name, or "%02x:%02x:%02x" if not known. */ -extern const gchar *get_manuf_name(const guint8 *addr); +extern const gchar *get_manuf_name(const guint8 *addr, size_t size); /* * Given a sequence of 3 octets containing an OID, get_manuf_name_if_known() * returns the vendor name, or NULL if not known. */ -WS_DLL_PUBLIC const gchar *get_manuf_name_if_known(const guint8 *addr); +WS_DLL_PUBLIC const gchar *get_manuf_name_if_known(const guint8 *addr, size_t size); /* * Given an integer containing a 24-bit OID, uint_get_manuf_name_if_known() diff --git a/epan/address_types.c b/epan/address_types.c index 86812af..776a02d 100644 --- a/epan/address_types.c +++ b/epan/address_types.c @@ -382,7 +382,7 @@ static const gchar* fcwwn_name_res_str(const address* addr) case FC_NH_NAA_IEEE_E: memcpy (oui, &addrp[2], 6); - return get_manuf_name(oui); + return get_manuf_name(oui, sizeof(oui)); case FC_NH_NAA_IEEE_R: oui[0] = ((addrp[0] & 0x0F) << 4) | ((addrp[1] & 0xF0) >> 4); @@ -392,7 +392,7 @@ static const gchar* fcwwn_name_res_str(const address* addr) oui[4] = ((addrp[4] & 0x0F) << 4) | ((addrp[5] & 0xF0) >> 4); oui[5] = ((addrp[5] & 0x0F) << 4) | ((addrp[6] & 0xF0) >> 4); - return get_manuf_name(oui); + return get_manuf_name(oui, sizeof(oui)); } return ""; -- 2.33.0