Optimizing

There is a lot of room to optimize this test scenario. You'll notice that with full logging on (and full hexdumping of input on), each run takes over a second for around 0.3 executions per second. While this is much better than nothing, his is quite poor performance for effective fuzzing.

Remove Target Software Output

First, we'll #ifdef out our print statements in our target software:

EFI_STATUS
EFIAPI
UefiMain(IN EFI_HANDLE ImageHandle, IN EFI_SYSTEM_TABLE *SystemTable) {
  UINTN MaxInputSize = 0x1000;
  UINTN InputSize = MaxInputSize;
  UINT8 *Input = (UINT8 *)AllocatePages(EFI_SIZE_TO_PAGES(MaxInputSize));

  if (!Input) {
    return EFI_OUT_OF_RESOURCES;
  }

  HARNESS_START(Input, &InputSize);

#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  Print(L"Input: %p Size: %d\n", Input, InputSize);
#endif
  UINT8 *Cert = Input;
  UINTN CertSize = InputSize / 2;
  UINT8 *CACert = (Input + CertSize);
  UINTN CACertSize = CertSize;

#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
  Print(L"Certificate:\n");
  hexdump(Cert, CertSize);
  Print(L"CA Certificate:\n");
  hexdump(CACert, CACertSize);
#endif

  BOOLEAN Status = X509VerifyCert(Cert, CertSize, CACert, CACertSize);

  if (Status) {
    HARNESS_ASSERT();
  } else {
    HARNESS_STOP();
  }

  if (Input) {
    FreePages(Input, EFI_SIZE_TO_PAGES(MaxInputSize));
  }

  return EFI_SUCCESS;
}
[tsffs info] Stopped after 1107 iterations in 11.048448 seconds (100.19507 exec/s).

We are now running at 100+ iterations per second! This is a massive increase. Let's take it a little further.

Turn Down Logging

TSFFS logs a large amount of redundant information at high log levels (primarily for debugging purposes). You can reduce the amount of information printed by setting:

tsffs.log-level 2

Where 0 is the lowest (error) and 4 is the highest (trace) logging level. Errors are always displayed. This can typically buy a few exec/s. Note that fuzzer status messages are printed at a logging level of info (2), so you likely want to at least set the log level to 2.

This can buy us a few executions per second:

[tsffs info] [Testcase #0] run time: 0h-0m-42s, clients: 1, corpus: 21, objectives: 0, executions: 4792, exec/sec: 112.5

Shorten The Testcase

In our case, we are calling one function, sandwiched between HARNESS_START and HARNESS_STOP. There is almost nothing we can do to shorten the runtime of each individual run here, but this is a good technique to keep in mind for your future fuzzing efforts.

Run More Instances

TSFFS includes stages for flushing the queue and synchronizing the queue from a shared corpus directory. This means you can run as many instances of TSFFS as you'd like in parallel, and they will periodically pick up new corpus entries from each other. Execution speed scales approximately linearly across cores.

We'll launch 8 instances, all in batch mode, using tmux:

#!/bin/bash

SESSION_NAME="my-tsffs-campaign"

# Create a new tmux session or attach to an existing one
tmux new-session -d -s "$SESSION_NAME"

# Loop to create 8 windows and run the command in each window
for i in {1..8}; do
    # Create a new window
    tmux new-window -t "$SESSION_NAME:$i" -n "${SESSION_NAME}-window-$i"

    # Run the command in the new window
    tmux send-keys -t "$SESSION_NAME:$i" "./simics -no-gui --no-win --batch-mode run.simics" C-m
done

# Attach to the tmux session
tmux attach-session -t "$SESSION_NAME"

You can select each window with (for example to select window 3 Ctrl+b 3), and you can detach and leave the campaign running in the background with Ctrl+b d. After detaching you can reattach using the last command in the script tmux attach-session -t my-tsffs-campaign. Running 8 instances of the fuzzer means approximately 8 times the exec/s of a single instance, however each instance operates independently, so bug finding does not scale in a correspondingly linear fashion. Regardless, the common wisdom of more iterations being better holds.