blob: a0d7176a4fab00e7e8bb9ec478d562c6ce4d5872 [file] [log] [blame]
// Copyright 2019 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.
#include <stddef.h>
#include <stdint.h>
#include <iostream>
#include <memory>
#include <base/at_exit.h>
#include <brillo/syslog_logging.h>
#include <libprotobuf-mutator/src/libfuzzer/libfuzzer_macro.h>
#include <gmock/gmock.h>
#include "vm_tools/cicerone/container_listener_impl.h"
#include "vm_tools/cicerone/service.h"
#include "vm_tools/cicerone/service_testing_helper.h"
#include "vm_tools/cicerone/tremplin_listener_impl.h"
#include "container_host.grpc.pb.h" // NOLINT(build/include)
#include "fuzzer.pb.h" // NOLINT(build/include)
namespace {
using ::testing::_;
using ::testing::AnyNumber;
using ::testing::InvokeWithoutArgs;
using ::testing::Return;
using ::vm_tools::cicerone::ContainerListenerImpl;
using ::vm_tools::cicerone::Service;
using ::vm_tools::cicerone::ServiceTestingHelper;
// Stuff to create & do once the first time the fuzzer runs.
struct SetupOnce {
SetupOnce() {
brillo::InitLog(brillo::kLogToSyslog | brillo::kLogToStderrIfTty);
// Disable logging, as suggested in fuzzing instructions.
logging::SetMinLogLevel(logging::LOG_FATAL);
}
// Protobuf Mutator will create invalid protos sometimes (with duplicate
// map keys). Silence those warnings as well.
protobuf_mutator::protobuf::LogSilencer log_silencer_;
base::AtExitManager at_exit_;
};
dbus::Response* ReturnDbusResponse() {
// Will be owned by the caller; see comments in MockObjectProxy.
return dbus::Response::CreateEmpty().release();
}
void SetUpMockObjectProxy(
const vm_tools::container::ContainerListenerFuzzerSingleAction& action,
dbus::MockObjectProxy* mock_object_proxy) {
if (action.return_dbus_response()) {
EXPECT_CALL(*mock_object_proxy, MockCallMethodAndBlock(_, _))
.WillRepeatedly(InvokeWithoutArgs(&ReturnDbusResponse));
EXPECT_CALL(*mock_object_proxy,
MockCallMethodAndBlockWithErrorDetails(_, _, _))
.WillRepeatedly(InvokeWithoutArgs(&ReturnDbusResponse));
} else {
EXPECT_CALL(*mock_object_proxy, MockCallMethodAndBlock(_, _))
.WillRepeatedly(Return(nullptr));
EXPECT_CALL(*mock_object_proxy,
MockCallMethodAndBlockWithErrorDetails(_, _, _))
.WillRepeatedly(Return(nullptr));
}
}
grpc::Status ToStatus(int integer_status_code) {
grpc::StatusCode status_code =
static_cast<grpc::StatusCode>(integer_status_code);
grpc::Status status(status_code, "");
return status;
}
void SetUpTremplinTestStub(
const vm_tools::container::ContainerListenerFuzzerSingleAction& action,
vm_tools::cicerone::TremplinTestStub* test_stub) {
test_stub->SetCreateContainerReturn(
ToStatus(action.tremplin_create_container_status()));
test_stub->SetCreateContainerResponse(
action.tremplin_create_container_response());
test_stub->SetStartContainerReturn(
ToStatus(action.tremplin_start_container_status()));
test_stub->SetStartContainerResponse(
action.tremplin_start_container_response());
test_stub->SetGetContainerUsernameReturn(
ToStatus(action.tremplin_get_container_username_status()));
test_stub->SetGetContainerUsernameResponse(
action.tremplin_get_container_username_response());
test_stub->SetSetUpUserReturn(ToStatus(action.tremplin_set_up_user_status()));
test_stub->SetSetUpUserResponse(action.tremplin_set_up_user_response());
test_stub->SetGetContainerInfoReturn(
ToStatus(action.tremplin_get_container_info_status()));
test_stub->SetGetContainerInfoResponse(
action.tremplin_get_container_info_response());
test_stub->SetSetTimezoneReturn(
ToStatus(action.tremplin_set_timezone_status()));
test_stub->SetSetTimezoneResponse(action.tremplin_set_timezone_response());
test_stub->SetExportContainerReturn(
ToStatus(action.tremplin_export_container_status()));
test_stub->SetExportContainerResponse(
action.tremplin_export_container_response());
test_stub->SetImportContainerReturn(
ToStatus(action.tremplin_import_container_status()));
test_stub->SetImportContainerResponse(
action.tremplin_import_container_response());
}
} // namespace
DEFINE_PROTO_FUZZER(
const vm_tools::container::ContainerListenerFuzzerInput& input) {
static SetupOnce* setup_once = new SetupOnce;
// Get rid of the unused variable warning.
(void)setup_once;
// We create the ServiceTestingHelper here, not in the static SetupOnce. This
// is to force the threads to finish up before exiting this function --
// destructing Service will force its threads to exit.
ServiceTestingHelper test_framework(ServiceTestingHelper::NICE_MOCKS);
test_framework.SetUpDefaultVmAndContainer();
for (const vm_tools::container::ContainerListenerFuzzerSingleAction& action :
input.action()) {
ContainerListenerImpl* container_listener =
test_framework.get_service().GetContainerListenerImpl();
container_listener->OverridePeerAddressForTesting(action.peer_address());
test_framework.get_service()
.GetTremplinListenerImpl()
->OverridePeerAddressForTesting(action.peer_address());
SetUpMockObjectProxy(
action, &test_framework.get_mock_vm_applications_service_proxy());
SetUpMockObjectProxy(action,
&test_framework.get_mock_url_handler_service_proxy());
SetUpMockObjectProxy(action,
&test_framework.get_mock_crosdns_service_proxy());
SetUpMockObjectProxy(action,
&test_framework.get_mock_concierge_service_proxy());
SetUpTremplinTestStub(action, &test_framework.get_tremplin_test_stub());
grpc::ServerContext context;
vm_tools::EmptyMessage response;
switch (action.input_case()) {
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kContainerStartupInfo:
container_listener->ContainerReady(
&context, &action.container_startup_info(), &response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kContainerShutdownInfo:
container_listener->ContainerShutdown(
&context, &action.container_shutdown_info(), &response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kUpdateApplicationListRequest:
container_listener->UpdateApplicationList(
&context, &action.update_application_list_request(), &response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kOpenUrlRequest:
container_listener->OpenUrl(&context, &action.open_url_request(),
&response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kInstallLinuxPackageProgressInfo:
container_listener->InstallLinuxPackageProgress(
&context, &action.install_linux_package_progress_info(), &response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kUninstallPackageProgressInfo:
container_listener->UninstallPackageProgress(
&context, &action.uninstall_package_progress_info(), &response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kOpenTerminalRequest:
container_listener->OpenTerminal(
&context, &action.open_terminal_request(), &response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
kUpdateMimeTypesRequest:
container_listener->UpdateMimeTypes(
&context, &action.update_mime_types_request(), &response);
break;
case vm_tools::container::ContainerListenerFuzzerSingleAction::
INPUT_NOT_SET:
break;
default:
NOTREACHED();
}
}
}