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

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

Merge "Add fuzzers for 10 libosi components" am: 031b5063

Change-Id: I767054e25fd5cba18c6cf734bff4b4d03ebea493
parents a0ceb008 031b5063
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