• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2023 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include <fuzzer/FuzzedDataProvider.h>
16 #include <pw_random/fuzzer.h>
17 
18 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
19 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
20 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.h"
21 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h"
22 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
23 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test_double_base.h"
24 
25 namespace bt::testing {
26 
27 // ACL Buffer Info
28 constexpr size_t kMaxDataPacketLength = 64;
29 // Ensure outbound ACL packets aren't queued.
30 constexpr size_t kBufferMaxNumPackets = 1000;
31 
32 // If the packet size is too large, we consume too much of the fuzzer data per
33 // packet without much benefit.
34 constexpr uint16_t kMaxAclPacketSize = 100;
35 
36 constexpr hci_spec::ConnectionHandle kHandle = 0x0001;
37 
38 // Don't toggle connection too often or else l2cap won't get very far.
39 constexpr float kToggleConnectionChance = 0.04;
40 
41 class FuzzerController : public ControllerTestDoubleBase,
42                          public WeakSelf<FuzzerController> {
43  public:
FuzzerController(pw::async::Dispatcher & pw_dispatcher)44   explicit FuzzerController(pw::async::Dispatcher& pw_dispatcher)
45       : ControllerTestDoubleBase(pw_dispatcher), WeakSelf(this) {}
46   ~FuzzerController() override = default;
47 
48  private:
49   // Controller overrides:
SendCommand(pw::span<const std::byte> command)50   void SendCommand(pw::span<const std::byte> command) override {}
SendAclData(pw::span<const std::byte> data)51   void SendAclData(pw::span<const std::byte> data) override {}
SendScoData(pw::span<const std::byte> data)52   void SendScoData(pw::span<const std::byte> data) override {}
53 };
54 
55 // Reuse ControllerTest test fixture code even though we're not using gtest.
56 using TestingBase = FakeDispatcherControllerTest<FuzzerController>;
57 class DataFuzzTest : public TestingBase {
58  public:
DataFuzzTest(const uint8_t * data,size_t size)59   DataFuzzTest(const uint8_t* data, size_t size)
60       : data_(data, size), rng_(&data_) {
61     set_random_generator(&rng_);
62     TestingBase::SetUp();
63     const auto bredr_buffer_info =
64         hci::DataBufferInfo(kMaxDataPacketLength, kBufferMaxNumPackets);
65     InitializeACLDataChannel(bredr_buffer_info);
66 
67     channel_manager_ =
68         l2cap::ChannelManager::Create(transport()->acl_data_channel(),
69                                       transport()->command_channel(),
70                                       /*random_channel_ids=*/true,
71                                       dispatcher());
72   }
73 
~DataFuzzTest()74   ~DataFuzzTest() override {
75     channel_manager_ = nullptr;
76     bt::set_random_generator(nullptr);
77     TestingBase::TearDown();
78   }
79 
TestBody()80   void TestBody() override {
81     RegisterService();
82 
83     while (data_.remaining_bytes() > 0) {
84       bool run_loop = data_.ConsumeBool();
85       if (run_loop) {
86         RunUntilIdle();
87       }
88 
89       if (!SendAclPacket()) {
90         break;
91       }
92 
93       if (data_.ConsumeProbability<float>() < kToggleConnectionChance) {
94         ToggleConnection();
95       }
96     }
97 
98     RunUntilIdle();
99   }
100 
SendAclPacket()101   bool SendAclPacket() {
102     if (data_.remaining_bytes() < sizeof(uint64_t)) {
103       return false;
104     }
105     // Consumes 8 bytes.
106     auto packet_size = data_.ConsumeIntegralInRange<uint16_t>(
107         sizeof(hci_spec::ACLDataHeader),
108         std::min(static_cast<size_t>(kMaxAclPacketSize),
109                  data_.remaining_bytes()));
110 
111     auto packet_data = data_.ConsumeBytes<uint8_t>(packet_size);
112     if (packet_data.size() < packet_size) {
113       // Check if we ran out of fuzzer data.
114       return false;
115     }
116 
117     MutableBufferView packet_view(packet_data.data(), packet_data.size());
118 
119     // Use correct length so packets aren't rejected for invalid length.
120     packet_view.AsMutable<hci_spec::ACLDataHeader>()->data_total_length =
121         htole16(packet_view.size() - sizeof(hci_spec::ACLDataHeader));
122 
123     // Use correct connection handle so packets aren't rejected/queued for
124     // invalid handle.
125     uint16_t handle_and_flags =
126         packet_view.ReadMember<&hci_spec::ACLDataHeader::handle_and_flags>();
127     handle_and_flags &= 0xF000;  // Keep flags, clear handle.
128     handle_and_flags |= kHandle;
129     packet_view.AsMutable<hci_spec::ACLDataHeader>()->handle_and_flags =
130         handle_and_flags;
131 
132     BT_ASSERT(test_device()->SendACLDataChannelPacket(packet_view));
133     return true;
134   }
135 
RegisterService()136   void RegisterService() {
137     channel_manager_->RegisterService(
138         l2cap::kAVDTP,
139         l2cap::ChannelParameters(),
140         [this](l2cap::Channel::WeakPtr chan) {
141           if (!chan.is_alive()) {
142             return;
143           }
144           chan->Activate(/*rx_callback=*/[](auto) {}, /*closed_callback=*/
145                          [this, id = chan->id()] { channels_.erase(id); });
146           channels_.emplace(chan->id(), std::move(chan));
147         });
148   }
149 
ToggleConnection()150   void ToggleConnection() {
151     if (connection_) {
152       channel_manager_->RemoveConnection(kHandle);
153       connection_ = false;
154       return;
155     }
156 
157     channel_manager_->AddACLConnection(
158         kHandle,
159         pw::bluetooth::emboss::ConnectionRole::CENTRAL,
160         /*link_error_callback=*/[] {},
161         /*security_callback=*/[](auto, auto, auto) {});
162     connection_ = true;
163   }
164 
165  private:
166   FuzzedDataProvider data_;
167   pw::random::FuzzerRandomGenerator rng_;
168   std::unique_ptr<l2cap::ChannelManager> channel_manager_;
169   bool connection_ = false;
170   std::unordered_map<l2cap::ChannelId, l2cap::Channel::WeakPtr> channels_;
171 };
172 
173 }  // namespace bt::testing
174 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)175 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
176   bt::testing::DataFuzzTest fuzz(data, size);
177   fuzz.TestBody();
178   return 0;
179 }
180