// 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 Cr50 commands related to Pinweaver. #include #include #include #include #include #include #include #include #define HIDE_EC_STDLIB #include "chip/host/persistence.h" #include "fuzz/pinweaver_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(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 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 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; }