xref: /aosp_15_r20/system/core/fs_mgr/liblp/fuzzer/liblp_builder_fuzzer.cpp (revision 00c7fec1bb09f3284aad6a6f96d2f63dfc3650ad)
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