Handle_0x38_RequestFileTransfer in the UDS server computes the file-path field offset as a 16-bit value, uint16_t byte_idx = 4 + file_path_len , where file_path_len is taken directly from the request. For file_path_len ≥ 0xFFFC this addition wraps to a small number, bypassing the only length-bound check in the handler. The server then forwards filePath = &recv_buf[4] together with filePathLen of up to 65535 to the application's UDS_EVT_RequestFileTransfer callback, even though only a handful of bytes were actually received. A conforming callback that reads filePathLen bytes of filePath (e.g. to open/log the file name) reads far past the receive buffer.
This is the same bug class (CWE‑191 integer wraparound → CWE‑125 out‑of‑bounds read, manifesting through the service callback) as CVE‑2026‑54413 , but in a different handler ( 0x38 RequestFileTransfer rather than 0x27 SecurityAccess) and is not covered by that advisory.
A second, lower-severity issue in the same handler (an off-by-one bound, > instead of >= ) is described under Related hardening and is fixed by the same patch.
Relevant code ( src/server.c , equivalently amalgamated iso14229.c ):
file_path_len is fully attacker-controlled from request bytes 2–3.
The bound at line 1158 is supposed to ensure the filePathLen -byte path (and the trailing fields) fit within recv_len . It checks the truncated byte_idx , so a request where file_path_len ∈ {0xFFFC..0xFFFF} makes byte_idx wrap to {0..3} and pass the check.
The handler then builds args.filePathLen = file_path_len (the un-truncated 16-bit value, up to 65535) and args.filePath = &recv_buf[4] , and invokes the user callback.
The library itself does not dereference filePath ; the out-of-bounds read occurs when a conforming UDS_EVT_RequestFileTransfer handler consumes filePathLen bytes — the documented contract, and exactly what the in-tree fuzz harness and any real file handler do.
mode_of_operation must be a value that yields a non-NULL filePath ( AddFile 0x01 , ReplaceFile 0x03 , or ReadFile 0x04 ). The minimum request length ( UDS_0X38_REQ_BASE_LEN = 5 ) is the only other precondition.
Trigger bytes (8-byte physical UDS request): 38 04 FF FF DE AD BE EF (SID 0x38 , mode ReadFile 0x04 , file_path_len = 0xFFFF , then ≥1 trailing byte so recv_len ≥ 5 ).
Standalone reproducer (public API + in-tree mock ISO-TP transport; the callback does the normal thing — reads the advertised path length):
AddressSanitizer output (clang 18.1.8):
The read can span up to ~64 KB beyond the receive buffer. On hosted targets with memory protection (e.g. a Linux/QNX DoIP gateway), hitting an unmapped page crashes the diagnostic server (denial of service). On bare-metal MCUs — the library's primary target — there is usually no MMU, so the access does not crash; instead it reads adjacent SRAM/flash/peripheral memory, which can be disclosed to the tester if the callback reflects the file path in a response, or otherwise causes the handler to act on out-of-bounds data.
The out-of-bounds read happens in the integrator's UDS_EVT_RequestFileTransfer callback , not inside the library. A defensive callback that bounds filePathLen itself before reading is not affected; however the library gives the callback no signal that the length is invalid, so the common/naïve implementation (open or log a filePathLen -byte path) is vulnerable. This is the same callback-mediated pattern accepted for CVE‑2026‑54413.
Reachability: a single, well-formed-looking 8-byte request; no priming, session, or prior state required at the library level. Note that many deployments gate RequestFileTransfer behind a programming session + SecurityAccess at the application layer; where that gating is enforced before the callback consumes the length, an attacker must be authenticated (raising attack complexity / privileges — see CVSS caveats).
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
