From: CPANSec Security Scanner Bot Subject: [PATCH] Net::IP::LPM: bound prefix length at the XS boundary (heap OOB read in addPrefixToTrie) This is the XS/C-layer alternative to the pure-Perl add() guard. lpm_add_raw() receives the packed-address byte length (len) from SvPV, so it can reject an out-of-range mask length before calling addPrefixToTrie(). addPrefixToTrie() walks prefix_len bits reading prefix[byte] over the 4-byte (IPv4) / 16-byte (IPv6) address with no internal bound, so any prefix_len > len*8 reads out of bounds (heap OOB read, lpm_lib.c:170). prefixLen is also an unsigned char, so an unchecked int wraps modulo 256 (256 -> /0). Fixing it here protects every caller of lpm_add_raw, not only the Perl add() path, and closes the truncation. len 0..32 (IPv4) / 0..128 (IPv6) still work. --- a/lpm_lib.c +++ b/lpm_lib.c @@ -413,6 +413,21 @@ prefix = SvPV(svprefix, len); + /* Bound the mask length to the address width before it reaches + * addPrefixToTrie(): that function walks prefix_len bits reading + * prefix[byte] for byte up to prefix_len/8 over the packed address + * (4 bytes IPv4 / 16 bytes IPv6) with no internal bound, so any + * prefix_len > len*8 reads out of bounds (heap OOB read, lpm_lib.c:170). + * It also takes prefixLen as unsigned char, so an unchecked int would + * wrap modulo 256 (256 -> /0). Reject out-of-range lengths here at the + * XS boundary so every caller of lpm_add_raw is protected. */ + if ((len == 4 || len == 16) + && (prefix_len < 0 || (STRLEN)prefix_len > len * 8)) { + croak("Net::IP::LPM: prefix length /%d out of range (max /%d)", + prefix_len, (int)(len * 8)); + return 0; + } + if (len == 4){ addPrefixToTrie((void *)prefix, prefix_len, value, &instance->pTrieIPV4); }