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 {