Skip to content

Commit

Permalink
Internal change
Browse files Browse the repository at this point in the history
PiperOrigin-RevId: 472813152
  • Loading branch information
SiliFuzz Team authored and Konstantin Shtoyk committed Sep 7, 2022
1 parent 83e4814 commit 6b59065
Show file tree
Hide file tree
Showing 7 changed files with 434 additions and 8 deletions.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -137,14 +137,29 @@ An (electrical) defect is an invalid CPU behavior that happens only on one or se

```shell
git checkout https://github.com/google/silifuzz.git && cd silifuzz
SILIFUZZ_SRC_DIR=`pwd`
./install_build_dependencies.sh # Currently, works for the latest Debian and Ubuntu only
bazel build @silifuzz//tools:{snap_corpus_tool,fuzz_filter_tool,snap_tool,silifuzz_platform_id} @silifuzz//runner:reading_runner_main_nolibc @silifuzz//orchestrator:silifuzz_orchestrator_main
SILIFUZZ_BIN_DIR=`pwd`/bazel-bin/
cd "${SILIFUZZ_BIN_DIR}"
```

### Prework (fetching and fuzzing Unicorn target)
### Prework (fuzzing Unicorn target)

```shell
cd "${SILIFUZZ_SRC_DIR}"
bazel build -c opt @silifuzz//proxies:unicorn_x86_64_sancov
bazel build -c opt @centipede//:centipede
mkdir -p /tmp/wd

# Fuzz unicorn proxies under centipede with parallelism of 30.
"${SILIFUZZ_BIN_DIR}/external/centipede/centipede" \
--binary "${SILIFUZZ_BIN_DIR}/proxies/unicorn_x86_64_sancov" \
--workdir /tmp/wd
-j 30
```

### Prework (collect corpus from fuzzing result)
TODO: Coming soon

## Tools
Expand Down
14 changes: 7 additions & 7 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ lss_ver = "32a80cda3c885e0db9bcd4c67d1c4b479057d943"

new_git_repository(
name = "lss",
build_file = "@//:third_party/BUILD.lss",
build_file = "@silifuzz//:third_party/BUILD.lss",
commit = lss_ver,
remote = "https://chromium.googlesource.com/linux-syscall-support",
shallow_since = "1657142711 +0000",
)

new_git_repository(
name = "cityhash",
build_file = "@//:third_party/BUILD.cityhash",
build_file = "@silifuzz//:third_party/BUILD.cityhash",
commit = "8af9b8c2b889d80c22d6bc26ba0df1afb79a30db",
patch_cmds = [
# Running "configure" creates the config.h file needed for this library.
Expand All @@ -112,7 +112,7 @@ new_git_repository(

new_git_repository(
name = "mbuild",
build_file = "@//:third_party/BUILD.mbuild",
build_file = "@silifuzz//:third_party/BUILD.mbuild",
commit = "1cb4f44e9b249626392a275e6f59c00ea16a47ed",
patch_cmds = [
"rm -f setup.py",
Expand All @@ -124,7 +124,7 @@ new_git_repository(

new_git_repository(
name = "libxed",
build_file = "@//:third_party/BUILD.libxed",
build_file = "@silifuzz//:third_party/BUILD.libxed",
commit = "801b876fe6a6d321b1f4027b6bb4adaee7ecd0a7",
patch_cmds = [
"sed -i -e 's|xed/xed-interface.h|xed-interface.h|' examples/xed-tester.c",
Expand All @@ -141,7 +141,7 @@ git_repository(

http_archive(
name = "liblzma",
build_file = "//:third_party/BUILD.liblzma",
build_file = "@silifuzz//:third_party/BUILD.liblzma",
sha256 = "f6f4910fd033078738bd82bfba4f49219d03b17eb0794eb91efbae419f4aba10",
strip_prefix = "xz-5.2.5",
urls = [
Expand All @@ -161,11 +161,11 @@ http_archive(
# Unicorn for the proxies
new_git_repository(
name = "unicorn",
build_file = "@//:third_party/BUILD.unicorn",
build_file = "@silifuzz//:third_party/BUILD.unicorn",
commit = "63a445cbba18bf1313ac3699b5d25462b5d529f4",
remote = "https://github.com/unicorn-engine/unicorn",
patch_cmds = [
"sed -i -e 's|ARM64_REGS_STORAGE_SIZE|DEFAULT_VISIBILITY ARM64_REGS_STORAGE_SIZE|' qemu/target-arm/unicorn.h",
],
remote = "https://github.com/unicorn-engine/unicorn",
shallow_since = "1639356032 +0800",
)
49 changes: 49 additions & 0 deletions proxies/BUILD
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Copyright 2022 The SiliFuzz Authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

load("@centipede//testing:build_defs.bzl", "centipede_fuzz_target")

licenses(["notice"])

package(default_visibility = ["//visibility:public"])

cc_library(
name = "unicorn_aarch64_lib",
testonly = True,
srcs = ["unicorn_aarch64.cc"],
deps = ["@unicorn//:unicorn_arm64"],
alwayslink = True,
)

cc_test(
name = "unicorn_aarch64_test",
size = "medium",
srcs = ["unicorn_aarch64_test.cc"],
deps = [
":unicorn_aarch64_lib",
"@com_google_googletest//:gtest_main",
],
)

centipede_fuzz_target(
name = "unicorn_aarch64_sancov",
srcs = ["unicorn_aarch64.cc"],
deps = ["@unicorn//:unicorn_arm64"],
)

centipede_fuzz_target(
name = "unicorn_x86_64_sancov",
srcs = ["unicorn_x86_64_example.cc"],
deps = ["@unicorn//:unicorn_x86"],
)
155 changes: 155 additions & 0 deletions proxies/unicorn_aarch64.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
// Copyright 2022 The SiliFuzz Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <cinttypes>
#include <cstdarg>
#include <cstdint>
#include <cstdio>
#include <cstdlib>

#include "third_party/unicorn/arm64.h"
#include "third_party/unicorn/unicorn.h"

namespace {

constexpr uint64_t kCodeAddr = 0x1000000;
constexpr uint64_t kCodeSize = 0x1000;

constexpr uint64_t kStackAddr = 0x2000000;
constexpr uint64_t kStackSize = 0x1000;

constexpr uint64_t kMem1Addr = 0x7000000;
constexpr uint64_t kMem1Size = 4 * 1024 * 1024;

constexpr uint64_t kMem2Addr = 0x10007000000;
constexpr uint64_t kMem2Size = 4 * 1024 * 1024;

#define LOG_ERROR(...) fprintf(stderr, __VA_ARGS__)

#define LOG_FATAL(...) \
do { \
fprintf(stderr, __VA_ARGS__); \
abort(); \
} while (0)

#define UNICORN_CHECK(...) \
do { \
uc_err __uc_check_err = __VA_ARGS__; \
if ((__uc_check_err != UC_ERR_OK)) { \
LOG_FATAL(#__VA_ARGS__ " failed %u: %s\n", __uc_check_err, \
uc_strerror(__uc_check_err)); \
} \
} while (0);

void map_memory(uc_engine *uc, uint64_t addr, uint64_t size, uint32_t prot) {
uc_err err = uc_mem_map(uc, addr, size, prot);
if (err != UC_ERR_OK) {
LOG_FATAL("mapping %" PRIx64 " failed with %u: %s\n", addr, err,
uc_strerror(err));
}
}

void set_reg(uc_engine *uc, uc_arm64_reg reg, uint64_t value) {
uc_err err = uc_reg_write(uc, reg, &value);
if (err != UC_ERR_OK) {
LOG_FATAL("trying to set %u to %" PRIx64 " failed with %u: %s\n", reg,
value, err, uc_strerror(err));
}
}

} // namespace

extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
// Require at least one instruction.
if (size < 4) {
return -1;
}

// Require complete instructions.
// This makes disassembling the corpus easier.
if (size % 4 != 0) {
return -1;
}

// Reject huge examples, for now.
if (size > kCodeSize) {
return -1;
}

// Initialize emulator.
uc_engine *uc;
UNICORN_CHECK(uc_open(UC_ARCH_ARM64, UC_MODE_ARM, &uc));

// Details to sort out later:
// TODO(ncbray) derive base address for code and validate lack of conflicts
// TODO(ncbray) verify we're running at EL1 and drop to EL0?
// TODO(ncbray) verify that the space around the code is initialized to zero.
// TODO(ncbray) what are the instructions that execute but can't disassemble?
// TODO(ncbray) why are system register load/stores _not_ generated?
// TODO(ncbray) why do PC-relative loads work w/ execute-only memory?
// 100001c: 980019c8 ldrsw x8, 0x1000354
// TODO(ncbray) why do atomic ops using the initial stack pointer not fault?
// 1000000: 787f63fc ldumaxlh wzr, w28, [sp]

// Map code execute-only to discourage depending on any widget that may exist
// before or after the code.
map_memory(uc, kCodeAddr, kCodeSize, UC_PROT_EXEC);

// Write the instructions to memory.
uc_mem_write(uc, kCodeAddr, data, size);

// Allocate stack.
map_memory(uc, kStackAddr, kStackSize, UC_PROT_READ | UC_PROT_WRITE);

// Stack grows towards zero, start at the largest address.
// Note this address is unmapped.
set_reg(uc, UC_ARM64_REG_SP, kStackAddr + kStackSize);

// Setup memory regions.
// HACK put the region addresses in an arbitrary register to make them
// discoverable. In the future we should seed the dictionary with instructions
// that materialize this constant instead.
map_memory(uc, kMem1Addr, kMem1Size, UC_PROT_READ | UC_PROT_WRITE);
set_reg(uc, UC_ARM64_REG_X6, kMem1Addr);
map_memory(uc, kMem2Addr, kMem2Size, UC_PROT_READ | UC_PROT_WRITE);
set_reg(uc, UC_ARM64_REG_X7, kMem2Addr);

// Execute the instructions.
// Stop at an arbitrary instruction count to avoid infinite loops.
bool input_is_acceptable = true;
uint64_t end_of_code = kCodeAddr + size;
size_t max_inst_executed = 0x1000;
uc_err err = uc_emu_start(uc, kCodeAddr, end_of_code, 0, max_inst_executed);

// Check if the emulator stopped cleanly.
if (err) {
LOG_ERROR("uc_emu_start() returned %u: %s\n", err, uc_strerror(err));
input_is_acceptable = false;
}

// Check if the emulator stopped at the right address.
// Unicorn does not return an error if it stops executing because it reached
// the maximum instruction count.
uint64_t pc = 0;
UNICORN_CHECK(uc_reg_read(uc, UC_ARM64_REG_PC, &pc));
if (pc != end_of_code) {
LOG_ERROR("expected PC would be %" PRIu64 ", but got %" PRIu64 " instead\n",
end_of_code, pc);
input_is_acceptable = false;
}

uc_close(uc);

return input_is_acceptable ? 0 : -1;
}
Loading

0 comments on commit 6b59065

Please sign in to comment.