
सॉफ़्टवेयर प्रॉक्सी से परीक्षण इनपुट उत्पन्न करके CPU कार्यान्वयनों की फ़ज़िंग करता है, फिर माइक्रोआर्किटेक्चर दोषों और एराटा का पता लगाने के लिए उन्हें वास्तविक हार्डवेयर पर निष्पादित करता है।
SiliFuzz एक ऐसी प्रणाली है जो सॉफ़्टवेयर प्रॉक्सी, जैसे CPU सिम्युलेटर या डिसअसेंबलर, को फ़ज़िंग करके CPU दोषों का पता लगाती है, और फिर संचित परीक्षण इनपुट्स (जिन्हें कॉर्पस कहा जाता है) को वास्तविक CPU पर बड़े पैमाने पर निष्पादित करती है। SiliFuzz एक निरंतर विकासशील कार्य है, विवरण के लिए कृपया पेपर देखें।
फ़ज़िंग, लक्ष्य (एक एप्लिकेशन या API) को मौके पर उत्पन्न बड़ी संख्या में परीक्षण इनपुट्स के साथ परखने की तकनीक है। इन इनपुट्स को यथासंभव रोचक और विविध बनाना लक्ष्य होता है ताकि किनारे के मामलों (corner cases) को ट्रिगर किया जा सके। दूसरे शब्दों में, फ़ज़िंग का उद्देश्य संयुक्त कोड कवरेज को अधिकतम करना है। कोड कवरेज के अलग-अलग अर्थ हो सकते हैं, जैसे कौन से बेसिक ब्लॉक निष्पादित होते हैं या प्रोग्राम में कौन से पथ लिए जाते हैं।
SiliFuzz के प्रयोजनों के लिए, प्रॉक्सी कोई भी सॉफ़्टवेयर या हार्डवेयर प्रणाली है जो लक्ष्य CPU के कुछ पहलुओं के समान व्यवहार करती है। उदाहरण के लिए, CPU एमुलेटर या डिसअसेंबलर। जब हम लक्ष्य से सीधे कवरेज जानकारी एकत्र नहीं कर सकते तब प्रॉक्सी की आवश्यकता होती है।
प्रॉक्सी पर फ़ज़िंग तकनीकों को लागू करके, हम परीक्षण इनपुट्स (कॉर्पस) की एक श्रृंखला उत्पन्न कर सकते हैं जो प्रॉक्सी में रोचक व्यवहार उत्पन्न करते हैं। हमारी अंतर्निहित धारणा यह है कि यह लक्ष्य में समान रूप से रोचक व्यवहार में परिवर्तित होता है। दस्तावेज़ में और पढ़ें।
लक्ष्य के परीक्षण के लिए उपयोग किए जाने वाले इनपुट्स का संग्रह कॉर्पस कहलाता है।
एक उचित रूप से बड़े कॉर्पस में लाखों इनपुट होते हैं और इसे आमतौर पर कई गैर-अतिव्यापी हिस्सों में विभाजित किया जाता है जिन्हें शार्ड्स कहा जाता है।
SiliFuzz स्नैपशॉट, CPU निर्देशों के एक छोटे अनुक्रम के साथ-साथ CPU रजिस्टरों और मेमोरी की प्रारंभिक स्थिति का वर्णन करता है ताकि उस अनुक्रम को नियतात्मक रूप से निष्पादित किया जा सके। एक सामान्य स्नैपशॉट में 100 बाइट्स से कम कोड होता है और यह माइक्रोसेकंड में चलता है, लेकिन यह मनमाने ढंग से बड़ा हो सकता है। स्नैपशॉट्स को silifuzz.proto.Snapshot प्रोटोकॉल बफ़र्स के रूप में संग्रहीत किया जाता है।
स्नैपशॉट्स आमतौर पर फ़ज़िंग इंजन द्वारा उत्पन्न इनपुट्स से बनाए जाते हैं। CPU परीक्षण के प्रयोजनों के लिए इन इनपुट्स को फ़िल्टर किया जाता है ताकि सभी गैर-नियतात्मक स्नैपशॉट्स को हटाया जा सके। दस्तावेज़ में और पढ़ें।
अंतिम स्थिति, स्नैपशॉट निष्पादन के अंत में मौजूद होने की अपेक्षित रजिस्टरों और मेमोरी की सामग्री का वर्णन करती है। यदि स्नैपशॉट विभिन्न CPU माइक्रोआर्किटेक्चर पर अलग-अलग निष्पादित होता है तो उसकी कई अपेक्षित अंतिम स्थितियाँ होंगी।
स्नैप (Snap), स्नैपशॉट का एक इन-मेमोरी प्रतिनिधित्व है जिसे रनर द्वारा आसानी से लोड और निष्पादित किया जा सकता है। स्नैप्स आमतौर पर रीडिंग रनर द्वारा डिस्क से लोड किए जाते हैं। स्नैप का डिस्क-प्रारूप अनिवार्य रूप से इन-मेमोरी प्रारूप के समान होता है, सिवाय इसके कि नेटिव पॉइंटर्स को ऑफ़सेट से बदल दिया जाता है। विवरण के लिए यह हेडर देखें। इस प्रारूप को अक्सर रिलोकेटेबल कहा जाता है। प्रत्येक स्नैप में ठीक एक अपेक्षित अंतिम स्थिति होती है, अर्थात स्नैप्स माइक्रोआर्किटेक्चर-विशिष्ट होते हैं। दस्तावेज़ में और पढ़ें।
रनर एकल CPU कोर के परीक्षण के लिए एक बाइनरी है। एक रनर कॉर्पस शार्ड का उपभोग करता है, उसमें यादृच्छिक स्नैप्स को बार-बार निष्पादित करता है और जाँचता है कि अपेक्षित अंतिम स्थिति प्राप्त हुई है या नहीं। रनर एक एकल-थ्रेडेड प्रक्रिया है।
ऑर्केस्ट्रेटर एक ऐसी प्रक्रिया है जो कई रनरों को संचालित करती है। सामान्य परिस्थिति में ऑर्केस्ट्रेटर प्रति लॉजिकल CPU कोर एक रनर को लगातार निष्पादित करेगा, और व्यक्तिगत रनर प्रक्रियाओं द्वारा उत्पन्न किसी भी विफलता को एकत्र कर रिपोर्ट करेगा।
समर्थित माइक्रोआर्किटेक्चर की सूची के लिए यह फ़ाइल देखें।
SiliFuzz x86_64 और aarch64 Linux प्रणालियों पर चलता है। इसका परीक्षण Linux कर्नेल संस्करण 5.x और 6.x के साथ किया गया है। इसकी कोई गारंटी नहीं है कि यह पुराने कर्नेल संस्करणों के साथ संगत है। झूठे सकारात्मक परिणामों से बचने के लिए लिगेसी vsyscall ABI को बंद किया जाना चाहिए।
SiliFuzz द्वारा खोजे गए बग्स और दोषों की एक असंपूर्ण सूची।
लॉजिक बग एक विशेष CPU माइक्रोआर्किटेक्चर या स्टेपिंग में निहित अमान्य CPU व्यवहार है। SiliFuzz ने निम्नलिखित बग्स की पहचान की है:
एक (विद्युतीय) दोष एक अमान्य CPU व्यवहार है जो केवल एक या कई चिप्स पर होता है। SiliFuzz ने निम्नलिखित दोष पाए हैं जिन्हें हमने पेपर में वर्णित किया है:
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}"
NOTE: आप होस्ट सिस्टम को प्रदूषित करने से बचने के लिए Docker कंटेनर का उपयोग कर सकते हैं: 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 ..."
Bazel के लिए, निम्नलिखित कमांड का उपयोग करें।
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
NOTE: कृपया फ़ज़िंग इंजन को कुशलतापूर्वक चलाने के तरीके के लिए Centipede दस्तावेज़ देखें।
यह सहायक उपकरण यह जाँचने के लिए है कि आप जिस मशीन पर चल रहे हैं वह समर्थित है या नहीं।
$ ${SILIFUZZ_BIN_DIR}/tools/silifuzz_platform_id --short
intel-skylake
NOTE: SiliFuzz CPU पहचान तर्क अन्यथा समर्थित CPU के कुछ डेस्कटॉप वेरिएंट को ध्यान में नहीं रखता है। ऐसे मामलों में उपकरण "Unsupported platform" की रिपोर्ट करेगा।
fuzz_filter_tool कच्चे निर्देशों को Snap-संगत स्नैपशॉट्स में परिवर्तित करता है। जब रूपांतरण संभव होता है तो यह 0 लौटाता है और अन्यथा 1। यह इंटरफ़ेस Centipede input_filter के साथ संगत है।
fuzz_filter_tool raw_input_sequence
raw_input_sequence फ़ाइल में कच्चे निर्देश होते हैं जिन्हें InstructionsToSnapshot का उपयोग करके स्नैपशॉट प्रारूप में परिवर्तित किया जाएगा।
नमूना उपयोग:
# INC EAX
echo -en '\xFF\xC0' > /tmp/inc_eax && ./tools/fuzz_filter_tool /tmp/inc_eax
echo $?
0
snap_tool बाइनरी स्नैपशॉट प्रोटो का निरीक्षण और हेरफेर करता है। यह वैकल्पिक रूप से कच्चे निर्देशों को लोड कर उन्हें स्नैपशॉट में परिवर्तित कर सकता है।
echo -en '\xFF\xC0' > /tmp/inc_eax
./tools/snap_tool --raw print /tmp/inc_eax
Metadata:
Id: inc_eax
Architecture: x86_64 Linux
Completeness: complete
Registers:
gregs (non-0 only)
rax = 0x20000000
....
सिंपल फिक्स टूल Centipede से फ़ज़िंग परिणाम लेता है, कच्चे निर्देशों को बिना अंतिम स्थिति वाले स्नैपशॉट्स में परिवर्तित करता है, स्नैपशॉट्स में अंतिम स्थितियाँ जोड़ता है और अंत में स्नैपशॉट्स को शार्डेड रिलोकेटेबल स्नैप कॉर्पस में पैकेज करता है।
वर्तमान में यह एकल होस्ट पर गैर-पुनरारंभ योग्य प्रक्रिया के रूप में चलता है और सब कुछ मेमोरी में डाल दिया जाता है, इसलिए संभाले जा सकने वाले कॉर्पस का आकार होस्ट की उपलब्ध मेमोरी द्वारा सीमित होता है। चूँकि अंतिम स्थितियाँ होस्ट पर उत्पन्न होती हैं, परिणामी कॉर्पस एकल आर्किटेक्चर वाला होता है।
प्रायोगिक: हैश टेस्ट यादृच्छिक संरचित परीक्षण हैं जो यादृच्छिक रूप से उत्पन्न निर्देशों में एन्ट्रॉपी डालते हैं और परिणामी आउटपुट को यथासंभव कुशलता से कैप्चर करते हैं। यह दृष्टिकोण इस अवलोकन पर आधारित है कि सही निर्देश को सही इनपुट के साथ बुलाकर दोषों का एक गैर-मामूली प्रतिशत पता लगाया जा सकता है। हैश टेस्ट Silifuzz के लिए तुलना का एक प्रायोगिक बिंदु प्रदान करने हेतु इस सरल श्रेणी के दोषों को आक्रामक रूप से लक्षित करते हैं। वर्तमान में केवल x86_64 समर्थित है।
यदि आप, उदाहरण के लिए, /tmp/hashtest निर्देशिका में Skylake प्रोसेसर द्वारा समर्थित निर्देशों वाले 30k हैश टेस्ट स्नैपशॉट उत्पन्न करना चाहते हैं, तो आप यह कमांड चला सकते हैं।
mkdir -p /tmp/hashtest && bazel run -c opt @silifuzz//fuzzer/hashtest:hashtest_generator -- --platform=intel-skylake -n 30000 --outdir /tmp/hashtest
शेष दस्तावेज़ How-to (कैसे करें) शैली में व्यवस्थित है, जिसमें प्रत्येक प्रश्न एक सामान्य उपयोग-मामले का वर्णन करता है। प्रश्नों की प्रगति उस कार्य की बढ़ती जटिलता को दर्शाती है जिसे कोई पूरा करने का प्रयास कर रहा है। प्रत्येक चरण के लिए आमतौर पर पिछले चरण में प्राप्त समझ या आर्टिफैक्ट्स (कभी-कभी दोनों) की आवश्यकता होती है।
NOTE: दस्तावेज़ x86_64 होस्ट/लक्ष्य CPU मानता है। CPU विक्रेता/स्टेपिंग/आदि और पर्यावरण (जैसे Docker/KVM) के आधार पर सटीक आउटपुट भिन्न हो सकता है।
चेतावनी: नीचे दिए गए कई निर्देश चल रहे उपयोगकर्ता के विशेषाधिकारों के साथ मनमाना बाइनरी कोड निष्पादित करते हैं। उपकरण seccomp(2) के साथ कोड को सैंडबॉक्स करने की पूरी कोशिश करता है। अपने जोखिम पर उपयोग करें।
# INC EAX
$ echo -en '\xFF\xC0' > /tmp/inc_eax
$ ./tools/snap_tool --raw --out=/tmp/inc_eax.pb make /tmp/inc_eax
# CPUID
$ echo -en '\x0F\xA2' > /tmp/cpuid
$ ./tools/snap_tool --raw --out=/tmp/cpuid.pb make /tmp/cpuid
<error log omitted>
Could not load snapshot: INTERNAL: Tracing failed: Banned instruction: CPUID
NOTE: गैर-नियतात्मक परिणामों से बचने के लिए, SiliFuzz के विभिन्न भाग निर्देशों की कुछ श्रेणियों को बाहर करते हैं, जैसे ऊपर दिया गया CPUID।
$ ./tools/snap_tool print /tmp/inc_eax.pb
Metadata:
Id: inc_eax
Architecture: x86_64 Linux
Completeness: complete
Registers:
gregs (non-0 only):
rax = 0x20000000
rip = 0xeb85c12b000
<omitted>
End states (1):
Endpoint:
Instruction address: 0xeb85c12b002
Platforms:
intel-skylake
Registers (diff vs snapshot's initial values):
gregs (modified only):
rax = 0x20000001
rip = 0xeb85c12b002
<omitted>
ध्यान दें कि RAX रजिस्टर का अंतिम स्थिति मान 0x20000001 है (0x20000000+1 जो वास्तव में INC EAX करता है)। यह भी ध्यान दें कि RIP मान मूल +2 है जो INC EAX निर्देश का आकार है।
$ ./tools/snap_tool play /tmp/inc_eax.pb
Snapshot played successfully.
नोट: कॉर्पस उत्पन्न करने के लिए आपको लक्ष्य प्लेटफ़ॉर्म निर्दिष्ट करना होगा। इस उदाहरण में, परिणामी कॉर्पस उसी प्लेटफ़ॉर्म को लक्षित करता है जिस पर इसे उत्पन्न किया गया था।
$ cd "${SILIFUZZ_BIN_DIR}"
$ PLATFORM_ID=$(./tools/silifuzz_platform_id --short)
$ ./tools/snap_tool generate_corpus /tmp/inc_eax.pb \
--target_platform="${PLATFORM_ID}" > /tmp/inc_eax.corpus
# Will play the same "INC EAX" snapshot 1M times
$ ./runner/reading_runner_main_nolibc /tmp/inc_eax.corpus
आप gdb के साथ प्रक्रिया का निरीक्षण कर सकते हैं:
$ gdb ./runner/reading_runner_main_nolibc
(gdb) b RestoreUContextNoSyscalls
(gdb) run /tmp/inc_eax.corpus
Starting program: .../reading_runner_main_nolibc /tmp/inc_eax.corpus
Breakpoint 1, 0x0000456700010598 in RestoreUContextNoSyscalls ()
(gdb) x/i 0xeb85c12b000 # same as the rip value produced by snap_tool print above
0xeb85c12b000: inc %eax
NOTE: यह चरण पहले वर्णित "Unicorn लक्ष्य को फ़ज़ करना" चरण पर निर्भर करता है।
वर्तमान आर्किटेक्चर के लिए फ़ज़िंग परिणाम corpus.* को 10-शार्ड वाले रनेबल कॉर्पस में बदलें।
cd "${SILIFUZZ_BIN_DIR}"
"${SILIFUZZ_BIN_DIR}/tools/simple_fix_tool_main" \
--num_output_shards=10 \
--output_path_prefix=/tmp/wd/runnable-corpus \
--runner="${SILIFUZZ_BIN_DIR}/runner/reading_runner_main_nolibc" \
/tmp/wd/corpus.*
कॉर्पस शार्ड्स /tmp/wd/runnable-corpus.* पर होंगे।
$ ./tools/snap_corpus_tool list_snaps /tmp/inc_eax.corpus
...
I0000 00:00:1661887744.019079 4074672 snap_corpus_tool.cc:155] inc_eax
NOTE: यह फ़िलहाल एक बहुत ही बुनियादी उपकरण है जो केवल कुछ कमांड प्रदान करता है।
# Will play the same "INC EAX" snapshot on CPU#1 10k times.
$ ./runner/reading_runner_main_nolibc \
--cpu=1 --num_iterations=10000 /tmp/inc_eax.corpus
ऑर्केस्ट्रेटर --shard_list_file तर्क में पारित फ़ाइल में सूचीबद्ध सभी शार्ड्स के माध्यम से चक्र (cycle) करेगा।
$ ls -1 /tmp/wd/runnable-corpus.* > /tmp/wd/shard_list
$ echo 'version: "local_corpus"' > /tmp/wd/corpus_metadata
# Will repeatedly run the corpus on all available CPU cores for 30s using
# /tmp/wd/runnable-corpus.* selected randomly.
$ ${SILIFUZZ_BIN_DIR}/orchestrator/silifuzz_orchestrator_main --duration=30s \
--runner=${SILIFUZZ_BIN_DIR}/runner/reading_runner_main_nolibc \
--shard_list_file=/tmp/wd/shard_list \
--corpus_metadata_file=/tmp/wd/corpus_metadata
NOTE: ऑर्केस्ट्रेटर .xz पर समाप्त होने वाली फ़ाइलों से XZ-संपीड़ित कॉर्पस शार्ड्स भी लोड कर सकता है।