Files
ce_cdm/oemcrypto/test/fuzz_tests
Googler 6d36a0c93d Source release 19.6.0
GitOrigin-RevId: 13a33e34413c19da1bfe76abcc66be519c9ac9d1
2025-06-09 23:44:53 -07:00
..
2024-06-25 14:03:53 -07:00
2022-07-07 17:14:31 -07:00
2024-03-29 10:49:35 -07:00
2024-03-28 19:15:22 -07:00
2024-06-25 14:03:53 -07:00
2024-06-25 14:03:53 -07:00
2024-03-29 10:49:35 -07:00
2024-03-29 10:49:35 -07:00

OEMCrypto fuzzing

ClusterFuzz and Google Cloud infrastructure continuously runs OEMCrypto fuzz tests and reports crashes. To create a new automated fuzzing setup, refer to ClusterFuzz setup.

Run fuzz tests locally

  1. Build the fuzz tests:

    $ cd <cdm_repo_path>
    $ oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests
    
  2. Run the fuzz test:

    $ out/Default/<fuzz_test> [<corpus_dir>]
    

    The corpus directory is optional and can either be a seed corpus from the corpus subdirectory or be an empty directory. The corpus will be extended with new inputs while the fuzz test is running.

Triage crashes

To reproduce a crash locally for debugging:

  1. Download the minimized testcase from the ClusterFuzz report.

  2. Build the fuzz tests:

    $ oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests
    
  3. Debug the crash:

    $ gdb --args <fuzz_test_path> -timeout=0 <testcase_path>
    

    Example after substituting fuzz test and test case paths:

    $ gdb --args out/Default/oemcrypto_opk_decrypt_cenc_fuzz -timeout=0 \
      clusterfuzz-testcase-minimized-oemcrypto_v17_opk_decrypt_cenc_fuzz-6727459932078080
    
  4. If reproducing the crash is unsuccessful, download the unminimized testcase from the ClusterFuzz report and try again. If still unsuccessful, this may indicate there is a persistent state issue with the fuzz test.

Once the root cause of the crash is identified, its severity and complexity should be assessed. The SEI CERT C Coding Standard is a good resource for risk assessment. The ClusterFuzz report will also provide input in the Security field. For complex fixes with a longer timeline, ClusterFuzz may report duplicate crashes with the same root cause.

Write fuzz tests

While fuzzing has random elements, input data mutations are heavily influenced by coverage feedback. Since discovering new control flow edges is a time consuming process, input bytes should map to control flow edges in a simple, predictable way. FuzzedDataProvider, a class supplied with LLVMs libFuzzer, can be used to easily split input data:

extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
  FuzzedDataProvider fuzzed_data(data, size);

  // One bit of input data maps to this control flow edge:
  if (fuzzed_data.ConsumeBool()) {
    // ...
  }

  // ...
}

Fuzzing API methods with complex, structured input, may benefit from a seed corpus containing a representative set of starting inputs. Unfortunately, FuzzedDataProvider is not suitable for fuzz tests utilizing a seed corpus since there is no equivalent serialization functionality for generating the corpus. OEMCrypto fuzz tests have previously used struct-based serialization, but this is no longer recommended due to portability issues. Protocol Buffers or another portable serialization format should be considered instead.

Fuzz tests must be deterministic to reproduce and debug a crash. A common pitfall is not resetting the OEMCrypto API state between calls to LLVMFuzzerTestOneInput. Fully terminating OEMCrypto between inputs is preferred, but in some cases, it may be necessary to implement careful optimizations to achieve acceptable performance. Candidates for optimization typically have less than 1000 executions per second (exec/s). LLVMFuzzerInitialize can be used for global initialization, but there is no corresponding termination method.

A good starting example is oemcrypto_install_oem_private_key_fuzz.cc. Targets should be added to oemcrypto_opk_fuzztests.gyp and, if the fuzz test applies to partner OEMCrypto implementations, partner_oemcrypto_fuzztests.gyp. The infrastructure expects that the target name starts with oemcrypto and ends with fuzz.

For additional information about writing fuzz tests, see What makes a good fuzz target.

Generate corpus with OEMCrypto unit tests

  1. Build the unit tests:

    $ cd <cdm_repo_path>
    $ export CDM_DIR=${PWD}
    $ export PATH_TO_CDM_DIR=..
    $ gyp --format=ninja --depth=${PWD} oemcrypto/oemcrypto_unittests.gyp
    $ ninja -C out/Default
    
  2. Run the unit tests with the --generate_corpus flag:

    $ mkdir oemcrypto/test/fuzz_tests/corpus/<fuzz_test>_seed_corpus
    $ out/Default/oemcrypto_unittests --generate_corpus --gtest_filter='-*Huge*'
    
  3. The unit tests can generate many duplicate corpus files. To minimize the corpus to only the subset of inputs that cover unique paths within the API:

    $ oemcrypto/test/fuzz_tests/build_oemcrypto_fuzztests
    $ mkdir /tmp/minimized_corpus
    $ out/Default/<fuzz_test> -merge=1 /tmp/minimized_corpus <full_corpus_dir>