├── .github └── workflows │ └── rust-clippy.yml ├── .gitignore ├── .gitmodules ├── .reuse └── dep5 ├── Cargo.toml ├── LICENSES ├── Apache-2.0.txt └── CC0-1.0.txt ├── README.md ├── dependabot.yml ├── doc ├── libverdi.md ├── mutation.jpg ├── opentitan.md └── overview.jpg ├── fuzzers ├── chipyard-vcs-fuzzer │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── chipyard_cov.patch │ ├── config.yml │ ├── plot.py │ ├── seeds │ │ └── seed.bin │ └── src │ │ ├── main.rs │ │ ├── simv.rs │ │ ├── testcase.S │ │ ├── testcase.ld │ │ └── trace_observer.rs ├── cva6-vcs-fuzzer │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── config.yml │ ├── cva6.patch │ ├── meta │ │ ├── testcase.S │ │ └── testcase.ld │ ├── plot.py │ ├── readme.md │ ├── run.sh │ ├── seeds │ │ └── seed.bin │ └── src │ │ ├── differential.rs │ │ ├── differential_feedback.rs │ │ ├── main.rs │ │ └── simv.rs ├── opentitan-fuzzer-vcs │ ├── Cargo.toml │ ├── Dockerfile │ ├── init.sh │ ├── run.sh │ ├── seeds │ │ ├── auto_cbc_128bit_decrypt_1block.hwf │ │ ├── auto_cbc_128bit_decrypt_2blocks.hwf │ │ ├── auto_cbc_128bit_encrypt_1block.hwf │ │ ├── auto_cbc_128bit_encrypt_2blocks.hwf │ │ ├── auto_ctr_128bit_decrypt_1block.hwf │ │ ├── auto_ctr_128bit_decrypt_2blocks.hwf │ │ ├── auto_ctr_128bit_encrypt_1block.hwf │ │ ├── auto_ctr_128bit_encrypt_2blocks.hwf │ │ ├── auto_ecb_128bit_decrypt_1block.hwf │ │ ├── auto_ecb_128bit_decrypt_2blocks.hwf │ │ ├── auto_ecb_128bit_encrypt_1block.hwf │ │ └── auto_ecb_128bit_encrypt_2blocks.hwf │ ├── src │ │ └── main.rs │ └── tb │ │ ├── tb_aes.sv │ │ ├── tb_hmac.sv │ │ ├── tb_kmac.sv │ │ └── tb_rv_timer.sv ├── opentitan-fuzzer-verilator-hw-cov │ ├── Cargo.toml │ ├── README.md │ ├── diff.patch │ ├── run.sh │ ├── seeds │ │ ├── auto_cbc_128bit_decrypt_1block.hwf │ │ ├── auto_cbc_128bit_decrypt_2blocks.hwf │ │ ├── auto_cbc_128bit_encrypt_1block.hwf │ │ ├── auto_cbc_128bit_encrypt_2blocks.hwf │ │ ├── auto_ctr_128bit_decrypt_1block.hwf │ │ ├── auto_ctr_128bit_decrypt_2blocks.hwf │ │ ├── auto_ctr_128bit_encrypt_1block.hwf │ │ ├── auto_ctr_128bit_encrypt_2blocks.hwf │ │ ├── auto_ecb_128bit_decrypt_1block.hwf │ │ ├── auto_ecb_128bit_decrypt_2blocks.hwf │ │ ├── auto_ecb_128bit_encrypt_1block.hwf │ │ └── auto_ecb_128bit_encrypt_2blocks.hwf │ ├── src │ │ ├── main.rs │ │ └── vcs_executor.rs │ └── tb │ │ ├── aes_core.sv │ │ ├── aes_tb.sv │ │ ├── hwf_assert.sv │ │ ├── include │ │ ├── .gitignore │ │ ├── ot_ip_fuzz_tb.h │ │ ├── rfuzz_tb.h │ │ ├── stdin_fuzz_tb.h │ │ ├── tlul_host_tb.h │ │ └── verilator_tb.h │ │ └── src │ │ ├── main.cpp │ │ ├── ot_ip_fuzz_tb.cpp │ │ ├── rfuzz_tb.cpp │ │ ├── stdin_fuzz_tb.cpp │ │ ├── tlul_host_tb.cpp │ │ └── verilator_tb.cpp ├── opentitan-fuzzer-verilator-sw-cov │ ├── Cargo.toml │ ├── init.sh │ ├── seeds │ │ ├── auto_cbc_128bit_decrypt_1block.hwf │ │ ├── auto_cbc_128bit_decrypt_2blocks.hwf │ │ ├── auto_cbc_128bit_encrypt_1block.hwf │ │ ├── auto_cbc_128bit_encrypt_2blocks.hwf │ │ ├── auto_ctr_128bit_decrypt_1block.hwf │ │ ├── auto_ctr_128bit_decrypt_2blocks.hwf │ │ ├── auto_ctr_128bit_encrypt_1block.hwf │ │ ├── auto_ctr_128bit_encrypt_2blocks.hwf │ │ ├── auto_ecb_128bit_decrypt_1block.hwf │ │ ├── auto_ecb_128bit_decrypt_2blocks.hwf │ │ ├── auto_ecb_128bit_encrypt_1block.hwf │ │ └── auto_ecb_128bit_encrypt_2blocks.hwf │ └── src │ │ ├── main.rs │ │ └── vcs_executor.rs └── secworks-vcs │ ├── Cargo.toml │ ├── README.md │ ├── build.rs │ ├── seeds │ └── fuzz_inputs.hex │ ├── src │ └── main.rs │ └── tb_fuzz.sv ├── libpresifuzz_ec ├── Cargo.toml └── src │ ├── lib.rs │ ├── llmp.rs │ └── manager.rs ├── libpresifuzz_feedbacks ├── Cargo.toml └── src │ ├── cycle_feedback.rs │ ├── differential_feedback.rs │ ├── lib.rs │ ├── transferred.rs │ ├── verdi_feedback.rs │ └── verdi_xml_feedback.rs ├── libpresifuzz_mutators ├── Cargo.toml ├── README.md └── src │ ├── lib.rs │ ├── mutational.rs │ ├── riscv_isa.rs │ └── scheduled.rs ├── libpresifuzz_observers ├── Cargo.toml ├── build.rs ├── spike.log ├── src │ ├── lib.rs │ ├── npi_c.c │ ├── trace_observer.rs │ ├── verdi_observer.rs │ └── verdi_xml_observer.rs └── test.vdb │ ├── .cmoptions │ ├── .mode64 │ ├── .vdb_version │ └── snps │ └── coverage │ └── db │ ├── .cm_totalPaths │ ├── auxiliary │ ├── dve_debug.xml │ ├── vcmArguments.xml │ ├── verilog.instance_parameters.txt │ └── verilog.sourceinfo.xml │ ├── design │ ├── verilog.compact_hier_file.txt │ └── verilog.design.xml │ ├── shape │ ├── branch.verilog.exclude.xml │ ├── branch.verilog.info.xml │ ├── branch.verilog.shape.xml │ ├── cond.verilog.exclude.xml │ ├── cond.verilog.info.xml │ ├── cond.verilog.shape.xml │ ├── fsm.verilog.exclude.xml │ ├── fsm.verilog.generated_config.txt │ ├── fsm.verilog.shape.xml │ ├── line.verilog.exclude.xml │ ├── line.verilog.info.xml │ ├── line.verilog.shape.xml │ ├── path.verilog.shape.xml │ ├── tgl.verilog.info.xml │ └── tgl.verilog.shape.xml │ └── testdata │ └── test │ ├── branch.verilog.data.xml │ ├── cond.verilog.data.xml │ ├── fsm.verilog.data.xml │ ├── line.verilog.data.xml │ ├── siminfo.xml │ ├── tgl.verilog.data.xml │ └── vcmArguments.xml ├── libpresifuzz_riscv ├── Cargo.toml └── src │ ├── cpu_profile.rs │ ├── dasm │ ├── gen.rs │ ├── helper.rs │ ├── mod.rs │ ├── objdump_dasm.rs │ └── spike_dasm.rs │ ├── defines.rs │ ├── disas.rs │ ├── elf.rs │ ├── instruction.rs │ ├── lib.rs │ ├── parse.py │ └── states.rs ├── libpresifuzz_schedulers ├── Cargo.toml └── src │ ├── hwminimizer.rs │ └── lib.rs ├── libpresifuzz_stages ├── Cargo.toml └── src │ ├── lib.rs │ └── sync.rs ├── libpresifuzz_verilator ├── Cargo.toml ├── build.rs └── src │ ├── lib.rs │ ├── verilator_feedback.rs │ └── verilator_observer.rs └── plot.py /.github/workflows/rust-clippy.yml: -------------------------------------------------------------------------------- 1 | name: rust-clippy analyze 2 | permissions: read-all 3 | on: 4 | push: 5 | branches: 6 | - main 7 | - 'bugfix/**' 8 | - 'feature/**' 9 | pull_request: 10 | types: 11 | - opened 12 | - reopened 13 | - ready_for_review 14 | - edited 15 | - synchronize 16 | branches: 17 | - main 18 | #schedule: 19 | # - cron: '5 * * * *' 20 | jobs: 21 | rust-clippy-analyze: 22 | name: Run rust-clippy analyzing 23 | env: 24 | PRESIFUZZ_DUMMY: 1 25 | runs-on: ubuntu-latest 26 | permissions: 27 | contents: read 28 | security-events: write 29 | actions: read 30 | steps: 31 | - name: Install Python and pip 32 | uses: actions/setup-python@v5 33 | with: 34 | python-version: '3.12.3' 35 | packages: fusesoc 36 | - name: Install Fusesoc 37 | run: pip3 install fusesoc 38 | - name: Checkout code 39 | uses: actions/checkout@v4.1.5 40 | with: 41 | submodules: 'recursive' 42 | - name: rust-toolchain 43 | uses: actions-rs/toolchain@v1.0.6 44 | with: 45 | toolchain: stable 46 | components: clippy 47 | - name: rust-cargo for presifuzz libraries 48 | uses: actions-rs/cargo@v1.0.1 49 | with: 50 | toolchain: stable 51 | components: clippy 52 | command: build 53 | - name: rust-cargo for secworks-vcs 54 | uses: actions-rs/cargo@v1.0.1 55 | with: 56 | toolchain: stable 57 | components: clippy 58 | command: build 59 | args: --manifest-path fuzzers/secworks-vcs/Cargo.toml 60 | - name: Install required packages clippy-sarif sarif-fmt 61 | run: cargo install clippy-sarif sarif-fmt 62 | - name: Run rust-clippy with test profile and all features enabled 63 | run: cargo clippy --all-features --profile=test --message-format=json | clippy-sarif | tee 64 | rust-clippy-results.sarif | sarif-fmt 65 | continue-on-error: true 66 | - name: Upload analysis results to GitHub 67 | uses: github/codeql-action/upload-sarif@v3 68 | with: 69 | sarif_file: rust-clippy-results.sarif 70 | wait-for-processing: true 71 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Original Authors: https://github.com/github/gitignore 2 | # SPDX-License-Identifier: CC0-1.0 3 | 4 | # Generated by Cargo 5 | # will have compiled files and executables 6 | debug/ 7 | target/ 8 | 9 | # These are backup files generated by rustfmt 10 | **/*.rs.bk 11 | 12 | # MSVC Windows builds of rustc generate these, which store debugging information 13 | *.pdb 14 | 15 | *.lafl_lock 16 | build/ 17 | fusesoc* 18 | output 19 | fuzzers/cva6-vcs-fuzzer/cva6/ 20 | 21 | chipyard 22 | build.err 23 | build.log 24 | 25 | # Mac files 26 | .DS_Store 27 | 28 | # Cargo.locks 29 | Cargo.lock 30 | -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/.gitmodules -------------------------------------------------------------------------------- /.reuse/dep5: -------------------------------------------------------------------------------- 1 | Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ 2 | Upstream-Name: Pre-Silicon Hardware Fuzzing Toolkit 3 | Upstream-Contact: Nassim Corteggiani 4 | Source: https://github.com/IntelLabs/PreSiFuzz/ 5 | 6 | # Sample paragraph, commented out: 7 | # 8 | # Files: src/* 9 | # Copyright: $YEAR $NAME <$CONTACT> 10 | # License: ... 11 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [profile.release] 6 | lto = true 7 | codegen-units = 1 8 | opt-level = 3 9 | debug = true 10 | 11 | [profile.runner] 12 | inherits = "release" 13 | debug = true 14 | out_dir = "custom" 15 | 16 | [workspace] 17 | members = [ 18 | "libpresifuzz_verilator", 19 | "libpresifuzz_feedbacks", 20 | "libpresifuzz_observers", 21 | "libpresifuzz_schedulers", 22 | "libpresifuzz_ec", 23 | "libpresifuzz_mutators", 24 | "libpresifuzz_riscv", 25 | "libpresifuzz_stages", 26 | ] 27 | resolver="2" 28 | exclude = [ 29 | "fuzzers", 30 | "dep" 31 | ] 32 | -------------------------------------------------------------------------------- /LICENSES/CC0-1.0.txt: -------------------------------------------------------------------------------- 1 | Creative Commons Legal Code 2 | 3 | CC0 1.0 Universal 4 | 5 | CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE 6 | LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN 7 | ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS 8 | INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES 9 | REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS 10 | PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM 11 | THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED 12 | HEREUNDER. 13 | 14 | Statement of Purpose 15 | 16 | The laws of most jurisdictions throughout the world automatically confer 17 | exclusive Copyright and Related Rights (defined below) upon the creator 18 | and subsequent owner(s) (each and all, an "owner") of an original work of 19 | authorship and/or a database (each, a "Work"). 20 | 21 | Certain owners wish to permanently relinquish those rights to a Work for 22 | the purpose of contributing to a commons of creative, cultural and 23 | scientific works ("Commons") that the public can reliably and without fear 24 | of later claims of infringement build upon, modify, incorporate in other 25 | works, reuse and redistribute as freely as possible in any form whatsoever 26 | and for any purposes, including without limitation commercial purposes. 27 | These owners may contribute to the Commons to promote the ideal of a free 28 | culture and the further production of creative, cultural and scientific 29 | works, or to gain reputation or greater distribution for their Work in 30 | part through the use and efforts of others. 31 | 32 | For these and/or other purposes and motivations, and without any 33 | expectation of additional consideration or compensation, the person 34 | associating CC0 with a Work (the "Affirmer"), to the extent that he or she 35 | is an owner of Copyright and Related Rights in the Work, voluntarily 36 | elects to apply CC0 to the Work and publicly distribute the Work under its 37 | terms, with knowledge of his or her Copyright and Related Rights in the 38 | Work and the meaning and intended legal effect of CC0 on those rights. 39 | 40 | 1. Copyright and Related Rights. A Work made available under CC0 may be 41 | protected by copyright and related or neighboring rights ("Copyright and 42 | Related Rights"). Copyright and Related Rights include, but are not 43 | limited to, the following: 44 | 45 | i. the right to reproduce, adapt, distribute, perform, display, 46 | communicate, and translate a Work; 47 | ii. moral rights retained by the original author(s) and/or performer(s); 48 | iii. publicity and privacy rights pertaining to a person's image or 49 | likeness depicted in a Work; 50 | iv. rights protecting against unfair competition in regards to a Work, 51 | subject to the limitations in paragraph 4(a), below; 52 | v. rights protecting the extraction, dissemination, use and reuse of data 53 | in a Work; 54 | vi. database rights (such as those arising under Directive 96/9/EC of the 55 | European Parliament and of the Council of 11 March 1996 on the legal 56 | protection of databases, and under any national implementation 57 | thereof, including any amended or successor version of such 58 | directive); and 59 | vii. other similar, equivalent or corresponding rights throughout the 60 | world based on applicable law or treaty, and any national 61 | implementations thereof. 62 | 63 | 2. Waiver. To the greatest extent permitted by, but not in contravention 64 | of, applicable law, Affirmer hereby overtly, fully, permanently, 65 | irrevocably and unconditionally waives, abandons, and surrenders all of 66 | Affirmer's Copyright and Related Rights and associated claims and causes 67 | of action, whether now known or unknown (including existing as well as 68 | future claims and causes of action), in the Work (i) in all territories 69 | worldwide, (ii) for the maximum duration provided by applicable law or 70 | treaty (including future time extensions), (iii) in any current or future 71 | medium and for any number of copies, and (iv) for any purpose whatsoever, 72 | including without limitation commercial, advertising or promotional 73 | purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each 74 | member of the public at large and to the detriment of Affirmer's heirs and 75 | successors, fully intending that such Waiver shall not be subject to 76 | revocation, rescission, cancellation, termination, or any other legal or 77 | equitable action to disrupt the quiet enjoyment of the Work by the public 78 | as contemplated by Affirmer's express Statement of Purpose. 79 | 80 | 3. Public License Fallback. Should any part of the Waiver for any reason 81 | be judged legally invalid or ineffective under applicable law, then the 82 | Waiver shall be preserved to the maximum extent permitted taking into 83 | account Affirmer's express Statement of Purpose. In addition, to the 84 | extent the Waiver is so judged Affirmer hereby grants to each affected 85 | person a royalty-free, non transferable, non sublicensable, non exclusive, 86 | irrevocable and unconditional license to exercise Affirmer's Copyright and 87 | Related Rights in the Work (i) in all territories worldwide, (ii) for the 88 | maximum duration provided by applicable law or treaty (including future 89 | time extensions), (iii) in any current or future medium and for any number 90 | of copies, and (iv) for any purpose whatsoever, including without 91 | limitation commercial, advertising or promotional purposes (the 92 | "License"). The License shall be deemed effective as of the date CC0 was 93 | applied by Affirmer to the Work. Should any part of the License for any 94 | reason be judged legally invalid or ineffective under applicable law, such 95 | partial invalidity or ineffectiveness shall not invalidate the remainder 96 | of the License, and in such case Affirmer hereby affirms that he or she 97 | will not (i) exercise any of his or her remaining Copyright and Related 98 | Rights in the Work or (ii) assert any associated claims and causes of 99 | action with respect to the Work, in either case contrary to Affirmer's 100 | express Statement of Purpose. 101 | 102 | 4. Limitations and Disclaimers. 103 | 104 | a. No trademark or patent rights held by Affirmer are waived, abandoned, 105 | surrendered, licensed or otherwise affected by this document. 106 | b. Affirmer offers the Work as-is and makes no representations or 107 | warranties of any kind concerning the Work, express, implied, 108 | statutory or otherwise, including without limitation warranties of 109 | title, merchantability, fitness for a particular purpose, non 110 | infringement, or the absence of latent or other defects, accuracy, or 111 | the present or absence of errors, whether or not discoverable, all to 112 | the greatest extent permissible under applicable law. 113 | c. Affirmer disclaims responsibility for clearing rights of other persons 114 | that may apply to the Work or any use thereof, including without 115 | limitation any person's Copyright and Related Rights in the Work. 116 | Further, Affirmer disclaims responsibility for obtaining any necessary 117 | consents, permissions or other rights required for any use of the 118 | Work. 119 | d. Affirmer understands and acknowledges that Creative Commons is not a 120 | party to this document and has no duty or obligation with respect to 121 | this CC0 or use of the Work. 122 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Disclaimer 8 | All components are provided for research and validation purposes only. Use at your own risk. 9 | 10 | # Pre-Silicon Hardware Fuzzing Toolkit 11 | From CPU to GPU, and IPU, the complexity of digital hardware design is 12 | increasing rapidly. This makes it more difficult to verify and/or test. 13 | However, detecting bugs before the hardware design is manufactured is a serious 14 | concern. This is because silicon chips often have no upgrade capability, making 15 | bugs persistent. In this repository, we provide building blocks to apply 16 | advanced software testing techniques to pre-silicon hardware testing. 17 | These blocks are based on LibAFL, a modern framework for building software 18 | fuzzer. 19 | 20 | # Supported OS 21 | 22 | This tool has only been tested on Linux based OS, and especially Ubuntu 20.04 LTS. 23 | 24 | # Dependencies 25 | 26 | This framework relies on the VCS simulator to simulate hardware design and 27 | VERDI to extract coverage information. Please, refer to the official 28 | documentation to install the tool. Please, note that some of these tools may 29 | require specific license scheme. 30 | 31 | # Installation 32 | 33 | This library is mostly designed around the RUST language. 34 | For this reason, the initial step is to install 'Cargo'. 35 | This can be easily done with the following command: 36 | ``` 37 | curl https://sh.rustup.rs -sSf | sh 38 | ``` 39 | 40 | Then, let's clone and build this tool: 41 | ``` 42 | git clone https://github.com/IntelLabs/PreSiFuzz PreSiFuzz 43 | 44 | cd PreSiFuzz 45 | 46 | cargo build 47 | ``` 48 | 49 | # Fuzzing Example 50 | 51 | To start playing with the tool, the secworks example is a good candidate. 52 | You can quickly get it running using the following commands: 53 | ``` 54 | cd secworks-vcs 55 | cargo build 56 | ./target/debug/secworks-vcs 57 | ``` 58 | 59 | # Example targets 60 | 61 | The target directory contains examples of design to demonstrate the approach. 62 | 63 | * [OpenTitan](/doc/opentitan.md) 64 | * [CVA6](/fuzzers/cva6-vcs-fuzzer/README.md) 65 | * [Chipyard with Rocket](/fuzzers/chipyard-vcs-fuzzer/README.md) 66 | 67 | 68 | # Documentation Components Overview 69 | 70 | This documentation describes the various components used in our system, including Observers, Feedback, Mutators, Schedulers, and Stages. Each component plays a critical role in the overall functioning and efficiency of the system. Below is a detailed description of each component: 71 | ![Overview of typical execution flow for LibAFL/PreSiFuzz](./doc/overview.jpg) 72 | 73 | ## Observers 74 | 75 | Observers collect information after the execution of test cases by the simulator(s) or emulator(s). The different types of observers available in `libpresifuzz_observers` include: 76 | 77 | - **`verdi_xml_observer`**: This observer extracts code coverage information from XML files produced by VCS. The generated bitmap assigns one bit per coverage point, with 0 indicating uncovered and 1 indicating covered points. 78 | - **`trace_observer`**: This observer parses execution trace logs from various tools, including Spike and simulated Rocket cores. The collected information can be used for additional coverage guidance or for identifying trace mismatches (see `differential_feedback`). 79 | 80 | ## Feedback 81 | 82 | Feedback components analyze the extracted information from the observers and return a single boolean signal indicating whether the feedback is interesting or not. Some feedback options include: 83 | 84 | - **`verdi_xml_feedback`**: Used for coverage feedback, it tracks any code coverage metrics for VCS. You can also track `assert` coverage and use it as an objective for bug detection. 85 | 86 | ## Mutators 87 | 88 | We have extended LibAFL mutators with RISCV-specific mutators. These mutators can delete, insert, or change opcodes and operands of instructions in a test case. Although their behavior is quite generic, the ISA definition is automatically generated using `riscv-opcodes`. This ISA layer is saved in `libpresifuzz_riscv/cpu_profile.rs`. Use the `parse.py` script to generate a new `cpu_profile` using `riscv-opcodes`. 89 | ![Example of RISCV mutations](./doc/mutation.jpg) 90 | 91 | ## Schedulers 92 | 93 | We have implemented a naive minimizer scheduler compatible with our `verdi_xml_observers`. This scheduler computes a subset of test cases from the corpus, aiming to maximize coverage. 94 | 95 | ## Stages 96 | 97 | Stages are logical units executed within the fuzzer pipeline. We have extended the LibAFL SyncOnDiskStage to replace the LLMP layer with a simple system-file-based synchronization layer. Since hardware fuzzing has a relatively slow throughput, using system files to synchronize fuzzers is rarely a bottleneck. It also scales easily on servers with NFS available. Fuzzer instances save serialized information into a `sync` directory, which contains observers, test cases, and some statistical information for monitoring. Additionally, we offer a `URGStage` to merge `vdb` reports into system files during fuzzing campaigns, saving disk space over time. 98 | 99 | ## Event Communication (EC) Library 100 | 101 | The EC library is a replacement for LLMP, providing an event manager to handle fired events. It simply saves new test case events into the system file and ignores other events. 102 | -------------------------------------------------------------------------------- /dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "cargo" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | ignore: 8 | - dependency-name: "libafl" 9 | - dependency-name: "libafl_bolts" 10 | - dependency-name: "libafl_targets" 11 | 12 | - package-ecosystem: "cargo" 13 | directory: "/chipyard-vcs-fuzzer" 14 | schedule: 15 | interval: "weekly" 16 | ignore: 17 | - dependency-name: "libafl" 18 | - dependency-name: "libafl_bolts" 19 | - dependency-name: "libafl_targets" 20 | 21 | - package-ecosystem: "cargo" 22 | directory: "/cva6-vcs-fuzzer" 23 | schedule: 24 | interval: "weekly" 25 | ignore: 26 | - dependency-name: "libafl" 27 | - dependency-name: "libafl_bolts" 28 | - dependency-name: "libafl_targets" 29 | 30 | - package-ecosystem: "cargo" 31 | directory: "/opentitan-fuzzer-vcs" 32 | schedule: 33 | interval: "weekly" 34 | ignore: 35 | - dependency-name: "libafl" 36 | - dependency-name: "libafl_bolts" 37 | - dependency-name: "libafl_targets" 38 | 39 | - package-ecosystem: "cargo" 40 | directory: "/opentitan-fuzzer-verilator-hw-cov" 41 | schedule: 42 | interval: "weekly" 43 | ignore: 44 | - dependency-name: "libafl" 45 | - dependency-name: "libafl_bolts" 46 | - dependency-name: "libafl_targets" 47 | 48 | - package-ecosystem: "cargo" 49 | directory: "/opentitan-fuzzer-verilator-sw-cov" 50 | schedule: 51 | interval: "weekly" 52 | ignore: 53 | - dependency-name: "libafl" 54 | - dependency-name: "libafl_bolts" 55 | - dependency-name: "libafl_targets" 56 | 57 | - package-ecosystem: "cargo" 58 | directory: "/secworks-vcs" 59 | schedule: 60 | interval: "weekly" 61 | ignore: 62 | - dependency-name: "libafl" 63 | - dependency-name: "libafl_bolts" 64 | - dependency-name: "libafl_targets" 65 | 66 | - package-ecosystem: "cargo" 67 | directory: "/libpresifuzz_ec" 68 | schedule: 69 | interval: "weekly" 70 | ignore: 71 | - dependency-name: "libafl" 72 | - dependency-name: "libafl_bolts" 73 | - dependency-name: "libafl_targets" 74 | 75 | - package-ecosystem: "cargo" 76 | directory: "/libpresifuzz_mutators" 77 | schedule: 78 | interval: "weekly" 79 | ignore: 80 | - dependency-name: "libafl" 81 | - dependency-name: "libafl_bolts" 82 | - dependency-name: "libafl_targets" 83 | 84 | - package-ecosystem: "cargo" 85 | directory: "/libpresifuzz_riscv" 86 | schedule: 87 | interval: "weekly" 88 | ignore: 89 | - dependency-name: "libafl" 90 | - dependency-name: "libafl_bolts" 91 | - dependency-name: "libafl_targets" 92 | 93 | - package-ecosystem: "cargo" 94 | directory: "/libpresifuzz_stages" 95 | schedule: 96 | interval: "weekly" 97 | ignore: 98 | - dependency-name: "libafl" 99 | - dependency-name: "libafl_bolts" 100 | - dependency-name: "libafl_targets" 101 | 102 | - package-ecosystem: "cargo" 103 | directory: "/libafl_verilator" 104 | schedule: 105 | interval: "weekly" 106 | ignore: 107 | - dependency-name: "libafl" 108 | - dependency-name: "libafl_bolts" 109 | - dependency-name: "libafl_targets" 110 | 111 | - package-ecosystem: "cargo" 112 | directory: "/libpresifuzz_feedbacks" 113 | schedule: 114 | interval: "weekly" 115 | ignore: 116 | - dependency-name: "libafl" 117 | - dependency-name: "libafl_bolts" 118 | - dependency-name: "libafl_targets" 119 | 120 | - package-ecosystem: "cargo" 121 | directory: "/libpresifuzz_observers" 122 | schedule: 123 | interval: "weekly" 124 | ignore: 125 | - dependency-name: "libafl" 126 | - dependency-name: "libafl_bolts" 127 | - dependency-name: "libafl_targets" 128 | 129 | - package-ecosystem: "cargo" 130 | directory: "/libpresifuzz_schedulers" 131 | schedule: 132 | interval: "weekly" 133 | ignore: 134 | - dependency-name: "libafl" 135 | - dependency-name: "libafl_bolts" 136 | - dependency-name: "libafl_targets" 137 | -------------------------------------------------------------------------------- /doc/libverdi.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # VCS and LIBVERDI 8 | 9 | In this section, we provides more details on the Synopsys based simulation setup. 10 | 11 | PreSiFuzz supports VCS based simulation with coverage guided fuzzing. Synopsys 12 | VCS is one industry leading solution for simulating hardware RTL written in 13 | either VHDL, SystemVerilog or Verilog. VCS offers at least 6 coverate metrics: 14 | line, FSM, condition, toggle, branch, and assertions. By default the coverage is 15 | off. To enable coverage some additional arguments are required to be passed 16 | during the compilation and when starting the simulator. 17 | 18 | When compiling add the following parameters: 19 | ``` 20 | vcs -cm line+fsm+cond+tgl+branch -cm_dir Coverage.vdb 21 | ``` 22 | 23 | When executing a simv (executable produced by vcs compilation flow), add the following parameters: 24 | ``` 25 | simv -cm tgl 26 | ``` 27 | 28 | VCS compilation flow produces a simv executable next to some dependencies, a 29 | crsr, Coverage.vdb, and daidir folder. All are required for the simulator to 30 | run properly. Please, note that vcs uses hardcoded path and so changing the 31 | csrc, simv or daidir names/paths could lead to some 'file not found exception'. 32 | Please, refer to the official documentation for more details (some parameters 33 | may enable to customize dependencies location). 34 | 35 | The Coverage.vdb is important as it contains the coverage + symbols that we 36 | need to compute the coverage score. Usually, VCS only admit one vdb per 37 | simulation run. However, a recent feature enable to share the vdb accross 38 | different simulation runs. The Coverage.vdb will then contain the union of all 39 | the previous coverage data. 40 | 41 | The following command makes the Coverage.vdb shareable. 42 | ``` 43 | crg -dir ./output/Coverage.vdb -shared init 44 | ``` 45 | 46 | We usually execute the above steps in a bash script named run.sh. While 47 | running, the fuzzer needs to parse the vdb structure after each simulation to 48 | indentify inputs of interest. This is the goal of libVerdi, it extracts the vdb 49 | content and create a map the fuzzer can read to identify new seeds. Verdi is a 50 | component from VCS with a couple of debugging features. Among these features, 51 | the libNPI.so (Native Programming Interface) enables users to parse 52 | the vdb structure. It is writtent in C++, and thanks to a custom C 53 | binding works well with Rust. The source code of this intermediate 54 | layer is stored in the C file 'npi_c.c'. 55 | 56 | The libverdi also contains a libafl based observer with the logic to 57 | interface libverdi and libafl. Please refer to the official 58 | documentation for more details. Note that the fourth parameter of 59 | 'update_cov_map' enables user to customized the coverage metric to 60 | parse. 61 | 62 | ``` 63 | unsafe { 64 | let pmap = self.map.as_mut_ptr(); 65 | self.map.set_len(self.cnt); 66 | 67 | let vdb = CString::new(self.vdb.clone()).expect("CString::new failed"); 68 | let db = vdb_cov_init(vdb.as_ptr()); 69 | 70 | update_cov_map(db, pmap as *mut c_char, self.cnt as c_uint, 5); 71 | 72 | vdb_cov_end(db); 73 | } 74 | ``` 75 | 76 | Coverage metrics identifier code: 77 | Toggle -> 5 78 | Line -> 4 79 | -------------------------------------------------------------------------------- /doc/mutation.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/doc/mutation.jpg -------------------------------------------------------------------------------- /doc/opentitan.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Fuzzing OpenTitan 8 | OpenTitan is an open-source silicon root-of-trust, please refer to [the official website](https://opentitan.org/) for more details. 9 | 10 | In the following, we explain how to start fuzzing OpenTitan AES IP using libAFL. 11 | ``` 12 | cd fuzzers/opentitan-fuzzer-vcs 13 | 14 | bash ./run.sh 15 | ``` 16 | Note: The docker build is deprecated. 17 | 18 | The environement variable 'TMPDIR' is used to set the workdir for the different fuzzers. By default `/tmp/presifuzz_*/` 19 | For every seed, the generated VCS files are saved in a dedicated folder whose name starts with 'backup_{id}', and where 'id' is a unique identifier. These directories contain the 'vdb' structures with coverage data. A merged report for all the 'vdb' can be generated using the following command: 20 | ``` 21 | urg $(find -maxdepth 2 -name "Coverage.vdb" -exec echo "-dir " {} \;) -format both -metric tgl -report urg_report 22 | ``` 23 | 24 | If you prefer getting a report per test: 25 | ``` 26 | find -maxdepth 2 -name "backup_*" -exec urg -dir {}/Coverage.vdb -format both -metric tgl -report urg_report_{} \; 27 | ``` 28 | 29 | # Credits 30 | 31 | This example replicates the work from [Timothy Tripple, et all](https://github.com/googleinterns/hw-fuzzing), except that we use vcs for simulating hardware. 32 | The seeds provided in the 'seeds' comes directly from [this repository](https://github.com/googleinterns/hw-fuzzing). 33 | 34 | The RTL code comes from the [OpenTitan team](https://opentitan.org/). 35 | -------------------------------------------------------------------------------- /doc/overview.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/doc/overview.jpg -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "chipyard_vcs_fuzzer" 3 | version = "0.0.1" 4 | edition = "2021" 5 | authors = ["Mohamadreza Rostami "] 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [profile.release] 10 | panic = "abort" 11 | lto = true 12 | codegen-units = 1 13 | opt-level = 3 14 | debug = false 15 | 16 | [profile.dev] 17 | opt-level = 0 18 | strip = "debuginfo" 19 | lto = false 20 | debug = true 21 | panic = "unwind" 22 | 23 | [dependencies] 24 | libpresifuzz_riscv = { path = "../../libpresifuzz_riscv"} 25 | libpresifuzz_ec = { path = "../../libpresifuzz_ec"} 26 | libpresifuzz_mutators = {path="../../libpresifuzz_mutators"} 27 | libpresifuzz_observers = { path = "../../libpresifuzz_observers"} 28 | libpresifuzz_feedbacks = { path = "../../libpresifuzz_feedbacks"} 29 | libpresifuzz_stages = { path = "../../libpresifuzz_stages"} 30 | libafl = { version = "0.11.2"} 31 | libafl_bolts = { version = "0.11.2"} 32 | yaml-rust = "0.4.5" 33 | rand = "0.8.5" 34 | serde_yaml = "0.9.27" 35 | tempdir = "0.3.7" 36 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 37 | clap = { version = "4.5.38", features = ["default"] } 38 | fs_extra = "1.2.0" 39 | wait-timeout = "0.1.5" 40 | color-print = "0.3.6" 41 | regex = "1" 42 | 43 | [features] 44 | debug = [] 45 | -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/README.md: -------------------------------------------------------------------------------- 1 | # Fuzzer Overview 2 | 3 | This documentation outlines the process of setting up and using an RTL fuzzer for the Chipyard framework using libAFL and PreSiFuzz. 4 | This setup demonstrates feedback-guided fuzzing using hardware code coverage reported by a commercial simulator. 5 | 6 | # Prerequisites 7 | 8 | The following tools need to be installed on your own. 9 | 10 | * Latest version of [Spike](https://github.com/riscv-software-src/riscv-isa-sim), the RISC-V ISA simulator, installed. 11 | Follow the installation instructions from the Spike GitHub repository. 12 | 13 | * Synopsys VCS (Verilog Compiler Simulator) installed and properly initialized. VCS is a widely used Verilog simulator. 14 | Ensure it is configured and ready for simulation tasks. 15 | 16 | * [RISC-V GNU Compiler Toolchain] (https://github.com/riscv-collab/riscv-gnu-toolchain) 17 | 18 | ## Building 19 | 20 | The build.rs script performs the following tasks: 21 | 22 | * Initially, it downloads the `Chipyard` mainstream, initializes submodules, and applies the `chipyard_cov.patch` patch to support coverage collection. 23 | * Next, build the default `Rocketchip` for VCS based simulation. 24 | * Finally, it compiles the `./src/testcase.S` file and builds the simv self-contained simulator. Generated files are then copied into the `build` folder. 25 | 26 | To complete the steps above, simply run: 27 | ```sh 28 | $ cargo build 29 | ``` 30 | ## Troubleshooting 31 | 32 | 33 | ## Running the fuzzer 34 | 35 | When starting, the fuzzer creates a work directory where it saves intermediates files such as mutants, and symbolic links to the `simv` and its dependencies in `./build`. 36 | Work directory are saved into `TMPDIR` with a unique directory per fuzzer instance. Naming follows `presifuzz_`. 37 | Synchronization information are saved into the `sync` directory, it includes `testcase` and associated `coverage map`. 38 | 39 | ``` 40 | $ cp ../../target/debug/chipyard_vcs_fuzzer . 41 | $ mkdir sync 42 | ``` 43 | 44 | To run a single fuzzer instance: 45 | ``` 46 | $ AFL_LAUNCHER_CLIENT=1 ./chipyard_vcs_fuzzer 47 | ``` 48 | 49 | To run multiple fuzzer instances: 50 | ``` 51 | for i in {1..10}; do AFL_LAUNCHER_CLIENT=$i ./chipyard_vcs_fuzzer & done 52 | ``` 53 | 54 | # Customizing 55 | 56 | The fuzzer is bootstraped using the seed files into the `seeds` folder. Feel free to customize the content of this file with any interesting seed. 57 | When starting the fuzzer loads the initial inputs (i.e., the seeds), and only keep interesting ones in the corpus (i.e., coverage novelty). 58 | Coverage novelty consider any changes for all supported code coverage metrics on vcs, i.e., branch, conditional, line, toggle, and FSM. 59 | Then, starts the fuzzer loop that iteratively calls the different stages. 60 | StdMutationalStage is responsible for generating new mutant by applying mutation to the existing testcase in the corpus. 61 | The mutations work at the ISA level by first deserializing the binary testcase into stream of instruction, then different mutations might be applied (e.g., adding instruction, removing instruction, changing opcode, ..). 62 | The mutation can easily be customized by changing `../../libpresifuzz_mutators/src/riscv_isa.rs`. 63 | The generated testcase is then inserted into a template ELF file by simplify injecting the code after the `payload` label. 64 | This template contains epilogue and prologue code. 65 | The current version is very simple. We first init registers to some known values, and we change the `mtvec` to points to our own trap handler. 66 | The trap handler is there to stop earlier the testcase execution if we trop too often. Otherwise, it always try to return to the instruction after the failing one. 67 | This version is a naive implementation, better performance could be achieved with some changes on the testharness (e.g., early simulation stop, irq support). 68 | 69 | 70 | # Ploting data 71 | 72 | The fuzzer saves statistics into the `sync`directory. 73 | It is possible to plot coverage over time using the `plot.py`: 74 | 75 | ```python 76 | python3 ./plot.py -m branch -d ./sync 77 | ``` 78 | 79 | The `-m` option is there to provide the coverage metric that is either tgl, cond, branch, line, fsm. 80 | The `-d` points to the directory where stats are saved. -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use std::path::{Path, PathBuf}; 6 | use std::env; 7 | use std::process::{Command, Stdio}; 8 | use std::fs; 9 | use std::fs::File; 10 | 11 | fn main() { 12 | println!("cargo:warning=MESSAGE"); 13 | 14 | assert!(fs::create_dir("./build").is_ok()); 15 | 16 | // Check if chipyard directory exists 17 | if !Path::new("chipyard").exists() { 18 | println!("chipyard is not present in the current directory. Downloading.."); 19 | clone_chipyard(); 20 | } else { 21 | println!("chipyard directory already exists."); 22 | } 23 | 24 | // Change directory to chipyard 25 | std::env::set_current_dir("chipyard").expect("Failed to change directory to chipyard"); 26 | let chipyard_root = format!("{}", env::current_dir().unwrap().display()); 27 | 28 | // Execute build-setup.sh 29 | run_command("./build-setup.sh", &["--skip-marshal", "--skip-firesim", "--skip-toolchain", "--skip-conda", "riscv-tools"]); 30 | 31 | // Source env.sh 32 | source_env_sh(); 33 | 34 | // Apply patch 35 | run_command("git", &["apply", "../chipyard_cov.patch"]); 36 | 37 | // Change directory to sims/vcs/ 38 | std::env::set_current_dir("sims/vcs/").expect("Failed to change directory to sims/vcs/"); 39 | 40 | // Compile with make 41 | run_command("make", &["-j", "12"]); 42 | 43 | // Build the testcase 44 | std::env::set_current_dir(chipyard_root).expect("Failed to change directory to chipyard"); 45 | build_testcase(); 46 | 47 | println!("INFO: Creating build dir."); 48 | 49 | run_command("bash", &["-c", "cp -r ./sims/vcs/* ../build"]); 50 | 51 | let key = "VERDI_HOME"; 52 | let mut verdi_lib = match env::var(key) { 53 | Ok(val) => val, 54 | Err(_e) => "".to_string(), 55 | }; 56 | 57 | if verdi_lib.is_empty() { 58 | println!("The env variable 'VERDI_HOME' is not set"); 59 | return; 60 | } 61 | 62 | verdi_lib.push_str("/share/NPI/lib/linux64"); 63 | 64 | println!("cargo:rustc-link-search=native=./build"); 65 | println!("cargo:rustc-link-search=native={}", verdi_lib); 66 | } 67 | 68 | fn is_conda_installed() -> bool { 69 | Command::new("conda").output().is_ok() 70 | } 71 | 72 | fn run_command(command: &str, args: &[&str]) { 73 | let status = Command::new(command) 74 | .args(args) 75 | .status() 76 | .expect(&format!("Failed to execute {}", command)); 77 | if !status.success() { 78 | panic!("Command {} failed with exit code {:?}", command, status.code()); 79 | } 80 | } 81 | 82 | fn clone_chipyard() { 83 | let repo_url = "https://github.com/ucb-bar/chipyard.git"; 84 | let branch = "1.11.0"; 85 | let status = Command::new("git") 86 | .args(&["clone", "-b", branch, repo_url]) 87 | .status() 88 | .expect("Failed to clone chipyard repository"); 89 | 90 | if !status.success() { 91 | panic!("Failed to clone chipyard repository"); 92 | } 93 | } 94 | 95 | fn source_env_sh() { 96 | let output = Command::new("bash") 97 | .arg("-c") 98 | .arg("source ./env.sh && env") 99 | .output() 100 | .expect("Failed to source env.sh"); 101 | 102 | if output.status.success() { 103 | let new_env: Vec<(String, String)> = String::from_utf8(output.stdout) 104 | .expect("Failed to parse output of env.sh") 105 | .lines() 106 | .filter_map(|line| { 107 | let parts: Vec<&str> = line.splitn(2, '=').collect(); 108 | if parts.len() == 2 { 109 | Some((parts[0].to_string(), parts[1].to_string())) 110 | } else { 111 | None 112 | } 113 | }) 114 | .collect(); 115 | for (key, value) in new_env { 116 | std::env::set_var(key, value); 117 | } 118 | } else { 119 | panic!("Sourcing env.sh failed"); 120 | } 121 | } 122 | 123 | fn build_testcase() { 124 | let status = Command::new("riscv64-unknown-elf-gcc") 125 | .args(&[ 126 | "-DPREALLOCATE=1", 127 | "-mcmodel=medany", 128 | "-static", 129 | "-std=gnu99", 130 | "-O2", 131 | "-ffast-math", 132 | "-fno-common", 133 | "-fno-builtin-printf", 134 | "-fno-tree-loop-distribute-patterns", 135 | "-o", "../build/iram.elf", 136 | "../src/testcase.S", 137 | "-static", 138 | "-nostdlib", 139 | "-nostartfiles", 140 | "-lm", 141 | "-lgcc", 142 | "-T", "../src/testcase.ld" 143 | ]) 144 | .status() 145 | .expect("Failed to build testcase"); 146 | 147 | if !status.success() { 148 | panic!("Building testcase failed"); 149 | } 150 | } 151 | 152 | 153 | // let build_exec_log = File::create("build.log").expect("Failed to build.log"); 154 | // let build_exec_err = File::create("build.err").expect("Failed to build.err"); 155 | // 156 | // let rtl_dir = PathBuf::from("chipyard"); 157 | // if !rtl_dir.exists() { 158 | // println!("INFO: Builing chipyard."); 159 | // 160 | // assert!(Command::new("bash") 161 | // .arg("build.sh") 162 | // .stdin(Stdio::null()) 163 | // .stdout(build_exec_log) 164 | // .stderr(build_exec_err) 165 | // .status() 166 | // .unwrap() 167 | // .success()) 168 | // } 169 | -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/chipyard_cov.patch: -------------------------------------------------------------------------------- 1 | diff --git a/sims/vcs/Makefile b/sims/vcs/Makefile 2 | index 8517fc1d..dc4c4e7c 100644 3 | --- a/sims/vcs/Makefile 4 | +++ b/sims/vcs/Makefile 5 | @@ -54,7 +54,7 @@ include $(base_dir)/common.mk 6 | ######################################################################################### 7 | # vcs binary and arguments 8 | ######################################################################################### 9 | -VCS = vcs -full64 10 | +VCS = vcs -full64 -LDFLAGS -Wl,--no-as-needed 11 | 12 | VCS_OPTS = $(VCS_CC_OPTS) $(VCS_NONCC_OPTS) $(SIM_PREPROC_DEFINES) $(VCS_PREPROC_DEFINES) 13 | 14 | @@ -69,7 +69,7 @@ model_dir_debug = $(build_dir)/$(long_name).debug 15 | ######################################################################################### 16 | $(sim): $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS) 17 | rm -rf $(model_dir) 18 | - $(VCS) $(VCS_OPTS) $(EXTRA_SIM_SOURCES) -o $@ -Mdir=$(model_dir) 19 | + $(VCS) $(VCS_OPTS) $(EXTRA_SIM_SOURCES) -o $@ -Mdir=$(model_dir) -lca -cm line+cond+fsm+tgl+path+branch+assert -cm_dir Coverage.vdb 20 | 21 | $(sim_debug): $(sim_common_files) $(dramsim_lib) $(EXTRA_SIM_REQS) 22 | rm -rf $(model_dir_debug) 23 | -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/config.yml: -------------------------------------------------------------------------------- 1 | fuzzer: 2 | max_testcase_size: 128 3 | simv: 4 | vcs_args: 5 | plus_args: 6 | cov_enable: true 7 | coverage_metrics: "line+fsm+cond+tgl+branch" 8 | coverage_directory: "Coverage.vdb" 9 | reset_coverage_before_use: false 10 | system_timeout_s: 180 11 | vcs_timeout: "10us" 12 | multi_seed: 0 13 | -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # SPDX-FileCopyrightText: 2022 Intel Corporation 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | import os 9 | import re 10 | import time 11 | import copy 12 | from datetime import datetime 13 | import matplotlib.pyplot as plt 14 | import numpy as np 15 | from collections import OrderedDict 16 | import pandas 17 | import seaborn as sns 18 | import json 19 | import argparse 20 | 21 | print(sns.__version__) 22 | 23 | 24 | def is_valid_directory(arg): 25 | if not os.path.isdir(arg): 26 | raise argparse.ArgumentTypeError(f"'{arg}' is not a valid directory") 27 | return arg 28 | 29 | def parse_args(): 30 | parser = argparse.ArgumentParser(description="Parse command line arguments") 31 | parser.add_argument("-d", "--directory", type=is_valid_directory, required=True, help="Input directory") 32 | parser.add_argument("-m", "--metric", choices=["line", "branch", "cond", "tgl", "fsm"], required=True, help="Metric to be provided") 33 | return parser.parse_args() 34 | 35 | args = parse_args() 36 | print("Input directory:", args.directory) 37 | print("Metric:", args.metric) 38 | 39 | stats_directories = [args.directory] 40 | metric = args.metric 41 | 42 | # first, let's load all the data 43 | data = [] 44 | for stats_directory in stats_directories: 45 | 46 | i = 0 47 | delta = 0 48 | for stats_filename in os.scandir(stats_directory): 49 | 50 | f = stats_filename 51 | 52 | if "stats" not in f.name: 53 | continue 54 | 55 | 56 | print(f"Analyzing file {f.name}: ") 57 | 58 | if os.path.isfile(f): 59 | f = open(f) 60 | 61 | last_runtime = 0 62 | last_coverage = 0 63 | 64 | lines = f.readlines() 65 | for l in lines: 66 | 67 | l = json.loads(l) 68 | 69 | if "coverage_verdi_"+metric in l["UpdateUserStats"]["name"]: 70 | a = l["UpdateUserStats"]["value"]["value"]["Ratio"][0] 71 | b = l["UpdateUserStats"]["value"]["value"]["Ratio"][1] 72 | last_coverage = a/b 73 | 74 | if "time_verdi_"+metric in l["UpdateUserStats"]["name"]: 75 | last_runtime = l["UpdateUserStats"]["value"]["value"]["Number"] 76 | data += [{"runtime": last_runtime, "score": last_coverage}] 77 | i += 1 78 | 79 | # let's order the timepoint 80 | dataset = [] 81 | runtime = [] 82 | coverage = [] 83 | max_cov = 0.0 84 | 85 | time_sorted = sorted(data, key=lambda x: x['runtime']) 86 | 87 | delta = time_sorted[0]["runtime"] 88 | 89 | for item in time_sorted: 90 | 91 | runtime += [item["runtime"]] 92 | 93 | if max_cov < item["score"]: 94 | max_cov = item["score"] 95 | 96 | coverage += [max_cov] 97 | 98 | dataset = {"Execution Time": runtime, "Score": coverage} 99 | print(dataset) 100 | ax = sns.lineplot(x=dataset["Execution Time"], y=dataset["Score"], legend="full") 101 | 102 | plt.title(f"{metric} coverage score over time.") 103 | plt.legend(loc='upper center') 104 | plt.savefig(f'{metric}.png') 105 | -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/seeds/seed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/chipyard-vcs-fuzzer/seeds/seed.bin -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/src/testcase.S: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Thales DIS design services SAS 2 | # 3 | # Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 6 | # You may obtain a copy of the License at https://solderpad.org/licenses/ 7 | # 8 | # Original Author: Guillaume Chauvon (guillaume.chauvon@thalesgroup.fr) 9 | 10 | #***************************************************************************** 11 | # custom_test_template.S 12 | #----------------------------------------------------------------------------- 13 | # 14 | DRAM_START: 15 | .word 0x90000000 16 | 17 | .align 2 18 | .globl _start 19 | .section ".text.init" 20 | _start: 21 | la t0, exception_entry 22 | csrw mtvec,t0 23 | la t4, DRAM_START 24 | sw x0, (t4) 25 | 26 | la x1, DRAM_START 27 | la x2, DRAM_START 28 | la x3, DRAM_START 29 | la x4, DRAM_START 30 | la x5, DRAM_START 31 | la x6, DRAM_START 32 | la x7, DRAM_START 33 | la x8, DRAM_START 34 | la x9, DRAM_START 35 | la x10,DRAM_START 36 | la x11,DRAM_START 37 | la x12,DRAM_START 38 | la x13,DRAM_START 39 | la x14,DRAM_START 40 | la x15,DRAM_START 41 | la x16,DRAM_START 42 | la x17,DRAM_START 43 | la x18,DRAM_START 44 | la x19,DRAM_START 45 | la x20,DRAM_START 46 | la x21,DRAM_START 47 | la x22,DRAM_START 48 | la x23,DRAM_START 49 | la x24,DRAM_START 50 | la x25,DRAM_START 51 | la x26,DRAM_START 52 | la x27,DRAM_START 53 | la x28,DRAM_START 54 | la x29,DRAM_START 55 | la x30,DRAM_START 56 | la x31,DRAM_START 57 | 58 | jal x0, payload 59 | 60 | .align 2 61 | exception_entry: 62 | csrr t0, mepc 63 | lb t1, 0(t0) 64 | li a0, 0x3 65 | and t1, t1, a0 66 | 67 | // stop the fuzzer if counter reaches threshold 68 | la t4, DRAM_START 69 | lw t5, (t4) 70 | add t5, t5, 1 71 | li t6, 10 72 | beq t5, t6, exit 73 | sw t5, (t4) 74 | /* Increment mepc by 2 or 4 depending on whether the instruction at mepc 75 | is compressed or not. */ 76 | bne t1, a0, end_handler_incr_mepc2 77 | addi t0, t0, 2 78 | end_handler_incr_mepc2: 79 | addi t0, t0, 2 80 | csrw mepc, t0 81 | end_handler_ret: 82 | mret 83 | 84 | //csrr t3, mepc 85 | //csrr t4, 0xfC2 #CSR_MSTATUS_REG_ADDR 86 | //andi t4, t4, 0x00000080 #MSTATUS_IL_MASK 87 | //srli t4, t4, 7 #MSTATUS_IL_SHIFT 88 | //slli t4, t4, 1 #*2 89 | //add t3, t3, t4 90 | //add t3, t3, 2 91 | //csrw mepc, t3 92 | //la t4, DRAM_START 93 | //lw t5, (t4) 94 | //add t5, t5, 1 95 | //li t6, 100 96 | //beq t5, t6, exit 97 | //sw t5, (t4) 98 | //mret 99 | //lui t0,0x101 100 | //lui t0,0x101 101 | //lui t0,0x101 102 | //lui t0,0x101 103 | //lui t0,0x101 104 | //lui t0,0x101 105 | //lui t0,0x101 106 | //lui t0,0x101 107 | //lui t0,0x101 108 | 109 | .align 4 110 | exit: 111 | la t3, end 112 | csrw sepc, t3 113 | mret 114 | .align 4 115 | end: 116 | wfi 117 | jal x0, end 118 | 119 | .globl payload 120 | .align 4 121 | .section ".text" 122 | payload: 123 | .rept 1024 124 | .word 0xDEADBEEF 125 | // .word 0xDEADBEAF 126 | // .word 0xABABABAB 127 | .endr 128 | 129 | -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/src/testcase.ld: -------------------------------------------------------------------------------- 1 | /*======================================================================*/ 2 | /* Proxy kernel linker script */ 3 | /*======================================================================*/ 4 | /* This is the linker script used when building the proxy kernel. */ 5 | 6 | /*----------------------------------------------------------------------*/ 7 | /* Setup */ 8 | /*----------------------------------------------------------------------*/ 9 | 10 | /* The OUTPUT_ARCH command specifies the machine architecture where the 11 | argument is one of the names used in the BFD library. More 12 | specifically one of the entires in bfd/cpu-mips.c */ 13 | 14 | OUTPUT_ARCH( "riscv" ) 15 | ENTRY(_start) 16 | 17 | /*----------------------------------------------------------------------*/ 18 | /* Sections */ 19 | /*----------------------------------------------------------------------*/ 20 | 21 | SECTIONS 22 | { 23 | 24 | /* text: test code section */ 25 | . = 0x80000000; 26 | .text.init : { *(.text.init) } 27 | 28 | . = ALIGN(0x1000); 29 | .tohost : { *(.tohost) } 30 | 31 | . = ALIGN(0x1000); 32 | .text : { *(.text) } 33 | 34 | /* data segment */ 35 | .data : { *(.data) } 36 | 37 | .sdata : { 38 | __global_pointer$ = . + 0x800; 39 | *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) 40 | *(.sdata .sdata.* .gnu.linkonce.s.*) 41 | } 42 | 43 | /* bss segment */ 44 | .sbss : { 45 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 46 | *(.scommon) 47 | } 48 | .bss : { *(.bss) } 49 | 50 | /* thread-local data segment */ 51 | .tdata : 52 | { 53 | _tdata_begin = .; 54 | *(.tdata) 55 | _tdata_end = .; 56 | } 57 | .tbss : 58 | { 59 | *(.tbss) 60 | _tbss_end = .; 61 | } 62 | 63 | /* End of uninitalized data segement */ 64 | _end = .; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /fuzzers/chipyard-vcs-fuzzer/src/trace_observer.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use libafl::{ 6 | executors::{ExitKind}, 7 | observers::{Observer}, 8 | Error, 9 | inputs::{UsesInput}, 10 | }; 11 | 12 | use core::{fmt::Debug}; 13 | use serde::{Deserialize, Serialize}; 14 | use libafl_bolts::{HasLen, Named}; 15 | 16 | use std::fs::File; 17 | 18 | extern crate fs_extra; 19 | use std::{str}; 20 | use regex::Regex; 21 | use std::io::{self, BufRead}; 22 | 23 | use libpresifuzz_observers::trace_observer::{ExecTraceParser, TraceLog, OpLog, RegOp, OpType}; 24 | 25 | 26 | #[derive(Copy, Clone, Serialize, Deserialize, Debug)] 27 | pub struct RocketExecTrace; 28 | 29 | impl ExecTraceParser for RocketExecTrace 30 | { 31 | fn new() -> Self { 32 | RocketExecTrace {} 33 | } 34 | fn parse(&self, workdir: &str) -> Result, Error> { 35 | let mut trace = Vec::::new(); 36 | 37 | let rocket_trace_file = format!("{}/terminal.err", workdir); 38 | 39 | let file = File::open(rocket_trace_file).expect("Unable to open rocket trace file"); 40 | let reader = io::BufReader::new(file); 41 | 42 | let rocket_re = Regex::new(r"C0:\s+\d+ \[\d+\] pc=\[(\w+)\] W\[r ?(\d+)=(\w+)\]\[\d+\] R\[r ?(\d+)=(\w+)\] R\[r ?(\d+)=(\w+)\] inst=\[(\w+)\]").unwrap(); 43 | 44 | for line in reader.lines() { 45 | if let Ok(log_line) = &line { 46 | if let Some(caps) = rocket_re.captures(log_line) { 47 | let ops = vec![ 48 | OpLog::RegOp(RegOp{op_type: OpType::Write, name: caps[2].to_string(), value: u64::from_str_radix(&caps[3], 16).unwrap()}), 49 | OpLog::RegOp(RegOp{op_type: OpType::Read, name: caps[4].to_string(), value: u64::from_str_radix(&caps[5], 16).unwrap()}), 50 | OpLog::RegOp(RegOp{op_type: OpType::Read, name: caps[6].to_string(), value: u64::from_str_radix(&caps[7], 16).unwrap()}) 51 | ]; 52 | 53 | trace.push(TraceLog { 54 | pc: u64::from_str_radix(&caps[1], 16).unwrap(), 55 | inst: u64::from_str_radix(&caps[8], 16).unwrap(), 56 | ops, 57 | }); 58 | } 59 | } 60 | } 61 | Ok(trace) 62 | } 63 | } 64 | 65 | pub struct BoomExecTrace; 66 | 67 | impl ExecTraceParser for BoomExecTrace 68 | { 69 | fn new() -> Self { 70 | BoomExecTrace {} 71 | } 72 | fn parse(&self, workdir: &str) -> Result, Error> { 73 | let mut trace = Vec::::new(); 74 | // TODO 75 | Ok(trace) 76 | } 77 | } 78 | 79 | pub struct CVA6ExecTrace; 80 | 81 | impl ExecTraceParser for CVA6ExecTrace 82 | { 83 | fn new() -> Self { 84 | CVA6ExecTrace {} 85 | } 86 | fn parse(&self, workdir: &str) -> Result, Error> { 87 | let trace = Vec::::new(); 88 | // TODO 89 | Ok(trace) 90 | } 91 | } -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "cva6_vcs_fuzzer" 3 | version = "0.0.1" 4 | edition = "2021" 5 | authors = ["Nassim Corteggiani "] 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [profile.release] 10 | panic = "abort" 11 | lto = true 12 | codegen-units = 1 13 | opt-level = 3 14 | debug = false 15 | 16 | [profile.dev] 17 | opt-level = 0 18 | strip = "debuginfo" 19 | lto = false 20 | debug = true 21 | panic = "unwind" 22 | 23 | [dependencies] 24 | libpresifuzz_riscv = { path = "../../libpresifuzz_riscv"} 25 | libpresifuzz_ec = { path = "../../libpresifuzz_ec", features=["debug"]} 26 | libpresifuzz_mutators = {path="../../libpresifuzz_mutators"} 27 | libpresifuzz_observers = { path = "../../libpresifuzz_observers"} 28 | libpresifuzz_feedbacks = { path = "../../libpresifuzz_feedbacks"} 29 | libpresifuzz_stages = { path = "../../libpresifuzz_stages"} 30 | libafl = { version = "0.11.2"} 31 | libafl_bolts = { version = "0.11.2"} 32 | yaml-rust = "0.4.5" 33 | rand = "0.8.5" 34 | serde_yaml = "0.9.27" 35 | tempdir = "0.3.7" 36 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 37 | clap = { version = "4.5.38", features = ["default"] } 38 | fs_extra = "1.2.0" 39 | wait-timeout = "0.1.5" 40 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/README.md: -------------------------------------------------------------------------------- 1 | # Fuzzer Overview 2 | 3 | This documentation outlines the process of setting up and using an RTL fuzzer for CVA6 architecture using libAFL and PreSiFuzz. 4 | This setup demonstrates feedback-guided fuzzing using hardware code coverage reported by commercial simulator. 5 | 6 | # Prerequisites 7 | 8 | The following tools need to be installed on your own. 9 | 10 | * Latest version of [Spike](https://github.com/riscv-software-src/riscv-isa-sim), the RISC-V ISA simulator, installed. 11 | Follow the installation instructions from the Spike GitHub repository. 12 | 13 | * Synopsys VCS (Verilog Compiler Simulator) installed and properly initialized. VCS is a widely used Verilog simulator. 14 | Ensure it is configured and ready for simulation tasks. 15 | 16 | * [RISC-V GNU Compiler Toolchain] (https://github.com/riscv-collab/riscv-gnu-toolchain) 17 | 18 | With everything properly installed, please make sure to set the right environment variables in your `bashrc` or equivalent file. The fuzzer expects the following configuration in bash: 19 | 20 | Please, find below an example of configuratio 21 | ```bash 22 | export RISCV=$HOME/riscv 23 | export VERDI_HOME=/usr/synopsys/verdi/U-2023.03-SP2 24 | export VCS_HOME=/usr/synopsys/vcs/U-2023.03-SP2 25 | export SNPSLMD_LICENSE_FILE=server@server.fr 26 | export LD_LIBRARY_PATH=$VERDI_HOME/share/NPI/lib/linux64 27 | ``` 28 | 29 | ## Building 30 | 31 | The build.rs script performs the following tasks: 32 | 33 | * Initially, it downloads the `cva6` mainstream, initializes submodules, and applies the `cva6.patch` patch. 34 | * Next, it downloads the source code for `libfesvr` and builds it. 35 | * Finally, it compiles the `./src/testcase.S` file and builds the simv self-contained simulator. Generated files are then copied into the `build` folder. 36 | 37 | To complete the steps above, simply run: 38 | ```sh 39 | $ cargo build 40 | ``` 41 | ## Troubleshooting 42 | 43 | It may happened that some environement variables are not properly define and the build script may fail. 44 | Please, check `./cva6/verif/simv/setup-env.sh` and make sure that settings are valid. 45 | 46 | ## Running the fuzzer 47 | 48 | When starting, the fuzzer creates a work directory where it saves intermediates files such as mutants, and symbolic links to the `simv` and its dependencies in `./build`. 49 | Work directory are saved into `TMPDIR` with a unique directory per fuzzer instance. Naming follows `presifuzz_`. 50 | Synchronization information are saved into the `sync` directory, it includes `testcase` and associated `coverage map`. 51 | 52 | ``` 53 | $ cp ../../target/debug/cva6_vcs_fuzzer . 54 | $ mkdir sync 55 | ``` 56 | 57 | To run a single fuzzer instance: 58 | ``` 59 | $ AFL_LAUNCHER_CLIENT=1 ./cva6_vcs_fuzzer 60 | ``` 61 | 62 | To run multiple fuzzer instances: 63 | ``` 64 | for i in {1..10}; do AFL_LAUNCHER_CLIENT=$i ./cva6_vcs_fuzzer & done 65 | ``` 66 | 67 | # Customizing 68 | 69 | The fuzzer is bootstraped using the seed files into the `seeds` folder. Feel free to customize the content of this file with any interesting seed. 70 | When starting the fuzzer loads the initial inputs (i.e., the seeds), and only keep interesting ones in the corpus (i.e., coverage novelty). 71 | Coverage novelty consider any changes for all supported code coverage metrics on vcs, i.e., branch, conditional, line, toggle, and FSM. 72 | 73 | Then, starts the fuzzer loop that iteratively calls the different stages. 74 | StdMutationalStage is responsible for generating new mutant by applying mutation to the existing testcase in the corpus. 75 | The mutations work at the ISA level by first deserializing the binary testcase into stream of instruction, then different mutations might be applied (e.g., adding instruction, removing instruction, changing opcode, ..). 76 | The mutation can easily be customized by changing `../../libpresifuzz_mutators/src/riscv_isa.rs`. 77 | 78 | The generated testcase is then inserted into a template ELF file by simplify injecting the code after the `payload` label. 79 | This template contains epilogue and prologue code. 80 | The current version is very simple. We first init registers to some known values, and we change the `mtvec` to points to our own trap handler. 81 | The trap handler is there to stop earlier the testcase execution if we trop too often. Otherwise, it always try to return to the instruction after the failing one. 82 | This version is a naive implementation, better performance could be achieved with some changes on the testharness (e.g., early simulation stop, irq support). 83 | 84 | 85 | # Ploting data 86 | 87 | The fuzzer saves statistics into the `sync`directory. 88 | It is possible to plot coverage over time using the `plot.py`: 89 | 90 | ```python 91 | python3 ./plot.py -m branch -d ./sync 92 | ``` 93 | 94 | The `-m` option is there to provide the coverage metric that is either tgl, cond, branch, line, fsm. 95 | The `-d` points to the directory where stats are saved. 96 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/config.yml: -------------------------------------------------------------------------------- 1 | fuzzer: 2 | max_testcase_size: 128 3 | simv: 4 | vcs_args: "+permissive +tohost_addr=80001000 +elf_file=./testcase.elf +permissive-off ++./testcase.elf +debug_disable=1 +ntb_random_seed=1 -sv_lib ~/riscv/lib/libfesvr" 5 | plus_args: 6 | cov_enable: true 7 | coverage_metrics: "line+fsm+cond+tgl+branch" 8 | coverage_directory: "Coverage.vdb" 9 | system_timeout_s: 180 10 | vcs_timeout: "30us" 11 | multi_seed: 0 12 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/cva6.patch: -------------------------------------------------------------------------------- 1 | diff --git a/Makefile b/Makefile 2 | index ce2452c3..65bb59b1 100644 3 | --- a/Makefile 4 | +++ b/Makefile 5 | @@ -381,7 +381,7 @@ vcs_build: $(dpi-library)/ariane_dpi.so 6 | vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -assert svaext +define+$(defines) +incdir+$(VCS_HOME)/etc/uvm/src $(VCS_HOME)/etc/uvm/src/uvm_pkg.sv $(filter %.sv,$(src)) $(list_incdir) &&\ 7 | vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -ntb_opts uvm-1.2 &&\ 8 | vlogan $(if $(VERDI), -kdb,) -full64 -nc -sverilog -ntb_opts uvm-1.2 $(tbs) +define+$(defines) $(list_incdir) &&\ 9 | - vcs -full64 $(if $(DEBUG), -debug_access+all $(if $(VERDI), -kdb),) $(if $(TRACE_COMPACT),+vcs+fsdbon) -ignore initializer_driver_checks -timescale=1ns/1ns -ntb_opts uvm-1.2 work.$(top_level) -error="IWNF" \ 10 | + vcs -full64 $(if $(DEBUG), -debug_access+all $(if $(VERDI), -kdb),) -lca -cm line+cond+fsm+tgl+path+branch+assert -cm_dir Coverage.vdb $(if $(TRACE_COMPACT),+vcs+fsdbon) -ignore initializer_driver_checks -timescale=1ns/1ns -ntb_opts uvm-1.2 work.$(top_level) -error="IWNF" \ 11 | $(if $(gate), -sdf Max:ariane_gate_tb.i_ariane.i_cva6:$(CVA6_REPO_DIR)/pd/synth/cva6_$(TARGET)_synth.sdf +neg_tchk, +notimingcheck) 12 | 13 | vcs: vcs_build 14 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/meta/testcase.S: -------------------------------------------------------------------------------- 1 | # Copyright 2022 Thales DIS design services SAS 2 | # 3 | # Licensed under the Solderpad Hardware Licence, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # SPDX-License-Identifier: Apache-2.0 WITH SHL-2.0 6 | # You may obtain a copy of the License at https://solderpad.org/licenses/ 7 | # 8 | # Original Author: Guillaume Chauvon (guillaume.chauvon@thalesgroup.fr) 9 | 10 | #***************************************************************************** 11 | # custom_test_template.S 12 | #----------------------------------------------------------------------------- 13 | # 14 | DRAM_START: 15 | .word 0x90000000 16 | 17 | .align 2 18 | .globl _start 19 | .section ".text.init" 20 | _start: 21 | la t0, exception_entry 22 | csrw mtvec,t0 23 | la t4, DRAM_START 24 | sw x0, (t4) 25 | 26 | la x1, DRAM_START 27 | la x2, DRAM_START 28 | la x3, DRAM_START 29 | la x4, DRAM_START 30 | la x5, DRAM_START 31 | la x6, DRAM_START 32 | la x7, DRAM_START 33 | la x8, DRAM_START 34 | la x9, DRAM_START 35 | la x10,DRAM_START 36 | la x11,DRAM_START 37 | la x12,DRAM_START 38 | la x13,DRAM_START 39 | la x14,DRAM_START 40 | la x15,DRAM_START 41 | la x16,DRAM_START 42 | la x17,DRAM_START 43 | la x18,DRAM_START 44 | la x19,DRAM_START 45 | la x20,DRAM_START 46 | la x21,DRAM_START 47 | la x22,DRAM_START 48 | la x23,DRAM_START 49 | la x24,DRAM_START 50 | la x25,DRAM_START 51 | la x26,DRAM_START 52 | la x27,DRAM_START 53 | la x28,DRAM_START 54 | la x29,DRAM_START 55 | la x30,DRAM_START 56 | la x31,DRAM_START 57 | 58 | jal x0, payload 59 | 60 | .align 2 61 | exception_entry: 62 | csrr t0, mepc 63 | lb t1, 0(t0) 64 | li a0, 0x3 65 | and t1, t1, a0 66 | 67 | // stop the fuzzer if counter reaches threshold 68 | la t4, DRAM_START 69 | lw t5, (t4) 70 | add t5, t5, 1 71 | li t6, 10 72 | beq t5, t6, exit 73 | sw t5, (t4) 74 | /* Increment mepc by 2 or 4 depending on whether the instruction at mepc 75 | is compressed or not. */ 76 | bne t1, a0, end_handler_incr_mepc2 77 | addi t0, t0, 2 78 | end_handler_incr_mepc2: 79 | addi t0, t0, 2 80 | csrw mepc, t0 81 | end_handler_ret: 82 | mret 83 | 84 | .align 4 85 | exit: 86 | la t3, end 87 | csrw sepc, t3 88 | mret 89 | .align 4 90 | end: 91 | wfi 92 | jal x0, end 93 | 94 | .globl payload 95 | .align 4 96 | .section ".text" 97 | payload: 98 | .rept 1024 99 | .word 0xDEADBEEF 100 | .endr 101 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/meta/testcase.ld: -------------------------------------------------------------------------------- 1 | /*======================================================================*/ 2 | /* Proxy kernel linker script */ 3 | /*======================================================================*/ 4 | /* This is the linker script used when building the proxy kernel. */ 5 | 6 | /*----------------------------------------------------------------------*/ 7 | /* Setup */ 8 | /*----------------------------------------------------------------------*/ 9 | 10 | /* The OUTPUT_ARCH command specifies the machine architecture where the 11 | argument is one of the names used in the BFD library. More 12 | specifically one of the entires in bfd/cpu-mips.c */ 13 | 14 | OUTPUT_ARCH( "riscv" ) 15 | ENTRY(_start) 16 | 17 | /*----------------------------------------------------------------------*/ 18 | /* Sections */ 19 | /*----------------------------------------------------------------------*/ 20 | 21 | SECTIONS 22 | { 23 | 24 | /* text: test code section */ 25 | . = 0x80000000; 26 | .text.init : { *(.text.init) } 27 | 28 | . = ALIGN(0x1000); 29 | .tohost : { *(.tohost) } 30 | 31 | . = ALIGN(0x1000); 32 | .text : { *(.text) } 33 | 34 | /* data segment */ 35 | .data : { *(.data) } 36 | 37 | .sdata : { 38 | __global_pointer$ = . + 0x800; 39 | *(.srodata.cst16) *(.srodata.cst8) *(.srodata.cst4) *(.srodata.cst2) *(.srodata*) 40 | *(.sdata .sdata.* .gnu.linkonce.s.*) 41 | } 42 | 43 | /* bss segment */ 44 | .sbss : { 45 | *(.sbss .sbss.* .gnu.linkonce.sb.*) 46 | *(.scommon) 47 | } 48 | .bss : { *(.bss) } 49 | 50 | /* thread-local data segment */ 51 | .tdata : 52 | { 53 | _tdata_begin = .; 54 | *(.tdata) 55 | _tdata_end = .; 56 | } 57 | .tbss : 58 | { 59 | *(.tbss) 60 | _tbss_end = .; 61 | } 62 | 63 | /* End of uninitalized data segement */ 64 | _end = .; 65 | } 66 | 67 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # SPDX-FileCopyrightText: 2022 Intel Corporation 5 | # 6 | # SPDX-License-Identifier: Apache-2.0 7 | 8 | import os 9 | import re 10 | import time 11 | import copy 12 | from datetime import datetime 13 | import matplotlib.pyplot as plt 14 | import numpy as np 15 | from collections import OrderedDict 16 | import pandas 17 | import seaborn as sns 18 | import json 19 | import argparse 20 | 21 | print(sns.__version__) 22 | 23 | 24 | def is_valid_directory(arg): 25 | if not os.path.isdir(arg): 26 | raise argparse.ArgumentTypeError(f"'{arg}' is not a valid directory") 27 | return arg 28 | 29 | def parse_args(): 30 | parser = argparse.ArgumentParser(description="Parse command line arguments") 31 | parser.add_argument("-d", "--directory", type=is_valid_directory, required=True, help="Input directory") 32 | parser.add_argument("-m", "--metric", choices=["line", "branch", "cond", "tgl", "fsm"], required=True, help="Metric to be provided") 33 | return parser.parse_args() 34 | 35 | args = parse_args() 36 | print("Input directory:", args.directory) 37 | print("Metric:", args.metric) 38 | 39 | stats_directories = [args.directory] 40 | metric = args.metric 41 | 42 | # first, let's load all the data 43 | data = [] 44 | for stats_directory in stats_directories: 45 | 46 | i = 0 47 | delta = 0 48 | for stats_filename in os.scandir(stats_directory): 49 | 50 | f = stats_filename 51 | 52 | if "stats" not in f.name: 53 | continue 54 | 55 | 56 | print(f"Analyzing file {f.name}: ") 57 | 58 | if os.path.isfile(f): 59 | f = open(f) 60 | 61 | last_runtime = 0 62 | last_coverage = 0 63 | 64 | lines = f.readlines() 65 | for l in lines: 66 | 67 | l = json.loads(l) 68 | 69 | if "coverage_verdi_"+metric in l["UpdateUserStats"]["name"]: 70 | a = l["UpdateUserStats"]["value"]["value"]["Ratio"][0] 71 | b = l["UpdateUserStats"]["value"]["value"]["Ratio"][1] 72 | last_coverage = a/b 73 | 74 | if "time_verdi_"+metric in l["UpdateUserStats"]["name"]: 75 | last_runtime = l["UpdateUserStats"]["value"]["value"]["Number"] 76 | data += [{"runtime": last_runtime, "score": last_coverage}] 77 | i += 1 78 | 79 | # let's order the timepoint 80 | dataset = [] 81 | runtime = [] 82 | coverage = [] 83 | max_cov = 0.0 84 | 85 | time_sorted = sorted(data, key=lambda x: x['runtime']) 86 | 87 | delta = time_sorted[0]["runtime"] 88 | 89 | for item in time_sorted: 90 | 91 | runtime += [item["runtime"]] 92 | 93 | if max_cov < item["score"]: 94 | max_cov = item["score"] 95 | 96 | coverage += [max_cov] 97 | 98 | dataset = {"Execution Time": runtime, "Score": coverage} 99 | print(dataset) 100 | ax = sns.lineplot(x=dataset["Execution Time"], y=dataset["Score"], legend="full") 101 | 102 | plt.title(f"{metric} coverage score over time.") 103 | plt.legend(loc='upper center') 104 | plt.savefig(f'{metric}.png') 105 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/readme.md: -------------------------------------------------------------------------------- 1 | # CVA6 Fuzzer 2 | 3 | Welcome to the CVA6 Fuzzer, a tool designed to fuzz the CVA6 CPU implementation, which can be found at [openhwgroup/cva6](https://github.com/openhwgroup/cva6). CVA6 is a CPU that implements a 64-bit RISC-V instruction set architecture. 4 | 5 | ## Installation 6 | 7 | To install the CVA6 Fuzzer, follow these steps: 8 | 9 | 1. Clone the repository: 10 | 11 | ```bash 12 | git clone https://github.com/yourusername/cva6-fuzzer.git 13 | 14 | 15 | 16 | # CVA6 17 | 18 | 19 | To synthetize the CVA6 vcs testbench, it is require to install libfesvre that is included Spike the riscv isa simulator. 20 | ```bash 21 | export RISCV=/home/$USER/riscv 22 | bash ./ci/install-fesvr.sh 23 | ``` 24 | 25 | ``` 26 | cd verif/core-v-verif/vendor/riscv/riscv-isa-sim/ 27 | mkdir build && cd build 28 | ../configure --prefix=$RISCV 29 | make install-config-hdrs install-hdrs libfesvr.so 30 | cp libfesvr.so $RISCV/lib 31 | popd 32 | ``` 33 | 34 | * Note: The `setup-env.sh` script complains if Verilator is not installed, however Verilator is not used by the fuzzer. 35 | If you do not have it already installed, feel free to comment the corresponding lines at the end of the script. 36 | ``` 37 | cd ./verif/sim 38 | 39 | source ./setup-env.sh 40 | 41 | export DV_SIMULATORS=vcs-testharness 42 | export CVA6_HOME_DIR=$(pwd)/../.. 43 | 44 | python3 cva6.py --target cv32a60x --iss=$DV_SIMULATORS --iss_yaml=cva6.yaml \ 45 | --c_tests ../tests/custom/hello_world/hello_world.c \ 46 | --linker=../tests/custom/common/test.ld \ 47 | --gcc_opts="-static -mcmodel=medany -fvisibility=hidden -nostdlib \ 48 | -nostartfiles -g \ 49 | ../tests/custom/common/crt.S -lgcc \ 50 | -I../tests/custom/env -I../tests/custom/common" 51 | ``` 52 | 53 | ``` 54 | cd fuzzers/cva6_vcs_fuzzer 55 | cargo build 56 | ``` 57 | 58 | ``` 59 | ./target/debug/cva6_vcs_fuzzer $CVA6_HOME_DIR/work-vcs/simv +permissive \ 60 | +tohost_addr=80001000 \ 61 | +elf_file=testcase.elf +permissive-off ++testcase.o +debug_disable=1 +ntb_random_seed=1 \ 62 | -sv_lib /home/nasm/riscv/lib/libfesvr 63 | ``` 64 | 65 | The fuzzer runs with a custom RISCV ISA mutator 66 | -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/run.sh: -------------------------------------------------------------------------------- 1 | ./simv +vcs+finish+20us -cm line+fsm+cond+tgl+branch -cm_dir Coverage.vdb +permissive +elf_file=./testcase.elf ++./testcase.elf +debug_disable=1 +ntb_random_seed=1 -sv_lib $RISCV/lib/libfesvr +ntb_random_seed=28072 -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/seeds/seed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/cva6-vcs-fuzzer/seeds/seed.bin -------------------------------------------------------------------------------- /fuzzers/cva6-vcs-fuzzer/src/differential_feedback.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | #![cfg_attr( 5 | test, 6 | deny( 7 | dead_code, 8 | unreachable_code 9 | ) 10 | )] 11 | #![allow(dead_code, unreachable_code, unused_variables, unused_mut)] 12 | 13 | use core::fmt::Debug; 14 | use libafl_bolts::Named; 15 | use libafl::{ 16 | corpus::Testcase, 17 | events::EventFirer, 18 | executors::ExitKind, 19 | feedbacks::Feedback, 20 | inputs::{UsesInput}, 21 | observers::ObserversTuple, 22 | state::State, 23 | Error, 24 | }; 25 | use serde::{Deserialize, Serialize}; 26 | use std::str; 27 | extern crate fs_extra; 28 | 29 | #[cfg(feature = "debug")] 30 | use color_print::cprintln; 31 | 32 | use std::fmt::Write; 33 | use std::{ 34 | fs, 35 | }; 36 | 37 | /// Nop feedback that annotates execution time in the new testcase, if any 38 | /// for this Feedback, the testcase is never interesting (use with an OR). 39 | /// It decides, if the given [`TimeObserver`] value of a run is interesting. 40 | #[derive(Serialize, Deserialize, Clone, Debug)] 41 | pub struct DifferentialFeedback { 42 | first_name: String, 43 | name: String, 44 | counter: u32, 45 | } 46 | 47 | impl Feedback for DifferentialFeedback 48 | where 49 | S: UsesInput + State 50 | { 51 | #[allow(clippy::wrong_self_convention)] 52 | #[allow(dead_code)] 53 | fn is_interesting( 54 | &mut self, 55 | _state: &mut S, 56 | _manager: &mut EM, 57 | _input: &S::Input, 58 | observers: &OT, 59 | _exit_kind: &ExitKind, 60 | ) -> Result 61 | where 62 | EM: EventFirer, 63 | OT: ObserversTuple, 64 | { 65 | 66 | #[cfg(feature = "debug")] 67 | cprintln!("[WARNING] Skipping trace comparison feedback because it is not implemented for cva6 ..."); 68 | return Ok(false); 69 | 70 | //TODO: implement differential testing for cva6 + Spike 71 | //let observer = observers.match_name::(self.first_name.as_str()).unwrap(); 72 | 73 | //let mut output_arg = String::new(); 74 | //write!(output_arg, "--ofile=backup_{}.log", self.counter).expect("Unable to backup compare.pl log"); 75 | 76 | //if observer.mismatch == true { 77 | // 78 | // interesting = true; 79 | // 80 | // let dst_file = format!("testcase_state_{}.log", self.counter); 81 | // fs::copy(observer.logfile.as_str(), dst_file).expect("Unable to create copy of log file"); 82 | 83 | // self.counter += 1; 84 | // 85 | // let dst_file = format!("testcase.elf_spike_{}.log", self.counter); 86 | // fs::copy("testcase.elf_spike.log", dst_file).expect("Unable to create copy of log file"); 87 | // 88 | // let dst_file = format!("testcase_{}.elf", self.counter); 89 | // fs::copy("testcase.elf", dst_file).expect("Unable to create copy of log file"); 90 | //} 91 | 92 | //let _ = std::fs::remove_file("testcase_state.log"); 93 | //let _ = std::fs::remove_file("testcase.elf_spike.log"); 94 | 95 | //return Ok(interesting); 96 | } 97 | 98 | #[inline] 99 | fn append_metadata( 100 | &mut self, 101 | _state: &mut S, 102 | _observers: &OT, 103 | _testcase: &mut Testcase, 104 | ) -> Result<(), Error> 105 | where 106 | OT: ObserversTuple 107 | { 108 | Ok(()) 109 | } 110 | 111 | /// Discard the stored metadata in case that the testcase is not added to the corpus 112 | #[inline] 113 | fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { 114 | Ok(()) 115 | } 116 | } 117 | 118 | impl Named for DifferentialFeedback { 119 | #[inline] 120 | fn name(&self) -> &str { 121 | self.name.as_str() 122 | } 123 | } 124 | 125 | impl DifferentialFeedback { 126 | /// Creates a new [`DifferentialFeedback`], deciding if the given [`VerdiObserver`] value of a run is interesting. 127 | #[must_use] 128 | pub fn new_with_observer( 129 | name: &'static str, 130 | first_name: &'static str, 131 | ) -> Self { 132 | Self { 133 | first_name: first_name.to_string(), 134 | name: name.to_string(), 135 | counter: 0, 136 | } 137 | } 138 | } 139 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "opentitan-fuzzer" 7 | version = "0.0.1" 8 | authors = ["Nassim Corteggiani "] 9 | edition = "2021" 10 | 11 | [features] 12 | default = ["std"] 13 | tui = [] 14 | std = [] 15 | libnpi = ["std"] 16 | 17 | [lints.rust] 18 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(libnpi)'] } 19 | 20 | [dependencies] 21 | cfg-if = "1" 22 | clap = { version = "4.5.38", features = ["default"] } 23 | libafl = { version = "0.11.2" } 24 | libpresifuzz_ec = { path = "../../libpresifuzz_ec" } 25 | libpresifuzz_observers = { path = "../../libpresifuzz_observers" } 26 | libpresifuzz_feedbacks = { path = "../../libpresifuzz_feedbacks" } 27 | libpresifuzz_stages = { path = "../../libpresifuzz_stages" } 28 | libafl_bolts = { version = "0.11.2" } 29 | nix = "0.24" 30 | num-traits = { version = "0.2", default-features = false } 31 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 32 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 33 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 34 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 35 | wait-timeout = "0.1.5" 36 | libc = "0.2" 37 | fs_extra = "1.2.0" 38 | tempdir = "0.3.7" 39 | 40 | 41 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/init.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: 2022 Intel Corporation 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | 7 | rm -rf build 8 | rm -rf template 9 | rm -rf output 10 | rm -rf fusesoc* 11 | 12 | fusesoc library add opentitan https://github.com/lowRISC/opentitan.git 13 | 14 | cp ./Dockerfile ./fusesoc_libraries/opentitan/util/container/Dockerfile 15 | 16 | if [[ "$(docker images -q opentitan 2> /dev/null)" == "" ]]; then 17 | cd ./fusesoc_libraries/opentitan 18 | docker build --network=host --build-arg proxy=$https_proxy -t opentitan -f ./util/container/Dockerfile . 19 | cd ../.. 20 | fi 21 | 22 | docker run -t -i --net host \ 23 | -v $(pwd)/../..:/home/dev/src \ 24 | -v /usr/synopsys:/usr/synopsys \ 25 | --env="DISPLAY" --volume="$HOME/.Xauthority:/root/.Xauthority:rw" \ 26 | --env DEV_UID=$(id -u) --env DEV_GID=$(id -g) \ 27 | --env USER_CONFIG=/home/dev/src/docker-user-config.sh \ 28 | --env SNPSLMD_LICENSE_FILE="$SNPSLMD_LICENSE_FILE" \ 29 | --env http_proxy="$http_proxy" \ 30 | --env https_proxy="$https_proxy" \ 31 | --env ftp_proxy="$ftp_proxy" \ 32 | opentitan \ 33 | bash 34 | 35 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: 2022 Intel Corporation 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | 7 | rm -rf build 8 | 9 | cargo clean \ 10 | && LIBRARY_PATH="$VERDI_HOME/share/NPI/lib/linux64/" cargo build \ 11 | && sudo -S ldconfig $VERDI_HOME/share/NPI/lib/LINUX64 \ 12 | && rm -rf fusesoc_libraries fusesoc.conf \ 13 | && fusesoc library add opentitan https://github.com/timothytrippel/opentitan.git \ 14 | && cd ./fusesoc_libraries/opentitan \ 15 | && git checkout hwfuzz-checkpoint \ 16 | && pip3 install -U -r python-requirements.txt \ 17 | && cd ../.. \ 18 | && cp ./tb/tb_aes.sv ./fusesoc_libraries/opentitan/hw/ip/aes/rtl/tb_aes.sv \ 19 | && sed -i '/aes.sv/a \ \ \ \ \ \ - rtl\/tb_aes.sv' fusesoc_libraries/opentitan/hw/ip/aes/aes.core \ 20 | && sed -i "s/toplevel: aes/toplevel: tb_aes/g" fusesoc_libraries/opentitan/hw/ip/aes/aes.core \ 21 | && sed -i "s/default_tool: icarus/default_tool: vcs/g" fusesoc_libraries/opentitan/hw/ip/aes/aes.core \ 22 | && fusesoc run --build --flag=fileset_ip --target=syn lowrisc:ip:aes:0.6 --SYNTHESIS --vcs_options "-LDFLAGS -Wl,--no-as-needed -kdb -cm line+fsm+cond+tgl+branch -cm_dir Coverage.vdb -full64 -sverilog -ntb_opts uvm-1.2 -debug_access+all -lca" \ 23 | && mv build/lowrisc_ip_aes_0.6 build/empty \ 24 | && mv build/empty/syn-vcs/* ./build \ 25 | && ./target/debug/opentitan-fuzzer 26 | 27 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_cbc_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ctr_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/seeds/auto_ecb_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/tb/tb_hmac.sv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/tb/tb_hmac.sv -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/tb/tb_kmac.sv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/tb/tb_kmac.sv -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-vcs/tb/tb_rv_timer.sv: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-vcs/tb/tb_rv_timer.sv -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "opentitan-fuzzer" 7 | version = "0.0.1" 8 | authors = ["Nassim Corteggiani "] 9 | edition = "2021" 10 | 11 | [features] 12 | default = ["std"] 13 | tui = [] 14 | std = [] 15 | 16 | [dependencies] 17 | clap = { version = "4.5.38", features = ["default"] } 18 | libafl = { version = "0.11.2", features = ["std"], no-default-features = true } 19 | nix = "0.24" 20 | num-traits = { version = "0.2", default-features = false } 21 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 22 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 23 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 24 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 25 | libc = "0.2" 26 | fs_extra = "1.2.0" 27 | libafl_verilator = { path = "../../libafl_verilator"} 28 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/README.md: -------------------------------------------------------------------------------- 1 | 6 | 7 | # Fuzzing OpenTitan 8 | OpenTitan is an open-source silicon root-of-trust, please refer to [the official website](https://opentitan.org/) for more details. 9 | 10 | In the following, we explain how to start fuzzing OpenTitan AES IP using libAFL + Verilator (toggle coverage). 11 | ``` 12 | cd fuzzers/opentitan-fuzzer-verilator-hw-cov 13 | 14 | bash ./run.sh 15 | ``` 16 | Note: The docker build is deprecated. Instead we use pip and fusesoc to install the requirements. 17 | The script also patches the `aes.core` file to switch from icarus to Verilator, and set `aes_tb` as top module. 18 | However, the Verilator testbench is written in c++ and saved into the `tb` folder. 19 | 20 | After each simulation completion, Verilator saves the toggle coverage onto the disk at 'logs/coverage.dat'. 21 | Please, refer to [Verilator-coverage](https://verilator.org/guide/latest/exe_verilator_coverage.html) if you need to aggregate the results. 22 | 23 | # Credits 24 | 25 | This example replicates the work from [Timothy Tripple, et all](https://github.com/googleinterns/hw-fuzzing), except that we use Verilator hardware coverage as a feedback signal for the fuzzer. 26 | The seeds provided in the 'seeds' comes directly from [this repository](https://github.com/googleinterns/hw-fuzzing). 27 | The testbench provided in the 'tb' comes directly from [this repository](https://github.com/googleinterns/hw-fuzzing). 28 | 29 | The RTL code comes from the [OpenTitan team](https://opentitan.org/). 30 | 31 | 32 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/diff.patch: -------------------------------------------------------------------------------- 1 | diff --git a/infra/base-afl/compile b/infra/base-afl/compile 2 | index 0b56d73..fd89683 100755 3 | --- a/infra/base-afl/compile 4 | +++ b/infra/base-afl/compile 5 | @@ -130,7 +130,9 @@ make \ 6 | VLTRT_CXX=$VLTRT_CXX \ 7 | VLTRT_CXXFLAGS="$VLTRT_CXXFLAGS" \ 8 | LINK=$LINK \ 9 | - DISABLE_VCD_TRACING=1 10 | + DISABLE_VCD_TRACING=1 \ 11 | + ENABLE_COVERAGE_TRACING=1 \ 12 | + VM_COVERAGE=1 13 | echo "Done!" 14 | 15 | ################################################################################ 16 | diff --git a/infra/base-sim/common.mk b/infra/base-sim/common.mk 17 | index b0b710a..65f2be0 100644 18 | --- a/infra/base-sim/common.mk 19 | +++ b/infra/base-sim/common.mk 20 | @@ -71,7 +71,7 @@ VFLAGS += $(addprefix -I, $(HDL_INC_DIRS)) 21 | endif 22 | 23 | ifdef ENABLE_COVERAGE_TRACING 24 | -VFLAGS += --coverage 25 | +VFLAGS += --coverage-toggle 26 | endif 27 | 28 | ifndef DISABLE_VCD_TRACING 29 | diff --git a/infra/base-sim/tb/cpp/src/ot_ip_fuzz_tb.cpp b/infra/base-sim/tb/cpp/src/ot_ip_fuzz_tb.cpp 30 | index 4fdb285..5a468bc 100644 31 | --- a/infra/base-sim/tb/cpp/src/ot_ip_fuzz_tb.cpp 32 | +++ b/infra/base-sim/tb/cpp/src/ot_ip_fuzz_tb.cpp 33 | @@ -221,6 +221,7 @@ void OTIPFuzzTb::SimulateDUT() { 34 | } 35 | 36 | default: { 37 | + std::cout << "(ignore)" << std::endl; 38 | // Handles a kInvalid fuzz opcode 39 | break; 40 | } 41 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | # SPDX-FileCopyrightText: 2022 Intel Corporation 4 | # 5 | # SPDX-License-Identifier: Apache-2.0 6 | 7 | rm -rf build 8 | 9 | cargo clean \ 10 | && cargo build \ 11 | && rm -rf fusesoc_libraries fusesoc.conf \ 12 | && fusesoc library add opentitan https://github.com/timothytrippel/opentitan.git \ 13 | && cd ./fusesoc_libraries/opentitan \ 14 | && git checkout hwfuzz-checkpoint \ 15 | && pip3 install --user -U -r python-requirements.txt \ 16 | && cd ../.. \ 17 | && cp ./tb/aes_tb.sv ./fusesoc_libraries/opentitan/hw/ip/aes/rtl/aes_tb.sv \ 18 | && cp ./tb/aes_core.sv ./fusesoc_libraries/opentitan/hw/ip/aes/rtl/aes_core.sv \ 19 | && sed -i '/aes.sv/a \ \ \ \ \ \ - rtl\/aes_tb.sv' fusesoc_libraries/opentitan/hw/ip/aes/aes.core \ 20 | && sed -i "s/toplevel: aes/toplevel: aes_tb/g" fusesoc_libraries/opentitan/hw/ip/aes/aes.core \ 21 | && sed -i "s/default_tool: icarus/default_tool: verilator/g" fusesoc_libraries/opentitan/hw/ip/aes/aes.core \ 22 | && fusesoc run --build --flag=fileset_ip --target=syn lowrisc:ip:aes:0.6 --SYNTHESIS --verilator_options="+incdir+$(pwd)/tb -I$(pwd)/tb/include --coverage-toggle --timing --report-unoptflat --cc --exe $(pwd)/tb/src/ot_ip_fuzz_tb.cpp $(pwd)/tb/src/stdin_fuzz_tb.cpp $(pwd)/tb/src/tlul_host_tb.cpp $(pwd)/tb/src/verilator_tb.cpp $(pwd)/tb/src/main.cpp " --make_options "CXXFLAGS=-I$(pwd)/tb/include" \ 23 | && mv build/lowrisc_ip_aes_0.6 build/empty \ 24 | && mv build/empty/syn-verilator/* ./build \ 25 | && ./target/debug/opentitan-fuzzer ./seeds 26 | 27 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_cbc_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ctr_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-hw-cov/seeds/auto_ecb_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/src/main.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use std::{ 6 | path::PathBuf, 7 | }; 8 | 9 | use clap::Arg; 10 | use clap::Command as clap_cmd; 11 | 12 | #[cfg(feature = "tui")] 13 | use libafl::monitors::tui::TuiMonitor; 14 | #[cfg(not(feature = "tui"))] 15 | use libafl::{ 16 | feedback_and_fast, feedback_or, 17 | bolts::{ 18 | current_nanos, 19 | rands::StdRand, 20 | tuples::tuple_list, 21 | }, 22 | events::SimpleEventManager, 23 | feedbacks::{CrashFeedback, TimeFeedback}, 24 | fuzzer::{Fuzzer, StdFuzzer}, 25 | monitors::SimpleMonitor, 26 | observers::{TimeObserver}, 27 | mutators::scheduled::{havoc_mutations, StdScheduledMutator}, 28 | schedulers::QueueScheduler, 29 | stages::mutational::StdMutationalStage, 30 | state::StdState, 31 | corpus::{OnDiskCorpus, InMemoryCorpus}, 32 | inputs::bytes::BytesInput, 33 | }; 34 | use libafl::executors::command::CommandConfigurator; 35 | use libafl::prelude::HitcountsMapObserver; 36 | use libafl::prelude::ConstMapObserver; 37 | use libafl::prelude::MaxMapFeedback; 38 | use libafl::prelude::ShMemId; 39 | use libafl::prelude::Input; 40 | use libafl::prelude::HasTargetBytes; 41 | use std::process::Child; 42 | use std::process::Stdio; 43 | use std::path::Path; 44 | use libafl::bolts::AsSlice; 45 | use std::process::Command; 46 | use std::io::Write; 47 | use libafl::bolts::shmem::UnixShMemProvider; 48 | use libafl::prelude::ShMemProvider; 49 | use libafl::bolts::AsMutSlice; 50 | use libafl::prelude::ShMem; 51 | use libafl::Error; 52 | 53 | use libafl_verilator::verilator_observer::VerilatorObserver; 54 | use libafl_verilator::verilator_feedback::VerilatorFeedback; 55 | 56 | mod vcs_executor; 57 | 58 | #[allow(clippy::similar_names)] 59 | pub fn main() { 60 | 61 | let res = clap_cmd::new("forkserver_simple") 62 | .about("Example Forkserver fuzer") 63 | .arg( 64 | Arg::new("corpus") 65 | .help("The directory to read initial inputs from ('seeds')") 66 | .required(true) 67 | .takes_value(true), 68 | ) 69 | .arg( 70 | Arg::new("timeout") 71 | .help("Timeout for each individual execution, in milliseconds") 72 | .short('t') 73 | .long("timeout") 74 | .default_value("1200"), 75 | ) 76 | .arg( 77 | Arg::new("debug_child") 78 | .help("If not set, the child's stdout and stderror will be redirected to /dev/null") 79 | .short('d') 80 | .long("debug-child"), 81 | ) 82 | .arg( 83 | Arg::new("arguments") 84 | .help("Arguments passed to the target") 85 | .multiple_values(true) 86 | .takes_value(true), 87 | ) 88 | .arg( 89 | Arg::new("signal") 90 | .help("Signal used to stop child") 91 | .short('s') 92 | .long("signal") 93 | .default_value("SIGKILL"), 94 | ) 95 | .get_matches(); 96 | 97 | let solution_dir = PathBuf::from("./solutions"); 98 | 99 | let map_size: usize = 42000; 100 | 101 | let verilator_observer = VerilatorObserver::new("verilator_map", &String::from("logs/coverage.dat"), map_size); 102 | 103 | // Create an observation channel to keep track of the execution time 104 | let time_observer = TimeObserver::new("time"); 105 | 106 | // Feedback to rate the interestingness of an input 107 | // This one is composed by two Feedbacks in OR 108 | let mut feedback = feedback_or!( 109 | VerilatorFeedback::new_with_observer("verilator_map", map_size, &String::from("logs/")), 110 | TimeFeedback::new_with_observer(&time_observer) 111 | ); 112 | 113 | // A feedback to choose if an input is a solution or not 114 | // We want to do the same crash deduplication that AFL does 115 | let mut objective = (); 116 | 117 | // If not restarting, create a State from scratch 118 | let corpus_dir = PathBuf::from(res.value_of("corpus").unwrap().to_string()); 119 | let mut state = StdState::new( 120 | // RNG 121 | StdRand::with_seed(current_nanos()), 122 | // Use on disk corpus, so that we keep trace of it 123 | // Performance impact is negligeable as the target is way slower 124 | InMemoryCorpus::::new(), 125 | // OnDiskCorpus::::new(&solution_dir).unwrap(), 126 | // Corpus in which we store solutions (crashes in this example), 127 | // on disk so the user can get them after stopping the fuzzer 128 | OnDiskCorpus::::new(&solution_dir).unwrap(), 129 | // States of the feedbacks. 130 | // The feedbacks can report the data that should persist in the State. 131 | &mut feedback, 132 | // Same for objective feedbacks 133 | &mut objective, 134 | ) 135 | .unwrap(); 136 | 137 | // The Monitor trait define how the fuzzer stats are displayed to the user 138 | let mon = SimpleMonitor::new(|s| println!("{}", s)); 139 | 140 | // The event manager handle the various events generated during the fuzzing loop 141 | // such as the notification of the addition of a new item to the corpus 142 | let mut mgr = SimpleEventManager::new(mon); 143 | 144 | // A queue policy to get testcasess from the corpus 145 | let scheduler = QueueScheduler::new(); 146 | 147 | // A fuzzer with feedbacks and a corpus scheduler 148 | let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); 149 | 150 | // Create the executor for an in-process function with just one observer 151 | #[derive(Debug)] 152 | struct MyExecutor { 153 | } 154 | 155 | impl CommandConfigurator for MyExecutor { 156 | fn spawn_child(&mut self, input: &I) -> Result { 157 | 158 | let mut command = Command::new("./build/Vaes_tb"); 159 | 160 | let command = command 161 | // .args(&[self.shmem_id.as_str()]) 162 | .env_clear() 163 | .stdin(Stdio::piped()); 164 | // .stdout(Stdio::piped()); 165 | 166 | let mut child = command.spawn().expect("failed to start process"); 167 | 168 | let mut stdin = child.stdin.take().unwrap(); 169 | stdin.write_all(input.target_bytes().as_slice())?; 170 | 171 | 172 | // let output = command.output().expect("failed to start process"); 173 | // println!("status: {}", String::from_utf8_lossy(&output.stdout)); 174 | 175 | Ok(child) 176 | } 177 | } 178 | 179 | let mut executor = MyExecutor { }.into_executor(tuple_list!(verilator_observer, time_observer)); 180 | 181 | // Load initial inputs from corpus 182 | let corpus_dir = PathBuf::from(res.value_of("corpus").unwrap().to_string()); 183 | state 184 | .load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[corpus_dir]) 185 | .expect("Failed to load the initial corpus"); 186 | 187 | // Setup a mutational stage with a basic bytes mutator 188 | let mutator = StdScheduledMutator::new(havoc_mutations()); 189 | let mut stages = tuple_list!(StdMutationalStage::new(mutator)); 190 | 191 | fuzzer 192 | .fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr) 193 | .expect("Error in the fuzzing loop"); 194 | 195 | } 196 | 197 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/src/vcs_executor.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | 6 | use std::{ 7 | process::{Child, Stdio}, 8 | }; 9 | use std::process::Command as pcmd; 10 | use libafl::{ 11 | bolts::{ 12 | // rands::Rand, 13 | AsSlice 14 | }, 15 | executors::command::CommandConfigurator, 16 | inputs::{HasTargetBytes, Input}, 17 | Error, 18 | }; 19 | use std::fs::File; 20 | use std::path::Path; 21 | use std::io::prelude::*; 22 | 23 | // Create the executor for an in-process function with just one observer 24 | #[derive(Debug)] 25 | pub struct VCSExecutor 26 | { 27 | pub executable: String, 28 | pub args: String, 29 | pub outdir: String 30 | } 31 | 32 | impl CommandConfigurator for VCSExecutor 33 | { 34 | fn spawn_child(&mut self, input: &I) -> Result { 35 | 36 | let mut input_filename = self.outdir.clone(); 37 | input_filename.push_str("/fuzz_input.hex"); 38 | 39 | let do_steps = || -> Result<(), Error> { 40 | 41 | let mut file = File::create(input_filename)?; 42 | let hex_input = input.target_bytes(); 43 | let hex_input2 = hex_input.as_slice(); 44 | for i in 0..hex_input2.len()-1 { 45 | let c: char = hex_input2[i].try_into().unwrap(); 46 | write!(file, "{}", c as char)?; 47 | } 48 | Ok(()) 49 | }; 50 | 51 | if let Err(_err) = do_steps() { 52 | println!("VCSExecutor failed to create new input file, please check output argument"); 53 | } 54 | 55 | let dir = Path::new(self.executable.as_str()).parent().unwrap(); 56 | std::env::set_current_dir(dir).expect("Unable to change into {dir}"); 57 | 58 | let mut command = pcmd::new(self.executable.as_str()); 59 | 60 | let command = command 61 | .args(self.args.as_str().split(' ')); 62 | 63 | command 64 | .stdin(Stdio::piped()) 65 | .stdout(Stdio::piped()) 66 | .stderr(Stdio::piped()); 67 | 68 | let child = command.spawn().expect("failed to start process"); 69 | // println!("Execution done"); 70 | 71 | // let output = command.output().expect("failed to start process"); 72 | // println!("status: {}", String::from_utf8_lossy(&output.stdout)); 73 | 74 | // let ten_millis = time::Duration::from_millis(30000); 75 | // thread::sleep(ten_millis); 76 | 77 | Ok(child) 78 | } 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/aes_tb.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | 16 | `include "hwf_assert.sv" 17 | 18 | module aes_tb 19 | import aes_reg_pkg::*; 20 | ( 21 | input clk_i, 22 | input rst_ni, 23 | 24 | output logic idle_o, 25 | 26 | input tlul_pkg::tl_h2d_t tl_i, 27 | output tlul_pkg::tl_d2h_t tl_o, 28 | 29 | input prim_alert_pkg::alert_rx_t [NumAlerts-1:0] alert_rx_i, 30 | output prim_alert_pkg::alert_tx_t [NumAlerts-1:0] alert_tx_o 31 | ); 32 | 33 | //////////////// 34 | // DUT // 35 | //////////////// 36 | aes dut ( 37 | .clk_i, 38 | .rst_ni, 39 | 40 | .idle_o, 41 | 42 | .tl_i, 43 | .tl_o, 44 | 45 | .alert_rx_i, 46 | .alert_tx_o 47 | ); 48 | 49 | `ifdef UNPACK_TLUL 50 | ////////////////// 51 | // Unpack TL-UL // 52 | ////////////////// 53 | tlul_inspect inspect ( 54 | .tl_i, 55 | .tl_o 56 | ); 57 | `endif 58 | 59 | //////////////// 60 | // Assertions // 61 | //////////////// 62 | 63 | endmodule 64 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/hwf_assert.sv: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | `ifndef HWF_ASSERT_SV 16 | `define HWF_ASSERT_SV 17 | 18 | // Modified OpenTitan macro bodies included by prim_assert.sv that are 19 | // compatable with Verilator's partial support of SystemVerilog SVA syntax. See 20 | // prim_assert.sv for documentation for each of the macros. 21 | 22 | // The list of basic macros supported is: 23 | // 24 | // ASSERT: Assert a concurrent property directly. It can be called as a module (or 25 | // interface) body item. 26 | // 27 | // Note: We use (__rst !== '0) in the disable iff statements instead of (__rst == 28 | // '1). This properly disables the assertion in cases when reset is X at the 29 | // beginning of a simulation. For that case, (reset == '1) does not disable the 30 | // assertion. 31 | // 32 | // ASSERT_NEVER: Assert a concurrent property NEVER happens 33 | // 34 | // ASSERT_KNOWN: Assert that signal has a known value (each bit is either '0' or '1') after reset. 35 | // It can be called as a module (or interface) body item. 36 | 37 | // ASSERT_RPT is available to change the reporting mechanism when an assert fails 38 | `define HWF_ASSERT_RPT(__name) \ 39 | $error("[ASSERT FAILED] [%m] %s (%s:%0d)", __name, `__FILE__, `__LINE__); \ 40 | 41 | // A subset of the concurrent assertion syntax *IS* supported by verilator 42 | `define HWF_ASSERT(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 43 | __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) __prop) \ 44 | else begin \ 45 | `HWF_ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 46 | end 47 | 48 | `define HWF_ASSERT_NEVER(__name, __prop, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 49 | __name: assert property (@(posedge __clk) disable iff ((__rst) !== '0) not __prop) \ 50 | else begin \ 51 | `HWF_ASSERT_RPT(`PRIM_STRINGIFY(__name)) \ 52 | end 53 | 54 | `define HWF_ASSERT_KNOWN(__name, __sig, __clk = `ASSERT_DEFAULT_CLK, __rst = `ASSERT_DEFAULT_RST) \ 55 | `HWF_ASSERT(__name, !$isunknown(__sig), __clk, __rst) 56 | 57 | `endif // HWF_ASSERT_SV 58 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/include/.gitignore: -------------------------------------------------------------------------------- 1 | # RFUZZ autogenerated header 2 | rfuzz_tb_interface.h 3 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/include/ot_ip_fuzz_tb.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef HW_TB_CPP_INCLUDE_OT_IP_FUZZ_TB_H_ 16 | #define HW_TB_CPP_INCLUDE_OT_IP_FUZZ_TB_H_ 17 | 18 | #include "tlul_host_tb.h" 19 | #include "verilator_tb.h" 20 | 21 | #define OPCODE_SIZE_BYTES 1 // number of opcode bytes to read from STDIN 22 | #define ADDRESS_SIZE_BYTES 4 // size of TL-UL address bus 23 | #define DATA_SIZE_BYTES 4 // size of TL-UL data bus 24 | #define WAIT_OPCODE_THRESHOLD 85 25 | #define RW_OPCODE_THRESHOLD 170 26 | #define NUM_RESET_CLK_PERIODS 1 27 | 28 | enum class HWFuzzOpcode { 29 | kInvalid = 0, 30 | kWait = 1, 31 | kRead = 2, 32 | kWrite = 3, 33 | }; 34 | 35 | struct HWFuzzInstruction { 36 | HWFuzzOpcode opcode; 37 | uint32_t address; 38 | uint32_t data; 39 | }; 40 | 41 | class OTIPFuzzTb : public TLULHostTb { 42 | public: 43 | OTIPFuzzTb(int argc, char** argv); 44 | ~OTIPFuzzTb(); 45 | void SimulateDUT(); 46 | 47 | private: 48 | void InitializeDUT(); 49 | bool GetFuzzOpcode(HWFuzzOpcode* opcode); 50 | bool GetFuzzInstruction(HWFuzzInstruction* instr); 51 | }; 52 | 53 | #endif // HW_TB_CPP_INCLUDE_OT_IP_FUZZ_TB_H_ 54 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/include/rfuzz_tb.h: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef HW_TB_CPP_INCLUDE_RFUZZ_TB_H_ 16 | #define HW_TB_CPP_INCLUDE_RFUZZ_TB_H_ 17 | 18 | #include "stdin_fuzz_tb.h" 19 | 20 | class RFUZZTb : public STDINFuzzTb { 21 | public: 22 | RFUZZTb(int argc, char** argv); 23 | ~RFUZZTb(); 24 | void SimulateDUT(); 25 | 26 | private: 27 | void InitializeDUT(); 28 | bool ResetDUT(); 29 | }; 30 | 31 | #endif // HW_TB_CPP_INCLUDE_RFUZZ_TB_H_ 32 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/include/stdin_fuzz_tb.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef HW_TB_CPP_INCLUDE_STDIN_FUZZ_TB_H_ 16 | #define HW_TB_CPP_INCLUDE_STDIN_FUZZ_TB_H_ 17 | 18 | #include "verilator_tb.h" 19 | 20 | class STDINFuzzTb : public VerilatorTb { 21 | public: 22 | STDINFuzzTb(int argc, char** argv); 23 | ~STDINFuzzTb(); 24 | bool ReadBytes(uint8_t* buffer, uint32_t num_bytes); 25 | uint32_t get_test_num(); 26 | 27 | private: 28 | uint32_t test_num_; // number of fuzz tests run read from STDIN 29 | }; 30 | 31 | #endif // HW_TB_CPP_INCLUDE_STDIN_FUZZ_TB_H_ 32 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/include/verilator_tb.h: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #ifndef HW_TB_CPP_INCLUDE_VERILATOR_TB_H_ 16 | #define HW_TB_CPP_INCLUDE_VERILATOR_TB_H_ 17 | 18 | #include 19 | 20 | #include "Vaes_tb.h" 21 | #include "verilated.h" 22 | #if VM_TRACE 23 | #include "verilated_vcd_c.h" 24 | #endif 25 | 26 | class VerilatorTb { 27 | public: 28 | VerilatorTb(int argc, char** argv); 29 | ~VerilatorTb(); 30 | virtual bool ResetDUT(vluint8_t* clk, vluint8_t* rst_n, 31 | uint32_t num_clk_periods); 32 | vluint64_t get_main_time(); 33 | 34 | protected: 35 | Vaes_tb dut_; // Verilator model of DUT 36 | vluint64_t main_time_; // Verilator simulation time 37 | #if VM_TRACE 38 | void DumpTrace(); 39 | #endif 40 | bool ToggleClock(vluint8_t* clk, uint32_t num_toggles); 41 | void set_main_time(vluint64_t main_time); 42 | 43 | private: 44 | #if VM_TRACE 45 | VerilatedVcdC* tracing_file_pointer_; // VCD file pointer 46 | std::string vcd_file_name_; // VCD file name 47 | void InitializeTracing(int argc, char** argv); 48 | #endif 49 | void InitializeVerilator(int argc, char** argv); 50 | }; 51 | 52 | #endif // HW_TB_CPP_INCLUDE_VERILATOR_TB_H_ 53 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/src/main.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "ot_ip_fuzz_tb.h" 16 | 17 | // Testbench needs to be global for sc_time_stamp() 18 | OTIPFuzzTb* tb = NULL; 19 | 20 | // needs to be defined so Verilog can call $time 21 | double sc_time_stamp() { return tb->get_main_time(); } 22 | 23 | int main(int argc, char** argv, char** env) { 24 | // Instantiate testbench 25 | tb = new OTIPFuzzTb(argc, argv); 26 | 27 | // Simulate the DUT 28 | tb->SimulateDUT(); 29 | 30 | // Teardown 31 | delete (tb); 32 | tb = NULL; 33 | exit(0); 34 | } 35 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/src/rfuzz_tb.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2021 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "rfuzz_tb.h" 16 | 17 | #include 18 | #include 19 | 20 | #include "rfuzz_tb_interface.h" 21 | 22 | const uint8_t ResetInput[InputSize] = {0}; 23 | 24 | // Constructor 25 | RFUZZTb::RFUZZTb(int argc, char** argv) : STDINFuzzTb(argc, argv) { 26 | InitializeDUT(); 27 | } 28 | 29 | // Destructor 30 | RFUZZTb::~RFUZZTb() {} 31 | 32 | // Initialize DUT inputs 33 | void RFUZZTb::InitializeDUT() { 34 | // Set some sensible values for DUT inputs 35 | apply_input(&dut_, ResetInput); 36 | 37 | // Evaluate the Model 38 | dut_.eval(); 39 | #if VM_TRACE 40 | // Dump VCD trace for current time 41 | DumpTrace(); 42 | #endif 43 | 44 | // Start time at 1 to align rising clock edges with even time values 45 | set_main_time(1); 46 | } 47 | 48 | bool RFUZZTb::ResetDUT() { 49 | // Print reset status 50 | std::cout << "Resetting the DUT (time: " << std::dec << unsigned(main_time_); 51 | std::cout << ") ..." << std::endl; 52 | 53 | // Apply reset input to DUT 54 | apply_input(&dut_, ResetInput); 55 | 56 | // Perform meta reset for 1 clock cycle 57 | dut_.io_meta_reset = 1; 58 | if (ToggleClock(&dut_.clock, 2)) { 59 | return true; 60 | } 61 | dut_.io_meta_reset = 0; 62 | 63 | // Perform circuit reset for 1 clock cycle 64 | dut_.reset = 1; 65 | if (ToggleClock(&dut_.clock, 2)) { 66 | return true; 67 | } 68 | dut_.reset = 0; 69 | 70 | // Print reset status 71 | std::cout << "Reset complete! (time = " << std::dec << unsigned(main_time_); 72 | std::cout << ")" << std::endl; 73 | 74 | // Indicate we have NOT reached a Verilog $finish statement 75 | return false; 76 | } 77 | 78 | // Simulate the DUT with testbench input file 79 | void RFUZZTb::SimulateDUT() { 80 | // Create buffer for test data 81 | uint8_t test_input[InputSize] = {0}; 82 | 83 | // Reset the DUT 84 | ResetDUT(); 85 | 86 | // Read tests and simulate DUT 87 | while (ReadBytes(test_input, InputSize) && !Verilated::gotFinish()) { 88 | // Load test into DUT 89 | apply_input(&dut_, test_input); 90 | 91 | // Toggle clock period 92 | ToggleClock(&dut_.clock, 2); 93 | } 94 | 95 | #if VM_TRACE 96 | // Toggle half a clock period 97 | ToggleClock(&dut_.clock, 1); 98 | #endif 99 | 100 | // Final model cleanup 101 | dut_.final(); 102 | } 103 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/src/stdin_fuzz_tb.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Timothy Trippel 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "stdin_fuzz_tb.h" 16 | 17 | #include 18 | 19 | STDINFuzzTb::STDINFuzzTb(int argc, char** argv) 20 | : VerilatorTb(argc, argv), test_num_(0) {} 21 | 22 | STDINFuzzTb::~STDINFuzzTb() {} 23 | 24 | bool STDINFuzzTb::ReadBytes(uint8_t* buffer, uint32_t num_bytes) { 25 | // Read num_bytes from input file stream into buffer 26 | if (!std::cin.eof()) { 27 | // Read file as a byte stream 28 | std::cin.read(reinterpret_cast(buffer), num_bytes); 29 | if (std::cin.gcount() < num_bytes) { 30 | return false; 31 | } 32 | // Increment test number 33 | test_num_++; 34 | return true; 35 | } 36 | return false; 37 | } 38 | 39 | // test 40 | uint32_t STDINFuzzTb::get_test_num() { return test_num_; } 41 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-hw-cov/tb/src/verilator_tb.cpp: -------------------------------------------------------------------------------- 1 | // Copyright 2020 Google LLC 2 | // 3 | // Licensed under the Apache License, Version 2.0 (the "License"); 4 | // you may not use this file except in compliance with the License. 5 | // You may obtain a copy of the License at 6 | // 7 | // http://www.apache.org/licenses/LICENSE-2.0 8 | // 9 | // Unless required by applicable law or agreed to in writing, software 10 | // distributed under the License is distributed on an "AS IS" BASIS, 11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | // See the License for the specific language governing permissions and 13 | // limitations under the License. 14 | 15 | #include "verilator_tb.h" 16 | 17 | #include 18 | 19 | // Constructor: initialize Verilator, and open a VCD trace and the testbench 20 | // input file 21 | VerilatorTb::VerilatorTb(int argc, char** argv) 22 | : dut_(), 23 | main_time_(0) 24 | #if VM_TRACE 25 | , 26 | tracing_file_pointer_(NULL), 27 | vcd_file_name_("") 28 | #endif 29 | { 30 | InitializeVerilator(argc, argv); 31 | #if VM_TRACE 32 | InitializeTracing(argc, argv); 33 | #endif 34 | } 35 | 36 | // Destructor: close testbench input and VCD files, report coverage, and destroy 37 | // model 38 | VerilatorTb::~VerilatorTb() { 39 | #if VM_TRACE 40 | // Close VCD trace if opened 41 | if (tracing_file_pointer_) { 42 | tracing_file_pointer_->close(); 43 | delete tracing_file_pointer_; 44 | tracing_file_pointer_ = NULL; 45 | } 46 | #endif 47 | #if VM_COVERAGE 48 | // Save coverage analysis (since test passed) 49 | Verilated::mkdir("logs"); 50 | VerilatedCov::write("logs/coverage.dat"); 51 | #endif 52 | } 53 | 54 | // Reset the DUT 55 | bool VerilatorTb::ResetDUT(vluint8_t* clk, vluint8_t* rst_n, 56 | uint32_t num_clk_periods) { 57 | // Print reset status 58 | std::cout << "Resetting the DUT (time: " << std::dec << unsigned(main_time_); 59 | std::cout << ") ..." << std::endl; 60 | 61 | // Place DUT in reset 62 | *rst_n = 0; 63 | 64 | // Toggle clock for NUM_RESET_PERIODS 65 | // Check if reached end of simulation 66 | if (ToggleClock(clk, (num_clk_periods * 2) + 1)) { 67 | return true; 68 | } 69 | 70 | // Pull DUT out of reset 71 | *rst_n = 1; 72 | 73 | // Print reset status 74 | std::cout << "Reset complete! (time = " << std::dec << unsigned(main_time_); 75 | std::cout << ")" << std::endl; 76 | 77 | // Indicate we have NOT reached a Verilog $finish statement 78 | return false; 79 | } 80 | 81 | #if VM_TRACE 82 | // Dump VCD trace to VCD file 83 | void VerilatorTb::DumpTrace() { 84 | if (tracing_file_pointer_) { 85 | tracing_file_pointer_->dump(main_time_); 86 | } else { 87 | std::cout << "WARNING: cannot dump VCD trace at time: " << std::dec 88 | << main_time_ << std::endl; 89 | } 90 | } 91 | #endif 92 | 93 | // Toggle clock for num_toggles half clock periods. 94 | // Model is evaluated AFTER clock state is toggled, 95 | // and regardless of current clock state. 96 | bool VerilatorTb::ToggleClock(vluint8_t* clk, uint32_t num_toggles) { 97 | for (uint32_t i = 0; i < num_toggles; i++) { 98 | // Toggle main clock 99 | if (*clk) { 100 | *clk = 0; 101 | } else { 102 | *clk = 1; 103 | } 104 | 105 | // Evaluate model 106 | dut_.eval(); 107 | 108 | #if VM_TRACE 109 | // Dump VCD trace for current time 110 | DumpTrace(); 111 | #endif 112 | 113 | // Increment Time 114 | main_time_++; 115 | 116 | // Check if reached end of simulation 117 | if (Verilated::gotFinish()) { 118 | return true; 119 | } 120 | } 121 | 122 | return false; 123 | } 124 | 125 | // main_time_ accessor 126 | vluint64_t VerilatorTb::get_main_time() { return main_time_; } 127 | 128 | // main_time_ setter 129 | void VerilatorTb::set_main_time(vluint64_t main_time) { 130 | main_time_ = main_time; 131 | } 132 | 133 | #if VM_TRACE 134 | // Enable Verilator VCD tracing 135 | void VerilatorTb::InitializeTracing(int argc, char** argv) { 136 | // If verilator was invoked with --trace argument enable VCD tracing 137 | std::cout << "---------------------------------" << std::endl; 138 | std::cout << "Tracing enabled." << std::endl; 139 | 140 | // Check if VCD filename provided 141 | if (argc == 2) { 142 | std::string fname = argv[1]; 143 | // Set VCD file name 144 | if (fname.find_last_of("\\/") != std::string::npos) { 145 | // input file name was a full path --> strip off base file name 146 | uint32_t base_file_name_start = fname.find_last_of("\\/") + 1; 147 | vcd_file_name_ = fname.substr(base_file_name_start) + ".vcd"; 148 | } else { 149 | vcd_file_name_ = fname + ".vcd"; 150 | } 151 | } else { 152 | vcd_file_name_ = "trace.vcd"; 153 | } 154 | std::cout << "VCD file: " << vcd_file_name_ << std::endl; 155 | 156 | // Turn on Verilator tracing 157 | Verilated::traceEverOn(true); // Verilator must compute traced signals 158 | tracing_file_pointer_ = new VerilatedVcdC(); 159 | dut_.trace(tracing_file_pointer_, 99); // Trace 99 levels of hierarchy 160 | tracing_file_pointer_->open(vcd_file_name_.c_str()); // Open the dump file 161 | } 162 | #endif 163 | 164 | // Initialize Verilator settings 165 | void VerilatorTb::InitializeVerilator(int argc, char** argv) { 166 | // Set debug level, 0 is off, 9 is highest presently used 167 | // May be overridden by commandArgs 168 | Verilated::debug(0); 169 | 170 | // Randomization reset policy 171 | // May be overridden by commandArgs 172 | Verilated::randReset(2); 173 | 174 | // Pass arguments so Verilated code can see them, e.g. $value$plusargs 175 | // This needs to be called before you create any model 176 | Verilated::commandArgs(argc, argv); 177 | } 178 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "opentitan-fuzzer" 7 | version = "0.0.1" 8 | authors = ["Nassim Corteggiani "] 9 | edition = "2021" 10 | 11 | [features] 12 | default = ["std"] 13 | tui = [] 14 | std = [] 15 | 16 | [dependencies] 17 | clap = { version = "4.5.38", features = ["default"] } 18 | libafl = "0.11.2" 19 | nix = "0.24" 20 | num-traits = { version = "0.2", default-features = false } 21 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 22 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 23 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 24 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 25 | libc = "0.2" 26 | fs_extra = "1.2.0" 27 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/init.sh: -------------------------------------------------------------------------------- 1 | 2 | 3 | git clone https://github.com/googleinterns/hw-fuzzing.git 4 | 5 | cargo build 6 | 7 | cd hw-fuzzing 8 | 9 | export HW_FUZZING=$(pwd) && export PYTHONPATH="./:../:$(pwd)/infra/hwfp:$(pwd)/infra/base-sim/hwfutils" 10 | 11 | python3 ./infra/hwfp/hwfp/fuzz.py hw/opentitan/aes/cpp_afl.hjson 12 | 13 | cd .. 14 | 15 | cp -r ./hw-fuzzing/hw/opentitan/aes/bin ./ 16 | 17 | cp ./target/debug/opentitan-fuzzer ./ 18 | 19 | ./opentitan-fuzzer ./seeds 20 | -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_cbc_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ctr_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_decrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_decrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_decrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_decrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_encrypt_1block.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_encrypt_1block.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_encrypt_2blocks.hwf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/fuzzers/opentitan-fuzzer-verilator-sw-cov/seeds/auto_ecb_128bit_encrypt_2blocks.hwf -------------------------------------------------------------------------------- /fuzzers/opentitan-fuzzer-verilator-sw-cov/src/vcs_executor.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | 6 | use std::{ 7 | process::{Child, Stdio}, 8 | }; 9 | use std::process::Command as pcmd; 10 | use libafl::{ 11 | bolts::{ 12 | // rands::Rand, 13 | AsSlice 14 | }, 15 | executors::command::CommandConfigurator, 16 | inputs::{HasTargetBytes, Input}, 17 | Error, 18 | }; 19 | use std::fs::File; 20 | use std::path::Path; 21 | use std::io::prelude::*; 22 | 23 | // Create the executor for an in-process function with just one observer 24 | #[derive(Debug)] 25 | pub struct VCSExecutor 26 | { 27 | pub executable: String, 28 | pub args: String, 29 | pub outdir: String 30 | } 31 | 32 | impl CommandConfigurator for VCSExecutor 33 | { 34 | fn spawn_child(&mut self, input: &I) -> Result { 35 | 36 | let mut input_filename = self.outdir.clone(); 37 | input_filename.push_str("/fuzz_input.hex"); 38 | 39 | let do_steps = || -> Result<(), Error> { 40 | 41 | let mut file = File::create(input_filename)?; 42 | let hex_input = input.target_bytes(); 43 | let hex_input2 = hex_input.as_slice(); 44 | for i in 0..hex_input2.len()-1 { 45 | let c: char = hex_input2[i].try_into().unwrap(); 46 | write!(file, "{}", c as char)?; 47 | } 48 | Ok(()) 49 | }; 50 | 51 | if let Err(_err) = do_steps() { 52 | println!("VCSExecutor failed to create new input file, please check output argument"); 53 | } 54 | 55 | let dir = Path::new(self.executable.as_str()).parent().unwrap(); 56 | std::env::set_current_dir(dir).expect("Unable to change into {dir}"); 57 | 58 | let mut command = pcmd::new(self.executable.as_str()); 59 | 60 | let command = command 61 | .args(self.args.as_str().split(' ')); 62 | 63 | command 64 | .stdin(Stdio::piped()) 65 | .stdout(Stdio::piped()) 66 | .stderr(Stdio::piped()); 67 | 68 | let child = command.spawn().expect("failed to start process"); 69 | // println!("Execution done"); 70 | 71 | // let output = command.output().expect("failed to start process"); 72 | // println!("status: {}", String::from_utf8_lossy(&output.stdout)); 73 | 74 | // let ten_millis = time::Duration::from_millis(30000); 75 | // thread::sleep(ten_millis); 76 | 77 | Ok(child) 78 | } 79 | } 80 | 81 | 82 | -------------------------------------------------------------------------------- /fuzzers/secworks-vcs/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "secworks-vcs" 7 | version = "0.0.1" 8 | authors = ["Nassim Corteggiani "] 9 | edition = "2021" 10 | 11 | [features] 12 | default = ["std"] 13 | tui = [] 14 | std = [] 15 | 16 | [profile.runner] 17 | inherits = "release" 18 | debug = true 19 | out_dir = "runner" 20 | 21 | [dependencies] 22 | cfg-if = "1" 23 | clap = { version = "4.5.38", features = ["default"] } 24 | libafl = { version = "0.11.2" } 25 | libafl_bolts = { version = "0.11.2" } 26 | libpresifuzz_ec = { path = "../../libpresifuzz_ec" } 27 | libpresifuzz_observers = { path = "../../libpresifuzz_observers" } 28 | libpresifuzz_feedbacks = { path = "../../libpresifuzz_feedbacks" } 29 | libpresifuzz_stages = { path = "../../libpresifuzz_stages" } 30 | nix = "0.24" 31 | num-traits = { version = "0.2", default-features = false } 32 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 33 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 34 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 35 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 36 | libc = "0.2" 37 | tempdir = "0.3.7" 38 | wait-timeout = "0.1.5" 39 | fs_extra = "1.2.0" 40 | -------------------------------------------------------------------------------- /fuzzers/secworks-vcs/README.md: -------------------------------------------------------------------------------- 1 | # SecWorks Fuzzing 2 | 3 | SecWorks is a collection of hardware implementation for cryptographic functions 4 | In this example, we use the SHA-256 as a target for our fuzzer. 5 | 6 | For more details, look at the official repo [here](https://github.com/secworks/sha256). 7 | 8 | # How to? 9 | 10 | First, install fusesoc dependency. 11 | ``` 12 | python3 -m venv .env 13 | 14 | .env/bin/pip3 install --upgrade fusesoc 15 | 16 | export PATH=$PWD/.env/bin:$PATH 17 | ``` 18 | 19 | Then, let's download the secwork design, path the testbench (testharness), and build all (design+fuzzer). 20 | Please, make sure ```VERDI_HOME``` and ```VCS_HOME``` environment variable are set and pointing to valid Synopsys toolchain. 21 | ``` 22 | cargo build 23 | ``` 24 | 25 | You should be able to run a single instance of the fuzzer using: 26 | ``` 27 | AFL_LAUNCHER_CLIENT=1 ./target/debug/secworks-vcs 28 | ``` 29 | 30 | To get more insight about fuzzer steps: 31 | ``` 32 | LIBAFL_DEBUG_OUTPUT=1 AFL_LAUNCHER_CLIENT=1 ./target/debug/secworks-vcs 33 | ``` 34 | 35 | ```AFL_LAUNCHER_CLIENT``` is a the fuzzer unique id. 36 | Without this environment variable, the fuzzer starts in broker mode collecting stats log into the systemfile to monitor other fuzzer instances. 37 | -------------------------------------------------------------------------------- /fuzzers/secworks-vcs/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use std::process::Command; 6 | use std::path::PathBuf; 7 | use std::fs::OpenOptions; 8 | use std::io::prelude::*; 9 | use std::env; 10 | 11 | fn main() { 12 | 13 | let rtl_dir = PathBuf::from("./fusesoc_libraries/sha256"); 14 | 15 | if !rtl_dir.exists() { 16 | 17 | assert!(Command::new("fusesoc") 18 | .arg("library") 19 | .arg("add") 20 | .arg("sha256") 21 | .arg("https://github.com/secworks/sha256") 22 | .status() 23 | .unwrap() 24 | .success()); 25 | 26 | assert!(Command::new("cp") 27 | .arg("./tb_fuzz.sv") 28 | .arg("./fusesoc_libraries/sha256/src/tb/") 29 | .status() 30 | .unwrap() 31 | .success()); 32 | 33 | let mut file = OpenOptions::new() 34 | .write(true) 35 | .append(true) 36 | .open("fusesoc_libraries/sha256/sha256.core") 37 | .unwrap(); 38 | 39 | if let Err(e) = writeln!(file, " tb_fuzz:") { 40 | eprintln!("Couldn't write to file: {}", e); 41 | } 42 | 43 | if let Err(e) = writeln!(file, " <<: *tb") { 44 | eprintln!("Couldn't write to file: {}", e); 45 | } 46 | 47 | if let Err(e) = writeln!(file, " toplevel : tb_fuzz") { 48 | eprintln!("Couldn't write to file: {}", e); 49 | } 50 | 51 | assert!(Command::new("sed") 52 | .arg("-i") 53 | .arg("s|- src/tb/tb_sha256.v|- src/tb/tb_fuzz.sv|g") 54 | .arg("fusesoc_libraries/sha256/sha256.core") 55 | .status() 56 | .unwrap() 57 | .success()); 58 | } 59 | 60 | if !env::var("PRESIFUZZ_DUMMY").is_ok() { 61 | assert!(Command::new("fusesoc") 62 | .arg("run") 63 | .arg("--build") 64 | .arg("--target=tb_fuzz") 65 | .arg("--tool=vcs") 66 | .arg("secworks:crypto:sha256") 67 | .arg("--vcs_options") 68 | .arg("-LDFLAGS -Wl,--no-as-needed -cm line+fsm+cond+tgl+branch -cm_dir Coverage.vdb -full64 -sverilog") 69 | .status() 70 | .unwrap() 71 | .success()); 72 | } 73 | 74 | // let args = "fusesoc run --target=tb_fuzz --tool=vcs secworks:crypto:sha256 --vcs_options '-LDFLAGS -Wl,--no-as-needed -cm line+fsm+cond+tgl+branch -cm_dir Coverage.vdb -full64 -sverilog' --run_options '+TESTCASE=/home/nasm/Projects/HW_Fuzzing/research.security.fuzzing.hardware-fuzzing/fuzzers/baby-rtl-fuzzer/fuzz_inputs.hex -cm tgl'"; 75 | // let args = args.split(' '); 76 | // 77 | // Command::new("fusesoc") 78 | // .args(args) 79 | // .output() 80 | // .expect("failed to execute process"); 81 | } 82 | -------------------------------------------------------------------------------- /fuzzers/secworks-vcs/seeds/fuzz_inputs.hex: -------------------------------------------------------------------------------- 1 | 0000000800000005 2 | -------------------------------------------------------------------------------- /fuzzers/secworks-vcs/tb_fuzz.sv: -------------------------------------------------------------------------------- 1 | //====================================================================== 2 | // 3 | // tb_fuzz.v 4 | // ----------- 5 | // Testbench for the fuzzing SHA-256. 6 | // 7 | // Modified by: Nassim Corteggiani 8 | // Based on tb_sha256.sv from https://github.com/secworks/sha256 9 | // SPDX-FileCopyrightText: 2022 Intel Corporation 10 | // SPDX-License-Identifier: BSD-2-Clause 11 | // 12 | // Redistribution and use in source and binary forms, with or 13 | // without modification, are permitted provided that the following 14 | // conditions are met: 15 | // 16 | // 1. Redistributions of source code must retain the above copyright 17 | // notice, this list of conditions and the following disclaimer. 18 | // 19 | // 2. Redistributions in binary form must reproduce the above copyright 20 | // notice, this list of conditions and the following disclaimer in 21 | // the documentation and/or other materials provided with the 22 | // distribution. 23 | // 24 | // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 25 | // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 26 | // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 27 | // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 28 | // COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 29 | // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 30 | // BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 31 | // LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 32 | // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 33 | // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 34 | // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 35 | // ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 | // 37 | //====================================================================== 38 | 39 | `default_nettype none 40 | 41 | module tb_fuzz(); 42 | 43 | parameter WIDTH = 32; 44 | 45 | int fd; 46 | int status; 47 | string test_case; 48 | 49 | //---------------------------------------------------------------- 50 | // Internal constant and parameter definitions. 51 | //---------------------------------------------------------------- 52 | parameter DEBUG = 0; 53 | 54 | parameter CLK_HALF_PERIOD = 2; 55 | parameter CLK_PERIOD = 2 * CLK_HALF_PERIOD; 56 | 57 | //---------------------------------------------------------------- 58 | // Register and Wire declarations. 59 | //---------------------------------------------------------------- 60 | reg tb_clk; 61 | reg tb_reset_n; 62 | reg tb_cs; 63 | reg tb_we; 64 | reg [7 : 0] tb_address; 65 | reg [31 : 0] tb_write_data; 66 | wire [31 : 0] tb_read_data; 67 | wire tb_error; 68 | 69 | reg [31 : 0] read_data; 70 | reg [255 : 0] digest_data; 71 | 72 | logic [32-1:0]address; 73 | logic [WIDTH-1:0]data; 74 | 75 | //---------------------------------------------------------------- 76 | // Device Under Test. 77 | //---------------------------------------------------------------- 78 | sha256 dut( 79 | .clk(tb_clk), 80 | .reset_n(tb_reset_n), 81 | 82 | .cs(tb_cs), 83 | .we(tb_we), 84 | 85 | 86 | .address(tb_address), 87 | .write_data(tb_write_data), 88 | .read_data(tb_read_data), 89 | .error(tb_error) 90 | ); 91 | 92 | 93 | //---------------------------------------------------------------- 94 | // clk_gen 95 | // 96 | // Clock generator process. 97 | //---------------------------------------------------------------- 98 | always 99 | begin : clk_gen 100 | #CLK_HALF_PERIOD tb_clk = !tb_clk; 101 | end // clk_gen 102 | 103 | 104 | //---------------------------------------------------------------- 105 | // sys_monitor 106 | // 107 | // Generates a cycle counter and displays information about 108 | // the dut as needed. 109 | //---------------------------------------------------------------- 110 | always 111 | begin : sys_monitor 112 | #(2 * CLK_HALF_PERIOD); 113 | end 114 | 115 | 116 | //---------------------------------------------------------------- 117 | // reset_dut() 118 | // 119 | // Toggles reset to force the DUT into a well defined state. 120 | //---------------------------------------------------------------- 121 | task reset_dut; 122 | begin 123 | tb_reset_n = 0; 124 | #(4 * CLK_HALF_PERIOD); 125 | tb_reset_n = 1; 126 | end 127 | endtask // reset_dut 128 | 129 | 130 | //---------------------------------------------------------------- 131 | // init_sim() 132 | // 133 | // Initialize all counters and testbed functionality as well 134 | // as setting the DUT inputs to defined values. 135 | //---------------------------------------------------------------- 136 | task init_sim; 137 | begin 138 | tb_clk = 0; 139 | tb_reset_n = 0; 140 | tb_cs = 0; 141 | tb_we = 0; 142 | tb_address = 6'h0; 143 | tb_write_data = 32'h0; 144 | end 145 | endtask // init_dut 146 | 147 | //---------------------------------------------------------------- 148 | // write_word() 149 | // 150 | // Write the given word to the DUT using the DUT interface. 151 | //---------------------------------------------------------------- 152 | task write_word(input [7 : 0] address, 153 | input [31 : 0] word); 154 | begin 155 | if (DEBUG) 156 | begin 157 | $display("*** Writing 0x%08x to 0x%02x.", word, address); 158 | $display(""); 159 | end 160 | 161 | tb_address = address; 162 | tb_write_data = word; 163 | tb_cs = 1; 164 | tb_we = 1; 165 | #(CLK_PERIOD); 166 | tb_cs = 0; 167 | tb_we = 0; 168 | end 169 | endtask // write_word 170 | 171 | 172 | //---------------------------------------------------------------- 173 | // Load fuzz input from file 174 | //---------------------------------------------------------------- 175 | initial 176 | begin : main 177 | $display(" -- Testbench for sha256 started --"); 178 | 179 | init_sim(); 180 | reset_dut(); 181 | 182 | if (!$value$plusargs("TESTCASE=%s", test_case)) 183 | begin 184 | test_case = "fuzz_inputs"; 185 | end 186 | $display("Testcase: %s", test_case ); 187 | 188 | fd = $fopen(test_case, "rb"); 189 | 190 | while (!$feof(fd)) begin 191 | 192 | status = $fread(address, fd); 193 | status = $fread(data, fd); 194 | 195 | address = {{address[07:00]}, {address[15:08]}, {address[23:16]}, {address[31:24]}}; 196 | data = {{data[07:00]}, {data[15:08]}, {data[23:16]}, {data[31:24]}}; 197 | 198 | $display("- {opcode: write, addr: %h, data: %h}", address, data); 199 | 200 | write_word(address, data); 201 | end 202 | 203 | $display(" -- Testbench for sha256 done. --"); 204 | $finish; 205 | end // main 206 | endmodule // tb_fuzz 207 | 208 | //====================================================================== 209 | // EOF tb_fuzz.v 210 | //====================================================================== 211 | -------------------------------------------------------------------------------- /libpresifuzz_ec/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libpresifuzz_ec" 7 | version = "0.0.2" 8 | authors = ["Nassim Corteggiani "] 9 | edition = "2021" 10 | description = "EC Support for hardware fuzzing" 11 | repository = "https://github.com/intel-sandbox/labs.presifuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std"] 19 | std = [] 20 | debug = [] 21 | serialize_bytes = ["std"] 22 | introspection = ["std"] 23 | fork = ["std"] 24 | 25 | [build-dependencies] 26 | cc = "1" 27 | 28 | [lints.rust] 29 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(serialize_bytes)', 'cfg(introspection)', 'cfg(serdeany_autoreg)', 'cfg(fork)'] } 30 | 31 | [dependencies] 32 | libafl = { version = "0.11.2"} 33 | libafl_bolts = { version = "0.11.2"} 34 | nix = "0.24" 35 | num-traits = { version = "0.2", default-features = false } 36 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 37 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 38 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 39 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 40 | libc = "0.2" 41 | fs_extra = "1.2.0" 42 | yaml-rust = "0.4.5" 43 | rand = "0.8.5" 44 | serde_yaml = "0.9.27" 45 | color-print = "0.3.5" 46 | subprocess = "0.2.9" 47 | chrono = "0.4.34" 48 | file_diff = "1.0.0" 49 | typed-builder = "0.18.1" 50 | tokio = { version = "1.44.2", features = ["sync", "net", "rt", "io-util", "macros"] } # only used for TCP Event Manager right now 51 | postcard = { version = "1.0", features = ["alloc"], default-features = false } # no_std compatible serde serialization format 52 | serde_json = "1.0.114" 53 | bincode = "1.3.3" 54 | -------------------------------------------------------------------------------- /libpresifuzz_ec/src/lib.rs: -------------------------------------------------------------------------------- 1 | pub mod llmp; 2 | pub mod manager; 3 | 4 | use libafl::prelude::Input; 5 | use core::marker::PhantomData; 6 | use libafl::prelude::UserStats; 7 | use libafl_bolts::ClientId; 8 | use core::time::Duration; 9 | use libafl::prelude::EventConfig; 10 | use libafl::prelude::ExitKind; 11 | use serde::Serialize; 12 | use serde::Deserialize; 13 | use libafl::prelude::LogSeverity; 14 | 15 | #[derive(Serialize, Deserialize, Clone, Debug)] 16 | #[serde(bound = "I: serde::de::DeserializeOwned")] 17 | pub enum Event 18 | where 19 | I: Input, 20 | { 21 | // TODO use an ID to keep track of the original index in the sender Corpus 22 | // The sender can then use it to send Testcase metadata with CustomEvent 23 | /// A fuzzer found a new testcase. Rejoice! 24 | NewTestcase { 25 | /// The input for the new testcase 26 | input: I, 27 | /// The state of the observers when this testcase was found 28 | observers_buf: Option>, 29 | /// The exit kind 30 | exit_kind: ExitKind, 31 | /// The new corpus size of this client 32 | corpus_size: usize, 33 | /// The client config for this observers/testcase combination 34 | client_config: EventConfig, 35 | /// The time of generation of the event 36 | time: Duration, 37 | /// The executions of this client 38 | executions: usize, 39 | /// The original sender if, if forwarded 40 | forward_id: Option, 41 | }, 42 | /// New stats event to monitor. 43 | UpdateExecStats { 44 | /// The time of generation of the [`Event`] 45 | time: Duration, 46 | /// The executions of this client 47 | executions: usize, 48 | /// [`PhantomData`] 49 | phantom: PhantomData, 50 | }, 51 | /// New user stats event to monitor. 52 | UpdateUserStats { 53 | /// Custom user monitor name 54 | name: String, 55 | /// Custom user monitor value 56 | value: UserStats, 57 | /// [`PhantomData`] 58 | phantom: PhantomData, 59 | }, 60 | /// New monitor with performance monitor. 61 | #[cfg(feature = "introspection")] 62 | UpdatePerfMonitor { 63 | /// The time of generation of the event 64 | time: Duration, 65 | /// The executions of this client 66 | executions: usize, 67 | /// Current performance statistics 68 | introspection_monitor: Box, 69 | 70 | /// phantomm data 71 | phantom: PhantomData, 72 | }, 73 | /// A new objective was found 74 | Objective { 75 | /// Objective corpus size 76 | objective_size: usize, 77 | }, 78 | /// Write a new log 79 | Log { 80 | /// the severity level 81 | severity_level: LogSeverity, 82 | /// The message 83 | message: String, 84 | /// `PhantomData` 85 | phantom: PhantomData, 86 | }, 87 | /// Sends a custom buffer to other clients 88 | CustomBuf { 89 | /// The buffer 90 | buf: Vec, 91 | /// Tag of this buffer 92 | tag: String, 93 | }, 94 | /*/// A custom type 95 | Custom { 96 | // TODO: Allow custom events 97 | // custom_event: Box>, 98 | },*/ 99 | } 100 | 101 | impl Event 102 | where 103 | I: Input, 104 | { 105 | pub fn name(&self) -> &str { 106 | match self { 107 | Event::NewTestcase { 108 | input: _, 109 | client_config: _, 110 | corpus_size: _, 111 | exit_kind: _, 112 | observers_buf: _, 113 | time: _, 114 | executions: _, 115 | forward_id: _, 116 | } => "Testcase", 117 | Event::UpdateExecStats { 118 | time: _, 119 | executions: _, 120 | phantom: _, 121 | } 122 | | Event::UpdateUserStats { 123 | name: _, 124 | value: _, 125 | phantom: _, 126 | } => "Stats", 127 | #[cfg(feature = "introspection")] 128 | Event::UpdatePerfMonitor { 129 | time: _, 130 | executions: _, 131 | introspection_monitor: _, 132 | phantom: _, 133 | } => "PerfMonitor", 134 | Event::Objective { .. } => "Objective", 135 | Event::Log { 136 | severity_level: _, 137 | message: _, 138 | phantom: _, 139 | } => "Log", 140 | Event::CustomBuf { .. } => "CustomBuf", 141 | /*Event::Custom { 142 | sender_id: _, /*custom_event} => custom_event.name()*/ 143 | } => "todo",*/ 144 | } 145 | } 146 | } 147 | 148 | 149 | -------------------------------------------------------------------------------- /libpresifuzz_ec/src/llmp.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | // TODO: Launch multiple fuzzer instance in parallel 6 | //! The [`Launcher`] launches multiple fuzzer instances in parallel. 7 | //! Thanks to it, we won't need a `for` loop in a shell script... 8 | //! 9 | //! It will hide child output, unless the settings indicate otherwise, or the `LIBAFL_DEBUG_OUTPUT` env variable is set. 10 | //! 11 | //! To use multiple [`Launcher`]`s` for individual configurations, 12 | //! we can set `spawn_broker` to `false` on all but one. 13 | //! 14 | //! To connect multiple nodes together via TCP, we can use the `remote_broker_addr`. 15 | //! (this requires the `llmp_bind_public` compile-time feature for `LibAFL`). 16 | //! 17 | //! On `Unix` systems, the [`Launcher`] will use `fork` if the `fork` feature is used for `LibAFL`. 18 | //! Else, it will start subsequent nodes with the same commandline, and will set special `env` variables accordingly. 19 | 20 | #[cfg(feature = "std")] 21 | use core::marker::PhantomData; 22 | use core::{ 23 | fmt::{self, Debug, Formatter}, 24 | }; 25 | 26 | #[cfg(feature = "std")] 27 | use libafl::{ 28 | events::{ 29 | EventConfig, 30 | }, 31 | monitors::Monitor, 32 | state::{HasExecutions, State, HasCorpus}, 33 | inputs::{Input}, 34 | Error, 35 | }; 36 | #[cfg(feature = "std")] 37 | use typed_builder::TypedBuilder; 38 | 39 | use crate::manager::SyncOnDiskRestartingMgr; 40 | use crate::manager::SyncOnDiskManagerKind; 41 | use crate::manager::SyncOnDiskRestartingEventManager; 42 | 43 | /// The (internal) `env` that indicates we're running as client. 44 | const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT"; 45 | 46 | /// Provides a [`Launcher`], which can be used to launch a fuzzing run on a specified list of cores 47 | /// 48 | /// Will hide child output, unless the settings indicate otherwise, or the `LIBAFL_DEBUG_OUTPUT` env variable is set. 49 | #[cfg(feature = "std")] 50 | #[allow( 51 | clippy::type_complexity, 52 | missing_debug_implementations, 53 | clippy::ignored_unit_patterns 54 | )] 55 | #[derive(TypedBuilder)] 56 | pub struct Launcher<'a, CF, MT, S, I> 57 | where 58 | CF: FnOnce(Option, SyncOnDiskRestartingEventManager, u32) -> Result<(), Error>, 59 | S::Input: 'a, 60 | MT: Monitor, 61 | S: State + 'a + HasCorpus, 62 | I: Input, 63 | { 64 | /// The monitor instance to use 65 | monitor: MT, 66 | /// The configuration 67 | configuration: EventConfig, 68 | #[builder(default = "/tmp/corpus".to_string())] 69 | sync_dir: String, 70 | /// The 'main' function to run for each client forked. This probably shouldn't return 71 | #[builder(default, setter(strip_option))] 72 | run_client: Option, 73 | /// A file name to write all client output to 74 | #[builder(default = None)] 75 | stdout_file: Option<&'a str>, 76 | /// A file name to write all client stderr output to. If not specified, output is sent to 77 | /// `stdout_file`. 78 | #[builder(default = None)] 79 | stderr_file: Option<&'a str>, 80 | #[builder(setter(skip), default = PhantomData)] 81 | phantom_data: PhantomData<(&'a S, I)>, 82 | } 83 | 84 | impl Debug for Launcher<'_, CF, MT, S, I> 85 | where 86 | CF: FnOnce(Option, SyncOnDiskRestartingEventManager, u32) -> Result<(), Error>, 87 | MT: Monitor + Clone, 88 | S: State + HasCorpus, 89 | I: Input, 90 | { 91 | fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { 92 | f.debug_struct("Launcher") 93 | .field("configuration", &self.configuration) 94 | .field("stdout_file", &self.stdout_file) 95 | .field("stderr_file", &self.stderr_file) 96 | .field("sync_dir", &self.sync_dir) 97 | .finish_non_exhaustive() 98 | } 99 | } 100 | 101 | #[cfg(feature = "std")] 102 | impl<'a, CF, MT, S, I> Launcher<'a, CF, MT, S, I> 103 | where 104 | CF: FnOnce(Option, SyncOnDiskRestartingEventManager, u32) -> Result<(), Error>, 105 | MT: Monitor + Clone, 106 | S: State + HasExecutions + HasCorpus, 107 | I: Input, 108 | { 109 | 110 | /// Launch the broker and the clients and fuzz 111 | #[cfg(all(feature = "std", any(windows, not(feature = "fork"))))] 112 | #[allow(unused_mut, clippy::match_wild_err_arm)] 113 | pub fn launch(&mut self) -> Result<(), Error> { 114 | 115 | let is_client = std::env::var(_AFL_LAUNCHER_CLIENT); 116 | 117 | match is_client { 118 | Ok(core_conf) => { 119 | let core_id = core_conf.parse()?; 120 | 121 | println!("I am client!! with id {}", core_id); 122 | 123 | // the actual client. do the fuzzing 124 | let (state, mgr) = SyncOnDiskRestartingMgr::::builder() 125 | .kind(SyncOnDiskManagerKind::Client { 126 | cpu_core: Some(core_id), 127 | }) 128 | .sync_dir(self.sync_dir.clone()) 129 | .configuration(self.configuration) 130 | .build() 131 | .launch()?; 132 | 133 | println!("Ready to fuzz!"); 134 | 135 | return (self.run_client.take().unwrap())(state, mgr, core_id); 136 | 137 | } 138 | Err(std::env::VarError::NotPresent) => { 139 | // I am a broker 140 | // before going to the broker loop, spawn n clients 141 | println!("I am broker!!."); 142 | 143 | SyncOnDiskRestartingMgr::::builder() 144 | .monitor(Some(self.monitor.clone())) 145 | .kind(SyncOnDiskManagerKind::Broker) 146 | .configuration(self.configuration) 147 | .sync_dir(self.sync_dir.clone()) 148 | .build() 149 | .launch()?; 150 | } 151 | Err(_) => panic!("Env variables are broken, received non-unicode!"), 152 | }; 153 | 154 | Ok(()) 155 | } 156 | } 157 | 158 | -------------------------------------------------------------------------------- /libpresifuzz_feedbacks/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libpresifuzz_feedbacks" 7 | version = "0.0.2" 8 | authors = ["Nassim Corteggiani "] 9 | edition = "2021" 10 | description = "Feedback to analyze coverage from a VerdiObserver" 11 | repository = "https://github.com/IntelLabs/PreSiFuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std"] 19 | const_false = [] 20 | const_true = [] 21 | std = [] 22 | serdeany_autoreg = ["std"] 23 | 24 | [build-dependencies] 25 | cc = "1" 26 | 27 | [lints.rust] 28 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(serdeany_autoreg)'] } 29 | 30 | [dependencies] 31 | libafl = { version = "0.11.2"} 32 | libafl_bolts = { version = "0.11.2"} 33 | nix = "0.24" 34 | num-traits = { version = "0.2", default-features = false } 35 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 36 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 37 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 38 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 39 | libc = "0.2" 40 | fs_extra = "1.2.0" 41 | libpresifuzz_observers = { path = "../libpresifuzz_observers"} 42 | 43 | -------------------------------------------------------------------------------- /libpresifuzz_feedbacks/src/differential_feedback.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use std::str; 6 | use core::{fmt::Debug}; 7 | use serde::{Deserialize, Serialize}; 8 | use libafl::{ 9 | events::EventFirer, 10 | executors::ExitKind, 11 | inputs::{UsesInput}, 12 | observers::{ObserversTuple}, 13 | Error, 14 | feedbacks::Feedback, 15 | state::{State}, 16 | }; 17 | 18 | use libafl_bolts::Named; 19 | 20 | use libpresifuzz_observers::trace_observer::{ExecTrace, ExecTraceParser}; 21 | 22 | 23 | #[derive(Clone, Serialize, Deserialize, Debug)] 24 | pub struct DifferentialFeedback 25 | { 26 | ref_observer_name: String, 27 | core_observer_name: String, 28 | rf_ob: R, 29 | co_ob: C, 30 | } 31 | 32 | impl Feedback for DifferentialFeedback 33 | where 34 | S: UsesInput + State, 35 | R: ExecTraceParser, 36 | C: ExecTraceParser, 37 | { 38 | 39 | #[allow(clippy::wrong_self_convention)] 40 | fn is_interesting( 41 | &mut self, 42 | _state: &mut S, 43 | _manager: &mut EM, 44 | _input: &S::Input, 45 | observers: &OT, 46 | _exit_kind: &ExitKind, 47 | ) -> Result 48 | where 49 | EM: EventFirer, 50 | OT: ObserversTuple 51 | { 52 | let ref_observer = observers.match_name::>(&self.ref_observer_name).unwrap(); 53 | let core_observer = observers.match_name::>(&self.core_observer_name).unwrap(); 54 | 55 | if core_observer.cnt() == ref_observer.cnt() { 56 | return Ok(false); 57 | } 58 | Ok(true) 59 | } 60 | } 61 | 62 | impl Named for DifferentialFeedback 63 | { 64 | #[inline] 65 | fn name(&self) -> &str { 66 | self.core_observer_name.as_str() 67 | } 68 | } 69 | 70 | impl DifferentialFeedback 71 | where 72 | R: ExecTraceParser, 73 | C: ExecTraceParser, 74 | { 75 | #[must_use] 76 | pub fn new(ref_observer_name: &'static str, core_observer_name: &'static str) -> Self { 77 | Self { 78 | core_observer_name: core_observer_name.to_string(), 79 | ref_observer_name: ref_observer_name.to_string(), 80 | rf_ob: R::new(), 81 | co_ob: C::new(), 82 | } 83 | } 84 | } 85 | 86 | 87 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /libpresifuzz_feedbacks/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | extern crate fs_extra; 6 | 7 | pub mod verdi_feedback; 8 | pub mod verdi_xml_feedback; 9 | pub mod transferred; 10 | pub mod cycle_feedback; 11 | pub mod differential_feedback; 12 | -------------------------------------------------------------------------------- /libpresifuzz_feedbacks/src/transferred.rs: -------------------------------------------------------------------------------- 1 | //! Feedbacks and associated metadata for detecting whether a given testcase was transferred from 2 | //! another node. 3 | 4 | use libafl_bolts::{impl_serdeany, Error, Named}; 5 | use serde::{Deserialize, Serialize}; 6 | 7 | use libafl::{ 8 | events::EventFirer, 9 | executors::ExitKind, 10 | feedbacks::Feedback, 11 | observers::ObserversTuple, 12 | state::{HasMetadata, State}, 13 | }; 14 | 15 | /// Constant name of the [`TransferringMetadata`]. 16 | pub const TRANSFERRED_FEEDBACK_NAME: &str = "transferred_feedback_internal"; 17 | 18 | /// Metadata which denotes whether we are currently transferring an input. Implementors of 19 | /// multi-node communication systems (like [`crate::events::LlmpEventManager`]) should wrap any 20 | /// [`crate::EvaluatorObservers::evaluate_input_with_observers`] or 21 | /// [`crate::ExecutionProcessor::process_execution`] calls with setting this metadata to true/false 22 | /// before and after. 23 | #[derive(Copy, Clone, Debug, Deserialize, Serialize)] 24 | pub struct TransferringMetadata { 25 | transferring: bool, 26 | } 27 | 28 | impl_serdeany!(TransferringMetadata); 29 | 30 | impl TransferringMetadata { 31 | /// Indicate to the metadata that we are currently transferring data. 32 | pub fn set_transferring(&mut self, transferring: bool) { 33 | self.transferring = transferring; 34 | } 35 | } 36 | 37 | /// Simple feedback which may be used to test whether the testcase was transferred from another node 38 | /// in a multi-node fuzzing arrangement. 39 | #[derive(Copy, Clone, Debug)] 40 | pub struct TransferredFeedback; 41 | 42 | impl Named for TransferredFeedback { 43 | fn name(&self) -> &str { 44 | TRANSFERRED_FEEDBACK_NAME 45 | } 46 | } 47 | 48 | impl Feedback for TransferredFeedback 49 | where 50 | S: HasMetadata + State, 51 | { 52 | fn init_state(&mut self, state: &mut S) -> Result<(), Error> { 53 | state.add_metadata(TransferringMetadata { transferring: true }); 54 | Ok(()) 55 | } 56 | 57 | fn is_interesting( 58 | &mut self, 59 | state: &mut S, 60 | _manager: &mut EM, 61 | _input: &S::Input, 62 | _observers: &OT, 63 | _exit_kind: &ExitKind, 64 | ) -> Result 65 | where 66 | EM: EventFirer, 67 | OT: ObserversTuple, 68 | { 69 | Ok(state.metadata::()?.transferring) 70 | } 71 | } 72 | 73 | -------------------------------------------------------------------------------- /libpresifuzz_mutators/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libpresifuzz_mutators" 7 | authors = ["Nassim Corteggiani , Sergej Schumilo "] 8 | version = "0.0.2" 9 | edition = "2021" 10 | description = "Mutators for hardware fuzzing" 11 | repository = "https://github.com/intel-sandbox/labs.presifuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std"] 19 | tui = [] 20 | std = [] 21 | debug = [] 22 | python = ["std"] 23 | 24 | [build-dependencies] 25 | cc = "1" 26 | 27 | [lints.rust] 28 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(python)'] } 29 | 30 | [dependencies] 31 | libafl = { version = "0.11.2"} 32 | libafl_bolts = { version = "0.11.2"} 33 | nix = "0.24" 34 | num-traits = { version = "0.2", default-features = false } 35 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 36 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 37 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 38 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 39 | libc = "0.2" 40 | fs_extra = "1.2.0" 41 | hamming = "0.1" 42 | lazy_static = "1.4.0" 43 | cargo-valgrind = "2.1.0" 44 | yaml-rust = "0.4.5" 45 | libpresifuzz_observers = { path = "../libpresifuzz_observers"} 46 | libpresifuzz_riscv = { path = "../libpresifuzz_riscv"} 47 | 48 | -------------------------------------------------------------------------------- /libpresifuzz_mutators/README.md: -------------------------------------------------------------------------------- 1 | # Command for testing 2 | 3 | To run the different tests: 4 | ``` 5 | cargo test -- --nocapture 6 | ``` 7 | 8 | To disassemble the payload section: 9 | ``` 10 | riscv64-unknown-elf-objdump -S -D ./testcase.elf | awk -v RS= '/^[[:xdigit:]]+ /' | head -n 20 11 | ``` 12 | 13 | To change endianess from raw data pinted by the tests: 14 | ``` 15 | python3 16 | >>> a = [177, 238, 129, 131] 17 | >>> print(hex(int.from_bytes(a, "big"))) 18 | 19 | ``` 20 | -------------------------------------------------------------------------------- /libpresifuzz_observers/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libpresifuzz_observers" 7 | authors = ["Nassim Corteggiani , Sergej Schumilo "] 8 | version = "0.0.2" 9 | edition = "2021" 10 | description = "Observer to collect coverage from vdb using VERDI NPI" 11 | repository = "https://github.com/IntelLabs/PreSiFuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std", "csv_dump"] 19 | input_injection = [] 20 | std = [] 21 | csv_dump = [] 22 | 23 | [build] 24 | build = "build.rs" 25 | 26 | [build-dependencies] 27 | cc = "1" 28 | 29 | [dependencies] 30 | libafl = { version = "0.11.2"} 31 | libafl_bolts = { version = "0.11.2"} 32 | nix = "0.24" 33 | num-traits = { version = "0.2", default-features = false } 34 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 35 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 36 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 37 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 38 | libc = "0.2" 39 | fs_extra = "1.2.0" 40 | csv = "1.3.0" 41 | serde_yaml = "0.9.27" 42 | hex = "0.4.3" 43 | lazy_static = "1.4.0" 44 | elf = "0.7.4" 45 | rand = "0.8.5" 46 | tempfile = "3.9.0" 47 | flate2 = "1.0" 48 | quick-xml = "0.32.0" 49 | regex = "1" 50 | -------------------------------------------------------------------------------- /libpresifuzz_observers/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use std::path::Path; 6 | use std::env; 7 | 8 | fn main() { 9 | 10 | println!("Compiling using profile {:?}. Please condiser using test profile to fake LibNPI.so", env::var("PROFILE")); 11 | 12 | if env::var("PRESIFUZZ_DUMMY").is_ok() { 13 | cc::Build::new() 14 | .cpp(true) // Switch to C++ library compilation. 15 | .file("./src/npi_c.c") 16 | .flag("-DDUMMY_LIB") 17 | .compile("npi_c"); 18 | 19 | } else { 20 | let key = "VERDI_HOME"; 21 | let mut verdi_lib = match env::var(key) { 22 | Ok(val) => val, 23 | Err(_e) => "".to_string(), 24 | }; 25 | 26 | let mut verdi_inc = verdi_lib.clone(); 27 | 28 | if verdi_inc.is_empty() || verdi_lib.is_empty() { 29 | println!("The env variable 'VERDI_HOME' is not set"); 30 | return; 31 | } 32 | 33 | verdi_lib.push_str("/share/NPI/lib/linux64"); 34 | verdi_inc.push_str("/share/NPI/inc"); 35 | 36 | let npi_library_path = Path::new(&verdi_lib); 37 | let npi_include_path = Path::new(&verdi_inc); 38 | 39 | cc::Build::new() 40 | .cpp(true) // Switch to C++ library compilation. 41 | .file("./src/npi_c.c") 42 | .flag("-lNPI -ldl -lpthread -lrt -lz") 43 | .include(npi_include_path) 44 | .include(npi_library_path) 45 | .compile("npi_c"); 46 | println!("cargo:rustc-link-lib=NPI"); 47 | 48 | 49 | let key = "VERDI_HOME"; 50 | let verdi_home = match env::var(key) { 51 | Ok(val) => val, 52 | Err(_e) => "".to_string(), 53 | }; 54 | 55 | println!("cargo:rustc-link-search=native={}/share/NPI/lib/linux64", verdi_home); 56 | } 57 | } 58 | 59 | -------------------------------------------------------------------------------- /libpresifuzz_observers/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | pub mod verdi_observer; 6 | pub mod verdi_xml_observer; 7 | pub mod trace_observer; 8 | -------------------------------------------------------------------------------- /libpresifuzz_observers/src/trace_observer.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use libafl::{ 6 | executors::{ExitKind}, 7 | observers::{Observer}, 8 | Error, 9 | inputs::{UsesInput}, 10 | }; 11 | 12 | use core::{fmt::Debug}; 13 | use serde::{Deserialize, Serialize}; 14 | use libafl_bolts::{HasLen, Named}; 15 | 16 | use std::fs::File; 17 | 18 | extern crate fs_extra; 19 | use std::{str}; 20 | use regex::Regex; 21 | use std::io::{self, BufRead}; 22 | 23 | 24 | 25 | 26 | #[derive(Copy, Clone, Serialize, Deserialize, Debug)] 27 | pub enum OpType { 28 | Read, 29 | Write, 30 | } 31 | 32 | #[derive(Copy, Clone, Serialize, Deserialize, Debug)] 33 | pub struct MemOp { 34 | pub op_type: OpType, 35 | pub address: u64, 36 | pub value: u64, 37 | 38 | } 39 | 40 | #[derive(Clone, Serialize, Deserialize, Debug)] 41 | pub struct RegOp { 42 | pub op_type: OpType, 43 | pub name: String, 44 | pub value: u64, 45 | 46 | } 47 | 48 | #[derive(Clone, Serialize, Deserialize, Debug)] 49 | pub enum OpLog { 50 | RegOp(RegOp), 51 | MemOp(MemOp), 52 | } 53 | 54 | #[derive(Clone, Serialize, Deserialize, Debug)] 55 | pub struct TraceLog { 56 | pub pc: u64, 57 | pub inst: u64, 58 | pub ops: Vec, 59 | } 60 | 61 | pub trait ExecTraceParser { 62 | fn new() -> Self; 63 | fn parse(&self, workdir: &str) -> Result, Error> ; 64 | } 65 | 66 | #[derive(Clone, Serialize, Deserialize, Debug)] 67 | #[allow(clippy::unsafe_derive_deserialize)] 68 | pub struct ExecTrace 69 | { 70 | name: String, 71 | workdir: String, 72 | trace: Vec, 73 | trace_parser: T, 74 | } 75 | 76 | impl ExecTrace 77 | where 78 | T: ExecTraceParser, 79 | { 80 | pub fn new(name: &str, workdir: &str) -> Self { 81 | Self { 82 | name: name.to_string(), 83 | trace: Vec::::new(), 84 | workdir: workdir.to_string(), 85 | trace_parser: T::new(), 86 | } 87 | } 88 | 89 | pub fn cnt(&self) -> usize { 90 | self.trace.len() 91 | } 92 | } 93 | 94 | 95 | impl Named for ExecTrace 96 | where 97 | T: ExecTraceParser, 98 | { 99 | fn name(&self) -> &str { 100 | &self.name 101 | } 102 | } 103 | 104 | impl HasLen for ExecTrace 105 | where 106 | T: ExecTraceParser, 107 | { 108 | fn len(&self) -> usize { 109 | self.trace.len() 110 | } 111 | } 112 | 113 | impl Observer for ExecTrace 114 | where 115 | S: UsesInput, 116 | T: ExecTraceParser, 117 | { 118 | fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { 119 | Ok(()) 120 | } 121 | 122 | #[inline] 123 | fn post_exec( 124 | &mut self, 125 | _state: &mut S, 126 | _input: &S::Input, 127 | _exit_kind: &ExitKind, 128 | ) -> Result<(), Error> { 129 | 130 | self.trace = self.trace_parser.parse(&self.workdir).unwrap(); 131 | 132 | Ok(()) 133 | } 134 | } 135 | 136 | #[derive(Copy, Clone, Serialize, Deserialize, Debug)] 137 | pub struct SpikeExecTrace; 138 | 139 | impl ExecTraceParser for SpikeExecTrace 140 | { 141 | fn new() -> Self { 142 | SpikeExecTrace {} 143 | } 144 | fn parse(&self, workdir: &str) -> Result, Error> { 145 | let mut trace = Vec::::new(); 146 | 147 | let spike_file = format!("{}/spike.err", workdir); 148 | 149 | let file = File::open(spike_file).expect("Unable to open spike trace file"); 150 | let reader = io::BufReader::new(file); 151 | 152 | let spike_store_commit_re = Regex::new(r"core\s+\d+: \d+ 0x(\w+) \(0x(\w+)\)\s+mem\s+0x(\w+)\s+0x(\w+)").unwrap(); 153 | let spike_rest_commit_re = Regex::new(r"core\s+\d+: \d+ 0x(\w+) \(0x(\w+)\)\s+(\w+)\s+0x(\w+)(\s+(\w+)\s+0x(\w+))?").unwrap(); 154 | for line in reader.lines() { 155 | if let Ok(log_line) = &line { 156 | if let Some(caps) = spike_store_commit_re.captures(log_line) { 157 | let ops = vec![ 158 | OpLog::MemOp(MemOp{op_type: OpType::Write, address: u64::from_str_radix(&caps[3], 16).unwrap(), value: u64::from_str_radix(&caps[4], 16).unwrap()}) 159 | ]; 160 | trace.push(TraceLog { 161 | pc: u64::from_str_radix(&caps[1], 16).unwrap(), 162 | inst: u64::from_str_radix(&caps[2], 16).unwrap(), 163 | ops, 164 | }); 165 | } 166 | else if let Some(caps) = spike_rest_commit_re.captures(log_line) { 167 | let mut ops = vec![ 168 | OpLog::RegOp(RegOp{op_type: OpType::Read, name: caps[3].to_string(), value: u64::from_str_radix(&caps[4], 16).unwrap()}) 169 | ]; 170 | 171 | if caps.get(5) != None && &caps[6] == "mem" { 172 | ops.push(OpLog::MemOp(MemOp{op_type: OpType::Read, address: u64::from_str_radix(&caps[7], 16).unwrap(), value: u64::from_str_radix(&caps[4], 16).unwrap()})); 173 | } else if caps.get(5) != None { 174 | ops.push(OpLog::RegOp(RegOp{op_type: OpType::Read, name: caps[6].to_string(), value: u64::from_str_radix(&caps[7], 16).unwrap()})); 175 | } 176 | 177 | trace.push(TraceLog { 178 | pc: u64::from_str_radix(&caps[1], 16).unwrap(), 179 | inst: u64::from_str_radix(&caps[2], 16).unwrap(), 180 | ops, 181 | }); 182 | } 183 | } 184 | } 185 | Ok(trace) 186 | } 187 | } 188 | 189 | 190 | 191 | // TODO: Re-enable this test using vdb from open source design 192 | #[cfg(feature = "std")] 193 | #[cfg(test)] 194 | mod tests { 195 | 196 | extern crate fs_extra; 197 | use libafl_bolts::prelude::StdRand; 198 | use libafl::prelude::BytesInput; 199 | use libafl::executors::{ExitKind}; 200 | use libafl_bolts::current_time; 201 | use libafl::prelude::InMemoryCorpus; 202 | use libafl::prelude::ConstFeedback; 203 | use crate::trace_observer::{ExecTrace, SpikeExecTrace}; 204 | use libafl::prelude::StdState; 205 | use libafl::state::HasMaxSize; 206 | use libafl::observers::Observer; 207 | 208 | #[test] 209 | fn test_spike_trace_observer() { 210 | 211 | let input = BytesInput::new(vec![1, 2, 3, 4]); 212 | 213 | let rand = StdRand::with_seed(current_time().as_nanos() as u64); 214 | let corpus = InMemoryCorpus::::new(); 215 | 216 | let mut feedback = ConstFeedback::new(true); 217 | let mut objective = ConstFeedback::new(false); 218 | 219 | let mut spike_trace_observer = ExecTrace::::new("spike_trace", "./"); 220 | 221 | let mut state = StdState::new( 222 | rand, 223 | corpus, 224 | InMemoryCorpus::::new(), 225 | &mut feedback, 226 | &mut objective, 227 | ) 228 | .unwrap(); 229 | state.set_max_size(1024); 230 | 231 | let _ = spike_trace_observer.post_exec(&mut state, &input, &ExitKind::Ok); 232 | println!("{:?}", spike_trace_observer.trace.len()) 233 | } 234 | } 235 | 236 | -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/.cmoptions: -------------------------------------------------------------------------------- 1 | Instrument 2 | cond 16643 3 | line 3 4 | fsm 65539 5 | tgl 8 6 | assign 0 7 | obc 0 8 | path 3 9 | branch 3 10 | Count 0 11 | Glitch -1 12 | cm_tglmda 0 13 | cm_tglstructarr 1 14 | cm_tglcount 0 15 | cm_tglunencryptedsignals 0 16 | cm_hier 0 17 | InstrSpecs 2 18 | TglUnpkdLimitVal -1 19 | IrisFlow -1 20 | scalene_no_dump_design 0 21 | cm_assert_hier 0 22 | cm_common_hier 0 23 | sdc 0 24 | CmHierOpt -1 -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/.mode64: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/.mode64 -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/.vdb_version: -------------------------------------------------------------------------------- 1 | V-2023.12 -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/.cm_totalPaths: -------------------------------------------------------------------------------- 1 | 49957302 -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/auxiliary/dve_debug.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/auxiliary/dve_debug.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/auxiliary/vcmArguments.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/auxiliary/vcmArguments.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/auxiliary/verilog.instance_parameters.txt: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/auxiliary/verilog.instance_parameters.txt -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/design/verilog.design.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/design/verilog.design.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/branch.verilog.exclude.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/branch.verilog.exclude.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/branch.verilog.info.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/branch.verilog.info.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/branch.verilog.shape.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/branch.verilog.shape.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/cond.verilog.exclude.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/cond.verilog.exclude.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/cond.verilog.info.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/cond.verilog.info.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/cond.verilog.shape.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/cond.verilog.shape.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/fsm.verilog.exclude.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/fsm.verilog.shape.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/fsm.verilog.shape.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/line.verilog.exclude.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/line.verilog.exclude.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/line.verilog.info.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/line.verilog.info.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/line.verilog.shape.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/line.verilog.shape.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/path.verilog.shape.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/path.verilog.shape.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/tgl.verilog.info.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/tgl.verilog.info.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/shape/tgl.verilog.shape.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/shape/tgl.verilog.shape.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/branch.verilog.data.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/branch.verilog.data.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/cond.verilog.data.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/cond.verilog.data.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/fsm.verilog.data.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/fsm.verilog.data.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/line.verilog.data.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/line.verilog.data.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/siminfo.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/siminfo.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/tgl.verilog.data.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/tgl.verilog.data.xml -------------------------------------------------------------------------------- /libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/vcmArguments.xml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IntelLabs/PreSiFuzz/2bbd19ade7cb62ac6961924654aca5b218df85a4/libpresifuzz_observers/test.vdb/snps/coverage/db/testdata/test/vcmArguments.xml -------------------------------------------------------------------------------- /libpresifuzz_riscv/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libpresifuzz_riscv" 7 | version = "0.0.1" 8 | authors = ["Nassim Corteggiani , Sergej Schumilo "] 9 | edition = "2021" 10 | description = "Carystus specific components used for Presifuzz" 11 | repository = "https://github.com/intel-sandbox/labs.presifuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std"] 19 | tui = [] 20 | std = [] 21 | 22 | [build-dependencies] 23 | cc = "1" 24 | 25 | [dependencies] 26 | libafl = { version = "0.11.2"} 27 | libafl_bolts = { version = "0.11.2"} 28 | nix = "0.24" 29 | num-traits = { version = "0.2", default-features = false } 30 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 31 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 32 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 33 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 34 | libc = "0.2" 35 | fs_extra = "1.2.0" 36 | csv = "1.3.0" 37 | serde_yaml = "0.9.27" 38 | hex = "0.4.3" 39 | lazy_static = "1.4.0" 40 | elf = "0.7.4" 41 | rand = "0.8.5" 42 | tempfile = "3.9.0" 43 | indexmap = "2.2.5" 44 | -------------------------------------------------------------------------------- /libpresifuzz_riscv/src/defines.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use crate::cpu_profile::ALL_RISCV_INSTR; 6 | use std::{collections::HashMap, fs::File, path::Path, io::{self, BufRead}}; 7 | 8 | const RISCV_COFI: &'static [&'static str] = &[ 9 | /* conditional branch instructions */ 10 | "c.beqz", "c.bnez", "beq", "beqz", "bge", "bgeu", "bgez", "blt", "bltu", "bltz", "bne", "bnez", 11 | 12 | /* unconditional relative jumps */ 13 | "c.j", "j", "jal", 14 | 15 | /* far jumps */ 16 | "c.jalr", "c.jr", "jalr", "jr", 17 | 18 | /* far transfer (not sure if we need to handle them to be honest) */ 19 | //"ret", "mret" 20 | ]; 21 | 22 | lazy_static! { 23 | 24 | pub static ref ALL_RISCV_INSTR_MAP: HashMap<&'static str, usize> = ALL_RISCV_INSTR.iter().enumerate().map(|x| (*x.1, x.0)).collect(); 25 | pub static ref ALL_BR_INSTR_MAP: HashMap<&'static str, usize> = ALL_BR_INSTR.iter().enumerate().map(|x| (*x.1, x.0)).collect(); 26 | 27 | pub static ref RISCV_COFI_MAP: HashMap<&'static str, usize> = RISCV_COFI.iter().enumerate().map(|x| (*x.1, x.0)).collect(); 28 | 29 | pub static ref BR_LIST_MAP: HashMap<&'static str, usize> = BR_LIST.iter().enumerate().map(|x| (*x.1, x.0)).collect(); 30 | pub static ref C_BR_LIST_MAP: HashMap<&'static str, usize> = C_BR_LIST.iter().enumerate().map(|x| (*x.1, x.0)).collect(); 31 | pub static ref BR_OFFSET_LIST_MAP: HashMap = BR_OFFSET_LIST.iter().enumerate().map(|x| (*x.1, x.0)).collect(); 32 | pub static ref C_BR_OFFSET_LIST_MAP: HashMap = C_BR_OFFSET_LIST.iter().enumerate().map(|x| (*x.1, x.0)).collect(); 33 | 34 | /* 35 | static ref RISCV_OBJDUMP_2_SPIKE_MAP: HashMap<&'static str, &'static str> = { 36 | let mut m = HashMap::new(); 37 | 38 | m.insert("lnop", "nop"); 39 | 40 | m 41 | }; 42 | 43 | static ref RISCV_SPIKE_2_OBJDUMP_MAP: HashMap<&'static str, &'static str> = { 44 | let mut m = HashMap::new(); 45 | 46 | m.insert("c.add", "add"); 47 | m.insert("c.addi", "addi"); 48 | m.insert("c.addi16sp", "addi"); 49 | m.insert("c.addi4spn", "addi"); 50 | m.insert("c.addiw", "addiw"); 51 | m.insert("c.addw", "addw"); 52 | m.insert("c.and", "and"); 53 | m.insert("c.andi", "andi"); 54 | m.insert("c.beqz", "beqz"); 55 | m.insert("c.bnez", "bnez"); 56 | m.insert("c.ebreak", "ebreak"); 57 | m.insert("c.j", "j"); 58 | 59 | m.insert("c.jalr", "jalr"); 60 | m.insert("c.jr", "jr"); 61 | m.insert("c.ld", "ld"); 62 | m.insert("c.ldsp", "ld"); 63 | m.insert("c.li", "li"); 64 | 65 | m.insert("c.lui", "lui"); 66 | m.insert("c.lw", "lw"); 67 | m.insert("c.lwsp", "lw"); 68 | m.insert("c.mv", "mv"); 69 | m.insert("c.nop", "nop"); 70 | 71 | m.insert("c.or", "or"); 72 | m.insert("c.sd", "sd"); 73 | m.insert("c.sdsp", "sd"); 74 | 75 | 76 | m.insert("c.sdsp", "sd"); 77 | m.insert("c.slli", "slli"); 78 | m.insert("c.srai", "srai"); 79 | m.insert("c.srli", "srli"); 80 | m.insert("c.sub", "sub"); 81 | m.insert("c.subw", "subw"); 82 | m.insert("c.sw", "sw"); 83 | m.insert("c.swsp", "sw"); 84 | m.insert("c.unimp", "unimp"); 85 | m.insert("c.xor", "xor"); 86 | 87 | m 88 | }; 89 | */ 90 | } 91 | 92 | pub fn read_lines

(filename: P) -> io::Result>> 93 | where P: AsRef, { 94 | let file = File::open(filename)?; 95 | Ok(io::BufReader::new(file).lines()) 96 | } 97 | 98 | const HI: i64 = 4096; 99 | const LO: i64 = -4096; 100 | 101 | const C_HI: i64 = 254; // TODO: check me -> is this value correct? 102 | const C_LO: i64 = -256; 103 | 104 | /* ============= make_branch_offset metric ============= */ 105 | pub const BR_LIST: &'static [&'static str] = &[ 106 | "beq", "bne", "blt", "bge", "bltu", "bgeu", 107 | ]; 108 | 109 | pub const C_BR_LIST: &'static [&'static str] = &[ 110 | "c.beqz", "c.bnez" 111 | ]; 112 | 113 | pub const ALL_BR_INSTR: &'static [&'static str] = &[ 114 | "beq", "bne", "blt", "bge", "bltu", "bgeu", "c.beqz", "c.bnez" 115 | ]; 116 | 117 | pub const BR_OFFSET_LIST: &'static [i64] = &[ 118 | 0, -2, -4, -6, -8, 2, 4, 6, 8, 119 | HI, HI-2, HI-4, HI-6, HI-8, LO, LO+2, LO+4, LO+6, LO+8 120 | ]; 121 | 122 | pub const C_BR_OFFSET_LIST: &'static [i64] = &[ 123 | 0, -2, -4, -6, -8, 2, 4, 6, 8, 124 | C_HI, C_HI-2, C_HI-4, C_HI-6, C_HI-8, C_LO, C_LO+2, C_LO+4, C_LO+6, C_LO+8 125 | ]; 126 | 127 | 128 | pub const ALL_RISCV_INSTR_LIST_SIZE: usize = ALL_RISCV_INSTR.len(); 129 | pub const BR_OFFSET_LIST_SIZE: usize = ALL_BR_INSTR.len(); 130 | pub const BR_OFFSET_RESULT_BUF_SIZE: usize = BR_OFFSET_LIST.len()+2; 131 | 132 | pub const MAX_STATES: usize = 3; 133 | 134 | -------------------------------------------------------------------------------- /libpresifuzz_riscv/src/instruction.rs: -------------------------------------------------------------------------------- 1 | use serde::{Deserialize, Serialize}; 2 | 3 | ////////////////////////////////////////////////////////// 4 | /// 5 | /// 6 | ////////////////////////////////////////////////////////// 7 | /// An input for gramatron grammar fuzzing 8 | 9 | #[derive(Serialize, Deserialize, Clone, Debug, Default, PartialEq, Eq, Hash)] 10 | pub struct Instruction { 11 | pub instruction: u64, 12 | pub length: usize, 13 | pub mask: u32, 14 | pub mmatch: u32, 15 | pub mnemonic: String, 16 | pub extension: String, 17 | pub operands: Vec<(u32, u32)>, 18 | } 19 | 20 | -------------------------------------------------------------------------------- /libpresifuzz_riscv/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2024 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | pub mod elf; 6 | pub mod disas; 7 | pub mod dasm; 8 | pub mod states; 9 | pub mod defines; 10 | pub mod instruction; 11 | pub mod cpu_profile; 12 | 13 | #[macro_use] 14 | extern crate lazy_static; 15 | -------------------------------------------------------------------------------- /libpresifuzz_schedulers/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libpresifuzz_schedulers" 7 | version = "0.0.2" 8 | authors = ["Nassim Corteggiani , Sergej Schumilo "] 9 | edition = "2021" 10 | description = "Mutators for hardware fuzzing" 11 | repository = "https://github.com/IntelLabs/PreSiFuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std"] 19 | tui = [] 20 | std = [] 21 | debug = [] 22 | 23 | [build-dependencies] 24 | cc = "1" 25 | 26 | [dependencies] 27 | libafl = { version = "0.11.2"} 28 | libafl_bolts = { version = "0.11.2"} 29 | nix = "0.24" 30 | num-traits = { version = "0.2", default-features = false } 31 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 32 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 33 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 34 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 35 | libc = "0.2" 36 | fs_extra = "1.2.0" 37 | hamming = "0.1" 38 | lazy_static = "1.4.0" 39 | cargo-valgrind = "2.1.0" 40 | yaml-rust = "0.4.5" 41 | libpresifuzz_observers = { path = "../libpresifuzz_observers"} 42 | libpresifuzz_feedbacks = { path = "../libpresifuzz_feedbacks"} 43 | rand = "0.8.5" 44 | hashbrown = "0.14.3" 45 | -------------------------------------------------------------------------------- /libpresifuzz_schedulers/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | pub mod hwminimizer; 6 | -------------------------------------------------------------------------------- /libpresifuzz_stages/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libpresifuzz_stages" 7 | version = "0.0.2" 8 | authors = ["Nassim Corteggiani , Sergej Schumilo "] 9 | edition = "2021" 10 | description = "Mutators for hardware fuzzing" 11 | repository = "https://github.com/intel-sandbox/labs.presifuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std"] 19 | tui = [] 20 | std = [] 21 | debug = [] 22 | serialize_bytes = ["std"] 23 | introspection = ["std"] 24 | serdeany_autoreg = ["std"] 25 | 26 | [build-dependencies] 27 | cc = "1" 28 | 29 | [lints.rust] 30 | unexpected_cfgs = { level = "warn", check-cfg = ['cfg(serialize_bytes)', 'cfg(introspection)', 'cfg(serdeany_autoreg)'] } 31 | 32 | [dependencies] 33 | libafl = { version = "0.11.2"} 34 | libafl_bolts = { version = "0.11.2"} 35 | nix = "0.24" 36 | num-traits = { version = "0.2", default-features = false } 37 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 38 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 39 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 40 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 41 | libc = "0.2" 42 | fs_extra = "1.2.0" 43 | hamming = "0.1" 44 | lazy_static = "1.4.0" 45 | cargo-valgrind = "2.1.0" 46 | yaml-rust = "0.4.5" 47 | libpresifuzz_observers = { path = "../libpresifuzz_observers"} 48 | libpresifuzz_mutators = { path = "../libpresifuzz_mutators"} 49 | libpresifuzz_feedbacks = { path = "../libpresifuzz_feedbacks"} 50 | libpresifuzz_riscv = { path = "../libpresifuzz_riscv"} 51 | wait-timeout = "0.2.0" 52 | bincode = "1.3.3" 53 | postcard = "1.0.8" 54 | serde_json = "1.0.114" 55 | -------------------------------------------------------------------------------- /libpresifuzz_stages/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | pub mod sync; 6 | 7 | -------------------------------------------------------------------------------- /libpresifuzz_verilator/Cargo.toml: -------------------------------------------------------------------------------- 1 | # SPDX-FileCopyrightText: 2022 Intel Corporation 2 | # 3 | # SPDX-License-Identifier: Apache-2.0 4 | 5 | [package] 6 | name = "libafl_verilator" 7 | version = "0.0.1" 8 | authors = ["Nassim Corteggiani "] 9 | edition = "2021" 10 | description = "Observer to collect coverage from vdb using VERDI NPI" 11 | repository = "https://github.com/IntelLabs/PreSiFuzz" 12 | readme = "README.md" 13 | license = "Apache-2.0" 14 | categories = ["development-tools::testing"] 15 | keywords = ["fuzzing", "hardware", "simulation"] 16 | 17 | [features] 18 | default = ["std"] 19 | tui = [] 20 | std = [] 21 | 22 | # [build] 23 | # build = "build.rs" 24 | 25 | [build-dependencies] 26 | cc = "1" 27 | 28 | [dependencies] 29 | clap = { version = "4.5.38", features = ["default"] } 30 | # libafl = { path = "../dep/libafl/libafl" } 31 | libafl = { version = "0.11.2" } 32 | libafl_bolts = { version = "0.11.2" } 33 | nix = "0.24" 34 | num-traits = { version = "0.2", default-features = false } 35 | serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib 36 | erased-serde = { version = "0.3.21", default-features = false, features = ["alloc"] } # erased serde 37 | ahash = { version = "0.7", default-features=false, features=["compile-time-rng"] } # The hash function already used in hashbrown 38 | intervaltree = { version = "0.2.7", default-features = false, features = ["serde"] } 39 | libc = "0.2" 40 | fs_extra = "1.2.0" 41 | hashbrown = { version = "0.13.1", features = ["serde"] } 42 | -------------------------------------------------------------------------------- /libpresifuzz_verilator/build.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | fn main() { 6 | } 7 | 8 | -------------------------------------------------------------------------------- /libpresifuzz_verilator/src/lib.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | pub mod verilator_feedback; 6 | pub mod verilator_observer; 7 | -------------------------------------------------------------------------------- /libpresifuzz_verilator/src/verilator_feedback.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | use std::str; 6 | use core::{ 7 | fmt::Debug, 8 | }; 9 | use serde::{Deserialize, Serialize}; 10 | use libafl::{ 11 | corpus::Testcase, 12 | events::EventFirer, 13 | executors::ExitKind, 14 | inputs::{UsesInput}, 15 | observers::{ObserversTuple}, 16 | state::State, 17 | Error, 18 | feedbacks::Feedback 19 | }; 20 | use libafl_bolts::Named; 21 | use crate::verilator_observer::VerilatorObserver; 22 | extern crate fs_extra; 23 | 24 | /// Nop feedback that annotates execution time in the new testcase, if any 25 | /// for this Feedback, the testcase is never interesting (use with an OR). 26 | /// It decides, if the given [`TimeObserver`] value of a run is interesting. 27 | #[derive(Serialize, Deserialize, Clone, Debug)] 28 | pub struct VerilatorFeedback { 29 | history: Vec, 30 | name: String, 31 | id: usize, 32 | outdir: String, 33 | } 34 | 35 | impl Feedback for VerilatorFeedback 36 | where 37 | S: UsesInput + State, 38 | { 39 | #[allow(clippy::wrong_self_convention)] 40 | fn is_interesting( 41 | &mut self, 42 | _state: &mut S, 43 | _manager: &mut EM, 44 | _input: &S::Input, 45 | observers: &OT, 46 | _exit_kind: &ExitKind, 47 | ) -> Result 48 | where 49 | EM: EventFirer, 50 | OT: ObserversTuple, 51 | { 52 | let observer = observers.match_name::(self.name()).unwrap(); 53 | 54 | let capacity = observer.cnt(); 55 | let mut interesting : bool = false; 56 | 57 | let o_map = observer.map(); 58 | 59 | for (i, item) in o_map.iter().enumerate().take(capacity) { 60 | if self.history[i] < *item { 61 | interesting = true; 62 | break; 63 | } 64 | } 65 | 66 | if interesting { 67 | self.history = observer.map().clone().to_vec(); 68 | self.id += 1; 69 | } 70 | Ok(interesting) 71 | } 72 | 73 | /// Append to the testcase the generated metadata in case of a new corpus item 74 | #[inline] 75 | fn append_metadata(&mut self, _state: &mut S, _observers: &OT ,_testcase: &mut Testcase) -> Result<(), Error> 76 | where 77 | OT: ObserversTuple, 78 | { 79 | Ok(()) 80 | } 81 | 82 | /// Discard the stored metadata in case that the testcase is not added to the corpus 83 | #[inline] 84 | fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { 85 | Ok(()) 86 | } 87 | } 88 | 89 | impl Named for VerilatorFeedback { 90 | #[inline] 91 | fn name(&self) -> &str { 92 | self.name.as_str() 93 | } 94 | } 95 | 96 | impl VerilatorFeedback { 97 | /// Creates a new [`VerilatorFeedback`], deciding if the given [`VerilatorObserver`] value of a run is interesting. 98 | #[must_use] 99 | pub fn new_with_observer(name: &'static str, capacity: usize, outdir: &String) -> Self { 100 | let mut map = Vec::::with_capacity(capacity); 101 | for _i in 0..capacity { 102 | map.push(0); 103 | } 104 | Self { 105 | name: name.to_string(), 106 | history: map, 107 | id: 0, 108 | outdir: outdir.to_string(), 109 | } 110 | } 111 | } 112 | 113 | 114 | -------------------------------------------------------------------------------- /libpresifuzz_verilator/src/verilator_observer.rs: -------------------------------------------------------------------------------- 1 | // SPDX-FileCopyrightText: 2022 Intel Corporation 2 | // 3 | // SPDX-License-Identifier: Apache-2.0 4 | 5 | #[cfg(not(feature = "tui"))] 6 | use libafl::{ 7 | executors::ExitKind, 8 | observers::{MapObserver, Observer}, 9 | Error, 10 | }; 11 | use libafl_bolts::{Named, AsIter, HasLen}; 12 | use std::str; 13 | use core::{ 14 | fmt::Debug, 15 | }; 16 | // use std::path::Path; 17 | use libafl::prelude::UsesInput; 18 | 19 | use ahash::AHasher; 20 | use serde::{Deserialize, Serialize}; 21 | 22 | extern crate fs_extra; 23 | use std::fs; 24 | 25 | use core::{ 26 | hash::Hasher, 27 | slice::{from_raw_parts}, 28 | }; 29 | 30 | /// Compute the hash of a slice 31 | fn hash_slice(slice: &[T]) -> u64 { 32 | let mut hasher = AHasher::new_with_keys(0, 0); 33 | let ptr = slice.as_ptr() as *const u8; 34 | let map_size = slice.len() / core::mem::size_of::(); 35 | unsafe { 36 | hasher.write(from_raw_parts(ptr, map_size)); 37 | } 38 | hasher.finish() 39 | } 40 | 41 | /// A simple observer, just overlooking the runtime of the target. 42 | #[derive(Serialize, Deserialize, Debug)] 43 | pub struct VerilatorObserver { 44 | name: String, 45 | vdb: String, 46 | initial: u32, 47 | cnt: usize, 48 | map: Vec 49 | } 50 | 51 | impl VerilatorObserver { 52 | /// Creates a new [`VerilatorObserver`] with the given name. 53 | #[must_use] 54 | pub fn new(name: &'static str, vdb: &String, size: usize) -> Self { 55 | Self { 56 | name: name.to_string(), 57 | vdb: vdb.to_string(), 58 | initial: 0, 59 | cnt: size, 60 | map: Vec::::with_capacity(size) 61 | } 62 | } 63 | 64 | /// Get a list ref 65 | #[must_use] 66 | pub fn map(&self) -> &Vec { 67 | self.map.as_ref() 68 | } 69 | 70 | /// Gets cnt as usize 71 | #[must_use] 72 | pub fn cnt(&self) -> usize { 73 | self.cnt 74 | } 75 | 76 | } 77 | 78 | impl Observer for VerilatorObserver 79 | where 80 | S: UsesInput, 81 | { 82 | fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { 83 | 84 | // let's clean the map 85 | let initial = self.initial; 86 | for x in self.map.iter_mut() { 87 | *x = initial; 88 | } 89 | Ok(()) 90 | } 91 | 92 | fn post_exec( 93 | &mut self, 94 | _state: &mut S, 95 | _input: &S::Input, 96 | _exit_kind: &ExitKind, 97 | ) -> Result<(), Error> { 98 | 99 | unsafe { 100 | self.map.set_len(self.cnt); 101 | 102 | let contents: String = fs::read_to_string(&self.vdb) 103 | .expect("Unable to open Verilator coverage file at"); 104 | 105 | let mut idx = 0; 106 | 107 | for line in contents.as_str().split('\n') { 108 | 109 | //Starting here, the code comes from https://github.com/AFLplusplus/LibAFL/pull/966 110 | if line.len() > 1 && line.as_bytes()[0] == b'C' { 111 | let mut separator = line.len(); 112 | for &entry in line.as_bytes().iter().rev() { 113 | if entry == b' ' { 114 | break; 115 | } 116 | separator -= 1; 117 | } 118 | let count = line.as_bytes().split_at(separator).1; 119 | // let (name, count) = line.as_bytes().split_at(separator); 120 | // let name = Vec::from(&name[3..(name.len() - 2)]); // "C '...' " 121 | let count: usize = std::str::from_utf8(count) 122 | .map_err(|_| Error::illegal_state("Couldn't parse the coverage count value!"))? 123 | .parse()?; 124 | 125 | let count : u32 = (count).try_into().unwrap(); 126 | self.map[idx] = count; 127 | idx += 1; 128 | } 129 | //End here 130 | } 131 | } 132 | 133 | Ok(()) 134 | } 135 | } 136 | 137 | impl Named for VerilatorObserver { 138 | fn name(&self) -> &str { 139 | &self.name 140 | } 141 | } 142 | 143 | impl HasLen for VerilatorObserver { 144 | fn len(&self) -> usize { 145 | self.map.len() 146 | } 147 | 148 | fn is_empty(&self) -> bool { 149 | self.map.is_empty() 150 | } 151 | } 152 | 153 | impl MapObserver for VerilatorObserver { 154 | type Entry = u32; 155 | 156 | fn get(&self, idx: usize) -> &Self::Entry { 157 | self.map.get(idx).unwrap() 158 | } 159 | 160 | fn get_mut(&mut self, idx: usize) -> &mut Self::Entry { 161 | self.map.get_mut(idx).unwrap() 162 | } 163 | 164 | fn usable_count(&self) -> usize { 165 | self.map.len() 166 | } 167 | 168 | fn count_bytes(&self) -> u64 { 169 | self.map.iter().filter(|&&e| e != self.initial()).count() as u64 170 | } 171 | 172 | fn hash(&self) -> u64 { 173 | hash_slice(&self.map) 174 | } 175 | 176 | #[inline(always)] 177 | fn initial(&self) -> Self::Entry { 178 | 0 179 | } 180 | 181 | fn reset_map(&mut self) -> Result<(), Error> { 182 | let len = self.map.len(); 183 | self.map.clear(); 184 | self.map.resize(len, 0); 185 | Ok(()) 186 | } 187 | 188 | fn to_vec(&self) -> Vec { 189 | self.map.clone() 190 | } 191 | 192 | fn how_many_set(&self, indexes: &[usize]) -> usize { 193 | indexes 194 | .iter() 195 | .map(|&idx| self.get(idx)) 196 | .filter(|&&e| e != self.initial()) 197 | .count() 198 | } 199 | } 200 | 201 | impl<'it> AsIter<'it> for VerilatorObserver { 202 | type Item = u32; 203 | type IntoIter = core::slice::Iter<'it, Self::Item>; 204 | 205 | fn as_iter(&'it self) -> Self::IntoIter { 206 | self.map.iter() 207 | } 208 | } 209 | -------------------------------------------------------------------------------- /plot.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # import libraries 5 | import time 6 | import matplotlib.pyplot as plt 7 | import pandas as pd 8 | import numpy as np 9 | import re 10 | from datetime import datetime 11 | 12 | # create an empty dataframe that will store streaming data 13 | df = pd.DataFrame({'run-time': [], 'coverage': [], 'corpus': [], 'objectives': [], 'executions': [], 'throughput': []}) 14 | 15 | plt.style.use('dark_background') 16 | 17 | # create plot 18 | plt.ion() # <-- work in "interactive mode" 19 | plt.show() 20 | 21 | fig, ((ax1, ax2, ax3), (ax4, ax5, ax6)) = plt.subplots(2,3) 22 | fig.suptitle('PreSiFuzz') 23 | 24 | # act on new data coming from streamer 25 | plot_data = {'run-time': [0], 'coverage': [0], 'corpus': [0], 'objectives': [0], 'executions': [0], 'throughput': [0]} 26 | 27 | corpus = 0 28 | objectives = 0 29 | executions = 0 30 | throughput = 0 31 | total_seconds = 0 32 | coverage = 0.0 33 | 34 | with open("./fuzzing_from_ram.txt") as f: 35 | 36 | for data in f: 37 | 38 | data = data.rstrip() 39 | 40 | if "(GLOBAL)" in data: 41 | regex = r"run time: ([\d\d]+h-[\d\d]+m-[\d\d]+s).*corpus: (\d+), objectives: (\d+), executions: (\d+), exec\/sec: ([\d.]+)" 42 | 43 | matches = re.findall(regex, data, re.MULTILINE) 44 | if len(matches) == 1 and len(matches[0]) == 5: 45 | matches = matches[0] 46 | runtime = matches[0] 47 | corpus = matches[1] 48 | objectives = matches[2] 49 | executions = matches[3] 50 | throughput = matches[4] 51 | 52 | pt = datetime.strptime(runtime,'%Hh-%Mm-%Ss') 53 | total_seconds = pt.second + pt.minute*60 + pt.hour*3600 54 | 55 | elif "coverage" in data: 56 | regex = r"VDB: ([\d\w.\/]+)" 57 | 58 | matches = re.findall(regex, data, re.MULTILINE) 59 | if len(matches) == 1: 60 | vdb = matches[0] 61 | 62 | regex = r"coverage: ([\d.]+)" 63 | 64 | matches = re.findall(regex, data, re.MULTILINE) 65 | if len(matches) == 1: 66 | coverage = matches[0] 67 | 68 | row = {'run-time': [total_seconds], 'coverage': [float(coverage)], 'corpus': [int(corpus)], 'objectives': [int(objectives)], 'executions': [int(executions)], 'throughput': [float(throughput)]} 69 | 70 | plot_data["coverage"].append(max(plot_data["coverage"][-1], row["coverage"][0])) 71 | plot_data["run-time"] += row["run-time"] 72 | plot_data["corpus"] += row["corpus"] 73 | plot_data["objectives"] += row["objectives"] 74 | plot_data["executions"] += row["executions"] 75 | plot_data["throughput"] += row["throughput"] 76 | 77 | # plot all data 78 | ax1.plot(plot_data["run-time"], plot_data["coverage"], color='b') 79 | ax1.set_title('Coverage over time') 80 | 81 | ax2.plot(plot_data["run-time"], plot_data["corpus"], color='b') 82 | ax2.set_title('|Corpus| over time') 83 | ax2.set_yscale("log") 84 | 85 | ax3.plot(plot_data["run-time"], plot_data["objectives"], color='b') 86 | ax3.set_title('|Objectives| over time') 87 | ax3.set_yscale("log") 88 | 89 | ax4.plot(plot_data["run-time"], plot_data["executions"], color='b') 90 | ax4.set_title('Cumulative executions over time') 91 | ax4.set_yscale("log") 92 | 93 | ax5.plot(plot_data["run-time"], plot_data["throughput"], color='b') 94 | ax5.set_title('throughput over time') 95 | 96 | # show the plot 97 | while 1: 98 | plt.draw() 99 | plt.pause(0.0001) # <-- sets the current plot until refreshed 100 | --------------------------------------------------------------------------------