A coverage-guided fuzzer for Python and Python extensions based on libFuzzer
npx @tessl/cli install tessl/pypi-atheris@2.3.0A coverage-guided Python fuzzing engine based on libFuzzer. Atheris enables fuzzing of Python code and native extensions, providing feedback-guided testing to discover bugs through automatic input generation and mutation.
pip install atherisimport atherisFor specific functionality:
from atheris import Setup, Fuzz, FuzzedDataProvider
from atheris import instrument_imports, instrument_func, instrument_all#!/usr/bin/python3
import atheris
import sys
# Import libraries to fuzz within instrumentation context
with atheris.instrument_imports():
import some_library
def TestOneInput(data):
"""Fuzzer entry point that receives random bytes from libFuzzer."""
some_library.parse(data)
# Configure and start fuzzing
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()Advanced usage with data provider:
import atheris
import sys
with atheris.instrument_imports():
import target_module
def TestOneInput(data):
fdp = atheris.FuzzedDataProvider(data)
# Extract structured data from raw bytes
length = fdp.ConsumeIntInRange(1, 100)
text = fdp.ConsumeUnicodeNoSurrogates(length)
flag = fdp.ConsumeBool()
target_module.process(text, flag)
atheris.Setup(sys.argv, TestOneInput)
atheris.Fuzz()Atheris implements coverage-guided fuzzing through several key components:
Essential functions for setting up and running the fuzzer, including configuration and execution control.
def Setup(args, test_one_input, internal_libfuzzer=None, custom_mutator=None, custom_crossover=None):
"""
Configure the fuzzer with test function and options.
Args:
args (list): Command-line arguments (typically sys.argv)
test_one_input (callable): Function that takes bytes and performs testing
internal_libfuzzer (bool, optional): Use internal libfuzzer (auto-detected if None)
custom_mutator (callable, optional): Custom mutation function
custom_crossover (callable, optional): Custom crossover function
Returns:
list: Remaining command-line arguments after fuzzer consumption
"""
def Fuzz():
"""
Start the fuzzing loop. Must call Setup() first.
This function does not return - it runs until the fuzzer stops
due to finding a crash, reaching run limits, or external termination.
"""
def Mutate(data, max_size):
"""
Mutate input data using libFuzzer's built-in mutator.
Args:
data (bytes): Input data to mutate
max_size (int): Maximum size of mutated output
Returns:
bytes: Mutated data
"""Utilities for converting raw fuzzer bytes into structured data types for more effective testing.
class FuzzedDataProvider:
"""Converts raw fuzzer bytes into various data types."""
def __init__(self, input_bytes: bytes):
"""Initialize with raw fuzzer input."""
def ConsumeBytes(self, count: int) -> bytes:
"""Consume count bytes from the input."""
def ConsumeInt(self, byte_size: int) -> int:
"""Consume a signed integer of specified byte size."""
def ConsumeIntInRange(self, min_val: int, max_val: int) -> int:
"""Consume an integer in the range [min_val, max_val]."""
def ConsumeBool(self) -> bool:
"""Consume either True or False."""Functions for adding coverage instrumentation to Python code at import-time, runtime, or globally.
def instrument_imports(include=None, exclude=None, enable_loader_override=True):
"""
Context manager that instruments Python modules imported within the context.
Args:
include (list, optional): Module names to include
exclude (list, optional): Module names to exclude
enable_loader_override (bool): Enable custom loader instrumentation
Returns:
Context manager for instrumented imports
"""
def instrument_func(func):
"""
Decorator that instruments a specific Python function.
Args:
func (callable): Function to instrument
Returns:
callable: Instrumented function
"""
def instrument_all():
"""Instrument all currently loaded Python functions."""Hook management, custom mutators, and specialized instrumentation for regex and string operations.
# Hook management
enabled_hooks = EnabledHooks() # Global hook manager
def gen_match(pattern):
"""
Generate a string that matches a regex pattern.
Args:
pattern (str or bytes): Regular expression pattern
Returns:
str or bytes: String that matches the pattern
"""
def path() -> str:
"""
Get the path to the Atheris installation directory.
Returns:
str: Path to the directory containing Atheris files
"""
# Constants
ALL_REMAINING: int # Special value for FuzzedDataProvider to consume all remaining bytesclass EnabledHooks:
"""Manages the set of enabled instrumentation hooks."""
def add(self, hook: str) -> None:
"""
Enable a specific hook.
Args:
hook (str): Hook name ('RegEx' or 'str')
"""
def __contains__(self, hook: str) -> bool:
"""
Check if a hook is enabled.
Args:
hook (str): Hook name to check
Returns:
bool: True if the hook is enabled
"""