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