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.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.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.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.
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.
Source Distribution
File details
Details for the file pyfuzzer-0.19.0.tar.gz
.
File metadata
- Download URL: pyfuzzer-0.19.0.tar.gz
- Upload date:
- Size: 12.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/1.13.0 pkginfo/1.5.0.1 requests/2.21.0 setuptools/40.8.0 requests-toolbelt/0.9.1 tqdm/4.31.1 CPython/3.7.3
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 95d88b716066522ba3eb7dba0aa6ba43ea852a34a9d250cfbff01bd10bdff588 |
|
MD5 | 832acc5aaad0d83bfcc76e2651a032bc |
|
BLAKE2b-256 | fbb807c19c09ed768a586986547d281709e84c73fc14087db124649ee0f08d05 |