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