From 67ad0ab22569d4cd344cbfb9ef38fa92ebe0113a Mon Sep 17 00:00:00 2001 From: Matt Jones <47545907+SoundMatt@users.noreply.github.com> Date: Tue, 5 May 2026 07:01:50 -0700 Subject: [PATCH] daemon: fix out-of-bounds read in dlt_daemon_control_set_log_level_v2 Mirror of #861 for the parallel SET_LOG_LEVEL V2 control handler. The fixed-size precheck validates only the 11-byte minimum SET_LOG_LEVEL V2 request (apidlen = ctidlen = 0). The function then reads two attacker- controlled uint8_t length fields (apidlen, ctidlen) and uses them to advance an offset into msg->databuffer, before passing pointers into the buffer to dlt_set_id_v2() (which reads up to apidlen / ctidlen bytes), a 1-byte log_level read, and a 4-byte memcpy of the trailing com field. A short message with non-zero length fields causes the variable-length reads to walk past the end of msg->databuffer. Add bounds checks after each length is parsed; on failure return without further processing (req is on the stack, no allocation cleanup required). --- src/daemon/dlt_daemon_client.c | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/daemon/dlt_daemon_client.c b/src/daemon/dlt_daemon_client.c index 4d576f583..18662c240 100644 --- a/src/daemon/dlt_daemon_client.c +++ b/src/daemon/dlt_daemon_client.c @@ -3682,10 +3682,26 @@ void dlt_daemon_control_set_log_level_v2(int sock, offset = offset + (int)sizeof(uint32_t); memcpy(&(req.apidlen), msg->databuffer + offset, sizeof(uint8_t)); offset = offset + (int)sizeof(uint8_t); + + /* apidlen and ctidlen are attacker-controlled (uint8_t each, up to 255). + * The fixed-size precheck at the top of this function only validates + * the empty case (apidlen = ctidlen = 0); before reading the + * variable-length apid (apidlen bytes) followed by ctidlen (1 byte), + * confirm the message is large enough to contain them. Otherwise + * dlt_set_id_v2() reads past msg->databuffer. */ + if ((offset + (int)req.apidlen + (int)sizeof(uint8_t)) > msg->datasize) + return; + dlt_set_id_v2(req.apid, (const char *)(msg->databuffer + offset), req.apidlen); offset = offset + req.apidlen; memcpy(&(req.ctidlen), msg->databuffer + offset, sizeof(uint8_t)); offset = offset + (int)sizeof(uint8_t); + + /* Same check for ctid (ctidlen bytes), the trailing log_level byte, + * and the com field (DLT_ID_SIZE bytes). */ + if ((offset + (int)req.ctidlen + (int)sizeof(uint8_t) + DLT_ID_SIZE) > msg->datasize) + return; + dlt_set_id_v2(req.ctid, (const char *)(msg->databuffer + offset), req.ctidlen); offset = offset + req.ctidlen; memcpy(&(req.log_level), msg->databuffer + offset, sizeof(uint8_t));