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_async/fake_dispatcher.h>
17 
18 #include <algorithm>
19 #include <limits>
20 
21 #include "pw_bluetooth_sapphire/internal/host/common/byte_buffer.h"
22 #include "pw_bluetooth_sapphire/internal/host/l2cap/enhanced_retransmission_mode_engines.h"
23 #include "pw_bluetooth_sapphire/internal/host/l2cap/fake_tx_channel.h"
24 #include "pw_bluetooth_sapphire/internal/host/l2cap/fragmenter.h"
25 #include "pw_bluetooth_sapphire/internal/host/l2cap/l2cap_defs.h"
26 
27 constexpr static bt::hci_spec::ConnectionHandle kTestHandle = 0x0001;
28 constexpr bt::l2cap::ChannelId kTestChannelId = 0x0001;
29 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)30 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
31   FuzzedDataProvider provider(data, size);
32 
33   pw::async::test::FakeDispatcher dispatcher;
34 
35   uint8_t tx_window =
36       std::max(provider.ConsumeIntegral<uint8_t>(), static_cast<uint8_t>(1u));
37 
38   uint8_t max_transmissions = provider.ConsumeIntegral<uint8_t>();
39   uint16_t max_tx_sdu_size =
40       std::max(provider.ConsumeIntegral<uint16_t>(), bt::l2cap::kMinACLMTU);
41 
42   bool failure = false;
43   auto failure_cb = [&failure] { failure = true; };
44 
45   bt::l2cap::internal::FakeTxChannel channel;
46   auto [rx_engine, tx_engine] =
47       bt::l2cap::internal::MakeLinkedEnhancedRetransmissionModeEngines(
48           kTestChannelId,
49           max_tx_sdu_size,
50           max_transmissions,
51           tx_window,
52           channel,
53           failure_cb,
54           dispatcher);
55 
56   // In the real stack, the engines are shut down on failure, so we do the same
57   // here.
58   while (provider.remaining_bytes() > 0 && !failure) {
59     bool tx = provider.ConsumeBool();
60     if (tx) {
61       auto n_bytes = provider.ConsumeIntegral<uint16_t>();
62       auto bytes = provider.ConsumeBytes<uint8_t>(n_bytes);
63       channel.QueueSdu(
64           std::make_unique<bt::DynamicByteBuffer>(bt::BufferView(bytes)));
65       tx_engine->NotifySduQueued();
66     } else {
67       bt::l2cap::Fragmenter fragmenter(kTestHandle);
68       auto n_bytes = provider.ConsumeIntegral<uint16_t>();
69       auto bytes = provider.ConsumeBytes<uint8_t>(n_bytes);
70       bool append_fcs = provider.ConsumeBool();
71       if (append_fcs) {
72         const size_t bounded_size =
73             std::min(bytes.size(),
74                      std::numeric_limits<uint16_t>::max() -
75                          sizeof(bt::l2cap::FrameCheckSequence));
76         bytes.resize(bounded_size);
77       }
78       auto fcs_option = append_fcs
79                             ? bt::l2cap::FrameCheckSequenceOption::kIncludeFcs
80                             : bt::l2cap::FrameCheckSequenceOption::kNoFcs;
81       auto pdu = fragmenter.BuildFrame(
82           kTestChannelId, bt::BufferView(bytes), fcs_option);
83       rx_engine->ProcessPdu(std::move(pdu));
84     }
85 
86     // Run for 0-255 seconds, which is enough to trigger poll timer and monitor
87     // timer.
88     auto run_duration =
89         std::chrono::seconds(provider.ConsumeIntegral<uint8_t>());
90     dispatcher.RunFor(run_duration);
91   }
92 
93   return 0;
94 }
95