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
__anonec8596930102() 33                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
34                     str1->bytes();
35                 },
__anonec8596930202() 36                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
37                     str1->empty();
38                 },
__anonec8596930302() 39                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
40                     str1->length();
41                 },
42 
43                 // Casing
__anonec8596930402() 44                 [](FuzzedDataProvider*, android::String8* str1, android::String8*) -> void {
45                     str1->toLower();
46                 },
__anonec8596930502() 47                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
48                     if (str2->size() == 0) return;
49 
50                     str1->removeAll(str2->c_str());
51                 },
__anonec8596930602() 52                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
53                     const android::String8& constRef(*str2);
54                     str1->compare(constRef);
55                 },
56 
57                 // Append and format
__anonec8596930702() 58                 [](FuzzedDataProvider*, android::String8* str1, android::String8* str2) -> void {
59                     str1->append(str2->c_str());
60                 },
61                 [](FuzzedDataProvider* dataProvider, android::String8* str1, android::String8*)
__anonec8596930802() 62                         -> void { fuzzFormat(dataProvider, str1, dataProvider->ConsumeBool()); },
63 
64                 // Find operation
65                 [](FuzzedDataProvider* dataProvider, android::String8* str1,
__anonec8596930902() 66                    android::String8* str2) -> void {
67                     // We need to get a value from our fuzzer here.
68                     int start_index = dataProvider->ConsumeIntegralInRange<int>(0, str1->size());
69                     str1->find(str2->c_str(), start_index);
70                 },
71 };
72 
fuzzFormat(FuzzedDataProvider * dataProvider,android::String8 * str1,bool shouldAppend)73 void fuzzFormat(FuzzedDataProvider* dataProvider, android::String8* str1, bool shouldAppend) {
74     FormatChar formatType = dataProvider->ConsumeEnum<FormatChar>();
75 
76     std::string formatString("%");
77     // Width specifier
78     if (dataProvider->ConsumeBool()) {
79         // Left pad with zeroes
80         if (dataProvider->ConsumeBool()) {
81             formatString.push_back('0');
82         }
83         // Right justify (or left justify if negative)
84         int32_t justify = dataProvider->ConsumeIntegralInRange<int32_t>(-kMaxFormatFlagValue,
85                                                                         kMaxFormatFlagValue);
86         formatString += std::to_string(justify);
87     }
88 
89     // The # specifier only works with o, x, X, a, A, e, E, f, F, g, and G
90     if (canApplyFlag(formatType, '#') && dataProvider->ConsumeBool()) {
91         formatString.push_back('#');
92     }
93 
94     // Precision specifier
95     if (canApplyFlag(formatType, '.') && dataProvider->ConsumeBool()) {
96         formatString.push_back('.');
97         formatString +=
98                 std::to_string(dataProvider->ConsumeIntegralInRange<int>(0, kMaxFormatFlagValue));
99     }
100 
101     formatString.push_back(kFormatChars.at(static_cast<uint8_t>(formatType)));
102 
103     switch (formatType) {
104         case SIGNED_DECIMAL: {
105             int val = dataProvider->ConsumeIntegral<int>();
106             if (shouldAppend) {
107                 str1->appendFormat(formatString.c_str(), val);
108             } else {
109                 str1->format(formatString.c_str(), dataProvider->ConsumeIntegral<int>());
110             }
111             break;
112         }
113 
114         case UNSIGNED_DECIMAL:
115         case UNSIGNED_OCTAL:
116         case UNSIGNED_HEX_LOWER:
117         case UNSIGNED_HEX_UPPER: {
118             // Unsigned integers for u, o, x, and X
119             uint val = dataProvider->ConsumeIntegral<uint>();
120             if (shouldAppend) {
121                 str1->appendFormat(formatString.c_str(), val);
122             } else {
123                 str1->format(formatString.c_str(), val);
124             }
125             break;
126         }
127 
128         case FLOAT_LOWER:
129         case FLOAT_UPPER:
130         case EXPONENT_LOWER:
131         case EXPONENT_UPPER:
132         case SHORT_EXP_LOWER:
133         case SHORT_EXP_UPPER:
134         case HEX_FLOAT_LOWER:
135         case HEX_FLOAT_UPPER: {
136             // Floating points for f, F, e, E, g, G, a, and A
137             float val = dataProvider->ConsumeFloatingPoint<float>();
138             if (shouldAppend) {
139                 str1->appendFormat(formatString.c_str(), val);
140             } else {
141                 str1->format(formatString.c_str(), val);
142             }
143             break;
144         }
145 
146         case CHAR: {
147             char val = dataProvider->ConsumeIntegral<char>();
148             if (shouldAppend) {
149                 str1->appendFormat(formatString.c_str(), val);
150             } else {
151                 str1->format(formatString.c_str(), val);
152             }
153             break;
154         }
155 
156         case STRING: {
157             std::string val = dataProvider->ConsumeRandomLengthString(MAX_STRING_BYTES);
158             if (shouldAppend) {
159                 str1->appendFormat(formatString.c_str(), val.c_str());
160             } else {
161                 str1->format(formatString.c_str(), val.c_str());
162             }
163             break;
164         }
165         case POINTER: {
166             uintptr_t val = dataProvider->ConsumeIntegral<uintptr_t>();
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 }
176 
callFunc(uint8_t index,FuzzedDataProvider * dataProvider,android::String8 * str1,android::String8 * str2)177 void callFunc(uint8_t index, FuzzedDataProvider* dataProvider, android::String8* str1,
178               android::String8* str2) {
179     operations[index](dataProvider, str1, str2);
180 }
181 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)182 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
183     FuzzedDataProvider dataProvider(data, size);
184     // Generate vector lengths
185     const size_t kVecOneLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
186     const size_t kVecTwoLen = dataProvider.ConsumeIntegralInRange<size_t>(1, MAX_STRING_BYTES);
187     // Populate vectors
188     std::vector<char> vec = dataProvider.ConsumeBytesWithTerminator<char>(kVecOneLen);
189     std::vector<char> vec_two = dataProvider.ConsumeBytesWithTerminator<char>(kVecTwoLen);
190     // Create UTF-8 pointers
191     android::String8 str_one_utf8 = android::String8(vec.data());
192     android::String8 str_two_utf8 = android::String8(vec_two.data());
193     // Run operations against strings
194     int opsRun = 0;
195     while (dataProvider.remaining_bytes() > 0 && opsRun++ < MAX_OPERATIONS) {
196         uint8_t op = dataProvider.ConsumeIntegralInRange<uint8_t>(0, operations.size() - 1);
197         operations[op](&dataProvider, &str_one_utf8, &str_two_utf8);
198     }
199     // Just to be extra sure these can be freed, we're going to explicitly clear
200     // them
201     str_one_utf8.clear();
202     str_two_utf8.clear();
203     return 0;
204 }
205