xref: /aosp_15_r20/external/pigweed/pw_protobuf/decoder_fuzzer.cc (revision 61c4878ac05f98d0ceed94b57d316916de578985)
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