1 /*
2  * Copyright 2020 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 #include <functional>
17 #include <iostream>
18 #include <memory>
19 
20 #include "FuzzFormatTypes.h"
21 #include "fuzzer/FuzzedDataProvider.h"
22 #include "utils/String8.h"
23 
24 static constexpr int MAX_STRING_BYTES = 256;
25 static constexpr uint8_t MAX_OPERATIONS = 50;
26 // Interestingly, 2147483614 (INT32_MAX - 33) seems to be the max value that is handled for format
27 // flags. Unfortunately we need to use a smaller value so we avoid consuming too much memory.
28 
29 void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend);
30 std::vector<std::function<void(FuzzedDataProvider*, android::String8*, android::String8*)>>
31         operations = {
32                 // Bytes and size
__anon14e4abfe0102() 33                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
34                     str1->bytes();
35                 },
__anon14e4abfe0202() 36                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
37                     str1->isEmpty();
38                 },
__anon14e4abfe0302() 39                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
40                     str1->length();
41                 },
42 
43                 // Casing
__anon14e4abfe0402() 44                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
45                     str1->toLower();
46                 },
__anon14e4abfe0502() 47                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
48                     str1->removeAll(str2->c_str());
49                 },
__anon14e4abfe0602() 50                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
51                     const android::String8& constRef(*str2);
52                     str1->compare(constRef);
53                 },
54 
55                 // Append and format
__anon14e4abfe0702() 56                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
57                     str1->append(str2->c_str());
58                 },
59                 [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
__anon14e4abfe0802() 60                         -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
61 
62                 // Find operation
63                 [](FuzzedDataProvider* dataProvider, android::String8* str1,
__anon14e4abfe0902() 64                    android::String8* str2) -> void {
65                     // We need to get a value from our fuzzer here.
66                     int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
67                     str1->find(str2->c_str(), start_index);
68                 },
69 
70                 // Path handling
__anon14e4abfe0a02() 71                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
72                     str1->getBasePath();
73                 },
__anon14e4abfe0b02() 74                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
75                     str1->getPathExtension();
76                 },
__anon14e4abfe0c02() 77                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
78                     str1->getPathLeaf();
79                 },
__anon14e4abfe0d02() 80                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
81                     str1->getPathDir();
82                 },
__anon14e4abfe0e02() 83                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
84                     str1->convertToResPath();
85                 },
__anon14e4abfe0f02() 86                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
87                     std::shared_ptr<android::String8> path_out_str =
88                             std::make_shared<android::String8>();
89                     str1->walkPath(path_out_str.get());
90                     path_out_str->clear();
91                 },
92                 [](FuzzedDataProvider* dataProvider, android::String8* str1,
__anon14e4abfe1002() 93                    android::String8*) -> void {
94                     str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
95                 },
96 };
97 
fuzzFormat(FuzzedDataProvider * dataProvider,android::String8 * str1,bool shouldAppend)98 void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
99     FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
100 
101     std::string formatString("%");
102     // Width specifier
103     if (dataProvider->ConsumeBool()) {
104         // Left pad with zeroes
105         if (dataProvider->ConsumeBool()) {
106             formatString.push_back('0');
107         }
108         // Right justify (or left justify if negative)
109         int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
110                                                                         kMaxFormatFlagValue);
111         formatString += std::to_string(justify);
112     }
113 
114     // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
115     if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
116         formatString.push_back('#');
117     }
118 
119     // Precision specifier
120     if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
121         formatString.push_back('.');
122         formatString +=
123                 std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
124     }
125 
126     formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
127 
128     switch (formatType) {
129         case SIGNED_DECIMAL: {
130             int val = dataProvider->ConsumeIntegral<int>();
131             if (shouldAppend) {
132                 str1->appendFormat(formatString.c_str(), val);
133             } else {
134                 str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
135             }
136             break;
137         }
138 
139         case UNSIGNED_DECIMAL:
140         case UNSIGNED_OCTAL:
141         case UNSIGNED_HEX_LOWER:
142         case UNSIGNED_HEX_UPPER: {
143             // Unsigned integers for u, o, x, and X
144             uint val = dataProvider->ConsumeIntegral<uint>();
145             if (shouldAppend) {
146                 str1->appendFormat(formatString.c_str(), val);
147             } else {
148                 str1->format(formatString.c_str(), val);
149             }
150             break;
151         }
152 
153         case FLOAT_LOWER:
154         case FLOAT_UPPER:
155         case EXPONENT_LOWER:
156         case EXPONENT_UPPER:
157         case SHORT_EXP_LOWER:
158         case SHORT_EXP_UPPER:
159         case HEX_FLOAT_LOWER:
160         case HEX_FLOAT_UPPER: {
161             // Floating points for f, F, e, E, g, G, a, and A
162             float val = dataProvider->ConsumeFloatingPoint<float>();
163             if (shouldAppend) {
164                 str1->appendFormat(formatString.c_str(), val);
165             } else {
166                 str1->format(formatString.c_str(), val);
167             }
168             break;
169         }
170 
171         case CHAR: {
172             char val = dataProvider->ConsumeIntegral<char>();
173             if (shouldAppend) {
174                 str1->appendFormat(formatString.c_str(), val);
175             } else {
176                 str1->format(formatString.c_str(), val);
177             }
178             break;
179         }
180 
181         case STRING: {
182             std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
183             if (shouldAppend) {
184                 str1->appendFormat(formatString.c_str(), val.c_str());
185             } else {
186                 str1->format(formatString.c_str(), val.c_str());
187             }
188             break;
189         }
190         case POINTER: {
191             uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
192             if (shouldAppend) {
193                 str1->appendFormat(formatString.c_str(), val);
194             } else {
195                 str1->format(formatString.c_str(), val);
196             }
197             break;
198         }
199     }
200 }
201 
callFunc(uint8_t index,FuzzedDataProvider * dataProvider,android::String8 * str1,android::String8 * str2)202 void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
203               android::String8* str2) {
204     operations[index](dataProvider, str1, str2);
205 }
206 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)207 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
208     FuzzedDataProvider dataProvider(data, size);
209     // Generate vector lengths
210     const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
211     const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
212     // Populate vectors
213     std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
214     std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
215     // Create UTF-8 pointers
216     android::String8 str_one_utf8 = android::String8(vec.data());
217     android::String8 str_two_utf8 = android::String8(vec_two.data());
218     // Run operations against strings
219     int opsRun = 0;
220     while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
221         uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
222         operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
223     }
224     // Just to be extra sure these can be freed, we're going to explicitly clear
225     // them
226     str_one_utf8.clear();
227     str_two_utf8.clear();
228     return 0;
229 }
230