• 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 #pragma once
16 #include <fuzzer/FuzzedDataProvider.h>
17 
18 #include <functional>
19 
20 #include "pw_bluetooth_sapphire/internal/host/gap/peer.h"
21 
22 namespace bt {
23 namespace testing {
24 
MakePublicDeviceAddress(FuzzedDataProvider & fdp)25 inline DeviceAddress MakePublicDeviceAddress(FuzzedDataProvider& fdp) {
26   DeviceAddressBytes device_address_bytes;
27   fdp.ConsumeData(&device_address_bytes, sizeof(device_address_bytes));
28   return DeviceAddress(fdp.PickValueInArray({DeviceAddress::Type::kBREDR,
29                                              DeviceAddress::Type::kLEPublic}),
30                        device_address_bytes);
31 }
32 
33 }  // namespace testing
34 
35 namespace gap::testing {
36 
37 class PeerFuzzer final {
38  public:
39   // Core Spec v5.2, Vol 6, Part B, Section 2.3.4.9
40   static constexpr size_t kMaxLeAdvDataLength = 1650;
41 
42   // Create a PeerFuzzer that mutates |peer| using |fuzzed_data_provider|. Both
43   // arguments must outlive this object.
PeerFuzzer(FuzzedDataProvider & fuzzed_data_provider,Peer & peer)44   PeerFuzzer(FuzzedDataProvider& fuzzed_data_provider, Peer& peer)
45       : fuzzed_data_provider_(fuzzed_data_provider), peer_(peer) {}
46 
47   // Use the FuzzedDataProvider with which this object was constructed to choose
48   // a member function that is then used to mutate the corresponding Peer field.
FuzzOneField()49   void FuzzOneField() {
50     // The decltype is easier to read than void (&PeerFuzzer::*)(), but this
51     // function isn't special and should not pick itself
52     using FuzzMemberFunction = decltype(&PeerFuzzer::FuzzOneField);
53     constexpr FuzzMemberFunction kFuzzFunctions[] = {
54         &PeerFuzzer::LEDataSetAdvertisingData,
55         &PeerFuzzer::LEDataRegisterInitializingConnection,
56         &PeerFuzzer::LEDataRegisterConnection,
57         &PeerFuzzer::LEDataSetConnectionParameters,
58         &PeerFuzzer::LEDataSetPreferredConnectionParameters,
59         &PeerFuzzer::LEDataSetBondData,
60         &PeerFuzzer::LEDataClearBondData,
61         &PeerFuzzer::LEDataSetFeatures,
62         &PeerFuzzer::LEDataSetServiceChangedGattData,
63         &PeerFuzzer::LEDataSetAutoConnectBehavior,
64         &PeerFuzzer::BrEdrDataSetInquiryData,
65         &PeerFuzzer::BrEdrDataSetInquiryDataWithRssi,
66         &PeerFuzzer::BrEdrDataSetInquiryDataFromExtendedInquiryResult,
67         &PeerFuzzer::BrEdrDataRegisterInitializingConnection,
68         &PeerFuzzer::BrEdrDataUnregisterInitializingConnection,
69         &PeerFuzzer::BrEdrDataRegisterConnection,
70         &PeerFuzzer::BrEdrUnregisterConnection,
71         &PeerFuzzer::BrEdrDataSetBondData,
72         &PeerFuzzer::BrEdrDataClearBondData,
73         &PeerFuzzer::BrEdrDataAddService,
74         &PeerFuzzer::RegisterName,
75         &PeerFuzzer::SetFeaturePage,
76         &PeerFuzzer::set_last_page_number,
77         &PeerFuzzer::set_version,
78         &PeerFuzzer::set_identity_known,
79         &PeerFuzzer::StoreBrEdrCrossTransportKey,
80         &PeerFuzzer::set_connectable,
81     };
82     std::invoke(fdp().PickValueInArray(kFuzzFunctions), this);
83   }
84 
LEDataSetAdvertisingData()85   void LEDataSetAdvertisingData() {
86     peer_.MutLe().SetAdvertisingData(
87         fdp().ConsumeIntegral<uint8_t>(),
88         DynamicByteBuffer(
89             BufferView(fdp().ConsumeBytes<uint8_t>(kMaxLeAdvDataLength))),
90         pw::chrono::SystemClock::time_point());
91   }
92 
LEDataRegisterInitializingConnection()93   void LEDataRegisterInitializingConnection() {
94     if (peer_.connectable() && fdp().ConsumeBool()) {
95       le_init_conn_tokens_.emplace_back(
96           peer_.MutLe().RegisterInitializingConnection());
97     } else if (!le_init_conn_tokens_.empty()) {
98       le_init_conn_tokens_.pop_back();
99     }
100   }
101 
LEDataRegisterConnection()102   void LEDataRegisterConnection() {
103     if (peer_.connectable() && fdp().ConsumeBool()) {
104       le_conn_tokens_.emplace_back(peer_.MutLe().RegisterConnection());
105     } else if (!le_conn_tokens_.empty()) {
106       le_conn_tokens_.pop_back();
107     }
108   }
109 
LEDataSetConnectionParameters()110   void LEDataSetConnectionParameters() {
111     if (!peer_.connectable()) {
112       return;
113     }
114     const hci_spec::LEConnectionParameters conn_params(
115         fdp().ConsumeIntegral<uint16_t>(),
116         fdp().ConsumeIntegral<uint16_t>(),
117         fdp().ConsumeIntegral<uint16_t>());
118     peer_.MutLe().SetConnectionParameters(conn_params);
119   }
120 
LEDataSetPreferredConnectionParameters()121   void LEDataSetPreferredConnectionParameters() {
122     if (!peer_.connectable()) {
123       return;
124     }
125     const hci_spec::LEPreferredConnectionParameters conn_params(
126         fdp().ConsumeIntegral<uint16_t>(),
127         fdp().ConsumeIntegral<uint16_t>(),
128         fdp().ConsumeIntegral<uint16_t>(),
129         fdp().ConsumeIntegral<uint16_t>());
130     peer_.MutLe().SetPreferredConnectionParameters(conn_params);
131   }
132 
LEDataSetBondData()133   void LEDataSetBondData() {
134     if (!peer_.connectable()) {
135       return;
136     }
137     sm::PairingData data;
138     auto do_if_fdp = [&](auto action) {
139       if (fdp().ConsumeBool()) {
140         action();
141       }
142     };
143     do_if_fdp([&] {
144       data.identity_address = bt::testing::MakePublicDeviceAddress(fdp());
145     });
146     do_if_fdp([&] { data.local_ltk = MakeLtk(); });
147     do_if_fdp([&] { data.peer_ltk = MakeLtk(); });
148     do_if_fdp([&] { data.cross_transport_key = MakeLtk(); });
149     do_if_fdp([&] { data.irk = MakeKey(); });
150     do_if_fdp([&] { data.csrk = MakeKey(); });
151     peer_.MutLe().SetBondData(data);
152   }
153 
LEDataClearBondData()154   void LEDataClearBondData() {
155     if (!peer_.le() || !peer_.le()->bonded()) {
156       return;
157     }
158     peer_.MutLe().ClearBondData();
159   }
160 
LEDataSetFeatures()161   void LEDataSetFeatures() {
162     hci_spec::LESupportedFeatures features = {};
163     fdp().ConsumeData(&features, sizeof(features));
164     peer_.MutLe().SetFeatures(features);
165   }
166 
LEDataSetServiceChangedGattData()167   void LEDataSetServiceChangedGattData() {
168     peer_.MutLe().set_service_changed_gatt_data(
169         {fdp().ConsumeBool(), fdp().ConsumeBool()});
170   }
171 
LEDataSetAutoConnectBehavior()172   void LEDataSetAutoConnectBehavior() {
173     peer_.MutLe().set_auto_connect_behavior(fdp().PickValueInArray(
174         {Peer::AutoConnectBehavior::kAlways,
175          Peer::AutoConnectBehavior::kSkipUntilNextConnection}));
176   }
177 
BrEdrDataSetInquiryData()178   void BrEdrDataSetInquiryData() {
179     if (!peer_.identity_known()) {
180       return;
181     }
182     StaticPacket<pw::bluetooth::emboss::InquiryResultWriter> inquiry_data;
183     fdp().ConsumeData(inquiry_data.mutable_data().mutable_data(),
184                       inquiry_data.data().size());
185     inquiry_data.view().bd_addr().CopyFrom(peer_.address().value().view());
186     peer_.MutBrEdr().SetInquiryData(inquiry_data.view());
187   }
188 
BrEdrDataSetInquiryDataWithRssi()189   void BrEdrDataSetInquiryDataWithRssi() {
190     StaticPacket<pw::bluetooth::emboss::InquiryResultWithRssiWriter>
191         inquiry_data;
192     fdp().ConsumeData(inquiry_data.mutable_data().mutable_data(),
193                       inquiry_data.data().size());
194     inquiry_data.view().bd_addr().CopyFrom(peer_.address().value().view());
195     peer_.MutBrEdr().SetInquiryData(inquiry_data.view());
196   }
197 
BrEdrDataSetInquiryDataFromExtendedInquiryResult()198   void BrEdrDataSetInquiryDataFromExtendedInquiryResult() {
199     if (!peer_.identity_known()) {
200       return;
201     }
202     StaticPacket<pw::bluetooth::emboss::ExtendedInquiryResultEventWriter>
203         inquiry_data;
204     fdp().ConsumeData(inquiry_data.mutable_data().mutable_data(),
205                       inquiry_data.data().size());
206     inquiry_data.view().bd_addr().CopyFrom(peer_.address().value().view());
207     peer_.MutBrEdr().SetInquiryData(inquiry_data.view());
208   }
209 
BrEdrDataRegisterInitializingConnection()210   void BrEdrDataRegisterInitializingConnection() {
211     if (!peer_.identity_known() || !peer_.connectable() ||
212         bredr_conn_token_.has_value()) {
213       return;
214     }
215     bredr_init_conn_tokens_.emplace_back(
216         peer_.MutBrEdr().RegisterInitializingConnection());
217   }
218 
BrEdrDataUnregisterInitializingConnection()219   void BrEdrDataUnregisterInitializingConnection() {
220     if (!bredr_init_conn_tokens_.empty()) {
221       bredr_init_conn_tokens_.pop_back();
222     }
223   }
224 
BrEdrDataRegisterConnection()225   void BrEdrDataRegisterConnection() {
226     if (!peer_.identity_known() || !peer_.connectable()) {
227       return;
228     }
229 
230     // Only 1 BR/EDR connection may be registered at a time.
231     bredr_conn_token_.reset();
232     bredr_conn_token_ = peer_.MutBrEdr().RegisterConnection();
233   }
234 
BrEdrUnregisterConnection()235   void BrEdrUnregisterConnection() { bredr_conn_token_.reset(); }
236 
BrEdrDataSetBondData()237   void BrEdrDataSetBondData() {
238     if (!peer_.identity_known() || !peer_.connectable()) {
239       return;
240     }
241     peer_.MutBrEdr().SetBondData(MakeLtk());
242   }
243 
BrEdrDataClearBondData()244   void BrEdrDataClearBondData() {
245     if (!peer_.bredr() || !peer_.bredr()->bonded()) {
246       return;
247     }
248     peer_.MutBrEdr().ClearBondData();
249   }
250 
BrEdrDataAddService()251   void BrEdrDataAddService() {
252     if (!peer_.identity_known() || !peer_.connectable()) {
253       return;
254     }
255     UUID uuid;
256     fdp().ConsumeData(&uuid, sizeof(uuid));
257     peer_.MutBrEdr().AddService(uuid);
258   }
259 
RegisterName()260   void RegisterName() { peer_.RegisterName(fdp().ConsumeRandomLengthString()); }
261 
SetFeaturePage()262   void SetFeaturePage() {
263     peer_.SetFeaturePage(
264         fdp().ConsumeIntegralInRange<size_t>(
265             0, bt::hci_spec::LMPFeatureSet::kMaxLastPageNumber),
266         fdp().ConsumeIntegral<uint64_t>());
267   }
268 
set_last_page_number()269   void set_last_page_number() {
270     peer_.set_last_page_number(fdp().ConsumeIntegral<uint8_t>());
271   }
272 
set_version()273   void set_version() {
274     peer_.set_version(
275         pw::bluetooth::emboss::CoreSpecificationVersion{
276             fdp().ConsumeIntegral<uint8_t>()},
277         fdp().ConsumeIntegral<uint16_t>(),
278         fdp().ConsumeIntegral<uint16_t>());
279   }
280 
set_identity_known()281   void set_identity_known() { peer_.set_identity_known(fdp().ConsumeBool()); }
282 
StoreBrEdrCrossTransportKey()283   void StoreBrEdrCrossTransportKey() {
284     if (!peer_.identity_known()) {
285       return;
286     }
287     if (!peer_.connectable()) {
288       return;
289     }
290     peer_.StoreBrEdrCrossTransportKey(MakeLtk());
291   }
292 
set_connectable()293   void set_connectable() {
294     // It doesn't make sense to make a peer unconnectable and it fires lots of
295     // asserts.
296     peer_.set_connectable(true);
297   }
298 
299  private:
fdp()300   FuzzedDataProvider& fdp() { return fuzzed_data_provider_; }
301 
MakeKey()302   sm::Key MakeKey() {
303     // Actual value of the key is not fuzzed.
304     return sm::Key(MakeSecurityProperties(), {});
305   }
306 
MakeLtk()307   sm::LTK MakeLtk() {
308     // Actual value of the key is not fuzzed.
309     return sm::LTK(MakeSecurityProperties(), {});
310   }
311 
MakeSecurityProperties()312   sm::SecurityProperties MakeSecurityProperties() {
313     sm::SecurityProperties security(
314         fdp().ConsumeBool(),
315         fdp().ConsumeBool(),
316         fdp().ConsumeBool(),
317         fdp().ConsumeIntegralInRange<size_t>(0, sm::kMaxEncryptionKeySize));
318     return security;
319   }
320 
321   FuzzedDataProvider& fuzzed_data_provider_;
322   Peer& peer_;
323   std::vector<Peer::ConnectionToken> le_conn_tokens_;
324   std::vector<Peer::InitializingConnectionToken> le_init_conn_tokens_;
325   std::optional<Peer::ConnectionToken> bredr_conn_token_;
326   std::vector<Peer::InitializingConnectionToken> bredr_init_conn_tokens_;
327 };
328 
329 }  // namespace gap::testing
330 }  // namespace bt
331