• 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_assert/check.h>
17 #include <pw_bytes/endian.h>
18 #include <pw_random/fuzzer.h>
19 
20 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
21 #include "pw_bluetooth_sapphire/internal/host/common/random.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/channel_manager.h"
24 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test.h"
25 #include "pw_bluetooth_sapphire/internal/host/testing/controller_test_double_base.h"
26 
27 namespace bt::testing {
28 
29 // ACL Buffer Info
30 constexpr size_t kMaxDataPacketLength = 64;
31 // Ensure outbound ACL packets aren't queued.
32 constexpr size_t kBufferMaxNumPackets = 1000;
33 
34 // If the packet size is too large, we consume too much of the fuzzer data per
35 // packet without much benefit.
36 constexpr uint16_t kMaxAclPacketSize = 100;
37 
38 constexpr hci_spec::ConnectionHandle kHandle = 0x0001;
39 
40 // Don't toggle connection too often or else l2cap won't get very far.
41 constexpr float kToggleConnectionChance = 0.04f;
42 
43 class FuzzerController : public ControllerTestDoubleBase,
44                          public WeakSelf<FuzzerController> {
45  public:
FuzzerController(pw::async::Dispatcher & pw_dispatcher)46   explicit FuzzerController(pw::async::Dispatcher& pw_dispatcher)
47       : ControllerTestDoubleBase(pw_dispatcher), WeakSelf(this) {}
48   ~FuzzerController() override = default;
49 
50  private:
51   // Controller overrides:
SendCommand(pw::span<const std::byte> command)52   void SendCommand(
53       [[maybe_unused]] pw::span<const std::byte> command) override {}
SendAclData(pw::span<const std::byte> data)54   void SendAclData([[maybe_unused]] pw::span<const std::byte> data) override {}
SendScoData(pw::span<const std::byte> data)55   void SendScoData([[maybe_unused]] pw::span<const std::byte> data) override {}
SendIsoData(pw::span<const std::byte> data)56   void SendIsoData([[maybe_unused]] pw::span<const std::byte> data) override {}
57 };
58 
59 // Reuse ControllerTest test fixture code even though we're not using gtest.
60 using TestingBase = FakeDispatcherControllerTest<FuzzerController>;
61 class DataFuzzTest : public TestingBase {
62  public:
DataFuzzTest(const uint8_t * data,size_t size)63   DataFuzzTest(const uint8_t* data, size_t size)
64       : data_(data, size), rng_(&data_) {
65     set_random_generator(&rng_);
66     TestingBase::SetUp();
67     const auto bredr_buffer_info =
68         hci::DataBufferInfo(kMaxDataPacketLength, kBufferMaxNumPackets);
69     InitializeACLDataChannel(bredr_buffer_info);
70 
71     channel_manager_ =
72         l2cap::ChannelManager::Create(transport()->acl_data_channel(),
73                                       transport()->command_channel(),
74                                       /*random_channel_ids=*/true,
75                                       dispatcher());
76   }
77 
~DataFuzzTest()78   ~DataFuzzTest() override {
79     channel_manager_ = nullptr;
80     bt::set_random_generator(nullptr);
81     TestingBase::TearDown();
82   }
83 
TestBody()84   void TestBody() override {
85     RegisterService();
86 
87     while (data_.remaining_bytes() > 0) {
88       bool run_loop = data_.ConsumeBool();
89       if (run_loop) {
90         RunUntilIdle();
91       }
92 
93       if (!SendAclPacket()) {
94         break;
95       }
96 
97       if (data_.ConsumeProbability<float>() < kToggleConnectionChance) {
98         ToggleConnection();
99       }
100     }
101 
102     RunUntilIdle();
103   }
104 
SendAclPacket()105   bool SendAclPacket() {
106     if (data_.remaining_bytes() < sizeof(uint64_t)) {
107       return false;
108     }
109     // Consumes 8 bytes.
110     auto packet_size = data_.ConsumeIntegralInRange<uint16_t>(
111         sizeof(hci_spec::ACLDataHeader),
112         static_cast<uint16_t>(std::min(static_cast<size_t>(kMaxAclPacketSize),
113                                        data_.remaining_bytes())));
114 
115     auto packet_data = data_.ConsumeBytes<uint8_t>(packet_size);
116     if (packet_data.size() < packet_size) {
117       // Check if we ran out of fuzzer data.
118       return false;
119     }
120 
121     MutableBufferView packet_view(packet_data.data(), packet_data.size());
122 
123     // Use correct length so packets aren't rejected for invalid length.
124     packet_view.AsMutable<hci_spec::ACLDataHeader>()->data_total_length =
125         pw::bytes::ConvertOrderTo(
126             cpp20::endian::little,
127             static_cast<uint16_t>(
128                 (packet_view.size() - sizeof(hci_spec::ACLDataHeader))));
129 
130     // Use correct connection handle so packets aren't rejected/queued for
131     // invalid handle.
132     uint16_t handle_and_flags =
133         packet_view.ReadMember<&hci_spec::ACLDataHeader::handle_and_flags>();
134     handle_and_flags &= 0xF000;  // Keep flags, clear handle.
135     handle_and_flags |= kHandle;
136     packet_view.AsMutable<hci_spec::ACLDataHeader>()->handle_and_flags =
137         handle_and_flags;
138 
139     PW_CHECK(test_device()->SendACLDataChannelPacket(packet_view));
140     return true;
141   }
142 
RegisterService()143   void RegisterService() {
144     channel_manager_->RegisterService(
145         l2cap::kAVDTP,
146         l2cap::ChannelParameters(),
147         [this](l2cap::Channel::WeakPtr chan) {
148           if (!chan.is_alive()) {
149             return;
150           }
151           chan->Activate(/*rx_callback=*/[](auto) {}, /*closed_callback=*/
152                          [this, id = chan->id()] { channels_.erase(id); });
153           channels_.emplace(chan->id(), std::move(chan));
154         });
155   }
156 
ToggleConnection()157   void ToggleConnection() {
158     if (connection_) {
159       channel_manager_->RemoveConnection(kHandle);
160       connection_ = false;
161       return;
162     }
163 
164     channel_manager_->AddACLConnection(
165         kHandle,
166         pw::bluetooth::emboss::ConnectionRole::CENTRAL,
167         /*link_error_callback=*/[] {},
168         /*security_callback=*/[](auto, auto, auto) {},
169         /*fixed_channels_callback=*/
170         [](l2cap::ChannelManager::BrEdrFixedChannels) {});
171     connection_ = true;
172   }
173 
174  private:
175   FuzzedDataProvider data_;
176   pw::random::FuzzerRandomGenerator rng_;
177   std::unique_ptr<l2cap::ChannelManager> channel_manager_;
178   bool connection_ = false;
179   std::unordered_map<l2cap::ChannelId, l2cap::Channel::WeakPtr> channels_;
180 };
181 
182 }  // namespace bt::testing
183 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)184 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
185   bt::testing::DataFuzzTest fuzz(data, size);
186   fuzz.TestBody();
187   return 0;
188 }
189