1 /*
2 * Copyright (C) 2023 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 */
17
18 #include <fuzzer/FuzzedDataProvider.h>
19 #include <liblp/builder.h>
20 #include <liblp/property_fetcher.h>
21 #include <storage_literals/storage_literals.h>
22
23 using namespace android::fs_mgr;
24 using namespace std;
25 using namespace android::storage_literals;
26
27 static constexpr uint64_t kValidBlockSize = 4096 * 50;
28 static constexpr uint64_t kBlockDeviceInfoSize = 1024 * 1024;
29 static constexpr uint64_t kValidBlockDeviceInfoSize = 8_GiB;
30 static constexpr uint64_t kValidMaxGroupSize = 40960;
31 static constexpr uint64_t kMinBlockDevValue = 1;
32 static constexpr uint64_t kMaxBlockDevValue = 100000;
33 static constexpr uint64_t kMinSectorValue = 1;
34 static constexpr uint64_t kMaxSectorValue = 1000000;
35 static constexpr uint64_t kMinValue = 0;
36 static constexpr uint64_t kMaxValue = 10000;
37 static constexpr uint64_t kValidNumSectors = 1901568;
38 static constexpr uint64_t kValidPhysicalSector = 3608576;
39 static constexpr uint64_t kMinElements = 0;
40 static constexpr uint64_t kMaxElements = 10;
41 static constexpr uint32_t kValidAlignment = 786432;
42 static constexpr uint32_t kValidMetadataSize = 40960;
43 static constexpr uint32_t kValidAlignmentOffset = 229376;
44 static constexpr uint32_t kValidLogicalBlockSize = 4096;
45 static constexpr uint32_t kValidMaxMetadataSize = 65536;
46 static constexpr uint32_t kMinMetadataValue = 0;
47 static constexpr uint32_t kMaxMetadataValue = 10000;
48 static constexpr uint32_t kZeroAlignment = 0;
49 static constexpr uint32_t kZeroAlignmentOffset = 0;
50 static constexpr uint32_t kMaxBytes = 20;
51 static constexpr uint32_t kMinBuilder = 0;
52 static constexpr uint32_t kMaxBuilder = 4;
53
54 const uint64_t kAttributeTypes[] = {
55 LP_PARTITION_ATTR_NONE, LP_PARTITION_ATTR_READONLY, LP_PARTITION_ATTR_SLOT_SUFFIXED,
56 LP_PARTITION_ATTR_UPDATED, LP_PARTITION_ATTR_DISABLED,
57 };
58
59 const string kFuzzPartitionName = "fuzz_partition_name";
60 const string kSuperPartitionName = "super_partition";
61 const string kDeviceInfoName = "super";
62 const string kDefaultGroupName = "default";
63
64 class BuilderFuzzer {
65 public:
BuilderFuzzer(const uint8_t * data,size_t size)66 BuilderFuzzer(const uint8_t* data, size_t size) : mFdp(data, size){};
67 void process();
68
69 private:
70 FuzzedDataProvider mFdp;
71 void invokeBuilderAPIs();
72 void selectRandomBuilder(int32_t randomBuilder, string superBlockDeviceName);
73 void setupBuilder(string superBlockDeviceName);
74 void callChangePartitionGroup();
75 void callVerifyExtentsAgainstSourceMetadata();
76 vector<BlockDeviceInfo> mBlockDevices;
77 unique_ptr<MetadataBuilder> mBuilder;
78 string mResizePartitionName;
79 string mGroupNames[4] = {
80 "default",
81 "group_a",
82 "group_b",
83 mFdp.ConsumeRandomLengthString(kMaxBytes),
84 };
85 string mPartitionNames[5] = {
86 "system_a",
87 "vendor_a",
88 "system_b",
89 "vendor_b",
90 mFdp.ConsumeRandomLengthString(kMaxBytes),
91 };
92 Partition* mPartition;
93 Partition* mFuzzPartition;
94 Partition* mResizePartition;
95 template <typename T>
getParamValue(T validValue)96 T getParamValue(T validValue) {
97 T parameter = validValue;
98 if (mFdp.ConsumeBool()) {
99 parameter = mFdp.ConsumeIntegralInRange<T>(kMinValue, kMaxValue);
100 }
101 return parameter;
102 }
103 };
104
selectRandomBuilder(int32_t randomBuilder,string superBlockDeviceName)105 void BuilderFuzzer::selectRandomBuilder(int32_t randomBuilder, string superBlockDeviceName) {
106 switch (randomBuilder) {
107 case 0: {
108 uint32_t maxMetadataSize = getParamValue(kValidMaxMetadataSize);
109 uint32_t numSlots = mFdp.ConsumeBool() ? 0 : 1;
110 mBuilder = MetadataBuilder::New(mBlockDevices, superBlockDeviceName, maxMetadataSize,
111 numSlots);
112 break;
113 }
114 case 1: {
115 uint64_t blockDevSize =
116 mFdp.ConsumeIntegralInRange<uint64_t>(kMinBlockDevValue, kMaxBlockDevValue);
117 uint32_t metadataMaxSize =
118 mFdp.ConsumeIntegralInRange<uint32_t>(kMinMetadataValue, kMaxMetadataValue);
119 uint32_t metadataSlotCount = mFdp.ConsumeBool() ? 0 : 1;
120 mBuilder = MetadataBuilder::New(blockDevSize, metadataMaxSize, metadataSlotCount);
121 break;
122 }
123 case 2: {
124 uint64_t blockDevSize = getParamValue(kValidBlockSize);
125 uint32_t metadataSize = getParamValue(kValidMetadataSize);
126 uint32_t metadataSlotCount = mFdp.ConsumeBool() ? 0 : 1;
127 mBuilder = MetadataBuilder::New(blockDevSize, metadataSize, metadataSlotCount);
128 break;
129 }
130 case 3: {
131 string superPartitionName = mFdp.ConsumeBool()
132 ? kSuperPartitionName
133 : mFdp.ConsumeRandomLengthString(kMaxBytes);
134 mBuilder = MetadataBuilder::New(PartitionOpener(), superPartitionName,
135 mFdp.ConsumeIntegralInRange(0, 1) /* slot_number */);
136 break;
137 }
138 case 4: {
139 string superPartitionName = mFdp.ConsumeBool()
140 ? kSuperPartitionName
141 : mFdp.ConsumeRandomLengthString(kMaxBytes);
142 mBuilder = MetadataBuilder::New(
143 superPartitionName,
144 mFdp.ConsumeIntegralInRange<uint32_t>(0, 1) /* slot_number */);
145 break;
146 }
147 }
148 }
149
setupBuilder(string superBlockDeviceName)150 void BuilderFuzzer::setupBuilder(string superBlockDeviceName) {
151 uint64_t blockDeviceInfoSize =
152 mFdp.ConsumeBool()
153 ? mFdp.ConsumeIntegralInRange<uint64_t>(kMinBlockDevValue, kMaxBlockDevValue)
154 : kValidBlockDeviceInfoSize;
155 uint32_t alignment = mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidAlignment;
156 uint32_t alignmentOffset =
157 mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>() : kValidAlignmentOffset;
158 uint32_t logicalBlockSize = mFdp.ConsumeBool() ? mFdp.ConsumeIntegralInRange<uint32_t>(
159 kMinBlockDevValue, kMaxBlockDevValue)
160 : kValidLogicalBlockSize;
161
162 BlockDeviceInfo super(superBlockDeviceName, blockDeviceInfoSize, alignment, alignmentOffset,
163 logicalBlockSize);
164 mBlockDevices.push_back(super);
165
166 mBuilder->AddGroup(kDefaultGroupName, mFdp.ConsumeIntegral<uint64_t>() /* max_size */);
167 mPartition = mBuilder->AddPartition(kSuperPartitionName, LP_PARTITION_ATTR_READONLY);
168
169 mFuzzPartition = mBuilder->AddPartition(kFuzzPartitionName, kDefaultGroupName,
170 LP_PARTITION_ATTR_READONLY);
171
172 string mResizePartitionName = mFdp.ConsumeRandomLengthString(kMaxBytes);
173 if (!mResizePartitionName.size()) {
174 mResizePartitionName = "resize_partition";
175 }
176 mResizePartition = mBuilder->AddPartition(mResizePartitionName, kDefaultGroupName,
177 LP_PARTITION_ATTR_READONLY);
178
179 string changePartitionDeviceInfoName =
180 mFdp.ConsumeBool() ? kDeviceInfoName : mFdp.ConsumeRandomLengthString(kMaxBytes);
181 BlockDeviceInfo changePartitionDeviceInfo(
182 changePartitionDeviceInfoName,
183 mFdp.ConsumeBool()
184 ? mFdp.ConsumeIntegralInRange<uint64_t>(kMinBlockDevValue, kMaxBlockDevValue)
185 : kBlockDeviceInfoSize /* size */,
186 mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>()
187 : kZeroAlignmentOffset /* alignment */,
188 mFdp.ConsumeBool() ? mFdp.ConsumeIntegral<uint32_t>()
189 : kZeroAlignmentOffset /* alignment_offset */,
190 mFdp.ConsumeBool()
191 ? mFdp.ConsumeIntegralInRange<uint32_t>(kMinBlockDevValue, kMaxBlockDevValue)
192 : kValidLogicalBlockSize);
193 mBlockDevices.push_back(changePartitionDeviceInfo);
194 }
195
callChangePartitionGroup()196 void BuilderFuzzer::callChangePartitionGroup() {
197 string group1 = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : "group1";
198 uint64_t group1Size = getParamValue(0);
199
200 string group2 = mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : "group2";
201 uint64_t group2Size = getParamValue(0);
202
203 bool group1Added = mBuilder->AddGroup(group1, group1Size);
204 bool group2Added = mBuilder->AddGroup(group2, group2Size);
205
206 string changeGroupPartitionName = mFdp.ConsumeRandomLengthString(kMaxBytes);
207 if (changeGroupPartitionName.size() && group1Added && group2Added) {
208 Partition* changeGroupPartition = mBuilder->AddPartition(changeGroupPartitionName, group1,
209 LP_PARTITION_ATTR_READONLY);
210 if (changeGroupPartition) {
211 mBuilder->ChangePartitionGroup(changeGroupPartition, group2);
212 }
213 }
214 }
215
callVerifyExtentsAgainstSourceMetadata()216 void BuilderFuzzer::callVerifyExtentsAgainstSourceMetadata() {
217 uint64_t sourceBlockDevSize = getParamValue(kValidBlockSize);
218 uint32_t sourceMetadataMaxSize = getParamValue(kValidMetadataSize);
219 uint32_t sourceSlotCount = mFdp.ConsumeIntegralInRange<uint32_t>(0, 1);
220 auto sourceBuilder =
221 MetadataBuilder::New(sourceBlockDevSize, sourceMetadataMaxSize, sourceSlotCount);
222
223 uint64_t targetBlockDevSize = getParamValue(kValidBlockSize);
224 uint32_t targetMetadataMaxSize = getParamValue(kValidMetadataSize);
225 uint32_t targetSlotCount = mFdp.ConsumeIntegralInRange<uint32_t>(0, 1);
226 auto targetBuilder =
227 MetadataBuilder::New(targetBlockDevSize, targetMetadataMaxSize, targetSlotCount);
228
229 if (sourceBuilder && targetBuilder) {
230 int64_t sourceGroups = mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
231 for (int64_t idx = 0; idx < sourceGroups; ++idx) {
232 sourceBuilder->AddGroup(
233 mFdp.PickValueInArray(mGroupNames),
234 mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral<uint64_t>());
235 }
236
237 int64_t sourcePartitions = mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
238 for (int64_t idx = 0; idx < sourcePartitions; ++idx) {
239 sourceBuilder->AddPartition(mFdp.PickValueInArray(mPartitionNames),
240 LP_PARTITION_ATTR_READONLY);
241 }
242
243 int64_t targetGroups = mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
244 for (int64_t idx = 0; idx < targetGroups; ++idx) {
245 targetBuilder->AddGroup(
246 mFdp.PickValueInArray(mGroupNames),
247 mFdp.ConsumeBool() ? kValidMaxGroupSize : mFdp.ConsumeIntegral<uint64_t>());
248 }
249
250 int64_t targetPartitions = mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
251 for (int64_t idx = 0; idx < targetPartitions; ++idx) {
252 targetBuilder->AddPartition(mFdp.PickValueInArray(mPartitionNames),
253 LP_PARTITION_ATTR_READONLY);
254 }
255
256 MetadataBuilder::VerifyExtentsAgainstSourceMetadata(
257 *sourceBuilder, mFdp.ConsumeBool() ? 0 : 1 /* source_slot_number */, *targetBuilder,
258 mFdp.ConsumeBool() ? 0 : 1 /* target_slot_number */,
259 vector<string>{"system", "vendor", mFdp.ConsumeRandomLengthString(kMaxBytes)});
260 }
261 }
262
invokeBuilderAPIs()263 void BuilderFuzzer::invokeBuilderAPIs() {
264 string superBlockDeviceName =
265 mFdp.ConsumeBool() ? mFdp.ConsumeRandomLengthString(kMaxBytes) : kDeviceInfoName;
266 uint32_t randomBuilder = mFdp.ConsumeIntegralInRange<uint32_t>(kMinBuilder, kMaxBuilder);
267 selectRandomBuilder(randomBuilder, superBlockDeviceName);
268
269 if (mBuilder.get()) {
270 setupBuilder(superBlockDeviceName);
271
272 while (mFdp.remaining_bytes()) {
273 auto invokeAPIs = mFdp.PickValueInArray<const function<void()>>({
274 [&]() { callChangePartitionGroup(); },
275 [&]() {
276 string addedGroupName = mFdp.PickValueInArray(mGroupNames);
277 mBuilder->AddGroup(addedGroupName,
278 mFdp.ConsumeIntegralInRange<uint64_t>(
279 kMinValue, kMaxValue) /* max_size */);
280 },
281 [&]() {
282 string partitionName = mFdp.PickValueInArray(mPartitionNames);
283 Partition* addedPartition = mBuilder->AddPartition(
284 partitionName, mFdp.PickValueInArray(kAttributeTypes));
285 },
286 [&]() {
287 int64_t numSectors = mFdp.ConsumeBool()
288 ? mFdp.ConsumeIntegralInRange<uint64_t>(
289 kMinSectorValue, kMaxSectorValue)
290 : kValidNumSectors;
291 int64_t physicalSector = mFdp.ConsumeBool()
292 ? mFdp.ConsumeIntegralInRange<uint64_t>(
293 kMinSectorValue, kMaxSectorValue)
294 : kValidPhysicalSector;
295
296 int64_t numExtents =
297 mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
298 if (mFuzzPartition) {
299 bool extentAdded = false;
300 for (int64_t i = 0; i <= numExtents; ++i) {
301 extentAdded =
302 mBuilder->AddLinearExtent(mFuzzPartition, kDeviceInfoName,
303 numSectors, physicalSector);
304 }
305
306 if (extentAdded) {
307 unique_ptr<LpMetadata> metadata = mBuilder->Export();
308 uint64_t alignedSize =
309 mFdp.ConsumeIntegralInRange<uint64_t>(kMinValue, kMaxValue);
310 mFuzzPartition->GetBeginningExtents(LP_SECTOR_SIZE * numExtents);
311 }
312 }
313 },
314 [&]() { callVerifyExtentsAgainstSourceMetadata(); },
315 [&]() { mBuilder->ListPartitionsInGroup(mFdp.PickValueInArray(mGroupNames)); },
316 [&]() {
317 int64_t maxSize = mFdp.ConsumeIntegral<uint64_t>();
318 mBuilder->ChangeGroupSize(mFdp.PickValueInArray(mGroupNames), maxSize);
319 },
320 [&]() {
321 string deviceInfoName = mFdp.ConsumeBool()
322 ? kDeviceInfoName
323 : mFdp.ConsumeRandomLengthString(kMaxBytes);
324 mBuilder->GetBlockDeviceInfo(deviceInfoName, &mBlockDevices[1]);
325 },
326 [&]() {
327 string deviceInfoName = mFdp.ConsumeBool()
328 ? kDeviceInfoName
329 : mFdp.ConsumeRandomLengthString(kMaxBytes);
330 mBuilder->UpdateBlockDeviceInfo(deviceInfoName, mBlockDevices[1]);
331 },
332 [&]() {
333 unique_ptr<LpMetadata> metadata = mBuilder->Export();
334 mBuilder->ImportPartitions(*metadata.get(),
335 {mFdp.PickValueInArray(mPartitionNames)});
336 },
337 [&]() { mBuilder->HasBlockDevice(mFdp.PickValueInArray(mPartitionNames)); },
338 [&]() { mBuilder->SetVirtualABDeviceFlag(); },
339 [&]() { mBuilder->SetAutoSlotSuffixing(); },
340 [&]() { mBuilder->ListGroups(); },
341 [&]() { mBuilder->UsedSpace(); },
342 [&]() { mBuilder->RequireExpandedMetadataHeader(); },
343 [&]() {
344 uint64_t resizedPartitionSize = getParamValue(0);
345 mBuilder->ResizePartition(mResizePartition, resizedPartitionSize);
346 },
347 [&]() {
348 uint32_t sourceSlot = mFdp.ConsumeBool() ? 0 : 1;
349 uint32_t targetSlot = mFdp.ConsumeBool() ? 0 : 1;
350 PartitionOpener partitionOpener;
351 string sourcePartition =
352 mFdp.ConsumeBool() ? kFuzzPartitionName : kDeviceInfoName;
353
354 MetadataBuilder::NewForUpdate(partitionOpener, sourcePartition, sourceSlot,
355 targetSlot);
356 partitionOpener.GetDeviceString(mFdp.PickValueInArray(mPartitionNames));
357 },
358 [&]() {
359 unique_ptr<LpMetadata> metadata = mBuilder->Export();
360 MetadataBuilder::New(*metadata.get());
361 },
362 [&]() { mBuilder->AllocatableSpace(); },
363 [&]() {
364 PartitionOpener pOpener;
365 string superPartitionName =
366 mFdp.ConsumeBool() ? kSuperPartitionName
367 : mFdp.ConsumeRandomLengthString(kMaxBytes);
368 pOpener.Open(superPartitionName, O_RDONLY);
369 pOpener.GetInfo(superPartitionName, &mBlockDevices[0]);
370 },
371 [&]() {
372 PartitionOpener pOpener;
373 string superPartitionName =
374 mFdp.ConsumeBool() ? kSuperPartitionName
375 : mFdp.ConsumeRandomLengthString(kMaxBytes);
376 pOpener.Open(superPartitionName, O_RDONLY);
377 pOpener.GetDeviceString(superPartitionName);
378 },
379 [&]() {
380 Interval::Intersect(
381 Interval(mFdp.ConsumeIntegral<uint64_t>() /* device _index */,
382 mFdp.ConsumeIntegral<uint64_t>() /* start */,
383 mFdp.ConsumeIntegral<uint64_t>()) /* end */,
384 Interval(mFdp.ConsumeIntegral<uint64_t>() /* device _index */,
385 mFdp.ConsumeIntegral<uint64_t>() /* start */,
386 mFdp.ConsumeIntegral<uint64_t>() /* end */));
387 },
388 [&]() {
389 vector<Interval> intervalVectorA;
390 int64_t internalVectorAElements =
391 mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
392 for (int64_t idx = 0; idx < internalVectorAElements; ++idx) {
393 intervalVectorA.push_back(
394 Interval(mFdp.ConsumeIntegral<uint64_t>() /* device _index */,
395 mFdp.ConsumeIntegral<uint64_t>() /* start */,
396 mFdp.ConsumeIntegral<uint64_t>() /* end */));
397 }
398
399 vector<Interval> intervalVectorB;
400 int64_t internalVectorBElements =
401 mFdp.ConsumeIntegralInRange<int64_t>(kMinElements, kMaxElements);
402 for (int64_t idx = 0; idx < internalVectorBElements; ++idx) {
403 intervalVectorB.push_back(
404 Interval(mFdp.ConsumeIntegral<uint64_t>() /* device _index */,
405 mFdp.ConsumeIntegral<uint64_t>() /* start */,
406 mFdp.ConsumeIntegral<uint64_t>() /* end */));
407 }
408
409 Interval::Intersect(intervalVectorA, intervalVectorB);
410 },
411 [&]() {
412 uint64_t numSectors =
413 mFdp.ConsumeIntegralInRange<uint64_t>(kMinValue, kMaxValue);
414 uint32_t deviceIndex =
415 mFdp.ConsumeIntegralInRange<uint32_t>(kMinValue, kMaxValue);
416 uint64_t physicalSector =
417 mFdp.ConsumeIntegralInRange<uint64_t>(kMinValue, kMaxValue);
418 LinearExtent extent(numSectors, deviceIndex, physicalSector);
419 extent.AsInterval();
420 },
421 [&]() {
422 IPropertyFetcher::OverrideForTesting(std::make_unique<PropertyFetcher>());
423 },
424 });
425 invokeAPIs();
426 }
427 if (mFdp.ConsumeBool()) {
428 mBuilder->RemoveGroupAndPartitions(mFdp.PickValueInArray(mGroupNames));
429 } else {
430 string removePartition = mFdp.PickValueInArray(mPartitionNames);
431 mBuilder->RemovePartition(removePartition);
432 }
433 }
434 }
435
process()436 void BuilderFuzzer::process() {
437 invokeBuilderAPIs();
438 }
439
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)440 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
441 BuilderFuzzer builderFuzzer(data, size);
442 builderFuzzer.process();
443 return 0;
444 }
445