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