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