DLMS/COSEM dissector infinite loop denial of service
## Summary The `dlms_dissect_data()` → `dlms_dissect_compact_array_content()` function in the `cosem` dissector hangs `tshark` with ~100% CPU usage until the process is killed - `kill -9 $(pidof tshark)`. Impact: - **CPU DoS**: tshark consumes 100% CPU indefinitely - **No timeout mechanism**: Process must be killed externally (SIGKILL) - **Single UDP packet**: 63-byte crafted packet is sufficient - **No user configuration needed**: Port 4059 is registered by default ## AI assistance Identified using Claude Opus 4.6. I've verified the bug, but not the root cause or mitigation. ## Sample capture file [generate_cosem.py](/uploads/ec3dd25295765452780fa5cdf71271b1/generate_cosem.py) [cosem_infinite_loop.pcap](/uploads/88f0af457a37615577cb4ab77297e1bc/cosem_infinite_loop.pcap) [cosem_infinite_loop_send.py](/uploads/70915a4aa2c625d56fd312764ec89709/cosem_infinite_loop_send.py) ## Steps to reproduce ``` $ ../.venv/bin/python3 generate_cosem.py [+] Generated cosem_infinite_loop.pcap Bug: packet-cosem.c:2203 - compact array with 0-element struct type Test: ./build/run/tshark -r pocs/cosem_infinite_loop.pcap Expected: tshark hangs (infinite loop, 100% CPU, must be killed) $ ../build/run/tshark -r cosem_infinite_loop.pcap ** (tshark:397963) 19:13:43.398763 [(none) MESSAGE] -- JSON Dictionary: No config.txt or jsonmain.xml found (using generic mode) ``` ``` $ top | grep tshark 397963 user 20 0 262168 158692 96528 R 100.0 1.3 0:07.96 tshark ``` Alternatively, use `cosem_infinite_loop_send.py` to send a UDP crashing packet Wireshark: ``` $ ../.venv/bin/python3 cosem_infinite_loop_send.py 127.0.0.1 [*] Sending COSEM/DLMS infinite-loop trigger to 127.0.0.1:4059 Payload: 21 bytes Bug: packet-cosem.c:2203 — compact array with 0-element struct (no root — using plain UDP socket instead of raw) [+] Sent. Any Wireshark/tshark instance capturing on port 4059 will hang. ``` ## What is the current bug behavior? **AI suggested root cause:** **File:** `epan/dissectors/packet-cosem.c:2203` **Function:** `dlms_dissect_data()` → `dlms_dissect_compact_array_content()` In `dlms_dissect_data()`, the compact-array case (choice == 19) loops: ```c while (*offset < content_end) { subitem = dlms_dissect_compact_array_content(tvb, pinfo, subtree, description_offset, offset); } ``` If the type description is a structure with 0 elements (`[0x02, 0x00]`), `dlms_dissect_compact_array_content()` enters the structure branch: ```c if (choice == 2) { /* structure */ unsigned elements = dlms_get_length(tvb, &description_offset); while (elements != 0) { /* SKIPPED when elements=0 */ } } ``` When `elements == 0`, the inner loop is skipped and `*content_offset` is **never modified**. The outer `while (*offset < content_end)` loop runs forever. The `increment_dissection_depth` / `decrement_dissection_depth` calls inside `dlms_dissect_compact_array_content` cancel each other out per iteration, so the depth check never triggers. ## What is the expected correct behavior? **AI suggested fix:** Detect when `*content_offset` hasn't advanced after `dlms_dissect_compact_array_content` returns, and break the loop: ```c while (*offset < content_end) { int saved_offset = *offset; subitem = dlms_dissect_compact_array_content(..., offset); if (*offset <= saved_offset) break; // prevent infinite loop } ``` ## Build information Built from master branch. ``` ** (tshark:396187) 19:08:22.771852 [(none) MESSAGE] -- JSON Dictionary: No config.txt or jsonmain.xml found (using generic mode) TShark (Wireshark) 4.7.0 (v4.7.0rc0-2101-g6fd3e409475e). Copyright 1998-2026 Gerald Combs <gerald@wireshark.org> and contributors. Licensed under the terms of the GNU General Public License (version 2 or later). This is free software; see the file named COPYING in the distribution. There is NO WARRANTY; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Compile-time info: Bit width: 64-bit Compiler: GCC 13.3.0 GLib: 2.80.0 With: +brotli +libxml2 2.9.14 +PCRE2 10.42 2022-12-11 +Gcrypt 1.10.3 +LZ4 1.9.4 +Snappy 1.1.10 +GnuTLS 3.8.3 and PKCS#11 +MaxMind +zlib 1.3 +Kerberos (MIT) +nghttp2 1.59.0 +Zstandard 1.5.5 +libpcap +nghttp3 0.8.0 Without: -libnl -Lua -xxhash -libsmi -POSIX capabilities -zlib-ng Runtime info: OS: Linux 6.8.0-100-generic CPU: [redacted] Memory: 11914 MB of physical memory GLib: 2.80.0 Locale: LC_TYPE=en_US.UTF-8 Plugins: supported, 0 loaded With: +brotli 1.1.0 +nghttp2 1.59.0 +c-ares 1.27.0 +nghttp3 0.8.0 +Gcrypt 1.10.3 +PCRE2 10.42 2022-12-11 +GnuTLS 3.8.3 +zlib 1.3 +libpcap 1.10.4 (with TPACKET_V3) +Zstandard 1.5.5 +LZ4 1.9.4 ``` (Also tested on Wireshark 4.6.4 on Windows 10 x64.)
issue