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