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

Commit 031b5063 authored by Treehugger Robot's avatar Treehugger Robot Committed by Gerrit Code Review
Browse files

Merge "Add fuzzers for 10 libosi components"

parents 165c4da3 f0b8122a
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
cc_defaults {
    name: "libosi_fuzz_defaults",
    defaults: ["fluoride_osi_defaults"],
    host_supported: true,
    static_libs: [
        "libosi",
    ],
}
+21 −0
Original line number Diff line number Diff line
cc_fuzz {
    name: "libosi_fuzz_alarm",
    defaults: ["libosi_fuzz_defaults"],
    host_supported: false,
    srcs: [
        "fuzz_alarm.cc",
    ],
    shared_libs: [
        "liblog",
        "libprotobuf-cpp-lite",
        "libcutils",
        "libcrypto",
    ],
    static_libs: [
        "libbt-common",
        "libbt-protos-lite",
        "libgmock",
        "libosi",
    ],
    cflags: [ "-Wno-unused-function" ],
}
+151 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#include <fcntl.h>
#include <fuzzer/FuzzedDataProvider.h>
#include "osi/include/alarm.h"
#include "osi/include/semaphore.h"

#include "common/message_loop_thread.h"

using base::Closure;
using base::TimeDelta;
using bluetooth::common::MessageLoopThread;

#define MAX_CONCURRENT_ALARMS 25
#define MAX_BUFFER_LEN 4096
#define MAX_ALARM_DURATION 25

static semaphore_t* semaphore;
static int cb_counter;
static base::MessageLoop* message_loop_;

base::MessageLoop* get_main_message_loop() { return message_loop_; }

static void cb(void* data) {
  ++cb_counter;
  semaphore_post(semaphore);
}

void setup() {
  cb_counter = 0;
  semaphore = semaphore_new(0);
}
void teardown() { semaphore_free(semaphore); }

alarm_t* fuzz_init_alarm(FuzzedDataProvider* dataProvider) {
  size_t name_len =
      dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUFFER_LEN);
  std::vector<char> alarm_name_vect =
      dataProvider->ConsumeBytesWithTerminator<char>(name_len, '\0');
  char* alarm_name = alarm_name_vect.data();

  // Determine if our alarm will be periodic
  if (dataProvider->ConsumeBool()) {
    return alarm_new_periodic(alarm_name);
  } else {
    return alarm_new(alarm_name);
  }
}

bool fuzz_set_alarm(alarm_t* alarm, uint64_t interval, alarm_callback_t cb,
                    FuzzedDataProvider* dataProvider) {
  // Generate a random buffer (or null)
  void* data_buffer = nullptr;
  size_t buff_len =
      dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUFFER_LEN);
  if (buff_len == 0) {
    return false;
  }

  // allocate our space
  std::vector<uint8_t> data_vector =
      dataProvider->ConsumeBytes<uint8_t>(buff_len);
  data_buffer = data_vector.data();

  // Make sure alarm is non-null
  if (alarm) {
    // Should this alarm be regular or on mloop?
    if (dataProvider->ConsumeBool()) {
      alarm_set_on_mloop(alarm, interval, cb, data_buffer);
    } else {
      alarm_set(alarm, interval, cb, data_buffer);
    }
  }

  return true;
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
  // Init our wrapper
  FuzzedDataProvider dataProvider(Data, Size);

  // Perform setup
  setup();

  alarm_t* alarm = nullptr;
  // Should our alarm be valid or null?
  if (dataProvider.ConsumeBool()) {
    // Init our alarm
    alarm = fuzz_init_alarm(&dataProvider);
  }

  // Set up the alarm & cancel
  // Alarm must be non-null, or set() will trigger assert
  if (alarm) {
    if (!fuzz_set_alarm(alarm, MAX_ALARM_DURATION, cb, &dataProvider)) {
      return 0;
    }
    alarm_cancel(alarm);
  }

  // Check if scheduled
  alarm_is_scheduled(alarm);

  if (alarm) {
    // Set up another set of alarms & let these ones run
    int num_alarms =
        dataProvider.ConsumeIntegralInRange<uint8_t>(0, MAX_CONCURRENT_ALARMS);
    for (int i = 0; i < num_alarms; i++) {
      uint64_t interval =
          dataProvider.ConsumeIntegralInRange<uint64_t>(0, MAX_ALARM_DURATION);
      if (fuzz_set_alarm(alarm, interval, cb, &dataProvider)) {
        return 0;
      }
      alarm_get_remaining_ms(alarm);
    }

    // Wait for them to complete
    for (int i = 1; i <= num_alarms; i++) {
      semaphore_wait(semaphore);
    }
  }

  // Free the alarm object
  alarm_free(alarm);

  // dump debug data to /dev/null
  int debug_fd = open("/dev/null", O_RDWR);
  alarm_debug_dump(debug_fd);

  // Cleanup
  alarm_cleanup();

  // Perform teardown
  teardown();

  return 0;
}
+14 −0
Original line number Diff line number Diff line
cc_fuzz {
    name: "libosi_fuzz_allocation_tracker",
    defaults: ["libosi_fuzz_defaults"],
    host_supported: true,
    srcs: [
        "fuzz_allocation_tracker.cc",
    ],
    shared_libs: [
        "liblog",
    ],
    static_libs: [
        "libosi",
    ],
}
+132 −0
Original line number Diff line number Diff line
/*
 * 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.
 */

#include <fuzzer/FuzzedDataProvider.h>
#include "osi/include/allocation_tracker.h"

#define MAX_NUM_FUNCTIONS 512
#define MAX_BUF_SIZE 256

struct alloc_struct {
  allocator_id_t alloc_id;
  void* ptr;
};

void freeAllocationVector(std::vector<alloc_struct>* alloc_vector) {
  // Free our allocated buffers
  for (const auto& alloc : *alloc_vector) {
    void* real_ptr = allocation_tracker_notify_free(alloc.alloc_id, alloc.ptr);
    if (real_ptr) {
      free(real_ptr);
    }
  }
  alloc_vector->clear();
}

void callArbitraryFunction(std::vector<alloc_struct>* alloc_vector,
                           FuzzedDataProvider* dataProvider) {
  // Get our function identifier
  switch (dataProvider->ConsumeIntegralInRange<char>(0, 6)) {
    // Let 0 be a NO-OP, as ConsumeIntegral will return 0 on an empty buffer
    // (This will likely bias whatever action is here to run more often)
    case 0:
      return;
    // Init
    case 1:
      allocation_tracker_init();
      return;
    case 2:
      // NOTE: This will print to stderr if allocations exist. May clutter logs
      allocation_tracker_expect_no_allocations();
      return;
    case 3: {
      alloc_struct alloc;
      // Determine allocator ID & buffer size (without canaries)
      alloc.alloc_id = dataProvider->ConsumeIntegral<allocator_id_t>();
      size_t size =
          dataProvider->ConsumeIntegralInRange<size_t>(1, MAX_BUF_SIZE);
      if (size == 0) {
        return;
      }
      // Get our size with canaries & allocate
      size_t real_size = allocation_tracker_resize_for_canary(size);
      void* tmp_ptr = malloc(real_size);
      if (tmp_ptr == nullptr) {
        return;
      }
      alloc.ptr =
          allocation_tracker_notify_alloc(alloc.alloc_id, tmp_ptr, size);
      // Put our id/ptr pair in our tracking vector to be freed later
      if (alloc.ptr) {
        alloc_vector->push_back(alloc);
      }
    }
      return;
    case 4: {
      // Grab a ptr from our tracking vector & free it
      if (!alloc_vector->empty()) {
        size_t index = dataProvider->ConsumeIntegralInRange<size_t>(
            0, alloc_vector->size() - 1);
        alloc_struct alloc = alloc_vector->at(index);
        void* real_ptr =
            allocation_tracker_notify_free(alloc.alloc_id, alloc.ptr);
        if (real_ptr) {
          free(real_ptr);
        }
        alloc_vector->erase(alloc_vector->begin() + index);
      }
    }
      return;
    case 5: {
      size_t size =
          dataProvider->ConsumeIntegralInRange<size_t>(0, MAX_BUF_SIZE);
      allocation_tracker_resize_for_canary(size);
    }
      return;
    // Reset
    // NOTE: Should this be exempted from fuzzing? Header says to not call this,
    //       but it's still exposed. It also doesn't perform a full reset.
    case 6:
      // Have to actually free the mem first as reset doesn't do it
      freeAllocationVector(alloc_vector);
      allocation_tracker_reset();
      return;
    default:
      return;
  }
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* Data, size_t Size) {
  // Init our wrapper
  FuzzedDataProvider dataProvider(Data, Size);

  // Keep a vector of our allocated pointers
  std::vector<alloc_struct> alloc_vector;

  // How many functions are we going to call?
  size_t num_functions =
      dataProvider.ConsumeIntegralInRange<size_t>(0, MAX_NUM_FUNCTIONS);
  for (size_t i = 0; i < num_functions; i++) {
    callArbitraryFunction(&alloc_vector, &dataProvider);
  }

  // Free anything we've allocated over the course of the fuzzer loop
  freeAllocationVector(&alloc_vector);

  // Reset our tracker for the next run
  allocation_tracker_reset();
  return 0;
}
Loading