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