blob: 7f97fe33f4a372ed62e5e48a04e5e99490fd9222 [file] [log] [blame]
// Copyright 2021 The Fuchsia 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 "src/sys/fuzzing/realmfuzzer/target/module.h"
#include <random>
#include <gtest/gtest.h>
#include "src/sys/fuzzing/realmfuzzer/testing/module.h"
namespace fuzzing {
namespace {
// Unit tests.
TEST(ModuleTest, Identifier) {
// Prepare a fixed module.
std::vector<ModulePC> pc_table1;
for (size_t i = 0; i < FakeRealmFuzzerModule::kNumPCs; ++i) {
pc_table1.emplace_back(0x1000 + i * 0x10, (i % 8) == 0);
}
FakeRealmFuzzerModule module1(std::move(pc_table1));
// The fnv1a hash of `pc_table1` is 0x878da8387ebd1694.
// The djb2a hash of `pc_table1` is 0xdbb7e009aa4e7634.
// The base-64 value can be obtained using:
// `echo 878da8387ebd1694dbb7e009aa4e7634 | xxd -r -p | xxd -e -g8 | xxd -r | base64`
std::string expected = "lBa9fjiojYc0dk6qCeC32w==";
EXPECT_EQ(module1.id(), expected);
// Shifting all the PCs by a random basis does not affect the source ID, i.e., the ID is
// independent of where it is mapped in memory.
std::vector<ModulePC> pc_table2;
for (size_t i = 0; i < FakeRealmFuzzerModule::kNumPCs; ++i) {
pc_table2.emplace_back(0xdeadbeef + i * 0x10, (i % 8) == 0);
}
FakeRealmFuzzerModule module2(std::move(pc_table2));
EXPECT_EQ(module1.id(), module2.id());
// Changing the counters has no effect on identifiers.
memset(module1.counters(), 1, module1.num_pcs());
EXPECT_EQ(module1.id(), expected);
// Check for collisions. This isn't exhaustive; it is simply a smoke test to check if things are
// very broken.
for (uint32_t i = 0; i < 100; ++i) {
FakeRealmFuzzerModule moduleN(/* seed */ i);
EXPECT_NE(moduleN.id(), expected);
}
// Check the identifier gets written to the VMO.
zx::vmo vmo;
EXPECT_EQ(module1.Share(&vmo), ZX_OK);
char name[ZX_MAX_NAME_LEN];
memset(name, 0, sizeof(name));
EXPECT_EQ(vmo.get_property(ZX_PROP_NAME, name, sizeof(name)), ZX_OK);
EXPECT_EQ(std::string(name), expected);
}
TEST(ModuleTest, UpdateAndClear) {
FakeRealmFuzzerModule module;
std::minstd_rand prng(1);
// Initial contents are shared.
for (size_t i = 0; i < module.num_pcs(); ++i) {
module[i] = static_cast<uint8_t>(prng());
}
std::vector<uint8_t> expected(module.counters(), module.counters_end());
zx::vmo vmo;
EXPECT_EQ(module.Share(&vmo), ZX_OK);
SharedMemory shmem;
EXPECT_EQ(shmem.Link(std::move(vmo)), ZX_OK);
auto* data = shmem.data();
module.Update();
std::vector<uint8_t> actual(data, data + module.num_pcs());
EXPECT_EQ(actual, expected);
// Changes to counters are not reflected until an |Update|.
for (size_t i = 0; i < module.num_pcs(); ++i) {
module[i] = static_cast<uint8_t>(prng());
}
actual = std::vector<uint8_t>(data, data + module.num_pcs());
EXPECT_EQ(actual, expected);
module.Update();
expected = std::vector<uint8_t>(module.counters(), module.counters_end());
actual = std::vector<uint8_t>(data, data + module.num_pcs());
EXPECT_EQ(actual, expected);
// Clearing resets counters to zero (but does not |Update|, for performance reasons).
module.Clear();
actual = std::vector<uint8_t>(data, data + module.num_pcs());
EXPECT_EQ(actual, expected);
expected = std::vector<uint8_t>(module.num_pcs(), 0);
actual = std::vector<uint8_t>(module.counters(), module.counters_end());
EXPECT_EQ(actual, expected);
}
} // namespace
} // namespace fuzzing