Skip to main content
Redhat Developers  Logo
  • Products

    Featured

    • Red Hat Enterprise Linux
      Red Hat Enterprise Linux Icon
    • Red Hat OpenShift AI
      Red Hat OpenShift AI
    • Red Hat Enterprise Linux AI
      Linux icon inside of a brain
    • Image mode for Red Hat Enterprise Linux
      RHEL image mode
    • Red Hat OpenShift
      Openshift icon
    • Red Hat Ansible Automation Platform
      Ansible icon
    • Red Hat Developer Hub
      Developer Hub
    • View All Red Hat Products
    • Linux

      • Red Hat Enterprise Linux
      • Image mode for Red Hat Enterprise Linux
      • Red Hat Universal Base Images (UBI)
    • Java runtimes & frameworks

      • JBoss Enterprise Application Platform
      • Red Hat build of OpenJDK
    • Kubernetes

      • Red Hat OpenShift
      • Microsoft Azure Red Hat OpenShift
      • Red Hat OpenShift Virtualization
      • Red Hat OpenShift Lightspeed
    • Integration & App Connectivity

      • Red Hat Build of Apache Camel
      • Red Hat Service Interconnect
      • Red Hat Connectivity Link
    • AI/ML

      • Red Hat OpenShift AI
      • Red Hat Enterprise Linux AI
    • Automation

      • Red Hat Ansible Automation Platform
      • Red Hat Ansible Lightspeed
    • Developer tools

      • Red Hat Trusted Software Supply Chain
      • Podman Desktop
      • Red Hat OpenShift Dev Spaces
    • Developer Sandbox

      Developer Sandbox
      Try Red Hat products and technologies without setup or configuration fees for 30 days with this shared Openshift and Kubernetes cluster.
    • Try at no cost
  • Technologies

    Featured

    • AI/ML
      AI/ML Icon
    • Linux
      Linux Icon
    • Kubernetes
      Cloud icon
    • Automation
      Automation Icon showing arrows moving in a circle around a gear
    • View All Technologies
    • Programming Languages & Frameworks

      • Java
      • Python
      • JavaScript
    • System Design & Architecture

      • Red Hat architecture and design patterns
      • Microservices
      • Event-Driven Architecture
      • Databases
    • Developer Productivity

      • Developer productivity
      • Developer Tools
      • GitOps
    • Secure Development & Architectures

      • Security
      • Secure coding
    • Platform Engineering

      • DevOps
      • DevSecOps
      • Ansible automation for applications and services
    • Automated Data Processing

      • AI/ML
      • Data Science
      • Apache Kafka on Kubernetes
      • View All Technologies
    • Start exploring in the Developer Sandbox for free

      sandbox graphic
      Try Red Hat's products and technologies without setup or configuration.
    • Try at no cost
  • Learn

    Featured

    • Kubernetes & Cloud Native
      Openshift icon
    • Linux
      Rhel icon
    • Automation
      Ansible cloud icon
    • Java
      Java icon
    • AI/ML
      AI/ML Icon
    • View All Learning Resources

    E-Books

    • GitOps Cookbook
    • Podman in Action
    • Kubernetes Operators
    • The Path to GitOps
    • View All E-books

    Cheat Sheets

    • Linux Commands
    • Bash Commands
    • Git
    • systemd Commands
    • View All Cheat Sheets

    Documentation

    • API Catalog
    • Product Documentation
    • Legacy Documentation
    • Red Hat Learning

      Learning image
      Boost your technical skills to expert-level with the help of interactive lessons offered by various Red Hat Learning programs.
    • Explore Red Hat Learning
  • Developer Sandbox

    Developer Sandbox

    • Access Red Hat’s products and technologies without setup or configuration, and start developing quicker than ever before with our new, no-cost sandbox environments.
    • Explore Developer Sandbox

    Featured Developer Sandbox activities

    • Get started with your Developer Sandbox
    • OpenShift virtualization and application modernization using the Developer Sandbox
    • Explore all Developer Sandbox activities

    Ready to start developing apps?

    • Try at no cost
  • Blog
  • Events
  • Videos

Introduction to using libFuzzer with llvm-toolset

March 5, 2019
Tom Stellard
Related topics:
LinuxSecurity
Related products:
Red Hat Enterprise Linux

Share:

    "Fuzzing" an application is a great way to find bugs that may be missed by other testing methods. Fuzzers test programs by generating random string inputs and feeding them into an application. Any program that accepts arbitrary inputs from its users is a good candidate for fuzzing. This includes compilers, interpreters, web applications, JSON or YAML parsers, and many more types of programs.

    libFuzzer is a library to assist with the fuzzing of applications and libraries. It is integrated into the Clang C compiler and can be enabled for your application with the addition of a compile flag and by adding a fuzzing target to your code. libFuzzer has been used successfully to find bugs in many programs, and in this article, I will show how you can integrate libFuzzer into your own applications.

    To get started with libFuzzer on Red Hat Enterprise Linux (RHEL) 7, you need to install the llvm-toolset-6.0 package, part of the LLVM Toolset software collection.  LLVM Toolset includes Clang. To install LLVM Toolset, you must first enable a few additional repositories:

    $ sudo subscription-manager repos --enable rhel-7-server-optional-rpms \
        --enable rhel-server-rhscl-7-rpms \
        --enable rhel-7-server-devtools-rpms

    (See How to enable sudo on RHEL if sudo isn't set up on your system.)

    Next, install llvm-toolset-6.0:

    $ sudo yum install llvm-toolset-6.0

    Since LLVM Toolset is delivered as a Red Hat Software Collection (RHSCL), you need to use scl enable to launch a new shell with the llvm-toolset-6.0 collection added to your path.

    $ scl enable llvm-toolset-6.0 bash

    Alternatively, you could permanently add the llvm-toolset-6.0 collection to your profile. For more information, see the article How to install Clang/LLVM 6 and GCC 8 on Red Hat Enterprise Linux 7.

    Let's start fuzzing

    We'll begin by fuzzing a simple C function that returns the first capital letter in a word:

    #include 
    
    char get_first_cap(const char *in, int size) {
      const char *first_cap = NULL;
    
      if (size == 0)
        return ' ';
      for ( ; *in != 0; in++) {
        if (*in >= 'A' && *in <= 'Z') {
          first_cap = in;
          break;
        }
      }
      return *first_cap;
    }
    
    int LLVMFuzzerTestOneInput(const char *Data, long long Size) {
      get_first_cap(Data, Size);
      return 0;
    }
    

    In this C file, we have the function we want to test (get_first_cap) along with a target function (LLVMFuzzerTestOneInput) that the fuzzer will call to pass its input to the function.

    Now we can compile this function using clang to create a fuzzable binary:

    $ clang -g -fsanitize=fuzzer first-cap.c -o fuzz-first-cap
    

    With the -fsantize=fuzzer flag, clang will automatically link our program against the fuzzer library, which includes its own main function. We now have an executable, fuzz-first-cap, that we can use to fuzz the get_first_cap function.

    If we run our fuzz-first-cap program with no arguments, libFuzzer will generate random inputs to test our program. We can also provide a corpus of legal inputs to help libFuzzer to be smarter about the kinds of inputs it generates.

    $ mkdir corpus
    $ echo "Apple" > corpus/Apple.txt
    $ echo "aPple" > corpus/aPple.txt
    $ echo "apPle" > corpus/apPle.txt
    

    Now if we run our program with this corpus, we will see that libFuzzer identifies a problem, right away (note we are only using the -seed=1 option to get reproducible output; this is optional):

    $ ./fuzz-first-cap -seed=1 corpus
    
    INFO: Seed: 1
    INFO: Loaded 1 modules   (8 inline 8-bit counters): 8 [0x670fa0, 0x670fa8), 
    INFO: Loaded 1 PC tables (8 PCs): 8 [0x45fd48,0x45fdc8), 
    INFO:        3 files found in corpus
    INFO: -max_len is not provided; libFuzzer will not generate inputs larger than 4096 bytes
    INFO: seed corpus: files: 3 min: 6b max: 6b total: 18b rss: 33Mb
    #4      INITED cov: 5 ft: 7 corp: 2/12b exec/s: 0 rss: 34Mb
    #6      REDUCE cov: 5 ft: 7 corp: 2/10b exec/s: 0 rss: 34Mb L: 4/6 MS: 2 ChangeBinInt-EraseBytes-
    UndefinedBehaviorSanitizer:DEADLYSIGNAL
    ==15554==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000045473a bp 0x7ffc2eacb4d0 sp 0x7ffc2eacb4a0 T15554)
    ==15554==The signal is caused by a READ memory access.
    ==15554==Hint: address points to the zero page.
        #0 0x454739 in get_first_cap /first-cap.c:13:11
        #1 0x4547b6 in LLVMFuzzerTestOneInput /first-cap.c:17:3
        #2 0x415b99 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (fuzz-first-cap+0x415b99)
        #3 0x418954 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) (fuzz-first-cap+0x418954)
        #4 0x41a1f7 in fuzzer::Fuzzer::MutateAndTestOne() (fuzz-first-cap+0x41a1f7)
        #5 0x41a9af in fuzzer::Fuzzer::Loop(std::vector<std::string, fuzzer::fuzzer_allocator > const&) (fuzz-first-cap+0x41a9af)
        #6 0x410193 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (fuzz-first-cap+0x410193)
        #7 0x406562 in main (fuzz-first-cap+0x406562)
        #8 0x7fcb5a8a53d4 in __libc_start_main (/lib64/libc.so.6+0x223d4)
        #9 0x4065aa in _start (fuzz-first-cap+0x4065aa)
    
    UndefinedBehaviorSanitizer can not provide additional info.
    ==15554==ABORTING
    MS: 4 ShuffleBytes-ShuffleBytes-ChangeBit-EraseBytes-; base unit: 7469c22975699536c6c6d00767e773b5429fefc6
    0x65,0x0,
    e\x00
    artifact_prefix='./'; Test unit written to ./crash-36282fac116d9fd6b37cc425310e1a8510f08a53
    Base64: ZQA=
    

    The most relevant part of the output, is the stack trace, which shows us there was a segmentation fault and then the information about the input that caused the crash, which comes at the end of the output. In this case, we crashed on a 2-byte input with no capital letters: e, \x00.

    There has also been a new file added to our corpus directory:

    $ cat corpus/7469c22975699536c6c6d00767e773b5429fefc6
    apP
    

    This is a "good" input that libFuzzer generated while fuzzing our program. libFuzzer will add all good inputs it finds to the corpus directory.

    So let's fix this bug and then try again:

    #include 
    
    char get_first_cap(const char *in, int size) {
      const char *first_cap = NULL;
    
      if (size == 0)
        return ' ';
      for ( ; *in != 0; in++) {
        if (*in >= 'A' && *in <= 'Z') {
          first_cap = in;
          break;
        }
      }
      if (first_cap)
        return *first_cap;
      else
        return ' ';
    }
    
    int LLVMFuzzerTestOneInput(const char *Data, long long Size) {
      get_first_cap(Data, Size);
      return 0;
    }
    

    Then recompile:

    $ clang -g -fsanitize=fuzzer first-cap.c -o fuzz-first-cap
    

    And run:

    $ ./fuzz-first-cap  -seed=1 corpus
    

    This time, libFuzzer did not find any issues after running for around 30 seconds. By default, libFuzzer, will run forever until it finds a bug, but you can configure this using the flag -runs=X.

    So far, our fuzzer has been used to detect segmentation faults, but you can also pair it without one of the clang sanitizers to check for other kinds of errors. For example, we can take our program and compile it with the address sanitizer enabled:

    clang -g -fsanitize=fuzzer,address first-cap.c -o fuzz-first-cap
    

    Now when we run the program, we see a new error:

    ==15569==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6020000000f1 at pc 0x000000558507 bp 0x7fff78272c30 sp 0x7fff78272c28
    READ of size 1 at 0x6020000000f1 thread T0
        #0 0x558506 in get_first_cap /first-cap.c:8:11
        #1 0x558766 in LLVMFuzzerTestOneInput /first-cap.c:21:3
        #2 0x42cea9 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) (fuzz-first-cap+0x42cea9)
        #3 0x42fc64 in fuzzer::Fuzzer::RunOne(unsigned char const*, unsigned long, bool, fuzzer::InputInfo*, bool*) (fuzz-first-cap+0x42fc64)
        #4 0x4317df in fuzzer::Fuzzer::ReadAndExecuteSeedCorpora(std::vector<std::string, fuzzer::fuzzer_allocator > const&) (fuzz-first-cap+0x4317df)
        #5 0x431b72 in fuzzer::Fuzzer::Loop(std::vector<std::string, fuzzer::fuzzer_allocator > const&) (fuzz-first-cap+0x431b72)
        #6 0x4274a3 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) (fuzz-first-cap+0x4274a3)
        #7 0x41d852 in main (fuzz-first-cap+0x41d852)
        #8 0x7f88abaca3d4 in __libc_start_main (/lib64/libc.so.6+0x223d4)
        #9 0x41d8bb in _start (fuzz-first-cap+0x41d8bb)
    ...

    Here the fuzzer has triggered a heap buffer overflow, which was caught by the address sanitizer. In this case, the input was a string without a null terminator and it caught a bug in our program where we assumed the input would be null terminated.

    Besides the address sanitizer, you can also use libFuzzer with LLVM's undefined behavior sanitizer (UBSAN).

    There is a lot more you can do with libFuzzer beyond what is shown here in this simple introduction. For more information see the libFuzzer documentation.

    Related Articles

    • Clang/LLVM 6.0, Go 1.10, and Rust 1.29 NOW GA for RHEL
    • Support Lifecycle for Clang/LLVM, Go, and Rust
    • GCC Undefined Behavior Sanitizer – ubsan
    • Detecting String Truncation with GCC 8
    • Usability improvements in GCC 8
    Last updated: November 1, 2023

    Recent Posts

    • GuideLLM: Evaluate LLM deployments for real-world inference

    • Unleashing multimodal magic with RamaLama

    • Integrate Red Hat AI Inference Server & LangChain in agentic workflows

    • Streamline multi-cloud operations with Ansible and ServiceNow

    • Automate dynamic application security testing with RapiDAST

    Red Hat Developers logo LinkedIn YouTube Twitter Facebook

    Products

    • Red Hat Enterprise Linux
    • Red Hat OpenShift
    • Red Hat Ansible Automation Platform

    Build

    • Developer Sandbox
    • Developer Tools
    • Interactive Tutorials
    • API Catalog

    Quicklinks

    • Learning Resources
    • E-books
    • Cheat Sheets
    • Blog
    • Events
    • Newsletter

    Communicate

    • About us
    • Contact sales
    • Find a partner
    • Report a website issue
    • Site Status Dashboard
    • Report a security problem

    RED HAT DEVELOPER

    Build here. Go anywhere.

    We serve the builders. The problem solvers who create careers with code.

    Join us if you’re a developer, software engineer, web designer, front-end designer, UX designer, computer scientist, architect, tester, product manager, project manager or team lead.

    Sign me up

    Red Hat legal and privacy links

    • About Red Hat
    • Jobs
    • Events
    • Locations
    • Contact Red Hat
    • Red Hat Blog
    • Inclusion at Red Hat
    • Cool Stuff Store
    • Red Hat Summit

    Red Hat legal and privacy links

    • Privacy statement
    • Terms of use
    • All policies and guidelines
    • Digital accessibility

    Report a website issue