OSDN Git Service

Adds fuzzer for l2cap
authorDylan Katz <dylan.katz@leviathansecurity.com>
Sun, 19 Jul 2020 17:25:44 +0000 (10:25 -0700)
committerDylan Katz <dylan.katz@leviathansecurity.com>
Wed, 2 Sep 2020 22:18:54 +0000 (15:18 -0700)
This adds a fuzzer for l2cap and a few related subcomponents.
Test: gd/fuzz/run bluetooth_gd_l2cap_fuzzer
Tag: #feature
Bug: 167425311
Sponsor: zachoverflow@

Signed-off-by: Dylan Katz <dylan.katz@leviathansecurity.com>
Change-Id: I052f103929749b6532c66881cf88589375cf8a5d

gd/l2cap/fuzz/Android.bp [new file with mode: 0755]
gd/l2cap/fuzz/channel_fuzz_controller.cc [new file with mode: 0755]
gd/l2cap/fuzz/channel_fuzz_controller.h [new file with mode: 0755]
gd/l2cap/fuzz/fuzz_dynamic_channel_manager.h [new file with mode: 0755]
gd/l2cap/fuzz/fuzz_dynamic_channel_manager_impl.h [new file with mode: 0755]
gd/l2cap/fuzz/fuzz_l2cap.cc [new file with mode: 0755]
gd/l2cap/fuzz/fuzz_l2cap_classic_module.h [new file with mode: 0755]
gd/l2cap/fuzz/shim_l2cap.h [new file with mode: 0755]

diff --git a/gd/l2cap/fuzz/Android.bp b/gd/l2cap/fuzz/Android.bp
new file mode 100755 (executable)
index 0000000..454c04b
--- /dev/null
@@ -0,0 +1,35 @@
+cc_fuzz {
+    name: "bluetooth_gd_l2cap_fuzzer",
+    defaults: ["gd_fuzz_defaults"],
+    include_dirs: [
+        "system/bt",
+        "system/bt/gd",
+        "system/bt/bta/include",
+        "system/bt/bta/sys",
+        "system/bt/bta/dm",
+        "system/bt/btcore/include",
+        "system/bt/internal_include",
+        "system/bt/stack/include",
+        "system/bt/stack/l2cap",
+        "system/bt/stack/a2dp",
+        "system/bt/stack/btm",
+        "system/bt/stack/avdt",
+        "system/bt/udrv/include",
+        "system/bt/btif/include",
+        "system/bt/btif/co",
+        "system/bt/hci/include",
+        "system/bt/vnd/include",
+        "system/bt/embdrv/sbc/encoder/include",
+        "system/bt/embdrv/sbc/decoder/include",
+        "system/bt/utils/include",
+        "system/security/keystore/include",
+        "hardware/interfaces/keymaster/4.0/support/include",
+    ],
+    srcs: [
+        "channel_fuzz_controller.cc",
+        "fuzz_l2cap.cc",
+    ],
+    static_libs: [
+        "libbte",
+    ],
+}
diff --git a/gd/l2cap/fuzz/channel_fuzz_controller.cc b/gd/l2cap/fuzz/channel_fuzz_controller.cc
new file mode 100755 (executable)
index 0000000..41738cc
--- /dev/null
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#include "channel_fuzz_controller.h"
+
+namespace bluetooth {
+using l2cap::classic::internal::FixedChannelImpl;
+using l2cap::internal::DynamicChannelImpl;
+using os::Handler;
+
+ChannelFuzzController::ChannelFuzzController(Handler* l2cap_handler, std::shared_ptr<DynamicChannelImpl> chan) {
+  EnqueueType* queue = reinterpret_cast<EnqueueType*>(chan->GetQueueUpEnd());
+  channelInject_ = std::make_shared<ChannelFuzzQueueType>(queue, l2cap_handler);
+}
+
+ChannelFuzzController::ChannelFuzzController(Handler* l2cap_handler, std::shared_ptr<FixedChannelImpl> chan) {
+  EnqueueType* queue = reinterpret_cast<EnqueueType*>(chan->GetQueueUpEnd());
+  channelInject_ = std::make_shared<ChannelFuzzQueueType>(queue, l2cap_handler);
+}
+
+void ChannelFuzzController::injectFrame(std::vector<uint8_t> data) {
+  CONSTRUCT_VALID_UNIQUE_OTHERWISE_BAIL(l2cap::BasicFrameView, packet, data);
+  channelInject_->Inject(std::move(packet));
+}
+}  // namespace bluetooth
diff --git a/gd/l2cap/fuzz/channel_fuzz_controller.h b/gd/l2cap/fuzz/channel_fuzz_controller.h
new file mode 100755 (executable)
index 0000000..ade2026
--- /dev/null
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#pragma once
+#include "gd/fuzz/helpers.h"
+#include "l2cap/classic/internal/fixed_channel_impl.h"
+#include "l2cap/internal/dynamic_channel_impl.h"
+#include "l2cap/l2cap_packets.h"
+#include "os/fuzz/fuzz_inject_queue.h"
+#include "os/handler.h"
+#include "packet/packet_view.h"
+
+namespace bluetooth {
+
+typedef os::IQueueEnqueue<packet::PacketView<packet::kLittleEndian>> EnqueueType;
+typedef os::fuzz::FuzzInjectQueue<packet::PacketView<packet::kLittleEndian>> ChannelFuzzQueueType;
+
+class ChannelFuzzController {
+ public:
+  ChannelFuzzController(os::Handler* l2cap_handler, std::shared_ptr<l2cap::internal::DynamicChannelImpl> chan);
+
+  ChannelFuzzController(os::Handler* l2cap_handler, std::shared_ptr<l2cap::classic::internal::FixedChannelImpl> chan);
+
+  void injectPacketData(std::vector<uint8_t> data);
+
+  void injectFrame(std::vector<uint8_t> data);
+
+ private:
+  std::shared_ptr<ChannelFuzzQueueType> channelInject_;
+};
+}  // namespace bluetooth
diff --git a/gd/l2cap/fuzz/fuzz_dynamic_channel_manager.h b/gd/l2cap/fuzz/fuzz_dynamic_channel_manager.h
new file mode 100755 (executable)
index 0000000..22b5291
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#pragma once
+
+#include <gd/l2cap/classic/dynamic_channel_service.h>
+#include <gd/l2cap/classic/internal/dynamic_channel_service_impl.h>
+#include <gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h>
+#include <memory>
+
+#include "hci/address.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/security_policy.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+
+#include "fuzz_dynamic_channel_manager_impl.h"
+
+namespace bluetooth {
+namespace shim {
+namespace {
+class FuzzDynamicChannelManager : public l2cap::classic::DynamicChannelManager {
+ public:
+  void ConnectChannel(
+      hci::Address device,
+      l2cap::classic::DynamicChannelConfigurationOption configuration_option,
+      l2cap::Psm psm,
+      l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
+      l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback) override {
+    impl_.ConnectChannel(device, configuration_option, psm, std::move(on_open_callback), std::move(on_fail_callback));
+  }
+
+  void RegisterService(
+      l2cap::Psm psm,
+      l2cap::classic::DynamicChannelConfigurationOption configuration_option,
+      const l2cap::classic::SecurityPolicy& security_policy,
+      l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
+      l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback) override {
+    impl_.RegisterService(
+        psm, configuration_option, security_policy, std::move(on_registration_complete), std::move(on_open_callback));
+  }
+  FuzzDynamicChannelManager(FuzzDynamicChannelManagerImpl& impl) : impl_(impl) {}
+  FuzzDynamicChannelManagerImpl& impl_;
+};
+}  // namespace
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/fuzz/fuzz_dynamic_channel_manager_impl.h b/gd/l2cap/fuzz/fuzz_dynamic_channel_manager_impl.h
new file mode 100755 (executable)
index 0000000..706550b
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#pragma once
+
+#include <gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h>
+#include <gd/shim/l2cap.h>
+#include <future>
+#include <memory>
+
+#include "hci/address.h"
+#include "l2cap/classic/dynamic_channel_configuration_option.h"
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/security_policy.h"
+#include "l2cap/psm.h"
+#include "os/handler.h"
+
+namespace bluetooth {
+namespace shim {
+namespace {
+class FuzzDynamicChannelManagerImpl {
+ public:
+  void ConnectChannel(
+      hci::Address device,
+      l2cap::classic::DynamicChannelConfigurationOption configuration_option,
+      l2cap::Psm,
+      l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback,
+      l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback) {
+    connections_++;
+    on_open_callback_ = std::move(on_open_callback);
+    on_fail_callback_ = std::move(on_fail_callback);
+
+    connected_promise_.set_value();
+  }
+  int connections_{0};
+
+  void RegisterService(
+      l2cap::Psm,
+      l2cap::classic::DynamicChannelConfigurationOption,
+      const l2cap::classic::SecurityPolicy&,
+      l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete,
+      l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback) {
+    services_++;
+    on_registration_complete_ = std::move(on_registration_complete);
+    on_open_callback_ = std::move(on_open_callback);
+
+    register_promise_.set_value();
+  }
+  int services_{0};
+
+  void SetConnectionFuture() {
+    connected_promise_ = std::promise<void>();
+  }
+
+  void WaitConnectionFuture() {
+    connected_future_ = connected_promise_.get_future();
+    connected_future_.wait();
+  }
+
+  void SetRegistrationFuture() {
+    register_promise_ = std::promise<void>();
+  }
+
+  void WaitRegistrationFuture() {
+    register_future_ = register_promise_.get_future();
+    register_future_.wait();
+  }
+
+  void SetConnectionOnFail(l2cap::classic::DynamicChannelManager::ConnectionResult result, std::promise<void> promise) {
+    std::move(on_fail_callback_).Invoke(result);
+    promise.set_value();
+  }
+
+  void SetConnectionOnOpen(std::unique_ptr<l2cap::DynamicChannel> channel, std::promise<void> promise) {
+    std::move(on_open_callback_).Invoke(std::move(channel));
+    promise.set_value();
+  }
+
+  l2cap::classic::DynamicChannelManager::OnRegistrationCompleteCallback on_registration_complete_{};
+  l2cap::classic::DynamicChannelManager::OnConnectionOpenCallback on_open_callback_{};
+  l2cap::classic::DynamicChannelManager::OnConnectionFailureCallback on_fail_callback_{};
+
+  FuzzDynamicChannelManagerImpl() = default;
+  ~FuzzDynamicChannelManagerImpl() = default;
+
+ private:
+  std::promise<void> connected_promise_;
+  std::future<void> connected_future_;
+
+  std::promise<void> register_promise_;
+  std::future<void> register_future_;
+};
+}  // namespace
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/fuzz/fuzz_l2cap.cc b/gd/l2cap/fuzz/fuzz_l2cap.cc
new file mode 100755 (executable)
index 0000000..6d8991d
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <hci/address.h>
+#include "l2cap/psm.h"
+#include "os/log.h"
+
+#include "channel_fuzz_controller.h"
+#include "shim_l2cap.h"
+
+namespace bluetooth {
+using hci::Address;
+using hci::AddressType;
+using hci::acl_manager::AclConnection;
+using hci::acl_manager::ClassicAclConnection;
+using l2cap::Cid;
+using l2cap::Psm;
+using l2cap::classic::internal::Link;
+
+using shim::ShimL2capFuzz;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+  FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+  ShimL2capFuzz l2shim(&fdp);
+
+  std::vector<uint8_t> addressVals = fdp.ConsumeBytes<uint8_t>(Address::kLength);
+
+  // Make sure the address is always at least kLength.
+  while (addressVals.size() < Address::kLength) {
+    addressVals.push_back(0);
+  }
+  Address myAddress;
+  myAddress.FromOctets(addressVals.data());
+  hci::AddressWithType addressWithType = hci::AddressWithType(myAddress, AddressType::PUBLIC_DEVICE_ADDRESS);
+
+  // Associate a ClassicAclConnection so that we can grab a link.
+  auto throwaway_queue = std::make_shared<AclConnection::Queue>(10);
+  l2shim.link_manager->OnConnectSuccess(
+      std::unique_ptr<ClassicAclConnection>(new ClassicAclConnection(throwaway_queue, nullptr, 0, myAddress)));
+  Link* link = l2shim.link_manager->GetLink(myAddress);
+
+  // 0x0001-0x007F Fixed, 0x0080-0x00FF Dynamic
+  uint16_t psm = fdp.ConsumeIntegralInRange<uint16_t>(0x0001, 0x007F);
+  psm = 0x0101u ^ 0x0100u;
+  uint16_t dynamicPsm = fdp.ConsumeIntegralInRange<uint16_t>(0x0080, 0x00FF);
+  dynamicPsm = 0x0101u ^ 0x0100u;
+
+  // Open a connection and assign an ID
+  uint16_t connectionId = l2shim.CreateConnection(psm, myAddress.ToString());
+  Cid fixedCid = l2cap::kLeSignallingCid;
+
+  // Fixed channels must be acquired.
+  auto fixedChannel = link->AllocateFixedChannel(fixedCid);
+  fixedChannel->RegisterOnCloseCallback(l2shim.handler_.get(), common::BindOnce([](hci::ErrorCode) {}));
+  fixedChannel->Acquire();
+  ChannelFuzzController fixedChannelController(l2shim.handler_.get(), fixedChannel);
+  // Generate a valid dynamic channel ID
+  Cid dynamicCid = fdp.ConsumeIntegralInRange<uint16_t>(l2cap::kFirstDynamicChannel, l2cap::kLastDynamicChannel);
+  auto dynamicChannel = link->AllocateDynamicChannel(dynamicPsm, dynamicCid);
+  ChannelFuzzController dynamicChannelController(l2shim.handler_.get(), dynamicChannel);
+
+  while (fdp.remaining_bytes() > 0) {
+    // Are we using the dynamic queue?
+    bool dynamic = fdp.ConsumeBool();
+
+    // Consume at most UINT16_MAX or remaining_bytes, whatever is smaller.
+    uint16_t packetSize =
+        static_cast<uint16_t>(std::min(static_cast<size_t>(fdp.ConsumeIntegral<uint16_t>()), fdp.remaining_bytes()));
+    std::vector<uint8_t> data = fdp.ConsumeBytes<uint8_t>(packetSize);
+    if (dynamic) {
+      dynamicChannelController.injectFrame(data);
+    } else {
+      fixedChannelController.injectFrame(data);
+    }
+  }
+
+  // Cleanup stuff.
+  fixedChannel->Release();
+  dynamicChannel->Close();
+  l2shim.shim_l2cap_->CloseClassicConnection(connectionId);
+  l2shim.stopRegistry();
+  link->OnAclDisconnected(hci::ErrorCode::SUCCESS);
+  l2shim.link_manager->OnDisconnect(myAddress, hci::ErrorCode::SUCCESS);
+  return 0;
+}
+}  // namespace bluetooth
diff --git a/gd/l2cap/fuzz/fuzz_l2cap_classic_module.h b/gd/l2cap/fuzz/fuzz_l2cap_classic_module.h
new file mode 100755 (executable)
index 0000000..7df2c46
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#pragma once
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gd/shim/l2cap.h>
+
+#include "l2cap/classic/dynamic_channel_manager.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+
+#include "fuzz_dynamic_channel_manager.h"
+#include "fuzz_dynamic_channel_manager_impl.h"
+
+namespace bluetooth {
+namespace shim {
+namespace {
+class FuzzL2capClassicModule : public l2cap::classic::L2capClassicModule {
+ public:
+  std::unique_ptr<l2cap::classic::DynamicChannelManager> GetDynamicChannelManager() override {
+    return std::make_unique<FuzzDynamicChannelManager>(*impl_);
+  }
+
+  void ListDependencies(ModuleList*) override {}
+  void Start() override;
+  void Stop() override;
+
+  std::unique_ptr<FuzzDynamicChannelManagerImpl> impl_;
+};
+
+void FuzzL2capClassicModule::Start() {
+  impl_ = std::make_unique<FuzzDynamicChannelManagerImpl>();
+}
+
+void FuzzL2capClassicModule::Stop() {
+  impl_.reset();
+}
+}  // namespace
+}  // namespace shim
+}  // namespace bluetooth
diff --git a/gd/l2cap/fuzz/shim_l2cap.h b/gd/l2cap/fuzz/shim_l2cap.h
new file mode 100755 (executable)
index 0000000..c689b34
--- /dev/null
@@ -0,0 +1,121 @@
+/*
+ * Copyright 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+//          dylan.katz@leviathansecurity.com
+
+#pragma once
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <gd/l2cap/classic/internal/dynamic_channel_service_manager_impl.h>
+#include <gd/l2cap/classic/internal/fixed_channel_service_manager_impl.h>
+#include <gd/l2cap/classic/internal/link_manager.h>
+#include <gd/l2cap/internal/parameter_provider.h>
+#include <gd/shim/l2cap.h>
+#include <future>
+#include <memory>
+
+#include "hci/fuzz/fuzz_hci_layer.h"
+#include "l2cap/classic/l2cap_classic_module.h"
+#include "os/handler.h"
+
+#include "fuzz_l2cap_classic_module.h"
+
+namespace bluetooth {
+
+namespace shim {
+namespace {
+class ShimL2capFuzz {
+ public:
+  void OnConnectionComplete(std::string string_address, uint16_t psm, uint16_t cid, bool connected) {
+    connection_string_address_ = string_address;
+    connection_psm_ = psm;
+    connection_cid_ = cid;
+    connection_connected_ = connected;
+    connection_complete_promise_.set_value();
+  }
+
+  uint16_t CreateConnection(uint16_t psm, std::string device_address) {
+    std::promise<uint16_t> promise;
+    auto future = promise.get_future();
+
+    shim_l2cap_->CreateClassicConnection(
+        psm,
+        device_address,
+        std::bind(
+            &shim::ShimL2capFuzz::OnConnectionComplete,
+            this,
+            std::placeholders::_1,
+            std::placeholders::_2,
+            std::placeholders::_3,
+            std::placeholders::_4),
+        std::move(promise));
+    return future.get();
+  }
+
+  ShimL2capFuzz(FuzzedDataProvider* fdp) {
+    hci::fuzz::FuzzHciLayer* fuzzHci = fake_registry_.Inject<hci::fuzz::FuzzHciLayer>(&hci::HciLayer::Factory);
+    fuzz_l2cap_classic_module_ = new FuzzL2capClassicModule();
+    fake_registry_.InjectTestModule(&l2cap::classic::L2capClassicModule::Factory, fuzz_l2cap_classic_module_);
+    fake_registry_.Start<shim::L2cap>();
+
+    // The autoreply is needed to prevent it from hanging.
+    fuzzHci->TurnOnAutoReply(fdp);
+    acl_manager_ = fake_registry_.Start<hci::AclManager>();
+    fuzzHci->TurnOffAutoReply();
+    shim_l2cap_ = static_cast<shim::L2cap*>(fake_registry_.GetModuleUnderTest(&shim::L2cap::Factory));
+
+    // Create the LinkManager
+    handler_ = std::unique_ptr<os::Handler>(new os::Handler(&thread_));
+    dynamic_channel_impl = std::unique_ptr<l2cap::classic::internal::DynamicChannelServiceManagerImpl>(
+        new l2cap::classic::internal::DynamicChannelServiceManagerImpl(handler_.get()));
+    fixed_channel_impl = std::unique_ptr<l2cap::classic::internal::FixedChannelServiceManagerImpl>(
+        new l2cap::classic::internal::FixedChannelServiceManagerImpl(handler_.get()));
+    parameter_provider = std::unique_ptr<l2cap::internal::ParameterProvider>(new l2cap::internal::ParameterProvider());
+    link_manager = std::unique_ptr<l2cap::classic::internal::LinkManager>(new l2cap::classic::internal::LinkManager(
+        handler_.get(), acl_manager_, fixed_channel_impl.get(), dynamic_channel_impl.get(), parameter_provider.get()));
+  }
+
+  ~ShimL2capFuzz() {
+    handler_->Clear();
+  }
+
+  void stopRegistry() {
+    fake_registry_.WaitForIdleAndStopAll();
+  }
+
+  std::string connection_string_address_;
+  uint16_t connection_psm_{0};
+  uint16_t connection_cid_{1000};
+  bool connection_connected_{false};
+  std::promise<void> connection_complete_promise_;
+
+  shim::L2cap* shim_l2cap_{nullptr};
+  FuzzL2capClassicModule* fuzz_l2cap_classic_module_{nullptr};
+  hci::AclManager* acl_manager_{nullptr};
+
+  std::unique_ptr<os::Handler> handler_;
+  std::unique_ptr<l2cap::classic::internal::FixedChannelServiceManagerImpl> fixed_channel_impl;
+  std::unique_ptr<l2cap::classic::internal::DynamicChannelServiceManagerImpl> dynamic_channel_impl;
+  std::unique_ptr<l2cap::classic::internal::LinkManager> link_manager;
+  std::unique_ptr<l2cap::internal::ParameterProvider> parameter_provider;
+
+ private:
+  FuzzTestModuleRegistry fake_registry_;
+  os::Thread& thread_ = fake_registry_.GetTestThread();
+};
+}  // namespace
+}  // namespace shim
+}  // namespace bluetooth