1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * This software is licensed under the terms of the GNU General Public
5 * License version 2, as published by the Free Software Foundation, and
6 * may be copied, distributed, and modified under those terms.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 */
13
14 #include <fstream>
15 #include <iostream>
16 #include <functional>
17 #include "diskio.h"
18 #include "gpt.h"
19 #include "parttypes.h"
20
21 #include <fuzzer/FuzzedDataProvider.h>
22
23 const int8_t kQuiet = 1;
24 const int8_t kMinRuns = 1;
25 const int8_t kGPTMaxRuns = 24;
26 const int16_t kMaxByte = 256;
27 const std::string kShowCommand = "show";
28 const std::string kGetCommand = "get";
29 const std::string kTempFile = "/dev/tempfile";
30 const std::string kNull = "/dev/null";
31 const std::string kBackup = "/dev/gptbackup";
32 const std::string kDoesNotExist = "/dev/does_not_exist";
33
34 std::ofstream silence(kNull);
35
36 class GptfFuzzer {
37 public:
GptfFuzzer(const uint8_t * data,size_t size)38 GptfFuzzer(const uint8_t *data, size_t size) : mFdp(data, size) {
39 mDisk.OpenForRead(static_cast<const unsigned char *>(data), size);
40 }
41
~GptfFuzzer()42 ~GptfFuzzer() { mDisk.Close(); }
43
44 void process();
45
46 private:
47 void init();
48 FuzzedDataProvider mFdp;
49 DiskIO mDisk;
50 GPTData mGptData;
51 };
52
init()53 void GptfFuzzer::init() {
54 if (mFdp.ConsumeBool()) {
55 mGptData.SetDisk(mDisk);
56 } else {
57 mGptData.SetDisk(kTempFile);
58 }
59
60 uint64_t startSector = mFdp.ConsumeIntegral<uint64_t>();
61 uint64_t endSector =
62 mFdp.ConsumeIntegralInRange<uint64_t>(startSector, UINT64_MAX);
63 mGptData.CreatePartition(mFdp.ConsumeIntegral<uint8_t>() /* partNum */,
64 startSector, endSector);
65
66 const UnicodeString name = mFdp.ConsumeRandomLengthString(NAME_SIZE);
67 uint8_t partNum = mFdp.ConsumeIntegral<uint8_t>();
68 if (mGptData.SetName(partNum, name)) {
69 PartType pType;
70 mGptData.ChangePartType(partNum, pType);
71 }
72
73 if (mFdp.ConsumeBool()) {
74 mGptData.SetAlignment(mFdp.ConsumeIntegral<uint32_t>() /* n */);
75 }
76
77 if (mFdp.ConsumeBool()) {
78 GUIDData gData(mFdp.ConsumeRandomLengthString(kMaxByte));
79 gData.Randomize();
80 mGptData.SetDiskGUID(gData);
81 mGptData.SaveGPTBackup(kBackup);
82 mGptData.SetPartitionGUID(mFdp.ConsumeIntegral<uint8_t>() /* pn */, gData);
83 }
84
85 if (mFdp.ConsumeBool()) {
86 mGptData.RandomizeGUIDs();
87 }
88
89 if (mFdp.ConsumeBool()) {
90 mGptData.LoadGPTBackup(kBackup);
91 }
92
93 if (mFdp.ConsumeBool()) {
94 mGptData.SaveGPTData(kQuiet);
95 }
96
97 if (mFdp.ConsumeBool()) {
98 mGptData.SaveMBR();
99 }
100 }
101
process()102 void GptfFuzzer::process() {
103 init();
104 int8_t runs = mFdp.ConsumeIntegralInRange<int32_t>(kMinRuns, kGPTMaxRuns);
105
106 while (--runs && mFdp.remaining_bytes()) {
107 auto invokeGPTAPI = mFdp.PickValueInArray<const std::function<void()>>({
108 [&]() {
109 mGptData.XFormDisklabel(
110 mFdp.ConsumeIntegral<uint8_t>() /* partNum */);
111 },
112 [&]() {
113 mGptData.OnePartToMBR(mFdp.ConsumeIntegral<uint8_t>() /* gptPart */,
114 mFdp.ConsumeIntegral<uint8_t>() /* mbrPart */);
115 },
116 [&]() {
117 uint32_t numSegments;
118 uint64_t largestSegment;
119 mGptData.FindFreeBlocks(&numSegments, &largestSegment);
120 },
121 [&]() {
122 mGptData.FindFirstInLargest();
123 },
124 [&]() {
125 mGptData.FindLastAvailable();
126 },
127 [&]() {
128 mGptData.FindFirstFreePart();
129 },
130 [&]() {
131 mGptData.MoveMainTable(
132 mFdp.ConsumeIntegral<uint64_t>() /* pteSector */);
133 },
134 [&]() {
135 mGptData.Verify();
136 },
137 [&]() {
138 mGptData.SortGPT();
139 },
140 [&]() {
141 std::string command = mFdp.ConsumeBool() ? kShowCommand : kGetCommand;
142 std::string randomCommand = mFdp.ConsumeRandomLengthString(kMaxByte);
143 mGptData.ManageAttributes(
144 mFdp.ConsumeIntegral<uint8_t>() /* partNum */,
145 mFdp.ConsumeBool() ? command : randomCommand,
146 mFdp.ConsumeRandomLengthString(kMaxByte) /* bits */);
147 },
148 });
149 invokeGPTAPI();
150 }
151 if (mFdp.ConsumeBool()) {
152 mGptData.LoadPartitions(kDoesNotExist);
153 }
154 if (mFdp.ConsumeBool()) {
155 mGptData.SwapPartitions(mFdp.ConsumeIntegral<uint8_t>() /* partNum1 */,
156 mFdp.ConsumeIntegral<uint8_t>() /* partNum2 */);
157 }
158 mGptData.DeletePartition(mFdp.ConsumeIntegral<uint8_t>() /* partNum */);
159 mGptData.DestroyMBR();
160 mGptData.DestroyGPT();
161 }
162
LLVMFuzzerInitialize(int *,char ***)163 extern "C" int LLVMFuzzerInitialize(int *, char ***) {
164 std::cout.rdbuf(silence.rdbuf());
165 std::cerr.rdbuf(silence.rdbuf());
166 return 0;
167 }
168
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)169 extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
170 GptfFuzzer gptfFuzzer(data, size);
171 gptfFuzzer.process();
172 return 0;
173 }
174