Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 6388c3a9 authored by Treehugger Robot's avatar Treehugger Robot Committed by Automerger Merge Worker
Browse files

Merge "Refactored avrcp_device_fuzz" into main am: 2d10c8e5 am: 352ad2a1

parents cd6454f2 352ad2a1
Loading
Loading
Loading
Loading
+311 −50
Original line number Diff line number Diff line
#include <cstddef>
#include <cstdint>
/*
 * Copyright (C) 2024 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.
 *
 */

#include "avrcp_packet.h"
#include "device.h"
#include "fuzzer/FuzzedDataProvider.h"
#include "internal_include/stack_config.h"
#include "packet_test_helper.h"
#include "stack/include/a2dp_api.h"
#include "types/raw_address.h"
#include "pass_through_packet.h"

bool btif_av_src_sink_coexist_enabled(void) { return true; }

namespace bluetooth {
namespace avrcp {

static uint32_t kMinSize = 0;
static uint32_t kMaxSize = 10;
static uint32_t kMaxLen = 100;
static uint8_t kMinScope = 0;
static uint8_t kMaxScope = 3;
static uint8_t kMediaOpId = 0x44;
static uint8_t kMask = 0xFF;
static uint8_t k8BitShift = 8;

const Opcode kValidOpCodes[] = {Opcode::VENDOR, Opcode::UNIT_INFO,
                                Opcode::SUBUNIT_INFO, Opcode::PASS_THROUGH};

const CType kValidCTypes[] = {
    CType::CONTROL,         CType::STATUS,   CType::NOTIFY,
    CType::NOT_IMPLEMENTED, CType::ACCEPTED, CType::REJECTED,
    CType::STABLE,          CType::CHANGED,  CType::INTERIM};

const BrowsePdu kPduVal[] = {BrowsePdu::SET_BROWSED_PLAYER,
                             BrowsePdu::GET_FOLDER_ITEMS,
                             BrowsePdu::CHANGE_PATH,
                             BrowsePdu::GET_ITEM_ATTRIBUTES,
                             BrowsePdu::GET_TOTAL_NUMBER_OF_ITEMS,
                             BrowsePdu::GENERAL_REJECT};

const CommandPdu kCommandPduVal[] = {
    CommandPdu::GET_CAPABILITIES,
    CommandPdu::LIST_PLAYER_APPLICATION_SETTING_ATTRIBUTES,
    CommandPdu::LIST_PLAYER_APPLICATION_SETTING_VALUES,
    CommandPdu::GET_CURRENT_PLAYER_APPLICATION_SETTING_VALUE,
    CommandPdu::SET_PLAYER_APPLICATION_SETTING_VALUE,
    CommandPdu::GET_ELEMENT_ATTRIBUTES,
    CommandPdu::GET_PLAY_STATUS,
    CommandPdu::REGISTER_NOTIFICATION,
    CommandPdu::SET_ABSOLUTE_VOLUME,
    CommandPdu::SET_ADDRESSED_PLAYER,
    CommandPdu::PLAY_ITEM};

class FakeMediaInterface : public MediaInterface {
 public:
  virtual void SendKeyEvent(uint8_t key, KeyState state) {}
  FakeMediaInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {}
  void SendKeyEvent(uint8_t /* key */, KeyState /* state */) { return; }
  using SongInfoCallback = base::Callback<void(SongInfo)>;
  virtual void GetSongInfo(SongInfoCallback info_cb) {}
  void GetSongInfo(SongInfoCallback info_cb) {
    SongInfo sInfo;
    sInfo.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
    sInfo.attributes.insert(AttributeEntry(
        Attribute(mFdp->ConsumeIntegralInRange<uint8_t>(
            uint8_t(Attribute::TITLE), uint8_t(Attribute::DEFAULT_COVER_ART))),
        mFdp->ConsumeRandomLengthString(kMaxLen)));
    info_cb.Run(sInfo);
    return;
  }
  using PlayStatusCallback = base::Callback<void(PlayStatus)>;
  virtual void GetPlayStatus(PlayStatusCallback status_cb) {}
  void GetPlayStatus(PlayStatusCallback status_cb) {
    PlayStatus pst;
    status_cb.Run(pst);
    return;
  }
  using NowPlayingCallback =
      base::Callback<void(std::string, std::vector<SongInfo>)>;
  virtual void GetNowPlayingList(NowPlayingCallback now_playing_cb) {}
  void GetNowPlayingList(NowPlayingCallback now_playing_cb) {
    std::string currentSongId = mFdp->ConsumeRandomLengthString(kMaxLen);
    size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
    std::vector<SongInfo> songInfoVec;
    for (size_t iter = 0; iter < size; ++iter) {
      SongInfo tempSongInfo;
      tempSongInfo.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
      tempSongInfo.attributes.insert(
          AttributeEntry(Attribute(mFdp->ConsumeIntegralInRange<uint8_t>(
                             uint8_t(Attribute::TITLE),
                             uint8_t(Attribute::DEFAULT_COVER_ART))),
                         mFdp->ConsumeRandomLengthString(kMaxLen)));
      songInfoVec.push_back(tempSongInfo);
    }
    now_playing_cb.Run(currentSongId, songInfoVec);
    return;
  }
  using MediaListCallback =
      base::Callback<void(uint16_t curr_player, std::vector<MediaPlayerInfo>)>;
  virtual void GetMediaPlayerList(MediaListCallback list_cb) {}
  void GetMediaPlayerList(MediaListCallback list_cb) {
    uint16_t currentPlayer = mFdp->ConsumeIntegral<uint16_t>();
    size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
    std::vector<MediaPlayerInfo> playerList;
    for (size_t iter = 0; iter < size; ++iter) {
      MediaPlayerInfo tempInfo;
      tempInfo.id = mFdp->ConsumeIntegral<uint16_t>();
      tempInfo.name = mFdp->ConsumeRandomLengthString(kMaxLen);
      tempInfo.browsing_supported = mFdp->ConsumeBool();
      playerList.push_back(tempInfo);
    }
    list_cb.Run(currentPlayer, playerList);
    return;
  }
  using FolderItemsCallback = base::Callback<void(std::vector<ListItem>)>;
  virtual void GetFolderItems(uint16_t player_id, std::string media_id,
                              FolderItemsCallback folder_cb) {}
  void GetFolderItems(uint16_t /* player_id */, std::string /* media_id */,
                      FolderItemsCallback folder_cb) {
    size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
    std::vector<ListItem> list;
    for (size_t iter = 0; iter < size; ++iter) {
      ListItem tempList;
      tempList.type = mFdp->ConsumeBool() ? ListItem::FOLDER : ListItem::SONG;
      tempList.folder.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
      tempList.folder.name = mFdp->ConsumeRandomLengthString(kMaxLen);
      tempList.folder.is_playable = mFdp->ConsumeBool();
      tempList.song.media_id = mFdp->ConsumeRandomLengthString(kMaxLen);
      tempList.song.attributes.insert(
          AttributeEntry(Attribute(mFdp->ConsumeIntegralInRange<uint8_t>(
                             uint8_t(Attribute::TITLE),
                             uint8_t(Attribute::DEFAULT_COVER_ART))),
                         mFdp->ConsumeRandomLengthString(kMaxLen)));
      list.push_back(tempList);
    }
    folder_cb.Run(list);
  }
  using SetBrowsedPlayerCallback = base::Callback<void(
      bool success, std::string root_id, uint32_t num_items)>;
  virtual void SetBrowsedPlayer(uint16_t player_id,
                                SetBrowsedPlayerCallback browse_cb) {}
  virtual void PlayItem(uint16_t player_id, bool now_playing,
                        std::string media_id) {}
  virtual void SetActiveDevice(const RawAddress& address) {}
  virtual void RegisterUpdateCallback(MediaCallbacks* callback) {}
  virtual void UnregisterUpdateCallback(MediaCallbacks* callback) {}
  void SetBrowsedPlayer(uint16_t player_id,
                        SetBrowsedPlayerCallback browse_cb) {
    std::string rootId = mFdp->ConsumeRandomLengthString(kMaxLen);
    uint32_t numItems = mFdp->ConsumeIntegral<uint32_t>();
    browse_cb.Run(player_id, rootId, numItems);
    return;
  }
  void PlayItem(uint16_t /* player_id */, bool /* now_playing */,
                std::string /* media_id */) {
    return;
  }
  void SetActiveDevice(const RawAddress& /* address */) { return; }
  void RegisterUpdateCallback(MediaCallbacks* /* callback */) { return; }
  void UnregisterUpdateCallback(MediaCallbacks* /* callback */) { return; }

 private:
  FuzzedDataProvider* mFdp;
};

class FakeVolumeInterface : public VolumeInterface {
 public:
  virtual void DeviceConnected(const RawAddress& bdaddr) {}
  virtual void DeviceConnected(const RawAddress& bdaddr, VolumeChangedCb cb) {}
  virtual void DeviceDisconnected(const RawAddress& bdaddr) {}
  virtual void SetVolume(int8_t volume) {}
  FakeVolumeInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {}
  void DeviceConnected(const RawAddress& /* bdaddr */) { return; }
  void DeviceConnected(const RawAddress& /* bdaddr */, VolumeChangedCb cb) {
    uint8_t volume = mFdp->ConsumeIntegral<uint8_t>();
    cb.Run(volume);
    return;
  }
  void DeviceDisconnected(const RawAddress& /* bdaddr */) { return; }
  void SetVolume(int8_t /* volume */) { return; }

 private:
  FuzzedDataProvider* mFdp;
};

class FakePlayerSettingsInterface : public PlayerSettingsInterface {
 public:
  virtual void ListPlayerSettings(ListPlayerSettingsCallback cb) {}
  virtual void ListPlayerSettingValues(PlayerAttribute setting,
                                       ListPlayerSettingValuesCallback cb) {}
  virtual void GetCurrentPlayerSettingValue(
      std::vector<PlayerAttribute> attributes,
      GetCurrentPlayerSettingValueCallback cb) {}
  virtual void SetPlayerSettings(std::vector<PlayerAttribute> attributes,
                                 std::vector<uint8_t> values,
                                 SetPlayerSettingValueCallback cb) {}
  FakePlayerSettingsInterface(FuzzedDataProvider* fdp) : mFdp(fdp) {}
  void ListPlayerSettings(ListPlayerSettingsCallback cb) {
    uint8_t label = mFdp->ConsumeIntegral<uint8_t>();
    size_t size = mFdp->ConsumeIntegralInRange<uint8_t>(kMinSize, kMaxSize);
    std::vector<PlayerAttribute> attributes;
    for (size_t iter = 0; iter < size; ++iter) {
      PlayerAttribute playerAttr =
          (PlayerAttribute)mFdp->ConsumeIntegralInRange<uint8_t>(
              uint8_t(PlayerAttribute::EQUALIZER),
              uint8_t(PlayerAttribute::SCAN));
      attributes.push_back(playerAttr);
    }
    cb.Run(attributes);
    return;
  }
  void ListPlayerSettingValues(PlayerAttribute setting,
                               ListPlayerSettingValuesCallback cb) {
    size_t size = mFdp->ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
    std::vector<uint8_t> values = mFdp->ConsumeBytes<uint8_t>(size);
    cb.Run(setting, values);
    return;
  }
  void GetCurrentPlayerSettingValue(std::vector<PlayerAttribute> attributes,
                                    GetCurrentPlayerSettingValueCallback cb) {
    std::vector<uint8_t> values(attributes.size());
    for (size_t iter = 0; iter < attributes.size(); ++iter) {
      values.push_back(mFdp->ConsumeIntegral<uint8_t>());
    }
    cb.Run(attributes, values);
    return;
  }
  void SetPlayerSettings(std::vector<PlayerAttribute> /* attributes */,
                         std::vector<uint8_t> /* values */,
                         SetPlayerSettingValueCallback cb) {
    bool success = mFdp->ConsumeBool();
    cb.Run(success);
    return;
  }

 private:
  FuzzedDataProvider* mFdp;
};

class FakeA2dpInterface : public A2dpInterface {
 public:
  virtual RawAddress active_peer() { return RawAddress(); }
  virtual bool is_peer_in_silence_mode(const RawAddress& peer_address) {
  RawAddress active_peer() { return RawAddress::kAny; }
  bool is_peer_in_silence_mode(const RawAddress& /* peer_address */) {
    return false;
  }
  virtual void connect_audio_sink_delayed(uint8_t handle,
                                          const RawAddress& peer_address) {
  void connect_audio_sink_delayed(uint8_t /* handle */,
                                  const RawAddress& /* peer_address */) {
    return;
  }
  virtual uint16_t find_audio_sink_service(const RawAddress& peer_address,
                                           tA2DP_FIND_CBACK p_cback) override {
  uint16_t find_audio_sink_service(const RawAddress& /* peer_address */,
                                   tA2DP_FIND_CBACK /* p_cback */) override {
    return 0;
  }
};
@@ -103,25 +265,124 @@ const stack_config_t interface = {get_pts_avrcp_test,

void Callback(uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
  FakeMediaInterface fmi;
  FakeVolumeInterface fvi;
class AVRCPDeviceFuzzer {
 public:
  AVRCPDeviceFuzzer(const uint8_t* Data, size_t Size) : mFdp(Data, Size) {}
  void Process();

 private:
  void CreateBrowsePacket(std::vector<uint8_t>& packet);
  void CreateAvrcpPacket(std::vector<uint8_t>& packet);
  FuzzedDataProvider mFdp;
};

void AVRCPDeviceFuzzer::CreateBrowsePacket(std::vector<uint8_t>& packet) {
  // Used to consume a maximum of 50% of the data to create packet.
  // This ensures that we don't completely exhaust data and use the rest 50% for
  // fuzzing of APIs.
  packet = mFdp.ConsumeBytes<uint8_t>(mFdp.ConsumeIntegralInRange<size_t>(
      0, mFdp.remaining_bytes() * 50 / 100));

  if (packet.size() < Packet::kMinSize()) {
    packet.resize(Packet::kMinSize());
  }
  packet[0] = (uint8_t)mFdp.PickValueInArray(kPduVal);
  // Set packet[1] and packet[2] to corresponding value of little endian
  uint16_t size = packet.size() - BrowsePacket::kMinSize();
  packet[1] = (size >> k8BitShift) & kMask;
  packet[2] = size & kMask;
}

void AVRCPDeviceFuzzer::CreateAvrcpPacket(std::vector<uint8_t>& packet) {
  // Used to consume a maximum of 50% of the data to create packet.
  // This ensures that we don't completely exhaust data and use the rest 50% for
  // fuzzing of APIs.
  packet = mFdp.ConsumeBytes<uint8_t>(mFdp.ConsumeIntegralInRange<size_t>(
      0, mFdp.remaining_bytes() * 50 / 100));
  if (packet.size() < Packet::kMinSize()) {
    packet.resize(Packet::kMinSize());
  }
  packet[0] = (uint8_t)mFdp.PickValueInArray(kValidCTypes);
  packet[2] = (uint8_t)mFdp.PickValueInArray(kValidOpCodes);
  if (packet[2] == uint8_t(Opcode::PASS_THROUGH)) {
    packet.resize(PassThroughPacket::kMinSize());
    packet[3] =
        mFdp.ConsumeBool() ? kMediaOpId : mFdp.ConsumeIntegral<uint8_t>();
  } else if (packet[2] == uint8_t(Opcode::VENDOR)) {
    if (packet.size() <= VendorPacket::kMinSize()) {
      packet.resize(VendorPacket::kMinSize() + 1);
    }
    packet[3] = mFdp.ConsumeIntegralInRange<uint8_t>(kMinScope, kMaxScope);
    packet[5] = (uint8_t)mFdp.ConsumeBool();  // Direction
    packet[6] = (uint8_t)mFdp.PickValueInArray(kCommandPduVal);
    // Set packet[8] and packet[9] to corresponding value of little endian
    uint16_t size = packet.size() - VendorPacket::kMinSize();
    packet[8] = (size >> k8BitShift) & kMask;
    packet[9] = size & kMask;
  }
}
void AVRCPDeviceFuzzer::Process() {
  FakeMediaInterface fmi(&mFdp);
  FakeVolumeInterface fvi(&mFdp);
  FakeA2dpInterface fai;
  FakePlayerSettingsInterface fpsi;
  FakePlayerSettingsInterface fpsi(&mFdp);

  std::vector<uint8_t> Packet(Data, Data + Size);
  Device device(
      RawAddress::kAny, true,
      RawAddress::kAny /* bdaddr */,
      mFdp.ConsumeBool() /* avrcp13_compatibility */,
      base::BindRepeating(
          [](uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {}),
      0xFFFF, 0xFFFF);
          [](uint8_t, bool, std::unique_ptr<::bluetooth::PacketBuilder>) {
          }) /* send_msg_cb */,
      mFdp.ConsumeIntegral<uint16_t>() /* ctrl_mtu */,
      mFdp.ConsumeIntegral<uint16_t>() /* browse_mtu */);

  device.RegisterInterfaces(&fmi, &fai, &fvi, &fpsi);

  auto browse_request = TestPacketType<BrowsePacket>::Make(Packet);
  device.BrowseMessageReceived(1, browse_request);
  while (mFdp.remaining_bytes()) {
    auto invokeAVRCP = mFdp.PickValueInArray<const std::function<void()>>({
        [&]() {
          device.SetBrowseMtu(
              mFdp.ConsumeIntegral<uint16_t>() /*  browse_mtu */);
        },
        [&]() {
          device.SetBipClientStatus(mFdp.ConsumeBool() /* connected */);
        },
        [&]() {
          std::vector<uint8_t> browse_packet;
          CreateBrowsePacket(browse_packet);
          auto browse_request =
              TestPacketType<BrowsePacket>::Make(browse_packet);
          device.BrowseMessageReceived(
              mFdp.ConsumeIntegral<uint8_t>() /* label */, browse_request);
        },
        [&]() {
          /* Crafting PassThroughPacket Packets */
          std::vector<uint8_t> avrcp_packet;
          CreateAvrcpPacket(avrcp_packet);
          auto avrcp_request =
              TestPacketType<avrcp::Packet>::Make(avrcp_packet);
          device.MessageReceived(mFdp.ConsumeIntegral<uint8_t>() /* label */,
                                 avrcp_request);
        },
        [&]() {
          device.SendMediaUpdate(mFdp.ConsumeBool() /* metadata */,
                                 mFdp.ConsumeBool() /* play_status */,
                                 mFdp.ConsumeBool() /* queue */);
        },
        [&]() {
          device.SendFolderUpdate(mFdp.ConsumeBool() /* available_players */,
                                  mFdp.ConsumeBool() /* addressed_player */,
                                  mFdp.ConsumeBool() /* uids */);
        },
    });
    invokeAVRCP();
  }
  device.DeviceDisconnected();
}

  auto avrcp_request = TestPacketType<avrcp::Packet>::Make(Packet);
  device.MessageReceived(1, avrcp_request);
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
  AVRCPDeviceFuzzer avrcp_device_fuzzer(Data, Size);
  avrcp_device_fuzzer.Process();
  return 0;
}
}  // namespace avrcp