1 /*
2 * Copyright (C) 2021 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 #include <android-base/file.h>
18 #include "fastboot.h"
19 #include "socket.h"
20 #include "socket_mock_fuzz.h"
21 #include "tcp.h"
22 #include "udp.h"
23 #include "vendor_boot_img_utils.h"
24
25 #include <fuzzer/FuzzedDataProvider.h>
26
27 using namespace std;
28
29 const size_t kYearMin = 2000;
30 const size_t kYearMax = 2127;
31 const size_t kMonthMin = 1;
32 const size_t kMonthMax = 12;
33 const size_t kDayMin = 1;
34 const size_t kDayMax = 31;
35 const size_t kVersionMin = 0;
36 const size_t kVersionMax = 127;
37 const size_t kMaxStringSize = 100;
38 const size_t kMinTimeout = 10;
39 const size_t kMaxTimeout = 3000;
40 const uint16_t kValidUdpPacketSize = 512;
41 const uint16_t kMinUdpPackets = 1;
42 const uint16_t kMaxUdpPackets = 10;
43
44 const string kValidTcpHandshakeString = "FB01";
45 const string kInvalidTcpHandshakeString = "FB00";
46 const string kValidRamdiskName = "default";
47 const string kVendorBootFile = "/tmp/vendorBootFile";
48 const string kRamdiskFile = "/tmp/ramdiskFile";
49 const char* kFsOptionsArray[] = {"casefold", "projid", "compress"};
50
51 class FastbootFuzzer {
52 public:
53 void Process(const uint8_t* data, size_t size);
54
55 private:
56 void InvokeParseApi();
57 void InvokeSocket();
58 void InvokeTcp();
59 void InvokeUdp();
60 void InvokeVendorBootImgUtils(const uint8_t* data, size_t size);
61 bool MakeConnectedSockets(Socket::Protocol protocol, unique_ptr<Socket>* server,
62 unique_ptr<Socket>* client, const string& hostname);
63 unique_ptr<FuzzedDataProvider> fdp_ = nullptr;
64 };
65
InvokeParseApi()66 void FastbootFuzzer::InvokeParseApi() {
67 boot_img_hdr_v1 hdr = {};
68 FastBootTool fastBoot;
69
70 int32_t year = fdp_->ConsumeIntegralInRange<int32_t>(kYearMin, kYearMax);
71 int32_t month = fdp_->ConsumeIntegralInRange<int32_t>(kMonthMin, kMonthMax);
72 int32_t day = fdp_->ConsumeIntegralInRange<int32_t>(kDayMin, kDayMax);
73 string date = to_string(year) + "-" + to_string(month) + "-" + to_string(day);
74 fastBoot.ParseOsPatchLevel(&hdr, date.c_str());
75
76 int32_t major = fdp_->ConsumeIntegralInRange<int32_t>(kVersionMin, kVersionMax);
77 int32_t minor = fdp_->ConsumeIntegralInRange<int32_t>(kVersionMin, kVersionMax);
78 int32_t patch = fdp_->ConsumeIntegralInRange<int32_t>(kVersionMin, kVersionMax);
79 string version = to_string(major) + "." + to_string(minor) + "." + to_string(patch);
80 fastBoot.ParseOsVersion(&hdr, version.c_str());
81
82 fastBoot.ParseFsOption(fdp_->PickValueInArray(kFsOptionsArray));
83 }
84
MakeConnectedSockets(Socket::Protocol protocol,unique_ptr<Socket> * server,unique_ptr<Socket> * client,const string & hostname="localhost")85 bool FastbootFuzzer::MakeConnectedSockets(Socket::Protocol protocol, unique_ptr<Socket>* server,
86 unique_ptr<Socket>* client,
87 const string& hostname = "localhost") {
88 *server = Socket::NewServer(protocol, 0);
89 if (*server == nullptr) {
90 return false;
91 }
92 *client = Socket::NewClient(protocol, hostname, (*server)->GetLocalPort(), nullptr);
93 if (*client == nullptr) {
94 return false;
95 }
96 if (protocol == Socket::Protocol::kTcp) {
97 *server = (*server)->Accept();
98 if (*server == nullptr) {
99 return false;
100 }
101 }
102 return true;
103 }
104
InvokeSocket()105 void FastbootFuzzer::InvokeSocket() {
106 unique_ptr<Socket> server, client;
107
108 for (Socket::Protocol protocol : {Socket::Protocol::kUdp, Socket::Protocol::kTcp}) {
109 if (MakeConnectedSockets(protocol, &server, &client)) {
110 string message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
111 client->Send(message.c_str(), message.length());
112 string received(message.length(), '\0');
113 if (fdp_->ConsumeBool()) {
114 client->Close();
115 }
116 if (fdp_->ConsumeBool()) {
117 server->Close();
118 }
119 server->ReceiveAll(&received[0], received.length(),
120 /* timeout_ms */
121 fdp_->ConsumeIntegralInRange<size_t>(kMinTimeout, kMaxTimeout));
122 server->Close();
123 client->Close();
124 }
125 }
126 }
127
InvokeTcp()128 void FastbootFuzzer::InvokeTcp() {
129 /* Using a raw SocketMockFuzz* here because ownership shall be passed to the Transport object */
130 SocketMockFuzz* tcp_mock = new SocketMockFuzz;
131 tcp_mock->ExpectSend(fdp_->ConsumeBool() ? kValidTcpHandshakeString
132 : kInvalidTcpHandshakeString);
133 tcp_mock->AddReceive(fdp_->ConsumeBool() ? kValidTcpHandshakeString
134 : kInvalidTcpHandshakeString);
135
136 string error;
137 unique_ptr<Transport> transport = tcp::internal::Connect(unique_ptr<Socket>(tcp_mock), &error);
138
139 if (transport.get()) {
140 string write_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
141 if (fdp_->ConsumeBool()) {
142 tcp_mock->ExpectSend(write_message);
143 } else {
144 tcp_mock->ExpectSendFailure(write_message);
145 }
146 string read_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
147 if (fdp_->ConsumeBool()) {
148 tcp_mock->AddReceive(read_message);
149 } else {
150 tcp_mock->AddReceiveFailure();
151 }
152
153 transport->Write(write_message.data(), write_message.length());
154
155 string buffer(read_message.length(), '\0');
156 transport->Read(&buffer[0], buffer.length());
157
158 transport->Close();
159 }
160 }
161
PacketValue(uint16_t value)162 static string PacketValue(uint16_t value) {
163 return string{static_cast<char>(value >> 8), static_cast<char>(value)};
164 }
165
ErrorPacket(uint16_t sequence,const string & message="",char flags=udp::internal::kFlagNone)166 static string ErrorPacket(uint16_t sequence, const string& message = "",
167 char flags = udp::internal::kFlagNone) {
168 return string{udp::internal::kIdError, flags} + PacketValue(sequence) + message;
169 }
170
InitPacket(uint16_t sequence,uint16_t version,uint16_t max_packet_size)171 static string InitPacket(uint16_t sequence, uint16_t version, uint16_t max_packet_size) {
172 return string{udp::internal::kIdInitialization, udp::internal::kFlagNone} +
173 PacketValue(sequence) + PacketValue(version) + PacketValue(max_packet_size);
174 }
175
QueryPacket(uint16_t sequence,uint16_t new_sequence)176 static string QueryPacket(uint16_t sequence, uint16_t new_sequence) {
177 return string{udp::internal::kIdDeviceQuery, udp::internal::kFlagNone} + PacketValue(sequence) +
178 PacketValue(new_sequence);
179 }
180
QueryPacket(uint16_t sequence)181 static string QueryPacket(uint16_t sequence) {
182 return string{udp::internal::kIdDeviceQuery, udp::internal::kFlagNone} + PacketValue(sequence);
183 }
184
FastbootPacket(uint16_t sequence,const string & data="",char flags=udp::internal::kFlagNone)185 static string FastbootPacket(uint16_t sequence, const string& data = "",
186 char flags = udp::internal::kFlagNone) {
187 return string{udp::internal::kIdFastboot, flags} + PacketValue(sequence) + data;
188 }
189
InvokeUdp()190 void FastbootFuzzer::InvokeUdp() {
191 /* Using a raw SocketMockFuzz* here because ownership shall be passed to the Transport object */
192 SocketMockFuzz* udp_mock = new SocketMockFuzz;
193 uint16_t starting_sequence = fdp_->ConsumeIntegral<uint16_t>();
194 int32_t device_max_packet_size = fdp_->ConsumeBool() ? kValidUdpPacketSize
195 : fdp_->ConsumeIntegralInRange<uint16_t>(
196 0, kValidUdpPacketSize - 1);
197 udp_mock->ExpectSend(QueryPacket(0));
198 udp_mock->AddReceive(QueryPacket(0, starting_sequence));
199 udp_mock->ExpectSend(InitPacket(starting_sequence, udp::internal::kProtocolVersion,
200 udp::internal::kHostMaxPacketSize));
201 udp_mock->AddReceive(
202 InitPacket(starting_sequence, udp::internal::kProtocolVersion, device_max_packet_size));
203
204 string error;
205 unique_ptr<Transport> transport = udp::internal::Connect(unique_ptr<Socket>(udp_mock), &error);
206 bool is_transport_initialized = transport != nullptr && error.empty();
207
208 if (is_transport_initialized) {
209 uint16_t num_packets =
210 fdp_->ConsumeIntegralInRange<uint16_t>(kMinUdpPackets, kMaxUdpPackets);
211
212 for (uint16_t i = 0; i < num_packets; ++i) {
213 string write_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
214 string read_message = fdp_->ConsumeRandomLengthString(kMaxStringSize);
215 if (fdp_->ConsumeBool()) {
216 udp_mock->ExpectSend(FastbootPacket(i, write_message));
217 } else {
218 udp_mock->ExpectSend(ErrorPacket(i, write_message));
219 }
220
221 if (fdp_->ConsumeBool()) {
222 udp_mock->AddReceive(FastbootPacket(i, read_message));
223 } else {
224 udp_mock->AddReceive(ErrorPacket(i, read_message));
225 }
226 transport->Write(write_message.data(), write_message.length());
227 string buffer(read_message.length(), '\0');
228 transport->Read(&buffer[0], buffer.length());
229 }
230 transport->Close();
231 }
232 }
233
InvokeVendorBootImgUtils(const uint8_t * data,size_t size)234 void FastbootFuzzer::InvokeVendorBootImgUtils(const uint8_t* data, size_t size) {
235 int32_t vendor_boot_fd = open(kVendorBootFile.c_str(), O_CREAT | O_RDWR, 0644);
236 if (vendor_boot_fd < 0) {
237 return;
238 }
239 int32_t ramdisk_fd = open(kRamdiskFile.c_str(), O_CREAT | O_RDWR, 0644);
240 if (ramdisk_fd < 0) {
241 return;
242 }
243 write(vendor_boot_fd, data, size);
244 write(ramdisk_fd, data, size);
245 string ramdisk_name = fdp_->ConsumeBool() ? kValidRamdiskName
246 : fdp_->ConsumeRandomLengthString(kMaxStringSize);
247 string content_vendor_boot_fd = {};
248 string content_ramdisk_fd = {};
249 lseek(vendor_boot_fd, 0, SEEK_SET);
250 lseek(ramdisk_fd, 0, SEEK_SET);
251 android::base::ReadFdToString(vendor_boot_fd, &content_vendor_boot_fd);
252 android::base::ReadFdToString(ramdisk_fd, &content_ramdisk_fd);
253 uint64_t vendor_boot_size =
254 fdp_->ConsumeBool() ? content_vendor_boot_fd.size() : fdp_->ConsumeIntegral<uint64_t>();
255 uint64_t ramdisk_size =
256 fdp_->ConsumeBool() ? content_ramdisk_fd.size() : fdp_->ConsumeIntegral<uint64_t>();
257 (void)replace_vendor_ramdisk(vendor_boot_fd, vendor_boot_size, ramdisk_name, ramdisk_fd,
258 ramdisk_size);
259 close(vendor_boot_fd);
260 close(ramdisk_fd);
261 }
262
Process(const uint8_t * data,size_t size)263 void FastbootFuzzer::Process(const uint8_t* data, size_t size) {
264 fdp_ = make_unique<FuzzedDataProvider>(data, size);
265 InvokeParseApi();
266 InvokeSocket();
267 InvokeTcp();
268 InvokeUdp();
269 InvokeVendorBootImgUtils(data, size);
270 }
271
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)272 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
273 FastbootFuzzer fastbootFuzzer;
274 fastbootFuzzer.Process(data, size);
275 return 0;
276 }
277