Skip to main content
← All libraries
Parser · C

How to fuzz protobuf-c

Protobuf's wire format is compact but its C deserializer has manual length arithmetic.

protobuf-c deserializes binary wire-format messages in C without the safety nets of the C++ runtime. Maliciously crafted varint sequences, embedded length fields, and repeated-field counts can trigger integer overflows in the allocator sizing path, affecting any embedded or IoT firmware that uses protobuf for IPC.

Common bug classes

  • Heap buffer overflow in repeated-field array allocation sizing
  • Integer overflow in varint 64-bit accumulation
  • Out-of-bounds read on truncated length-delimited field
  • Null dereference on missing required field in strict mode
  • Infinite loop on varint with all high bits set

Recommended setup

Fuzzers

  • AFL++
  • libFuzzer

Sanitizers

  • ASan
  • UBSan

Harness scaffold

#include <stdint.h>
#include <stddef.h>
#include <protobuf-c/protobuf-c.h>

int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
  /* Generic unpack into scratch descriptor — replace MyMsg with target */
  ProtobufCAllocator alloc = PROTOBUF_C_ALLOCATOR_DEFAULT;
  /* Demonstrate wire-format scan without a concrete descriptor */
  ProtobufCBufferSimple buf = PROTOBUF_C_BUFFER_SIMPLE_INIT(NULL);
  protobuf_c_buffer_simple_append(&buf.base, size, data);
  PROTOBUF_C_BUFFER_SIMPLE_CLEAR(&buf);
  return 0;
}

Save this as fuzz_target.cc, build with your compiler + sanitizer flags, and you have a working starting point.

Start fuzzing protobuf-c on Fuzze.rs →

Push the harness above + a Dockerfile. First month 50% off.