1 // Copyright 2019 The Chromium OS Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include <stddef.h>
6 #include <stdint.h>
7
8 #include <base/files/file_path.h>
9 #include <base/files/file_util.h>
10 #include <base/files/scoped_temp_dir.h>
11 #include <base/logging.h>
12 #include <brillo/http/http_form_data.h>
13 #include <brillo/streams/memory_stream.h>
14 #include <fuzzer/FuzzedDataProvider.h>
15
16 namespace {
17 constexpr int kRandomDataMaxLength = 64;
18 constexpr int kMaxRecursionDepth = 256;
19
CreateTextFormField(FuzzedDataProvider * data_provider)20 std::unique_ptr<brillo::http::TextFormField> CreateTextFormField(
21 FuzzedDataProvider* data_provider) {
22 return std::make_unique<brillo::http::TextFormField>(
23 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
24 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
25 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
26 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength));
27 }
28
CreateFileFormField(FuzzedDataProvider * data_provider)29 std::unique_ptr<brillo::http::FileFormField> CreateFileFormField(
30 FuzzedDataProvider* data_provider) {
31 brillo::StreamPtr mem_stream = brillo::MemoryStream::OpenCopyOf(
32 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength), nullptr);
33 return std::make_unique<brillo::http::FileFormField>(
34 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
35 std::move(mem_stream),
36 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
37 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
38 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
39 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength));
40 }
41
CreateMultipartFormField(FuzzedDataProvider * data_provider,int depth)42 std::unique_ptr<brillo::http::MultiPartFormField> CreateMultipartFormField(
43 FuzzedDataProvider* data_provider, int depth) {
44 std::unique_ptr<brillo::http::MultiPartFormField> multipart_field =
45 std::make_unique<brillo::http::MultiPartFormField>(
46 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
47 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength),
48 data_provider->ConsumeRandomLengthString(kRandomDataMaxLength));
49
50 // Randomly add fields to this like we do the base FormData, but don't loop
51 // forever.
52 while (data_provider->ConsumeBool()) {
53 if (data_provider->ConsumeBool()) {
54 // Add a random text field to the form.
55 multipart_field->AddCustomField(CreateTextFormField(data_provider));
56 }
57 if (data_provider->ConsumeBool()) {
58 // Add a random file field to the form.
59 multipart_field->AddCustomField(CreateFileFormField(data_provider));
60 }
61 // Limit our recursion depth. We could make this part of our code iterative,
62 // but that won't help because in libbrillo we use recursion to generate the
63 // stream so we would hit a stack depth limit there as well.
64 if (depth < kMaxRecursionDepth && data_provider->ConsumeBool()) {
65 // Add a random multipart form field to the form.
66 multipart_field->AddCustomField(
67 CreateMultipartFormField(data_provider, depth + 1));
68 }
69 }
70
71 return multipart_field;
72 }
73
74 } // namespace
75
IgnoreLogging(int,const char *,int,size_t,const std::string &)76 bool IgnoreLogging(int, const char*, int, size_t, const std::string&) {
77 return true;
78 }
79
80 class Environment {
81 public:
Environment()82 Environment() {
83 // Disable logging. Normally this would be done with logging::SetMinLogLevel
84 // but that doesn't work for brillo::Error for because it's not using the
85 // LOG(ERROR) macro which is where the actual log level check occurs.
86 logging::SetLogMessageHandler(&IgnoreLogging);
87 }
88 };
89
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)90 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
91 static Environment env;
92 FuzzedDataProvider data_provider(data, size);
93 // Randomly add a bunch of fields to the FormData and then when done extract
94 // and consume the data stream.
95 brillo::http::FormData form_data(
96 data_provider.ConsumeRandomLengthString(kRandomDataMaxLength));
97 while (data_provider.remaining_bytes() > 0) {
98 if (data_provider.ConsumeBool()) {
99 // Add a random text field to the form.
100 form_data.AddCustomField(CreateTextFormField(&data_provider));
101 }
102 if (data_provider.ConsumeBool()) {
103 // Add a random file field to the form.
104 form_data.AddCustomField(CreateFileFormField(&data_provider));
105 }
106 if (data_provider.ConsumeBool()) {
107 // Add a random multipart form field to the form.
108 form_data.AddCustomField(CreateMultipartFormField(&data_provider, 0));
109 }
110 }
111
112 brillo::StreamPtr form_stream = form_data.ExtractDataStream();
113 if (!form_stream)
114 return 0;
115
116 // We need to use a decent sized buffer and call ReadAllBlocking to avoid
117 // excess overhead with reading here that can make the fuzzer timeout.
118 uint8_t buffer[32768];
119 while (form_stream->GetRemainingSize() > 0) {
120 if (!form_stream->ReadAllBlocking(buffer, sizeof(buffer), nullptr)) {
121 // If there's an error reading from the stream, then bail since we'd
122 // likely just see repeated errors and never exit.
123 break;
124 }
125 }
126
127 return 0;
128 }
129