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
__anon90faaa7c0102() 33                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
34                     str1->bytes();
35                 },
__anon90faaa7c0202() 36                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
37                     str1->isEmpty();
38                 },
__anon90faaa7c0302() 39                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
40                     str1->length();
41                 },
42 
43                 // Casing
__anon90faaa7c0402() 44                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
45                     str1->toLower();
46                 },
__anon90faaa7c0502() 47                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
48                     str1->removeAll(str2->c_str());
49                 },
__anon90faaa7c0602() 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
__anon90faaa7c0702() 56                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
57                     str1->append(str2->c_str());
58                 },
59                 [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
__anon90faaa7c0802() 60                         -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
61 
62                 // Find operation
63                 [](FuzzedDataProvider* dataProvider, android::String8* str1,
__anon90faaa7c0902() 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
__anon90faaa7c0a02() 71                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
72                     str1->getBasePath();
73                 },
__anon90faaa7c0b02() 74                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
75                     str1->getPathExtension();
76                 },
__anon90faaa7c0c02() 77                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
78                     str1->getPathLeaf();
79                 },
__anon90faaa7c0d02() 80                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
81                     str1->getPathDir();
82                 },
__anon90faaa7c0e02() 83                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
84                     str1->convertToResPath();
85                 },
__anon90faaa7c0f02() 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,
__anon90faaa7c1002() 93                    android::String8*) -> void {
94                     str1->setPathName(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
95                 },
96                 [](FuzzedDataProvider* dataProvider, android::String8* str1,
__anon90faaa7c1102() 97                    android::String8*) -> void {
98                     str1->appendPath(dataProvider->ConsumeBytesWithTerminator<char>(5).data());
99                 },
100 };
101 
fuzzFormat(FuzzedDataProvider * dataProvider,android::String8 * str1,bool shouldAppend)102 void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
103     FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
104 
105     std::string formatString("%");
106     // Width specifier
107     if (dataProvider->ConsumeBool()) {
108         // Left pad with zeroes
109         if (dataProvider->ConsumeBool()) {
110             formatString.push_back('0');
111         }
112         // Right justify (or left justify if negative)
113         int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
114                                                                         kMaxFormatFlagValue);
115         formatString += std::to_string(justify);
116     }
117 
118     // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
119     if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
120         formatString.push_back('#');
121     }
122 
123     // Precision specifier
124     if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
125         formatString.push_back('.');
126         formatString +=
127                 std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
128     }
129 
130     formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
131 
132     switch (formatType) {
133         case SIGNED_DECIMAL: {
134             int val = dataProvider->ConsumeIntegral<int>();
135             if (shouldAppend) {
136                 str1->appendFormat(formatString.c_str(), val);
137             } else {
138                 str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
139             }
140             break;
141         }
142 
143         case UNSIGNED_DECIMAL:
144         case UNSIGNED_OCTAL:
145         case UNSIGNED_HEX_LOWER:
146         case UNSIGNED_HEX_UPPER: {
147             // Unsigned integers for u, o, x, and X
148             uint val = dataProvider->ConsumeIntegral<uint>();
149             if (shouldAppend) {
150                 str1->appendFormat(formatString.c_str(), val);
151             } else {
152                 str1->format(formatString.c_str(), val);
153             }
154             break;
155         }
156 
157         case FLOAT_LOWER:
158         case FLOAT_UPPER:
159         case EXPONENT_LOWER:
160         case EXPONENT_UPPER:
161         case SHORT_EXP_LOWER:
162         case SHORT_EXP_UPPER:
163         case HEX_FLOAT_LOWER:
164         case HEX_FLOAT_UPPER: {
165             // Floating points for f, F, e, E, g, G, a, and A
166             float val = dataProvider->ConsumeFloatingPoint<float>();
167             if (shouldAppend) {
168                 str1->appendFormat(formatString.c_str(), val);
169             } else {
170                 str1->format(formatString.c_str(), val);
171             }
172             break;
173         }
174 
175         case CHAR: {
176             char val = dataProvider->ConsumeIntegral<char>();
177             if (shouldAppend) {
178                 str1->appendFormat(formatString.c_str(), val);
179             } else {
180                 str1->format(formatString.c_str(), val);
181             }
182             break;
183         }
184 
185         case STRING: {
186             std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
187             if (shouldAppend) {
188                 str1->appendFormat(formatString.c_str(), val.c_str());
189             } else {
190                 str1->format(formatString.c_str(), val.c_str());
191             }
192             break;
193         }
194         case POINTER: {
195             uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
196             if (shouldAppend) {
197                 str1->appendFormat(formatString.c_str(), val);
198             } else {
199                 str1->format(formatString.c_str(), val);
200             }
201             break;
202         }
203     }
204 }
205 
callFunc(uint8_t index,FuzzedDataProvider * dataProvider,android::String8 * str1,android::String8 * str2)206 void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
207               android::String8* str2) {
208     operations[index](dataProvider, str1, str2);
209 }
210 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)211 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
212     FuzzedDataProvider dataProvider(data, size);
213     // Generate vector lengths
214     const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
215     const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
216     // Populate vectors
217     std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
218     std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
219     // Create UTF-8 pointers
220     android::String8 str_one_utf8 = android::String8(vec.data());
221     android::String8 str_two_utf8 = android::String8(vec_two.data());
222     // Run operations against strings
223     int opsRun = 0;
224     while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
225         uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
226         operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
227     }
228     // Just to be extra sure these can be freed, we're going to explicitly clear
229     // them
230     str_one_utf8.clear();
231     str_two_utf8.clear();
232     return 0;
233 }
234