{"id":551,"date":"2023-08-30T16:43:54","date_gmt":"2023-08-30T14:43:54","guid":{"rendered":"https:\/\/ackeeblockchain.com\/blog\/?p=551"},"modified":"2024-07-04T14:26:27","modified_gmt":"2024-07-04T12:26:27","slug":"introducing-trdelnik-fuzz-testing-framework-for-solana-and-anchor","status":"publish","type":"post","link":"https:\/\/ackee.xyz\/blog\/introducing-trdelnik-fuzz-testing-framework-for-solana-and-anchor\/","title":{"rendered":"Introducing Trdelnik: Fuzz Testing Framework for Solana and Anchor"},"content":{"rendered":"<p><span style=\"font-weight: 400;\">Developers need to test the reliability and security of their programs before deployment. Traditional unit tests often fail to reveal the edge-case vulnerabilities. Trdelnik addresses this by introducing fuzz testing for Solana programs, which generates a large set of random inputs and call orders to probe for unexpected weaknesses.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Why we created Trdelnik\u00a0<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">Programs for the Solana blockchain are mostly written in Rust programming language. There is a good reason to use Rust because it guarantees memory safety without compromising performance as it is the case with other programming languages that use garbage collection. Rust on the other hand uses a new unique concept of ownership. The downside is that Rust might become very complex and the learning curve is steep.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">But wait, have you also heard that \u201conly the best programmers can write in Rust and the best make fewer mistakes\u201d? Well even if it was partially true, there are better ways to prevent bugs and one of them is testing. Extensive and systematic testing is an integral part of any software development and is a great way to discover bugs early during development.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">How is it possible that most projects have only basic tests or no tests at all? Believe it or not, writing good tests is not as easy as it might seem and in some cases can take even longer than the development of the product alone. In the fast-paced world of crypto, the timelines are often very short and the pressure to launch new projects is extremely high.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">That is why we have developed <\/span><a href=\"https:\/\/github.com\/Ackee-Blockchain\/trdelnik\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Trdelnik<\/span><\/a><span style=\"font-weight: 400;\">, our Rust-based testing framework providing several convenient developer tools for testing Solana programs written in<\/span> <a href=\"https:\/\/github.com\/project-serum\/anchor\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">Anchor<\/span><\/a><span style=\"font-weight: 400;\">. The main goal of Trdelnik is to simplify the setup of the testing environment, provide an automatically generated API to send instructions to custom programs and accelerate the testing process.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Fuzz Testing Solana Programs<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">A new feature recently introduced to Trdelnik is fuzz testing. It is an automated software testing technique that provides generated random, invalid, or unexpected input data to your program. This helps to discover unknown bugs and vulnerabilities and may prevent zero-day exploits of your program.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">There are several fuzzers used for Rust programs, however, googling for Solana fuzz tests does not show any results and that is why we decided to integrate this feature into our framework. Under the hood, Trdelnik uses a well known fuzzer <\/span><a href=\"https:\/\/github.com\/google\/honggfuzz\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">honggfuzz<\/span><\/a><span style=\"font-weight: 400;\"> developed by Google.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In the following text we will describe step by step how to use Trdelnik for fuzz testing.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">TL;DR Solana Fuzzing<\/span><\/h2>\n<pre><code class=\"language-rust\"># In the root of your Anchor project, execute these commands:\ncargo install trdelnik-cli\ncargo install honggfuzz\ntrdelnik init\n# now to go .\/trdelnik-tests\/src\/bin\/fuzz_target.rs and edit the fuzz test template\n# to run the fuzz test replace &lt;TARGET_NAME&gt; with fuzz_target\ntrdelnik fuzz run &lt;TARGET_NAME&gt;\n# to debug a crash pass in a crash *.fuzz file with following path  trdelnik-tests\/hfuzz_workspace\/&lt;TARGET_NAME&gt;\/&lt;CRASH_FILE&gt;.fuzz\ntrdelnik fuzz run-debug &lt;TARGET_NAME&gt; &lt;CRASH_FILE_PATH&gt;<\/code><\/pre>\n<h3><span style=\"font-weight: 400;\">Fuzzing with Trdelnik Step by Step<\/span><\/h3>\n<p><span style=\"font-weight: 400;\">In this tutorial we will go through the complete setup involving these steps:<\/span><\/p>\n<ol>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Setting up a new Anchor project<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Creating a program that contains bugs to detect<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Initializing Trdelnik test framework<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Writing a simple fuzz test<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Running the fuzz test<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Debugging our program using fuzz test crash files<\/span><\/li>\n<li style=\"font-weight: 400;\" aria-level=\"1\"><span style=\"font-weight: 400;\">Setting up a new Anchor project<\/span><\/li>\n<\/ol>\n<p><span style=\"font-weight: 400;\">For the purpose of this tutorial we will create a new Anchor project. If you do not have Anchor framework yet, then <\/span><a href=\"https:\/\/www.anchor-lang.com\/docs\/installation\" target=\"_blank\" rel=\"noopener\"><span style=\"font-weight: 400;\">install<\/span><\/a><span style=\"font-weight: 400;\"> the version 0.28.0.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Open a terminal and go to your project folder where we will create the new project and verify if the project can be built:<\/span><\/p>\n<pre><code class=\"language-rust\">anchor init my-trdelnik-fuzz-test\ncd my-trdelnik-fuzz-test\nanchor build<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">Verify that the Anchor project is initialized and built successfully.<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">Creating a program that contains bugs to detect<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Next we will create a simple program where we will intentionally introduce bugs that we will try to find with our fuzzer. Open the source file of your program <\/span><span style=\"font-weight: 400;\">programs <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">\/my-trdelnik-fuzz-test\/src\/lib.rs<\/code><\/span><span style=\"font-weight: 400;\"> and replace everything after the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">declare_id!()<\/code> <\/span><span style=\"font-weight: 400;\">macro with the following code:<\/span><\/p>\n<pre><code class=\"language-rust\">const MAGIC_NUMBER: u8 = 254;\n\n#[program]\npub mod my_trdelnik_fuzz_test {\n   use super::*;\n\n   pub fn initialize(ctx: Context&lt;Initialize&gt;) -&gt; Result&lt;()&gt; {\n       let counter = &amp;mut ctx.accounts.counter;\n\n       counter.count = 0;\n       counter.authority = ctx.accounts.user.key();\n\n       Ok(())\n   }\n\n   pub fn update(ctx: Context&lt;Update&gt;, input1: u8, input2: u8) -&gt; Result&lt;()&gt; {\n       let counter = &amp;mut ctx.accounts.counter;\n\n       msg!(&quot;input1 = {}, input2 = {}&quot;, input1, input2);\n\n       \/\/ comment this to fix the black magic panic\n       if input1 == MAGIC_NUMBER {\n           panic!(&quot;Black magic not supported!&quot;);\n       }\n       counter.count = buggy_math_function(input1, input2).into();\n       Ok(())\n   }\n}\npub fn buggy_math_function(input1: u8, input2: u8) -&gt; u8 {\n   \/\/ comment the if statement to cause div-by-zero or subtract with overflow panic\n   if input2 &gt;= MAGIC_NUMBER {\n       return 0;\n   }\n   let divisor = MAGIC_NUMBER - input2;\n   input1 \/ divisor\n}\n\n#[derive(Accounts)]\npub struct Initialize&lt;&#039;info&gt; {\n   #[account(init, payer = user, space = 8 + 40)]\n   pub counter: Account&lt;&#039;info, Counter&gt;,\n\n   #[account(mut)]\n   pub user: Signer&lt;&#039;info&gt;,\n   pub system_program: Program&lt;&#039;info, System&gt;,\n}\n\n#[derive(Accounts)]\npub struct Update&lt;&#039;info&gt; {\n   #[account(mut, has_one = authority)]\n   pub counter: Account&lt;&#039;info, Counter&gt;,\n   pub authority: Signer&lt;&#039;info&gt;,\n}\n\n#[account]\npub struct Counter {\n   pub authority: Pubkey,\n   pub count: u64,\n}<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">It is a simple program with two instructions: <\/span><span style=\"font-weight: 400;\"><span style=\"font-weight: 400;\"><code class=\"codehl\">initialize<\/code><\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">update<\/code><\/span><span style=\"font-weight: 400;\">. The <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">initialize<\/code><\/span><span style=\"font-weight: 400;\"> instruction will create the necessary data account and the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">update<\/code><\/span><span style=\"font-weight: 400;\"> instruction will update the on-chain data. It also contains an intentional <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">panic!<\/code><\/span><span style=\"font-weight: 400;\"> macro that will immediately terminate the program simulating a crash if the first input to the program equals the constant <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">MAGIC_NUMBER<\/code><\/span><\/span><span style=\"font-weight: 400;\">.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now you can again verify if your program builds successfully using <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">anchor build<\/code><\/span><span style=\"font-weight: 400;\">.<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">Initialize Trdelnik test framework<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">In order to use Trdelnik and the fuzzer, we have to install them:<\/span><\/p>\n<pre><code class=\"language-rust\">cargo install trdelnik-cli\ncargo install honggfuzz<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">If you had Trdelnik already installed then you need to upgrade to version 0.5.0.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">After that, we must initialize Trdelnik framework in our project using the command:<\/span><\/p>\n<pre><code class=\"language-rust\">trdelnik init\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">This command will automatically generate the .program_client folder with an API to our program, add necessary dependencies to the configuration files and generate trdelnik tests templates.\u00a0<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">Write a simple fuzz test<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">The fuzz test target template is located in the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">trdelnik-tests\/src\/bin\/fuzz_target.rs<\/code><\/span><span style=\"font-weight: 400;\"> file. This file can be modified according to your needs.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now, you can only replace its content with the following code:<\/span><\/p>\n<pre><code class=\"language-rust\">use my_trdelnik_fuzz_test::entry;\nuse program_client::my_trdelnik_fuzz_test_instruction::*;\nconst PROGRAM_NAME: &amp;str  = &quot;my_trdelnik_fuzz_test&quot;;\nuse assert_matches::*;\nuse trdelnik_client::fuzzing::*;\n\n#[derive(Arbitrary)]\npub struct FuzzData {\n   param1: u8,\n   param2: u8,\n}\n\nfn main() {\n   loop {\n       fuzz!(|fuzz_data: FuzzData| {\n           Runtime::new().unwrap().block_on(async {\n               let program_test = ProgramTest::new(PROGRAM_NAME, PROGRAM_ID, processor!(entry));\n\n               let mut ctx = program_test.start_with_context().await;\n\n               let counter = Keypair::new();\n\n               let init_ix =\n                   initialize_ix(counter.pubkey(), ctx.payer.pubkey(), SYSTEM_PROGRAM_ID);\n               let mut transaction =\n                   Transaction::new_with_payer(&amp;[init_ix], Some(&amp;ctx.payer.pubkey().clone()));\n\n               transaction.sign(&amp;[&amp;ctx.payer, &amp;counter], ctx.last_blockhash);\n               let res = ctx.banks_client.process_transaction(transaction).await;\n               assert_matches!(res, Ok(()));\n\n               let res = fuzz_update_ix(\n                   &amp;fuzz_data,\n                   &amp;mut ctx.banks_client,\n                   &amp;ctx.payer,\n                   &amp;counter,\n                   ctx.last_blockhash,\n               )\n               .await;\n               assert_matches!(res, Ok(()));\n           });\n       });\n   }\n}\n\nasync fn fuzz_update_ix(\n   fuzz_data: &amp;FuzzData,\n   banks_client: &amp;mut BanksClient,\n   payer: &amp;Keypair,\n   counter: &amp;Keypair,\n   blockhash: Hash,\n) -&gt; core::result::Result&lt;(), BanksClientError&gt; {\n   let update_ix = update_ix(\n       fuzz_data.param1,\n       fuzz_data.param2,\n       counter.pubkey(),\n       payer.pubkey(),\n   );\n\n   let mut transaction = Transaction::new_with_payer(&amp;[update_ix], Some(&amp;payer.pubkey()));\n   transaction.sign(&amp;[payer], blockhash);\n\n   banks_client.process_transaction(transaction).await<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">For the purpose of this tutorial and for simplicity we are fuzzing only the instruction parameters. Namely the two parameters <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">input1<\/code><\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">input2<\/code><\/span><span style=\"font-weight: 400;\"> of the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">update<\/code><\/span><span style=\"font-weight: 400;\"> instruction.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">If you look at the fuzz target code, you can see that the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">main<\/code><\/span><span style=\"font-weight: 400;\"> function contains an infinite loop with the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">fuzz!<\/code><\/span><span style=\"font-weight: 400;\"> macro that takes a closure where we pass the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">FuzzData<\/code><\/span><span style=\"font-weight: 400;\"> structure.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Let\u2019s dissect the code a little. The entry point of the fuzz target is the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">main<\/code><\/span><span style=\"font-weight: 400;\"> function, where we call the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">fuzz!<\/code><\/span><span style=\"font-weight: 400;\"> macro over and over again. This macro executes the code in the closure, and in each loop, the passed <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">fuzz_data<\/code><\/span><span style=\"font-weight: 400;\"> are different.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">We are using the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">arbitrary<\/code><\/span><span style=\"font-weight: 400;\"> crate that enables us to easily transform unstructured random data to structured data as we defined it in the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">FuzzData<\/code><\/span><span style=\"font-weight: 400;\"> structure. The closure code gets executed, and if the program does not crash, the fuzz test continues with a new loop iteration, and the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">fuzz_data<\/code><\/span><span style=\"font-weight: 400;\"> passed to the closure is modified. If the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">fuzz_data<\/code><\/span><span style=\"font-weight: 400;\"> variable contains data that produces a crash in our program, the fuzzer automatically stores the data in a separate fuzz crash file <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">.\/trdelnik-tests\/hfuzz_workspace\/&lt;TARGET_NAME&gt;\/&lt;CRASH_FILE_NAME&gt;.fuzz<\/code><\/span><span style=\"font-weight: 400;\">. This is useful especially for subsequent debugging.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The code executed in the closure in our fuzz target first creates a new <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">TestProgram<\/code><\/span><span style=\"font-weight: 400;\"> and adds our program to the test environment. Then the test client is started that enables us to send transactions to our program. Having that, we have to first initialize our program. We create the initialize instruction with the help of Trdelnik that automatically generated the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">initialize_ix<\/code><\/span><span style=\"font-weight: 400;\"> function for us. Finally we create a new transaction, that we sign and send via the client to the test environment. Great, our program is initialized!<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now we call the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">fuzz_update_ix<\/code><\/span><span style=\"font-weight: 400;\"> function in order to supply random data to the update instruction that we want to fuzz and where we want to find bugs. Again, we construct the update instruction using the automatically generated <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">update_ix<\/code><\/span><span style=\"font-weight: 400;\"> function and we supply the randomly generated parameters from the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">FuzzData<\/code><\/span><span style=\"font-weight: 400;\"> structure. Finally, we create the transaction, sign and send it. And that\u2019s it, our fuzz target is ready to go!<\/span><\/p>\n<h4><span style=\"font-weight: 400;\">Run the fuzz test<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">Trdelnik provides a convenient way to run the fuzz tests. Anywhere in your Anchor project, you can execute the command:<\/span><\/p>\n<pre><code class=\"language-rust\">trdelnik fuzz run &lt;TARGET_NAME&gt;\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">So in our case if we replace the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">&lt;TARGET_NAME&gt;<\/code><\/span><span style=\"font-weight: 400;\"> with the actual name it gets the following:<\/span><\/p>\n<pre><code class=\"language-rust\">trdelnik fuzz run fuzz_target\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">Once you execute this command, the whole project has to be built with instrumentation for fuzzing so it takes some time. After the build is finished, the fuzzer starts automatically and looks like this:<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-558 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/08\/tg_image_2104029818.jpeg\" alt=\"\" width=\"578\" height=\"243\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_2104029818.jpeg 1204w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_2104029818-300x126.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_2104029818-1024x430.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_2104029818-768x323.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_2104029818-370x155.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_2104029818-760x319.jpeg 760w\" sizes=\"auto, (max-width: 578px) 100vw, 578px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">At the top, you can see fuzzing statistics. Especially how many times your program crashed, how many of these crashes were unique, how many iterations were done and so on.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">To stop fuzzing, you can simply hit CTRL+C. As Trdelnik uses Honggfuzz under the hood, you can also pass parameters directly to the fuzzer using environment variables.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">For example:<\/span><\/p>\n<pre><code class=\"language-rust\"># Time-out: 10 secs\n# Number of concurrent fuzzing threads: 1\n# Number of fuzzing iterations: 10000\n# Display Solana logs in the terminal\n# Exit upon crash\nHFUZZ_RUN_ARGS=&quot;-t 10 -n 1 -N 10000 -Q --exit_upon_crash&quot; trdelnik fuzz run fuzz_target<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">If you run the command above, the fuzzer will stop after the first encountered crash and passing the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">-Q<\/code><\/span><span style=\"font-weight: 400;\"> flag allows us to see the Solana logs. In our Solana example program, we use the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">msg!<\/code><\/span><span style=\"font-weight: 400;\"> macro to display the value of the update instruction parameters <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">input1<\/code><\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">input2<\/code><\/span><span style=\"font-weight: 400;\"> that you can see from the log that have values 254 and 255 respectively.<\/span><\/p>\n<p><strong><img loading=\"lazy\" decoding=\"async\" class=\" wp-image-562 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-scaled.jpeg\" alt=\"\" width=\"735\" height=\"190\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-scaled.jpeg 2560w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-300x77.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-1024x264.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-768x198.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-1536x397.jpeg 1536w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-2048x529.jpeg 2048w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-370x96.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/tg_image_1391487941-760x196.jpeg 760w\" sizes=\"auto, (max-width: 735px) 100vw, 735px\" \/><\/strong><\/p>\n<h4><span style=\"font-weight: 400;\">Debug our program using fuzz test crash files<\/span><\/h4>\n<p><span style=\"font-weight: 400;\">As you can see from the log above, the data that caused the crash of our program was stored in the fuzz crash file in <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">.\/trdelnik-tests\/hfuzz_workspace\/fuzz_target<\/code><\/span><span style=\"font-weight: 400;\"> folder.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now it is possible to use this crash file and \u201creplay\u201d the crash in the debugger to inspect the bug. The corresponding command is:<\/span><\/p>\n<pre><code class=\"language-rust\">trdelnik fuzz run-debug &lt;TARGET_NAME&gt; &lt;CRASH_FILE_PATH&gt;\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">So in our case if we replace the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">&lt;TARGET_NAME&gt;<\/code><\/span><span style=\"font-weight: 400;\"> and <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">&lt;CRASH_FILE_PATH&gt;<\/code><\/span><span style=\"font-weight: 400;\"> with the actual values. The name of the crash file might differ so you will have to modify it accordingly.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">In our case the resulting command is as follows:<\/span><\/p>\n<pre><code class=\"language-shell-session\">trdelnik fuzz run-debug fuzz_target .\/trdelnik-tests\/hfuzz_workspace\/fuzz_target\/SIGABRT.PC.7ffff7c8e83c.STACK.1b3a7a7882.CODE.-6.ADDR.0.INSTR.mov____\\%eax,\\%ebx.fuzz\n<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">Once you execute this command, the whole project has to be built for debugging. After that, the fuzzer runs your program with supplied parameters from the crash file and simulates the crash again for inspection.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Now you can see in the debugger, that the thread panicked at &#8216;Black magic not supported!&#8217;, programs\/my-trdelnik-fuzz-test\/src\/lib.rs:27:13<\/span><\/p>\n<p><img loading=\"lazy\" decoding=\"async\" class=\"wp-image-559 aligncenter\" src=\"https:\/\/abchprod.wpengine.com\/wp-content\/uploads\/2023\/08\/2.jpeg\" alt=\"\" width=\"841\" height=\"90\" srcset=\"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2.jpeg 2210w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2-300x32.jpeg 300w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2-1024x109.jpeg 1024w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2-768x82.jpeg 768w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2-1536x164.jpeg 1536w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2-2048x219.jpeg 2048w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2-370x40.jpeg 370w, https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/2-760x81.jpeg 760w\" sizes=\"auto, (max-width: 841px) 100vw, 841px\" \/><\/p>\n<p><span style=\"font-weight: 400;\">This is the expected output because we have intentionally introduced a panic in our program if the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">input1<\/code><\/span><span style=\"font-weight: 400;\"> variable is equal to our <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">MAGIC_NUMBER<\/code><\/span><span style=\"font-weight: 400;\"> which is 254.<\/span><\/p>\n<pre><code class=\"language-rust\">if input1 == MAGIC_NUMBER {\n    panic!(&quot;Black magic not supported!&quot;);\n}<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">While in the debugger, you can either execute a <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">help<\/code><\/span><span style=\"font-weight: 400;\"> command for further actions or quit by executing the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">q<\/code><\/span><span style=\"font-weight: 400;\"> command.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">If you want to try to find another bug in the program, you can uncomment the if statement<\/span><\/p>\n<pre><code class=\"language-rust\">if input2 &gt;= MAGIC_NUMBER {\n       return 0;\n   }<\/code><\/pre>\n<p><span style=\"font-weight: 400;\">in the <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">buggy_math_function<\/code><\/span><span style=\"font-weight: 400;\"> function in the Solana program in <\/span><span style=\"font-weight: 400;\"><code class=\"codehl\">programs\/my-trdelnik-fuzz-test\/src\/lib.rs<\/code><\/span><span style=\"font-weight: 400;\"> and run the fuzzer again. After some time, a new unique crash should be found that you can again analyze using the debugger as shown before.<\/span><\/p>\n<h2><span style=\"font-weight: 400;\">Conclusion<\/span><\/h2>\n<p><span style=\"font-weight: 400;\">We have shown how to use the Trdelnik framework to write fuzz tests for Solana programs written in Anchor. You can find the whole example project in <a href=\"https:\/\/github.com\/Ackee-Blockchain\/trdelnik\/tree\/master\/examples\/fuzzer.\" target=\"_blank\" rel=\"noopener\">Trdelnik\u2019s GitHub repository<\/a>.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The goal of Trdelnik is not to implement a new fuzzer but rather to provide a convenient way to use the existing honggfuzz fuzzer without the hassle of setting up the testing environment.\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">It is as simple as initializing Trdelnik in your project and you are ready to fuzz!\u00a0<\/span><\/p>\n<p><span style=\"font-weight: 400;\">The next steps will be the accounts and instructions flow fuzzing.<\/span><\/p>\n<p><span style=\"font-weight: 400;\">Stay tuned for more tutorials in the future!<\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Developers need to test the reliability and security of their programs before deployment. Traditional unit tests often fail to reveal the edge-case vulnerabilities. Trdelnik addresses this by introducing fuzz testing for Solana programs, which generates a large set of random inputs and call orders to probe for unexpected weaknesses. Why we created Trdelnik\u00a0 Programs for the Solana blockchain are mostly written in&hellip;<\/p>\n","protected":false},"author":20,"featured_media":563,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[65,5,113,63],"tags":[6,114],"class_list":["post-551","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-announcements","category-solana","category-trident","category-tutorial","tag-solana","tag-trident"],"aioseo_notices":[],"featured_image_src":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/Trdelnik-600x400.png","featured_image_src_square":"https:\/\/ackee.xyz\/blog\/wp-content\/uploads\/2023\/08\/Trdelnik-600x600.png","author_info":{"display_name":"Adam Hrazdira","author_link":"https:\/\/ackee.xyz\/blog\/author\/adam-hrazdira\/"},"_links":{"self":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/551","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/users\/20"}],"replies":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/comments?post=551"}],"version-history":[{"count":0,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/posts\/551\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media\/563"}],"wp:attachment":[{"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/media?parent=551"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/categories?post=551"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/ackee.xyz\/blog\/wp-json\/wp\/v2\/tags?post=551"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}