blob: 1e86d0cb92c7dc80698d6c00255db111753bcd07 [file] [log] [blame] [edit]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include <fuzzer/FuzzedDataProvider.h>
#include <vector>
#include <base/command_line.h>
#include <base/files/scoped_temp_dir.h>
#include <base/logging.h>
#include <base/test/task_environment.h>
#include <base/test/test_timeouts.h>
#include <libhwsec/factory/fuzzed_factory.h>
#include "chaps/chaps_interface.h"
#include "chaps/fuzzers/fuzzed_chaps_factory.h"
#include "chaps/fuzzers/fuzzed_object_pool.h"
#include "chaps/session.h"
#include "chaps/slot_manager_impl.h"
#include "chaps/token_manager_interface.h"
namespace {
enum class SlotManagerRequest {
kInit,
kGetSlotCount,
kIsTokenAccessible,
kIsTokenPresent,
kGetSlotInfo,
kGetTokenInfo,
kGetMechanismInfo,
kOpenSession,
kCloseSession,
kCloseAllSessions,
kGetSession,
kMaxValue = kGetSession,
};
enum class TokenManagerInterfaceRequest {
kOpenIsolate,
kCloseIsolate,
kLoadToken,
kUnloadToken,
kGetTokenPath,
kMaxValue = kGetTokenPath,
};
// An arbitrary choice that provides satisfactory coverage
constexpr int kSuccessProbability = 90;
// Provide max iterations for a single fuzz run, otherwise it might timeout.
constexpr int kMaxIterations = 100;
class SlotManagerFuzzer {
public:
explicit SlotManagerFuzzer(FuzzedDataProvider* hwsec_data_provider,
FuzzedDataProvider* data_provider)
: data_provider_(data_provider) {
chaps_metrics_ = std::make_unique<chaps::ChapsMetrics>();
factory_ = std::make_unique<chaps::FuzzedChapsFactory>(data_provider_);
hwsec_factory_ =
std::make_unique<hwsec::FuzzedFactory>(*hwsec_data_provider);
hwsec_ = hwsec_factory_->GetChapsFrontend();
bool auto_load_system_token = data_provider_->ConsumeBool();
slot_manager_ = std::make_unique<chaps::SlotManagerImpl>(
factory_.get(), hwsec_.get(), auto_load_system_token, nullptr,
chaps_metrics_.get());
}
~SlotManagerFuzzer() {
slot_manager_.reset();
hwsec_.reset();
hwsec_factory_.reset();
factory_.reset();
chaps_metrics_.reset();
}
void Run() {
CHECK(tmp_dir_.CreateUniqueTempDir());
int rounds = 0;
while (data_provider_->remaining_bytes() > 0 && rounds < kMaxIterations) {
if (data_provider_->ConsumeBool()) {
FuzzSlotManagerRequest();
} else {
FuzzTokenManagerInterfaceRequest();
}
task_environment_.RunUntilIdle();
rounds++;
}
}
private:
bool IsTokenPresent(const brillo::SecureBlob& isolate_credential,
int slot_id) {
return slot_id < slot_manager_->GetSlotCount() &&
slot_manager_->IsTokenAccessible(isolate_credential, slot_id) &&
slot_manager_->IsTokenPresent(isolate_credential, slot_id);
}
void FuzzSlotManagerRequest() {
auto request = data_provider_->ConsumeEnum<SlotManagerRequest>();
brillo::SecureBlob isolate_credential;
int slot_id;
LOG(INFO) << "slot manager request: " << static_cast<int>(request);
if (!ConsumeProbability(kSuccessProbability) ||
generated_isolate_credentials_.empty()) {
isolate_credential =
brillo::SecureBlob(ConsumeLowEntropyRandomLengthString(16));
} else {
auto idx = data_provider_->ConsumeIntegralInRange(
0ul, generated_isolate_credentials_.size() - 1);
isolate_credential =
brillo::SecureBlob(generated_isolate_credentials_[idx]);
}
if (!ConsumeProbability(kSuccessProbability) ||
generated_slot_ids_.empty()) {
slot_id = data_provider_->ConsumeIntegral<int>();
} else {
auto idx = data_provider_->ConsumeIntegralInRange(
0ul, generated_slot_ids_.size() - 1);
slot_id = generated_slot_ids_[idx];
}
switch (request) {
case SlotManagerRequest::kInit: {
slot_manager_->Init();
break;
}
case SlotManagerRequest::kGetSlotCount: {
slot_manager_->GetSlotCount();
break;
}
case SlotManagerRequest::kIsTokenAccessible: {
slot_id < slot_manager_->GetSlotCount() &&
slot_manager_->IsTokenAccessible(isolate_credential, slot_id);
break;
}
case SlotManagerRequest::kIsTokenPresent: {
IsTokenPresent(isolate_credential, slot_id);
break;
}
case SlotManagerRequest::kGetSlotInfo: {
CK_SLOT_INFO slot_info;
if (IsTokenPresent(isolate_credential, slot_id))
slot_manager_->GetSlotInfo(isolate_credential, slot_id, &slot_info);
break;
}
case SlotManagerRequest::kGetTokenInfo: {
CK_TOKEN_INFO token_info;
if (IsTokenPresent(isolate_credential, slot_id))
slot_manager_->GetTokenInfo(isolate_credential, slot_id, &token_info);
break;
}
case SlotManagerRequest::kGetMechanismInfo: {
if (IsTokenPresent(isolate_credential, slot_id))
slot_manager_->GetMechanismInfo(isolate_credential, slot_id);
break;
}
case SlotManagerRequest::kOpenSession: {
if (IsTokenPresent(isolate_credential, slot_id))
slot_manager_->OpenSession(isolate_credential, slot_id,
data_provider_->ConsumeBool());
break;
}
case SlotManagerRequest::kCloseSession: {
slot_manager_->CloseSession(isolate_credential, slot_id);
break;
}
case SlotManagerRequest::kCloseAllSessions: {
if (slot_id < slot_manager_->GetSlotCount() &&
slot_manager_->IsTokenAccessible(isolate_credential, slot_id)) {
slot_manager_->CloseAllSessions(isolate_credential, slot_id);
}
break;
}
case SlotManagerRequest::kGetSession: {
chaps::Session* session = nullptr;
slot_manager_->GetSession(isolate_credential, slot_id, &session);
break;
}
}
}
void FuzzTokenManagerInterfaceRequest() {
auto request = data_provider_->ConsumeEnum<TokenManagerInterfaceRequest>();
brillo::SecureBlob isolate_credential;
LOG(INFO) << "token manager request: " << static_cast<int>(request);
if (data_provider_->ConsumeBool() ||
generated_isolate_credentials_.empty()) {
isolate_credential =
brillo::SecureBlob(ConsumeLowEntropyRandomLengthString(16));
} else {
auto idx = data_provider_->ConsumeIntegralInRange(
0ul, generated_isolate_credentials_.size() - 1);
isolate_credential =
brillo::SecureBlob(generated_isolate_credentials_[idx]);
}
switch (request) {
case TokenManagerInterfaceRequest::kOpenIsolate: {
bool new_isolate_created;
if (slot_manager_->OpenIsolate(&isolate_credential,
&new_isolate_created) &&
new_isolate_created) {
generated_isolate_credentials_.push_back(
isolate_credential.to_string());
}
break;
}
case TokenManagerInterfaceRequest::kCloseIsolate: {
slot_manager_->CloseIsolate(isolate_credential);
break;
}
case TokenManagerInterfaceRequest::kLoadToken: {
auto path = tmp_dir_.GetPath();
auto auth_data =
brillo::SecureBlob(ConsumeLowEntropyRandomLengthString(10));
std::string label = ConsumeLowEntropyRandomLengthString(10);
int slot_id;
if (slot_manager_->LoadToken(isolate_credential, path, auth_data, label,
&slot_id)) {
generated_slot_ids_.push_back(slot_id);
}
break;
}
case TokenManagerInterfaceRequest::kUnloadToken: {
auto path = tmp_dir_.GetPath();
slot_manager_->UnloadToken(isolate_credential, path);
break;
}
case TokenManagerInterfaceRequest::kGetTokenPath: {
base::FilePath path;
int slot_id = data_provider_->ConsumeIntegral<int>();
slot_manager_->GetTokenPath(isolate_credential, slot_id, &path);
break;
}
}
}
bool ConsumeProbability(uint32_t probability) {
return data_provider_->ConsumeIntegralInRange<uint32_t>(0, 9) * 10 <
probability;
}
std::string ConsumeLowEntropyRandomLengthString(int len) {
return std::string(
data_provider_->ConsumeIntegralInRange<size_t>(0, len - 1),
'0') +
data_provider_->ConsumeBytesAsString(1);
}
FuzzedDataProvider* data_provider_;
std::unique_ptr<chaps::SlotManagerImpl> slot_manager_;
std::unique_ptr<chaps::ChapsMetrics> chaps_metrics_;
std::unique_ptr<chaps::FuzzedChapsFactory> factory_;
std::unique_ptr<hwsec::FuzzedFactory> hwsec_factory_;
std::unique_ptr<const hwsec::ChapsFrontend> hwsec_;
base::test::TaskEnvironment task_environment_{
base::test::TaskEnvironment::TimeSource::MOCK_TIME};
std::vector<std::string> generated_isolate_credentials_;
std::vector<int> generated_slot_ids_;
base::ScopedTempDir tmp_dir_;
};
} // namespace
class Environment {
public:
Environment() {
logging::SetMinLogLevel(logging::LOGGING_FATAL);
base::CommandLine::Init(0, nullptr);
TestTimeouts::Initialize();
}
};
extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
static Environment env;
if (size <= 1) {
return 0;
}
size_t hwsec_data_size = size / 2;
FuzzedDataProvider hwsec_data_provider(data, hwsec_data_size),
data_provider(data + hwsec_data_size, size - hwsec_data_size);
SlotManagerFuzzer fuzzer(&hwsec_data_provider, &data_provider);
fuzzer.Run();
return 0;
}