diff options
Diffstat (limited to 'fuzz/cr50_fuzz.cc')
-rw-r--r-- | fuzz/cr50_fuzz.cc | 148 |
1 files changed, 148 insertions, 0 deletions
diff --git a/fuzz/cr50_fuzz.cc b/fuzz/cr50_fuzz.cc new file mode 100644 index 0000000000..186700f415 --- /dev/null +++ b/fuzz/cr50_fuzz.cc @@ -0,0 +1,148 @@ +// Copyright 2018 The Chromium OS Authors. All rights reserved. +// Use of this source code is governed by a BSD-style license that can be +// found in the LICENSE file. + +// Fuzzer for the TPM2 and vendor specific Cr50 commands. + +#include <unistd.h> + +#include <cassert> +#include <cstdint> +#include <cstring> +#include <unordered_map> +#include <vector> + +#include <src/libfuzzer/libfuzzer_macro.h> +#include <src/mutator.h> + +#define HIDE_EC_STDLIB +#include "chip/host/persistence.h" +#include "fuzz/cr50_fuzz.pb.h" +#include "fuzz/fuzz_config.h" +#include "fuzz/pinweaver_model.h" +#include "fuzz/span.h" +#include "include/nvmem.h" +#include "include/nvmem_vars.h" +#include "include/pinweaver.h" + +using protobuf_mutator::libfuzzer::LoadProtoInput; + +namespace { +constexpr size_t kBufferAlignment = alignof(pw_request_t) > + alignof(pw_response_t) + ? alignof(pw_request_t) + : alignof(pw_response_t); +} // namespace + +extern "C" uint32_t nvmem_user_sizes[NVMEM_NUM_USERS] = {NVMEM_TPM_SIZE, + NVMEM_CR50_SIZE}; + +extern "C" void rand_bytes(void* data, size_t len) { + size_t x = 0; + + uint8_t* buffer = reinterpret_cast<uint8_t*>(data); + for (; x < len; ++x) { + buffer[x] = rand(); + } +} + +extern "C" void get_storage_seed(void* buf, size_t* len) { + memset(buf, 0x77, *len); +} + +extern "C" uint8_t get_current_pcr_digest(const uint8_t bitmask[2], + uint8_t sha256_of_selected_pcr[32]) { + memset(sha256_of_selected_pcr, 0, 32); + return 0; +} + +extern "C" int DCRYPTO_ladder_is_enabled(void) { + return 1; +} + +extern "C" void nvmem_wipe_cache(void) { + // Nothing to do since there is no cache in this implementation. +} + +// Needed for test targets to build. +extern "C" void run_test(void) {} + +void InitializeFuzzerRun() { + memset(__host_flash, 0xff, sizeof(__host_flash)); + nvmem_init(); + nvmem_enable_commits(); + srand(0); +} + +// Used to verify the model hasn't become out of sync with the implementation. +// The usefulness of this fuzzer comes from its ability to reach all the code +// paths. +bool SelfTest() { + InitializeFuzzerRun(); + + PinweaverModel pinweaver_model; + alignas(kBufferAlignment) uint8_t buffer[PW_MAX_MESSAGE_SIZE] = {}; + fuzz::span<uint8_t> buffer_view(buffer, sizeof(buffer)); + fuzz::pinweaver::Request request; + + fuzz::pinweaver::ResetTree* reset_tree = request.mutable_reset_tree(); + reset_tree->set_height(2); + reset_tree->set_bits_per_level(2); + assert(pinweaver_model.ApplyRequest(request, buffer_view) == EC_SUCCESS); + + fuzz::pinweaver::InsertLeaf* insert_leaf = request.mutable_insert_leaf(); + constexpr char delay_schedule[] = "\000\000\000\005\377\377\377\377"; + insert_leaf->mutable_delay_schedule()->assign( + delay_schedule, delay_schedule + sizeof(delay_schedule)); + assert(pinweaver_model.ApplyRequest(request, buffer_view) == EC_SUCCESS); + + request.mutable_try_auth(); + assert(pinweaver_model.ApplyRequest(request, buffer_view) == EC_SUCCESS); + + request.mutable_get_log(); + assert(pinweaver_model.ApplyRequest(request, buffer_view) == EC_SUCCESS); + + request.mutable_log_replay(); + assert(pinweaver_model.ApplyRequest(request, buffer_view) == EC_SUCCESS); + + request.mutable_reset_auth(); + assert(pinweaver_model.ApplyRequest(request, buffer_view) == EC_SUCCESS); + + request.mutable_remove_leaf(); + assert(pinweaver_model.ApplyRequest(request, buffer_view) == EC_SUCCESS); + + return true; +} + +DEFINE_CUSTOM_PROTO_MUTATOR_IMPL(false, fuzz::Cr50FuzzerInput) +DEFINE_CUSTOM_PROTO_CROSSOVER_IMPL(false, fuzz::Cr50FuzzerInput) + +extern "C" int test_fuzz_one_input(const uint8_t* data, unsigned int size) { + static bool initialized = SelfTest(); + assert(initialized); + + fuzz::Cr50FuzzerInput input; + if (!LoadProtoInput(false, data, size, &input)) { + return 0; + } + + InitializeFuzzerRun(); + + PinweaverModel pinweaver_model; + alignas(kBufferAlignment) uint8_t buffer[PW_MAX_MESSAGE_SIZE] = {}; + fuzz::span<uint8_t> buffer_view(buffer, sizeof(buffer)); + for (const fuzz::Cr50SubAction& action : input.sub_actions()) { + switch (action.sub_action_case()) { + case fuzz::Cr50SubAction::kRandomBytes: + fuzz::CopyWithPadding(action.random_bytes().value(), buffer_view, 0); + pinweaver_model.SendBuffer(buffer_view); + break; + case fuzz::Cr50SubAction::kPinweaver: + pinweaver_model.ApplyRequest(action.pinweaver(), buffer_view); + break; + case fuzz::Cr50SubAction::SUB_ACTION_NOT_SET: + break; + } + } + return 0; +} |