The function in question is dissect_register contained within epan/dissectors/packet-gvcp.c.
There is a global array to store the registers and their respective values. If the packet contains more than 16 registers that is being written to then a global buffer overflow occurs. The data length field divided by 8 is how the codes calculates the number of writes.
This vulnerability was inspired by historical global buffer overflow vulnerabilities present within wireshark.
The “write register value to set state” pattern is a common one among not only these types of network protocols, but also firmware software. Correctly bounding and ensuring that global variable access/read/write overflows do not occur are a staple of good programming practices, so this vulnerability is representative of a “newer” or a less experienced programmer introducing a bug into a codebase.
GVCP (GigE Vision Control Protocol) is a UDP-based protocol used in the GigE Vision standard to communicate with industrial cameras over Ethernet. It handles device discovery, configuration, and register-level control, allowing software on a host PC to interact with camera hardware in a standardized way.
GVCP typically uses UDP port 3956 and supports commands like register read/write, memory access, and event handling. It operates alongside GVSP (GigE Vision Streaming Protocol), which is responsible for streaming image data.
Writing to a register is performed using the WRITEREG_CMD command, identified by opcode 0x0082. This command allows a host to send a 32-bit value to a 32-bit register address on the device.
| Field | Size | Description |
|---|---|---|
| Flags | 1 bytes | Packet Flags |
| Opcode | 2 bytes | Command type (0x0082 for WRITEREG) |
| Data Length | 2 bytes | Length of the data after Request ID |
| Request ID | 2 bytes | Used to match responses with requests |
| Register Address | 4 bytes | Target register to write to |
| Value | 4 bytes | 32-bit value to be written |
These packets are typically sent directly over UDP without a handshake, and the device may respond with a WRITEREG_ACK if acknowledgment is supported or required.
Register writing is commonly used to:
Care must be taken not to write to protected or reserved registers unless explicitly allowed by the device’s documentation.
=================================================================
==18==ERROR: AddressSanitizer: global-buffer-overflow on address 0x00001168c900 at pc 0x00000120ad7a bp 0x7fff2caa3f70 sp 0x7fff2caa3f68
WRITE of size 4 at 0x00001168c900 thread T0
SCARINESS: 36 (4-byte-write-global-buffer-overflow)
#0 0x120ad79 in dissect_register /src/wireshark/epan/dissectors/packet-gvcp.c:984:44
#1 0x120690f in dissect_writereg_cmd /src/wireshark/epan/dissectors/packet-gvcp.c:1844:5
#2 0x120690f in dissect_gvcp /src/wireshark/epan/dissectors/packet-gvcp.c:2766:4
#3 0x73991d in call_dissector_through_handle /src/wireshark/epan/packet.c:887:9
#4 0x73991d in call_dissector_work /src/wireshark/epan/packet.c:975:9
#5 0x744574 in call_dissector_only /src/wireshark/epan/packet.c:3621:8
#6 0x744574 in call_all_postdissectors /src/wireshark/epan/packet.c:4166:3
#7 0x10906b7 in dissect_frame /src/wireshark/epan/dissectors/packet-frame.c:1438:5
#8 0x73991d in call_dissector_through_handle /src/wireshark/epan/packet.c:887:9
#9 0x73991d in call_dissector_work /src/wireshark/epan/packet.c:975:9
#10 0x735417 in call_dissector_only /src/wireshark/epan/packet.c:3621:8
#11 0x735417 in call_dissector_with_data /src/wireshark/epan/packet.c:3634:8
#12 0x735417 in dissect_record /src/wireshark/epan/packet.c:687:3
#13 0x726cb0 in epan_dissect_run /src/wireshark/epan/epan.c:666:2
#14 0x5971f8 in LLVMFuzzerTestOneInput /src/wireshark/fuzz/fuzzshark.c:359:2
#15 0x44bb70 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:614:13
#16 0x436de5 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:327:6
#17 0x43c87f in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:862:9
#18 0x467b22 in main /src/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
#19 0x7f1c559e0082 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24082) (BuildId: 0323ab4806bee6f846d9ad4bccfc29afdca49a58)
#20 0x42efcd in _start (/out/fuzzshark+0x42efcd)
DEDUP_TOKEN: dissect_register--dissect_writereg_cmd--dissect_gvcp
0x00001168c900 is located 32 bytes before global variable 'gvcp_register_value' defined in '/src/wireshark/epan/dissectors/packet-gvcp.c:282' (0x1168c920) of size 64
0x00001168c900 is located 0 bytes after global variable 'gvcp_register_number' defined in '/src/wireshark/epan/dissectors/packet-gvcp.c:281' (0x1168c8c0) of size 64
SUMMARY: AddressSanitizer: global-buffer-overflow /src/wireshark/epan/dissectors/packet-gvcp.c:984:44 in dissect_register
Shadow bytes around the buggy address:
0x00001168c680: 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9
0x00001168c700: 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 00 f9 f9 f9
0x00001168c780: 00 f9 f9 f9 00 f9 f9 f9 00 f9 f9 f9 00 f9 f9 f9
0x00001168c800: 00 f9 f9 f9 04 f9 f9 f9 01 f9 f9 f9 00 f9 f9 f9
0x00001168c880: 00 f9 f9 f9 04 f9 f9 f9 00 00 00 00 00 00 00 00
=>0x00001168c900:[f9]f9 f9 f9 00 00 00 00 00 00 00 00 f9 f9 f9 f9
0x00001168c980: 00 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9
0x00001168ca00: 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9
0x00001168ca80: 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9
0x00001168cb00: 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9
0x00001168cb80: 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9 04 f9 f9 f9
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
==18==ABORTING
MS: 0 ; base unit: 0000000000000000000000000000000000000000
subprocess command returned a non-zero exit status: 1