1*61c4878aSAndroid Build Coastguard Worker // Copyright 2022 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include <algorithm>
16*61c4878aSAndroid Build Coastguard Worker #include <cstddef>
17*61c4878aSAndroid Build Coastguard Worker #include <cstdint>
18*61c4878aSAndroid Build Coastguard Worker #include <cstring>
19*61c4878aSAndroid Build Coastguard Worker #include <vector>
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker #include "fuzz.h"
22*61c4878aSAndroid Build Coastguard Worker #include "pw_fuzzer/fuzzed_data_provider.h"
23*61c4878aSAndroid Build Coastguard Worker #include "pw_protobuf/stream_decoder.h"
24*61c4878aSAndroid Build Coastguard Worker #include "pw_span/span.h"
25*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status.h"
26*61c4878aSAndroid Build Coastguard Worker #include "pw_status/status_with_size.h"
27*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/memory_stream.h"
28*61c4878aSAndroid Build Coastguard Worker #include "pw_stream/stream.h"
29*61c4878aSAndroid Build Coastguard Worker
30*61c4878aSAndroid Build Coastguard Worker namespace pw::protobuf::fuzz {
31*61c4878aSAndroid Build Coastguard Worker namespace {
32*61c4878aSAndroid Build Coastguard Worker
RecursiveFuzzedDecode(FuzzedDataProvider & provider,StreamDecoder & decoder,uint32_t depth=0)33*61c4878aSAndroid Build Coastguard Worker void RecursiveFuzzedDecode(FuzzedDataProvider& provider,
34*61c4878aSAndroid Build Coastguard Worker StreamDecoder& decoder,
35*61c4878aSAndroid Build Coastguard Worker uint32_t depth = 0) {
36*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxRepeatedRead = 256;
37*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxDepth = 3;
38*61c4878aSAndroid Build Coastguard Worker
39*61c4878aSAndroid Build Coastguard Worker if (depth > kMaxDepth) {
40*61c4878aSAndroid Build Coastguard Worker return;
41*61c4878aSAndroid Build Coastguard Worker }
42*61c4878aSAndroid Build Coastguard Worker while (provider.remaining_bytes() != 0 && decoder.Next().ok()) {
43*61c4878aSAndroid Build Coastguard Worker FieldType field_type = provider.ConsumeEnum<FieldType>();
44*61c4878aSAndroid Build Coastguard Worker switch (field_type) {
45*61c4878aSAndroid Build Coastguard Worker case kUint32:
46*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadUint32().status().ok()) {
47*61c4878aSAndroid Build Coastguard Worker return;
48*61c4878aSAndroid Build Coastguard Worker }
49*61c4878aSAndroid Build Coastguard Worker break;
50*61c4878aSAndroid Build Coastguard Worker case kPackedUint32: {
51*61c4878aSAndroid Build Coastguard Worker uint32_t packed[kMaxRepeatedRead] = {0};
52*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedUint32(packed).status().ok()) {
53*61c4878aSAndroid Build Coastguard Worker return;
54*61c4878aSAndroid Build Coastguard Worker }
55*61c4878aSAndroid Build Coastguard Worker } break;
56*61c4878aSAndroid Build Coastguard Worker case kUint64:
57*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadUint64().status().ok()) {
58*61c4878aSAndroid Build Coastguard Worker return;
59*61c4878aSAndroid Build Coastguard Worker }
60*61c4878aSAndroid Build Coastguard Worker break;
61*61c4878aSAndroid Build Coastguard Worker case kPackedUint64: {
62*61c4878aSAndroid Build Coastguard Worker uint64_t packed[kMaxRepeatedRead] = {0};
63*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedUint64(packed).status().ok()) {
64*61c4878aSAndroid Build Coastguard Worker return;
65*61c4878aSAndroid Build Coastguard Worker }
66*61c4878aSAndroid Build Coastguard Worker } break;
67*61c4878aSAndroid Build Coastguard Worker case kInt32:
68*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadInt32().status().ok()) {
69*61c4878aSAndroid Build Coastguard Worker return;
70*61c4878aSAndroid Build Coastguard Worker }
71*61c4878aSAndroid Build Coastguard Worker break;
72*61c4878aSAndroid Build Coastguard Worker case kPackedInt32: {
73*61c4878aSAndroid Build Coastguard Worker int32_t packed[kMaxRepeatedRead] = {0};
74*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedInt32(packed).status().ok()) {
75*61c4878aSAndroid Build Coastguard Worker return;
76*61c4878aSAndroid Build Coastguard Worker }
77*61c4878aSAndroid Build Coastguard Worker } break;
78*61c4878aSAndroid Build Coastguard Worker case kInt64:
79*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadInt64().status().ok()) {
80*61c4878aSAndroid Build Coastguard Worker return;
81*61c4878aSAndroid Build Coastguard Worker }
82*61c4878aSAndroid Build Coastguard Worker break;
83*61c4878aSAndroid Build Coastguard Worker case kPackedInt64: {
84*61c4878aSAndroid Build Coastguard Worker int64_t packed[kMaxRepeatedRead] = {0};
85*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedInt64(packed).status().ok()) {
86*61c4878aSAndroid Build Coastguard Worker return;
87*61c4878aSAndroid Build Coastguard Worker }
88*61c4878aSAndroid Build Coastguard Worker } break;
89*61c4878aSAndroid Build Coastguard Worker case kSint32:
90*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadSint32().status().ok()) {
91*61c4878aSAndroid Build Coastguard Worker return;
92*61c4878aSAndroid Build Coastguard Worker }
93*61c4878aSAndroid Build Coastguard Worker break;
94*61c4878aSAndroid Build Coastguard Worker case kPackedSint32: {
95*61c4878aSAndroid Build Coastguard Worker int32_t packed[kMaxRepeatedRead] = {0};
96*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedSint32(packed).status().ok()) {
97*61c4878aSAndroid Build Coastguard Worker return;
98*61c4878aSAndroid Build Coastguard Worker }
99*61c4878aSAndroid Build Coastguard Worker } break;
100*61c4878aSAndroid Build Coastguard Worker case kSint64:
101*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadSint64().status().ok()) {
102*61c4878aSAndroid Build Coastguard Worker return;
103*61c4878aSAndroid Build Coastguard Worker }
104*61c4878aSAndroid Build Coastguard Worker break;
105*61c4878aSAndroid Build Coastguard Worker case kPackedSint64: {
106*61c4878aSAndroid Build Coastguard Worker int64_t packed[kMaxRepeatedRead] = {0};
107*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedSint64(packed).status().ok()) {
108*61c4878aSAndroid Build Coastguard Worker return;
109*61c4878aSAndroid Build Coastguard Worker }
110*61c4878aSAndroid Build Coastguard Worker } break;
111*61c4878aSAndroid Build Coastguard Worker case kBool:
112*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadBool().status().ok()) {
113*61c4878aSAndroid Build Coastguard Worker return;
114*61c4878aSAndroid Build Coastguard Worker }
115*61c4878aSAndroid Build Coastguard Worker break;
116*61c4878aSAndroid Build Coastguard Worker case kFixed32:
117*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadFixed32().status().ok()) {
118*61c4878aSAndroid Build Coastguard Worker return;
119*61c4878aSAndroid Build Coastguard Worker }
120*61c4878aSAndroid Build Coastguard Worker break;
121*61c4878aSAndroid Build Coastguard Worker case kPackedFixed32: {
122*61c4878aSAndroid Build Coastguard Worker uint32_t packed[kMaxRepeatedRead] = {0};
123*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedFixed32(packed).status().ok()) {
124*61c4878aSAndroid Build Coastguard Worker return;
125*61c4878aSAndroid Build Coastguard Worker }
126*61c4878aSAndroid Build Coastguard Worker } break;
127*61c4878aSAndroid Build Coastguard Worker case kFixed64:
128*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadFixed64().status().ok()) {
129*61c4878aSAndroid Build Coastguard Worker return;
130*61c4878aSAndroid Build Coastguard Worker }
131*61c4878aSAndroid Build Coastguard Worker break;
132*61c4878aSAndroid Build Coastguard Worker case kPackedFixed64: {
133*61c4878aSAndroid Build Coastguard Worker uint64_t packed[kMaxRepeatedRead] = {0};
134*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedFixed64(packed).status().ok()) {
135*61c4878aSAndroid Build Coastguard Worker return;
136*61c4878aSAndroid Build Coastguard Worker }
137*61c4878aSAndroid Build Coastguard Worker } break;
138*61c4878aSAndroid Build Coastguard Worker case kSfixed32:
139*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadSfixed32().status().ok()) {
140*61c4878aSAndroid Build Coastguard Worker return;
141*61c4878aSAndroid Build Coastguard Worker }
142*61c4878aSAndroid Build Coastguard Worker break;
143*61c4878aSAndroid Build Coastguard Worker case kPackedSfixed32: {
144*61c4878aSAndroid Build Coastguard Worker int32_t packed[kMaxRepeatedRead] = {0};
145*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedSfixed32(packed).status().ok()) {
146*61c4878aSAndroid Build Coastguard Worker return;
147*61c4878aSAndroid Build Coastguard Worker }
148*61c4878aSAndroid Build Coastguard Worker } break;
149*61c4878aSAndroid Build Coastguard Worker case kSfixed64:
150*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadSfixed64().status().ok()) {
151*61c4878aSAndroid Build Coastguard Worker return;
152*61c4878aSAndroid Build Coastguard Worker }
153*61c4878aSAndroid Build Coastguard Worker break;
154*61c4878aSAndroid Build Coastguard Worker case kPackedSfixed64: {
155*61c4878aSAndroid Build Coastguard Worker int64_t packed[kMaxRepeatedRead] = {0};
156*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedSfixed64(packed).status().ok()) {
157*61c4878aSAndroid Build Coastguard Worker return;
158*61c4878aSAndroid Build Coastguard Worker }
159*61c4878aSAndroid Build Coastguard Worker } break;
160*61c4878aSAndroid Build Coastguard Worker case kFloat:
161*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadFloat().status().ok()) {
162*61c4878aSAndroid Build Coastguard Worker return;
163*61c4878aSAndroid Build Coastguard Worker }
164*61c4878aSAndroid Build Coastguard Worker break;
165*61c4878aSAndroid Build Coastguard Worker case kPackedFloat: {
166*61c4878aSAndroid Build Coastguard Worker float packed[kMaxRepeatedRead] = {0};
167*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedFloat(packed).status().ok()) {
168*61c4878aSAndroid Build Coastguard Worker return;
169*61c4878aSAndroid Build Coastguard Worker }
170*61c4878aSAndroid Build Coastguard Worker } break;
171*61c4878aSAndroid Build Coastguard Worker case kDouble:
172*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadDouble().status().ok()) {
173*61c4878aSAndroid Build Coastguard Worker return;
174*61c4878aSAndroid Build Coastguard Worker }
175*61c4878aSAndroid Build Coastguard Worker break;
176*61c4878aSAndroid Build Coastguard Worker case kPackedDouble: {
177*61c4878aSAndroid Build Coastguard Worker double packed[kMaxRepeatedRead] = {0};
178*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadPackedDouble(packed).status().ok()) {
179*61c4878aSAndroid Build Coastguard Worker return;
180*61c4878aSAndroid Build Coastguard Worker }
181*61c4878aSAndroid Build Coastguard Worker } break;
182*61c4878aSAndroid Build Coastguard Worker case kBytes: {
183*61c4878aSAndroid Build Coastguard Worker std::byte bytes[kMaxRepeatedRead] = {std::byte{0}};
184*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadBytes(bytes).status().ok()) {
185*61c4878aSAndroid Build Coastguard Worker return;
186*61c4878aSAndroid Build Coastguard Worker }
187*61c4878aSAndroid Build Coastguard Worker } break;
188*61c4878aSAndroid Build Coastguard Worker case kString: {
189*61c4878aSAndroid Build Coastguard Worker char str[kMaxRepeatedRead] = {0};
190*61c4878aSAndroid Build Coastguard Worker if (!decoder.ReadString(str).status().ok()) {
191*61c4878aSAndroid Build Coastguard Worker return;
192*61c4878aSAndroid Build Coastguard Worker }
193*61c4878aSAndroid Build Coastguard Worker } break;
194*61c4878aSAndroid Build Coastguard Worker case kPush: {
195*61c4878aSAndroid Build Coastguard Worker StreamDecoder nested_decoder = decoder.GetNestedDecoder();
196*61c4878aSAndroid Build Coastguard Worker RecursiveFuzzedDecode(provider, nested_decoder, depth + 1);
197*61c4878aSAndroid Build Coastguard Worker } break;
198*61c4878aSAndroid Build Coastguard Worker case kPop:
199*61c4878aSAndroid Build Coastguard Worker if (depth > 0) {
200*61c4878aSAndroid Build Coastguard Worker // Special "field". The marks the end of a nested message.
201*61c4878aSAndroid Build Coastguard Worker return;
202*61c4878aSAndroid Build Coastguard Worker }
203*61c4878aSAndroid Build Coastguard Worker }
204*61c4878aSAndroid Build Coastguard Worker }
205*61c4878aSAndroid Build Coastguard Worker }
206*61c4878aSAndroid Build Coastguard Worker
TestOneInput(FuzzedDataProvider & provider)207*61c4878aSAndroid Build Coastguard Worker void TestOneInput(FuzzedDataProvider& provider) {
208*61c4878aSAndroid Build Coastguard Worker constexpr size_t kMaxFuzzedProtoSize = 4096;
209*61c4878aSAndroid Build Coastguard Worker std::vector<std::byte> proto_message_data = provider.ConsumeBytes<std::byte>(
210*61c4878aSAndroid Build Coastguard Worker provider.ConsumeIntegralInRange<size_t>(0, kMaxFuzzedProtoSize));
211*61c4878aSAndroid Build Coastguard Worker stream::MemoryReader memory_reader(proto_message_data);
212*61c4878aSAndroid Build Coastguard Worker StreamDecoder decoder(memory_reader);
213*61c4878aSAndroid Build Coastguard Worker RecursiveFuzzedDecode(provider, decoder);
214*61c4878aSAndroid Build Coastguard Worker }
215*61c4878aSAndroid Build Coastguard Worker
216*61c4878aSAndroid Build Coastguard Worker } // namespace
217*61c4878aSAndroid Build Coastguard Worker } // namespace pw::protobuf::fuzz
218*61c4878aSAndroid Build Coastguard Worker
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)219*61c4878aSAndroid Build Coastguard Worker extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
220*61c4878aSAndroid Build Coastguard Worker FuzzedDataProvider provider(data, size);
221*61c4878aSAndroid Build Coastguard Worker pw::protobuf::fuzz::TestOneInput(provider);
222*61c4878aSAndroid Build Coastguard Worker return 0;
223*61c4878aSAndroid Build Coastguard Worker }
224