BT-DHT dissector stack overflow via nested structs
## Summary
The `dissect_bencoded_list()` function in the `BT-DHT` dissector crashes due to a stack overflow. Crash occurs when using 'Decode As' on a system with limited stack (`ulimit -s 1024`).
Impact:
- **SIGSEGV crash** on systems with ≤~ 1MB stack
- **Does NOT crash** on default 8MB Linux stack (stack usage is only ~1.6MB)
- **Requires decode-as**: BT-DHT heuristic is registered as `HEURISTIC_DISABLE`
## AI assistance
Identified using Claude Opus 4.6. I've verified the bug, but not the root cause or mitigation.
## Sample capture file
[generate_bt_dht.py](/uploads/dd15b1797558e2e1f32a07a334cb9363/generate_bt_dht.py)
[bt_dht_stack_overflow.pcap](/uploads/c42f7e4d9468b7f773ddd9fe499d6cbc/bt_dht_stack_overflow.pcap)
## Steps to reproduce
```
$ ../.venv/bin/python3 generate_bt_dht.py
[+] Generated bt_dht_stack_overflow.pcap (64013 byte payload, 32000 levels)
Bug: packet-bt-dht.c:217 dissect_bencoded_list() - no recursion depth guard
Test: ./build/run/tshark -d udp.port==6881,bt-dht -r pocs/bt_dht_stack_overflow.pcap
Expected: SIGSEGV (exit code 139) or abort due to stack overflow
$ bash -c 'ulimit -s 1024 && ../build/run/tshark -d udp.port==6881,bt-dht -r bt_dht_stack_overflow.pcap'
** (tshark:430983) 21:06:59.450076 [(none) MESSAGE] -- JSON Dictionary: No config.txt or jsonmain.xml found (using generic mode)
Segmentation fault (core dumped)
$ bash -c 'ulimit -s 2048 && ../build/run/tshark -d udp.port==6881,bt-dht -r bt_dht_stack_overflow.pcap'
** (tshark:431033) 21:07:08.625887 [(none) MESSAGE] -- JSON Dictionary: No config.txt or jsonmain.xml found (using generic mode)
1 0.000000 10.0.0.1 → 10.0.0.2 BT-DHT 64055
```
## What is the current bug behavior?
**AI suggested root cause:**
`dissect_bencoded_list()` recurses for each nested bencoded list element. Each `l` byte in the payload triggers one recursion level consuming only 2 bytes (the `l` prefix + corresponding `e` suffix). No `increment_dissection_depth()` is used.
With a 64KB UDP payload: 32,000 nested lists × ~50 bytes/frame ≈ 1.6MB stack usage.
## What is the expected correct behavior?
**AI suggested fix:**
Add `increment_dissection_depth(pinfo)` / `decrement_dissection_depth(pinfo)` guards to the two recursive entry points:
**`dissect_bencoded_list()`** (line 217):
```c
static int
dissect_bencoded_list(tvbuff_t *tvb, packet_info *pinfo, proto_tree *tree, unsigned offset, const char *label)
{
increment_dissection_depth(pinfo);
// ... existing body ...
decrement_dissection_depth(pinfo);
return offset;
}
```
## 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
```
issue