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