Fuzz test Python modules with libFuzzer.
Project description
About
Use libFuzzer to fuzz test Python 3.6+ C extension modules.
Installation
clang 8 or later is required.
$ apt install clang $ pip install pyfuzzer
Example Usage
Hello world
Use the default mutator pyfuzzer.mutators.generic when testing the module hello_world.
$ cd examples/hello_world $ pyfuzzer run -l max_total_time=1 hello_world hello_world.c <lots of libFuzzer output>
Print the function calls that found new code paths. This information is usually useful when writing unit tests.
$ pyfuzzer print_corpus corpus/25409981b15b978c9fb5a5a2f4dab0c4b04e295f: tell(b'') = 5 corpus/a8a4e6c9abfd3c6cba171579190702ddc1317df0: tell(b'\xfd#') = b'Hello!' corpus/80f87702ef9fbe4baf17095c79ff928b9fa1ea14: tell(b'\x00') = True corpus/be3d1b7df189727b2cecd6526aa8f24abbf6df10: tell(b'\x00\xfd\x00') = 0 corpus/defd8787d638f271cd83362eafe7fdeed9fa4a8f: tell(None) raises: Traceback (most recent call last): File "/home/erik/workspace/pyfuzzer/pyfuzzer/mutators/utils.py", line 35, in print_callable res = obj(*args) TypeError: expected bytes, NoneType found
See the hello_world for all files.
Hello world fatal error
Similar to the previous example, but triggers a fatal error when tell() is called with a bytes object longer than 2 bytes as its first argument.
$ cd examples/hello_world_fatal_error $ pyfuzzer run hello_world hello_world.c ... Fatal Python error: deallocating None Current thread 0x00007f7ca99c2780 (most recent call first): ...
Print the function call that caused the crash. Just as expected, the first argument is clearly longer than 2 bytes.
$ pyfuzzer print_crashes crash-1013ed88cd71fd14407b2bdbc17b95d7bc317c21: tell(b'\n\xbf+') = None
See the hello_world_fatal_error for all files.
Custom mutator
Use the custom mutator hello_world_mutator when testing the module hello_world.
Testing with a custom mutator is often more efficient than using a generic one.
$ cd examples/hello_world_custom_mutator $ pyfuzzer run -l max_total_time=1 -m hello_world_mutator.py hello_world hello_world.c ...
See the hello_world_custom_mutator for all files.
Mutators
A mutator module uses data from libFuzzer to test a module. A mutator module must implement the function setup(module), where module is the module under test. It shall return a mutator instance that implements the methods test_one_input(self, data) and test_one_input_print(self, data), where data is the data generated by libFuzzer (as a bytes object).
test_one_input(self, data) performs the actual fuzz testing, while test_one_input_print(self, data) prints corpus and crashes.
A minimal mutator fuzz testing a CRC-32 algorithm could look like below. It simply calls crc_32() with data as its only argument.
from pyfuzzer.mutators.generic import print_callable class Mutator: def __init__(self, module): self._module = module def test_one_input(self, data): return module.crc_32(data) def test_one_input_print(self, data): print_callable(self._module.crc_32, [data]) def setup(module): return Mutator(module)
Ideas
- Add support to fuzz test pure Python modules by generating C code using Cython.
- Colors!
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Filename, size | File type | Python version | Upload date | Hashes |
---|---|---|---|---|
Filename, size pyfuzzer-0.16.0.tar.gz (11.5 kB) | File type Source | Python version None | Upload date | Hashes View |