--- /dev/null
+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",
+ ],
+}
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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