
Fuzzt CPU-Implementierungen, indem es Testeingaben aus Software-Proxys generiert und sie dann auf realer Hardware ausführt, um Mikroarchitektur-Defekte und Errata zu erkennen.
SiliFuzz ist ein System, das CPU-Defekte durch Fuzzing von Software-Proxys (wie CPU-Simulatoren oder Disassembler) findet und die angesammelten Testeingaben (auch als Corpus bekannt) anschließend in großem Umfang auf echten CPUs ausführt. SiliFuzz befindet sich in der Entwicklung; weitere Details finden Sie im Paper.
Fuzzing ist eine Technik, bei der ein Ziel (eine Anwendung oder eine API) mit einer großen Anzahl spontan erzeugter Testeingaben getestet wird. Ziel ist es, diese Eingaben so interessant und vielfältig wie möglich zu gestalten, um Randfälle auszulösen. Mit anderen Worten: Fuzzing zielt darauf ab, die kombinierte Codeabdeckung zu maximieren. Codeabdeckung kann unterschiedliche Bedeutungen haben, z. B. welche Basisblöcke ausgeführt werden oder welche Pfade im Programm genommen werden.
Im Sinne von SiliFuzz ist ein Proxy jedes Software- oder Hardwaresystem, das sich in Bezug auf bestimmte Aspekte der Ziel-CPU ähnlich verhält, z. B. ein CPU-Emulator oder ein Disassembler. Ein Proxy wird benötigt, wenn wir keine Coverage-Informationen direkt vom Ziel sammeln können.
Durch die Anwendung von Fuzzing-Techniken auf einen Proxy können wir eine Reihe von Testeingaben (Corpus) erzeugen, die im Proxy ein interessantes Verhalten hervorrufen. Unsere zugrunde liegende Annahme ist, dass sich dies in ein ähnlich interessantes Verhalten im Ziel übersetzt. Mehr dazu in der Dokumentation.
Eine Sammlung von Eingaben, die zum Testen des Ziels verwendet wird, wird als Corpus bezeichnet.
Ein einigermaßen großer Corpus enthält Millionen von Eingaben und wird normalerweise in mehrere nicht überlappende Teile, sogenannte Shards, aufgeteilt.
Ein SiliFuzz-Snapshot beschreibt eine kurze Sequenz von CPU-Instruktionen sowie einen Anfangszustand der CPU-Register und des Speichers, um diese Sequenz deterministisch auszuführen. Ein typischer Snapshot enthält weniger als 100 Bytes Code und läuft in Mikrosekunden, kann aber beliebig groß sein. Snapshots werden als Protocol-Buffer silifuzz.proto.Snapshot gespeichert.
Snapshots werden typischerweise aus den Eingaben einer Fuzzing-Engine erstellt. Für CPU-Testzwecke werden diese Eingaben gefiltert, um alle nicht-deterministischen Snapshots zu eliminieren. Mehr dazu in der Dokumentation.
Ein Endzustand beschreibt die Inhalte von Registern und Speicher, die am Ende einer Snapshot-Ausführung erwartet werden. Wenn der Snapshot auf verschiedenen CPU-Mikroarchitekturen unterschiedlich ausgeführt wird, hat er mehrere erwartete Endzustände.
Ein Snap ist eine In-Memory-Darstellung eines Snapshots, die vom Runner einfach geladen und ausgeführt werden kann. Snaps werden normalerweise von einem Reading Runner von der Festplatte geladen. Das On-Disk-Format von Snaps entspricht im Wesentlichen dem In-Memory-Format, außer dass native Zeiger durch Offsets ersetzt werden. Details siehe dieser Header. Dieses Format wird oft als relocatable bezeichnet. Jeder Snap enthält genau einen erwarteten Endzustand, d. h. Snaps sind mikroarchitekturspezifisch. Mehr dazu in der Dokumentation.
Der Runner ist eine Binärdatei zum Testen eines einzelnen CPU-Kerns. Ein Runner verarbeitet einen Corpus-Shard, führt darin wiederholt zufällige Snaps aus und prüft, ob der erwartete Endzustand erreicht wird. Der Runner ist ein Single-Thread-Prozess.
Der Orchestrator ist ein Prozess, der mehrere Runner steuert. In einer typischen Konfiguration führt der Orchestrator kontinuierlich einen Runner pro logischem CPU-Kern aus, sammelt alle von den einzelnen Runner-Prozessen erzeugten Fehler und meldet sie.
Siehe diese Datei für die Liste der unterstützten Mikroarchitekturen.
SiliFuzz läuft auf x86_64- und aarch64-Linux-Systemen. Es wurde mit Linux-Kernelversionen 5.x und 6.x getestet. Es gibt keine Garantie, dass es mit älteren Kernelversionen kompatibel ist. Die Legacy-vsyscall-ABI muss deaktiviert sein, um Fehlalarme zu vermeiden.
Eine nicht abschließende Liste von Bugs und Defekten, die SiliFuzz gefunden hat.
Ein Logik-Bug ist ein ungültiges CPU-Verhalten, das einer bestimmten CPU-Mikroarchitektur oder einem bestimmten Stepping innewohnt. SiliFuzz hat die folgenden Bugs identifiziert:
Ein (elektrischer) Defekt ist ein ungültiges CPU-Verhalten, das nur auf einem oder mehreren Chips auftritt. SiliFuzz hat die folgenden Defekte gefunden, die wir im Paper beschrieben haben:
git clone https://github.com/google/silifuzz.git && cd silifuzz
SILIFUZZ_SRC_DIR=`pwd`
./install_build_dependencies.sh # Currently, works for the latest Ubuntu only.
bazel build -c opt @silifuzz//tools:{snap_corpus_tool,fuzz_filter_tool,snap_tool,silifuzz_platform_id,simple_fix_tool_main} \
@silifuzz//runner:reading_runner_main_nolibc \
@silifuzz//orchestrator:silifuzz_orchestrator_main
SILIFUZZ_BIN_DIR=`pwd`/bazel-bin
cd "${SILIFUZZ_BIN_DIR}"
HINWEIS: Sie können einen Docker-Container verwenden, um das Hostsystem nicht zu verschmutzen: docker run -it --tty --security-opt seccomp=unconfined --mount type=bind,source=${SILIFUZZ_SRC_DIR},target=/app ubuntu:noble /bin/bash -c "cd /app && ./install_build_dependencies.sh && bazel build ... && bazel test ..."
Für Bazel verwenden Sie die folgenden Befehle.
cd "${SILIFUZZ_SRC_DIR}"
COV_FLAGS_FILE="$(bazel info output_base)/external/fuzztest+/centipede/clang-flags.txt"
bazel build -c opt --copt=-UNDEBUG --dynamic_mode=off \
--per_file_copt=unicorn/.*@$(xargs < "${COV_FLAGS_FILE}" |sed -e 's/,/\\,/g' -e 's/ /,/g') @//proxies:unicorn_x86_64
bazel build -c opt @fuzztest//centipede:centipede
mkdir -p /tmp/wd
# Fuzz the Unicorn proxy under Centipede 1000 times with parallelism of 30.
"${SILIFUZZ_BIN_DIR}/external/fuzztest+/centipede/centipede" \
--binary="${SILIFUZZ_BIN_DIR}/proxies/unicorn_x86_64" \
--workdir=/tmp/wd \
-j=30 --num_runs=1000