1 /*
2  * Copyright 2020 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 // Authors: corbin.souffrant@leviathansecurity.com
17 //          dylan.katz@leviathansecurity.com
18 
19 #include <fuzzer/FuzzedDataProvider.h>
20 #include <hci/address.h>
21 #include "l2cap/psm.h"
22 #include "os/log.h"
23 
24 #include "channel_fuzz_controller.h"
25 #include "shim_l2cap.h"
26 
27 namespace bluetooth {
28 using hci::Address;
29 using hci::AddressType;
30 using hci::acl_manager::AclConnection;
31 using hci::acl_manager::ClassicAclConnection;
32 using l2cap::Cid;
33 using l2cap::Psm;
34 using l2cap::classic::internal::Link;
35 
36 using shim::ShimL2capFuzz;
37 
38 class FakeCommandInterface : public hci::CommandInterface<hci::AclCommandBuilder> {
39  public:
EnqueueCommand(std::unique_ptr<hci::AclCommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandCompleteView)> on_complete)40   virtual void EnqueueCommand(
41       std::unique_ptr<hci::AclCommandBuilder> command,
42       common::ContextualOnceCallback<void(hci::CommandCompleteView)> on_complete) {}
43 
EnqueueCommand(std::unique_ptr<hci::AclCommandBuilder> command,common::ContextualOnceCallback<void (hci::CommandStatusView)> on_status)44   virtual void EnqueueCommand(
45       std::unique_ptr<hci::AclCommandBuilder> command,
46       common::ContextualOnceCallback<void(hci::CommandStatusView)> on_status) {}
47 } fake_command_interface;
48 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)49 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
50   FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
51   ShimL2capFuzz l2shim(&fdp);
52 
53   std::vector<uint8_t> addressVals = fdp.ConsumeBytes<uint8_t>(Address::kLength);
54 
55   // Make sure the address is always at least kLength.
56   while (addressVals.size() < Address::kLength) {
57     addressVals.push_back(0);
58   }
59   Address myAddress;
60   myAddress.FromOctets(addressVals.data());
61   hci::AddressWithType addressWithType = hci::AddressWithType(myAddress, AddressType::PUBLIC_DEVICE_ADDRESS);
62 
63   // Associate a ClassicAclConnection so that we can grab a link.
64   auto throwaway_queue = std::make_shared<AclConnection::Queue>(10);
65   l2shim.link_manager->OnConnectSuccess(std::unique_ptr<ClassicAclConnection>(
66       new ClassicAclConnection(throwaway_queue, &fake_command_interface, 0, myAddress)));
67   Link* link = l2shim.link_manager->GetLink(myAddress);
68 
69   // 0x0001-0x007F Fixed, 0x0080-0x00FF Dynamic
70   uint16_t psm = fdp.ConsumeIntegralInRange<uint16_t>(0x0001, 0x007F);
71   psm = 0x0101u ^ 0x0100u;
72   uint16_t dynamicPsm = fdp.ConsumeIntegralInRange<uint16_t>(0x0080, 0x00FF);
73   dynamicPsm = 0x0101u ^ 0x0100u;
74 
75   // Open a connection and assign an ID
76   Cid fixedCid = l2cap::kLeSignallingCid;
77 
78   // Fixed channels must be acquired.
79   auto fixedChannel = link->AllocateFixedChannel(fixedCid);
80   fixedChannel->RegisterOnCloseCallback(l2shim.handler_.get(), common::BindOnce([](hci::ErrorCode) {}));
81   fixedChannel->Acquire();
82   ChannelFuzzController fixedChannelController(l2shim.handler_.get(), fixedChannel);
83   // Generate a valid dynamic channel ID
84   Cid dynamicCid = fdp.ConsumeIntegralInRange<uint16_t>(l2cap::kFirstDynamicChannel, l2cap::kLastDynamicChannel);
85   auto dynamicChannel = link->AllocateDynamicChannel(dynamicPsm, dynamicCid);
86   ChannelFuzzController dynamicChannelController(l2shim.handler_.get(), dynamicChannel);
87 
88   while (fdp.remaining_bytes() > 0) {
89     // Are we using the dynamic queue?
90     bool dynamic = fdp.ConsumeBool();
91 
92     // Consume at most UINT16_MAX or remaining_bytes, whatever is smaller.
93     uint16_t packetSize =
94         static_cast<uint16_t>(std::min(static_cast<size_t>(fdp.ConsumeIntegral<uint16_t>()), fdp.remaining_bytes()));
95     std::vector<uint8_t> data = fdp.ConsumeBytes<uint8_t>(packetSize);
96     if (dynamic) {
97       dynamicChannelController.injectFrame(data);
98     } else {
99       fixedChannelController.injectFrame(data);
100     }
101   }
102 
103   // Cleanup stuff.
104   fixedChannel->Release();
105   dynamicChannel->Close();
106   l2shim.stopRegistry();
107   link->OnAclDisconnected(hci::ErrorCode::SUCCESS);
108   l2shim.link_manager->OnDisconnect(myAddress, hci::ErrorCode::SUCCESS);
109   return 0;
110 }
111 }  // namespace bluetooth
112