Commit 7ae198bd604 for php
commit 7ae198bd604e7e20bac0a544bb3505557d745264
Author: Thomas Vincent <thomasvincent@gmail.com>
Date: Sun Nov 1 12:40:58 2026 +0000
ext/snmp: hardening: replace unbounded strcat with offset-tracked snprintf
The suffix-as-keys code path in php_snmp builds a dotted OID suffix
string by appending with strcat into a fixed 2048-byte buf2 array.
The overflow is not reachable in practice: net-snmp's BER decoder
enforces MAX_OID_LEN=128, and the worst-case suffix (128 subidentifiers
at 11 bytes each) is 1408 bytes, within the buffer.
Replace the strcat loop with direct snprintf into buf2 at a tracked
size_t offset, breaking out of the loop if the buffer would be exhausted.
Defense-in-depth against future net-snmp parser regressions.
Signed-off-by: Thomas Vincent <thomasvincent@gmail.com>
Close GH-21341
diff --git a/ext/snmp/snmp.c b/ext/snmp/snmp.c
index 0c060739236..79c58987b8c 100644
--- a/ext/snmp/snmp.c
+++ b/ext/snmp/snmp.c
@@ -535,14 +535,21 @@ static void php_snmp_internal(INTERNAL_FUNCTION_PARAMETERS, int st,
} else if (st & SNMP_USE_SUFFIX_AS_KEYS && st & SNMP_CMD_WALK) {
snprint_objid(buf2, sizeof(buf2), vars->name, vars->name_length);
if (rootlen <= vars->name_length && snmp_oid_compare(root, rootlen, vars->name, rootlen) == 0) {
- buf2[0] = '\0';
+ size_t pos = 0;
count = rootlen;
- while(count < vars->name_length){
- snprintf(buf, sizeof(buf), "%lu.", vars->name[count]);
- strcat(buf2, buf);
+ while (count < vars->name_length) {
+ int written = snprintf(buf2 + pos, sizeof(buf2) - pos, "%lu.", vars->name[count]);
+ if (written < 0 || (size_t)written >= sizeof(buf2) - pos) {
+ break;
+ }
+ pos += (size_t)written;
count++;
}
- buf2[strlen(buf2) - 1] = '\0'; /* remove trailing '.' */
+ if (pos > 0) {
+ buf2[pos - 1] = '\0'; /* remove trailing '.' */
+ } else {
+ buf2[0] = '\0';
+ }
}
add_assoc_zval(return_value, buf2, &snmpval);
} else {