From f9e63d2c8221f040325a56037a7c417cb04ba68d Mon Sep 17 00:00:00 2001 From: Florian Date: Thu, 18 Jun 2026 21:06:47 -0500 Subject: [PATCH] Guard vdata_make() against strdup(NULL) for DATA_FORMAT A decoder passing a NULL format to data_make/data_int/data_dbl reaches vdata_make()'s DATA_FORMAT case, which calls strdup() on the argument unconditionally. strdup(NULL) is undefined and dereferences a null pointer, crashing the decoder task with a LoadProhibited exception (EXCVADDR 0x0) and rebooting the gateway. This is reachable from normal operation: digitech_xc0324_decode() emits its 'message_num' field with a NULL format (data_int(data, "message_num", "Message repeat count", NULL, events)), so any successful XC-0324 decode -- including the false-positive decodes that ambient RF noise produces every few hours -- crashes the device. Captured on an ESP32 as: Guru Meditation Error: Core 1 panic'ed (LoadProhibited) ... strlen <- _strdup_r <- strdup <- vdata_make <- data_int <- digitech_xc0324_decode <- pulse_slicer_ppm <- run_ook_demods Read the format into a temporary and only strdup() it when non-NULL, leaving format NULL otherwise. A NULL format is legitimate and widely used; the output backends already treat it as optional (the JSON string formatter does UNUSED(format)). Fixes the reboots reported in 1technophile/OpenMQTTGateway#2317. --- src/rtl_433/data.c | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/rtl_433/data.c b/src/rtl_433/data.c index d7b540e..b147e06 100644 --- a/src/rtl_433/data.c +++ b/src/rtl_433/data.c @@ -171,18 +171,25 @@ static data_t *vdata_make(data_t *first, const char *key, const char *pretty_key skip |= !va_arg(ap, int); type = va_arg(ap, data_type_t); continue; - case DATA_FORMAT: + case DATA_FORMAT: { if (format) { fprintf(stderr, "vdata_make() format type used twice\n"); goto alloc_error; } - format = strdup(va_arg(ap, char *)); - if (!format) { - WARN_STRDUP("vdata_make()"); - goto alloc_error; + char const *format_arg = va_arg(ap, char *); + // A NULL format is legitimate (many decoders pass NULL, e.g. + // digitech_xc0324's "message_num"); strdup(NULL) is UB and crashed + // the decoder task with a LoadProhibited null deref. + if (format_arg) { + format = strdup(format_arg); + if (!format) { + WARN_STRDUP("vdata_make()"); + goto alloc_error; + } } type = va_arg(ap, data_type_t); continue; + } case DATA_COUNT: assert(0); break;