Skip to content

Commit edfbf4b

Browse files
committed
fix(fuzz): update protobuf_wire_fuzzer to the reader-based decode API
The harness called free functions decode_tag(data,size,offset), decode_varint and decode_length_delimited that no longer exist; the decoder is now a stateful reader class. Rewrite LLVMFuzzerTestOneInput to construct a reader and drive decode_tag(reader&, field, wt) plus read_varint / read_fixed64 / read_fixed32 / read_length_delimited, preserving the forward-progress and graceful-rejection guarantees.
1 parent 8aa83eb commit edfbf4b

1 file changed

Lines changed: 32 additions & 36 deletions

File tree

fuzz/protobuf_wire_fuzzer.cpp

Lines changed: 32 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,14 @@
22
* @file protobuf_wire_fuzzer.cpp
33
* @brief libFuzzer harness for the internal protobuf wire-format decoder.
44
*
5-
* Targets kcenon::monitoring::protobuf_wire's decode primitives
6-
* (decode_varint / decode_tag / decode_length_delimited), which are the
5+
* Targets kcenon::monitoring::protobuf_wire's decode primitives via the
6+
* `reader` class (decode_tag / reader::read_varint / reader::read_fixed64 /
7+
* reader::read_fixed32 / reader::read_length_delimited), which are the
78
* monitoring_system's lowest-level untrusted-input parsing surface: they are
89
* used to deserialize Jaeger api_v2 and Zipkin proto3 span messages received
910
* over the wire by the trace exporters. Malformed or adversarial bytes must be
10-
* rejected gracefully (std::nullopt) without out-of-bounds reads, overflow, or
11-
* other undefined behavior.
11+
* rejected gracefully (false / std::nullopt) without out-of-bounds reads,
12+
* overflow, or other undefined behavior.
1213
*
1314
* The header is fully inline / header-only, so this harness needs no link
1415
* against the monitoring_system library.
@@ -28,59 +29,54 @@
2829
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
2930
namespace pw = kcenon::monitoring::protobuf_wire;
3031

32+
pw::reader r(data, size);
33+
3134
// Walk the buffer as a sequence of protobuf fields, exactly as a real
3235
// message decoder would, exercising every decode primitive. The loop must
3336
// terminate on any malformed field; the decoders signal that by returning
34-
// std::nullopt and not advancing past the buffer end.
35-
std::size_t offset = 0;
36-
while (offset < size) {
37-
const std::size_t before = offset;
37+
// false / std::nullopt without advancing past the buffer end.
38+
while (!r.eof()) {
39+
const std::size_t before = r.position();
3840

39-
auto tag = pw::decode_tag(data, size, offset);
40-
if (!tag.has_value()) {
41+
std::uint32_t field_number = 0;
42+
pw::wire_type wt{};
43+
if (!pw::decode_tag(r, field_number, wt)) {
4144
break; // truncated/invalid tag
4245
}
4346

44-
switch (tag->second) {
45-
case pw::wire_type::varint: {
46-
auto v = pw::decode_varint(data, size, offset);
47-
if (!v.has_value()) {
48-
offset = size; // stop: truncated varint
47+
switch (wt) {
48+
case pw::wire_type::varint:
49+
if (!r.read_varint().has_value()) {
50+
return 0; // truncated varint
4951
}
5052
break;
51-
}
52-
case pw::wire_type::length_delimited: {
53-
auto ld = pw::decode_length_delimited(data, size, offset);
54-
if (!ld.has_value()) {
55-
offset = size; // stop: bad length-delimited field
53+
case pw::wire_type::fixed64:
54+
if (!r.read_fixed64().has_value()) {
55+
return 0; // truncated fixed64
5656
}
5757
break;
58-
}
59-
case pw::wire_type::fixed64: {
60-
if (offset + 8 > size) {
61-
offset = size;
62-
} else {
63-
offset += 8;
58+
case pw::wire_type::fixed32:
59+
if (!r.read_fixed32().has_value()) {
60+
return 0; // truncated fixed32
6461
}
6562
break;
66-
}
67-
case pw::wire_type::fixed32: {
68-
if (offset + 4 > size) {
69-
offset = size;
70-
} else {
71-
offset += 4;
63+
case pw::wire_type::length_delimited: {
64+
const std::uint8_t* ptr = nullptr;
65+
std::size_t len = 0;
66+
if (!r.read_length_delimited(&ptr, &len)) {
67+
return 0; // bad length-delimited field
7268
}
7369
break;
7470
}
7571
default:
76-
// Unknown wire type: cannot safely skip; stop.
77-
offset = size;
78-
break;
72+
// Unknown/unsupported wire type (e.g. deprecated groups):
73+
// cannot safely skip; stop.
74+
return 0;
7975
}
8076

8177
// Guard against any decoder that fails to make forward progress, which
8278
// would otherwise spin forever on a crafted input.
83-
if (offset == before) {
79+
if (r.position() == before) {
8480
break;
8581
}
8682
}

0 commit comments

Comments
 (0)