From dab2e75f4bd56c8d53db0be843295f60c61b8c95 Mon Sep 17 00:00:00 2001 From: TristanInSec Date: Tue, 26 May 2026 15:00:56 -0400 Subject: [PATCH] in_collectd: reject parts with length < 4 and fix null-terminator OOB The collectd binary protocol parser enters an infinite loop when it receives a part with part_len=0: the loop counters are not advanced and the while condition remains true forever. A single 4-byte UDP packet can permanently hang the worker thread. Additionally, the null-terminator check for string parts reads one byte past the end of the received data (ptr[size] where size = part_len - 4 accesses buf[part_len], which is past the buffer when the last part fills exactly to the end). Fix both by rejecting parts with part_len < 4 (minimum valid part is 4 bytes: 2 type + 2 length) and checking ptr[size - 1] instead of ptr[size] for the null terminator. Signed-off-by: Tristan --- plugins/in_collectd/netprot.c | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/plugins/in_collectd/netprot.c b/plugins/in_collectd/netprot.c index a7f13e92d1f..dd2d11104a9 100644 --- a/plugins/in_collectd/netprot.c +++ b/plugins/in_collectd/netprot.c @@ -247,8 +247,9 @@ int netprot_to_msgpack(char *buf, int len, struct mk_list *tdb, part_type = be16read(buf); part_len = be16read((unsigned char *) buf + 2); - if (len < part_len) { - flb_error("[in_collectd] data truncated (%i < %i)", len, part_len); + if (part_len < 4 || len < part_len) { + flb_error("[in_collectd] invalid part length (%i, remaining %i)", + part_len, len); return -1; } @@ -268,7 +269,7 @@ int netprot_to_msgpack(char *buf, int len, struct mk_list *tdb, switch (part_type) { case PART_HOST: - if (ptr[size] == '\0') { + if (size > 0 && ptr[size - 1] == '\0') { hdr.host = ptr; } break; @@ -279,22 +280,22 @@ int netprot_to_msgpack(char *buf, int len, struct mk_list *tdb, hdr.time = hr2time(be64read(ptr)); break; case PART_PLUGIN: - if (ptr[size] == '\0') { + if (size > 0 && ptr[size - 1] == '\0') { hdr.plugin = ptr; } break; case PART_PLUGIN_INSTANCE: - if (ptr[size] == '\0') { + if (size > 0 && ptr[size - 1] == '\0') { hdr.plugin_instance = ptr; } break; case PART_TYPE: - if (ptr[size] == '\0') { + if (size > 0 && ptr[size - 1] == '\0') { hdr.type = ptr; } break; case PART_TYPE_INSTANCE: - if (ptr[size] == '\0') { + if (size > 0 && ptr[size - 1] == '\0') { hdr.type_instance = ptr; } break;