Skip to main content

Fuzz test Python modules with libFuzzer.

Project description

buildstatus

About

Use libFuzzer to fuzz test Python 3.6+ C extension modules.

Ideas

  • Use type annotations for less type errors in generic mutator.
  • Add support to fuzz test pure Python modules by generating C code from them using Cython.

Installation

$ apt install clang
$ pip install pyfuzzer

Example Usage

Use the default generic mutator when testing the module hello_world.

$ cd examples/hello_world
$ pyfuzzer hello_world hello_world.c
clang -fprofile-instr-generate -fcoverage-mapping -g -fsanitize=fuzzer -fsanitize=signed-integer-overflow -fno-sanitize-recover=all -I/usr/include/python3.7m hello_world.c module.c /home/erik/workspace/pyfuzzer/pyfuzzer/pyfuzzer.c -Wl,-Bsymbolic-functions -Wl,-z,relro -lpython3.7m -o hello_world
rm -f hello_world.profraw
./hello_world -max_total_time=1 -max_len=4096
INFO: Seed: 1479758674
INFO: Loaded 1 modules   (22 inline 8-bit counters): 22 [0x47446d, 0x474483),
INFO: Loaded 1 PC tables (22 PCs): 22 [0x4616e0,0x461840),
ModuleNotFoundError: No module named 'mutator'
INFO: A corpus is not provided, starting from an empty corpus
#2   INITED cov: 7 ft: 8 corp: 1/1b lim: 4 exec/s: 0 rss: 44Mb
#10  NEW    cov: 8 ft: 9 corp: 2/3b lim: 4 exec/s: 0 rss: 44Mb L: 2/2 MS: 3 ChangeByte-ChangeBit-CopyPart-
#11  NEW    cov: 9 ft: 10 corp: 3/6b lim: 4 exec/s: 0 rss: 44Mb L: 3/3 MS: 1 CopyPart-
#23  NEW    cov: 10 ft: 11 corp: 4/10b lim: 4 exec/s: 0 rss: 44Mb L: 4/4 MS: 2 CopyPart-CrossOver-
#1044738     DONE   cov: 10 ft: 11 corp: 4/10b lim: 4096 exec/s: 522369 rss: 44Mb
Done 1044738 runs in 2 second(s)
llvm-profdata merge -sparse hello_world.profraw -o hello_world.profdata
llvm-cov show hello_world -instr-profile=hello_world.profdata -ignore-filename-regex=\.h|pyfuzzer.c|module.c
    1|       |#include <Python.h>
    2|       |
    3|       |PyDoc_STRVAR(
    4|       |    tell_doc,
    5|       |    "tell(message)\n"
    6|       |    "--\n"
    7|       |    "Arguments: (message:bytes)\n");
    8|       |
    9|       |static PyObject *m_tell(PyObject *module_p, PyObject *message_p)
   10|  1.04M|{
   11|  1.04M|    Py_ssize_t size;
   12|  1.04M|    char* buf_p;
   13|  1.04M|    int res;
   14|  1.04M|    PyObject *res_p;
   15|  1.04M|
   16|  1.04M|    res = PyBytes_AsStringAndSize(message_p, &buf_p, &size);
   17|  1.04M|
   18|  1.04M|    if (res != -1) {
   19|  1.04M|        switch (size) {
   20|  1.04M|
   21|  1.04M|        case 0:
   22|  47.6k|            res_p = PyLong_FromLong(5);
   23|  47.6k|            break;
   24|  1.04M|
   25|  1.04M|        case 1:
   26|   107k|            res_p = PyBool_FromLong(1);
   27|   107k|            break;
   28|  1.04M|
   29|  1.04M|        case 2:
   30|   114k|            res_p = PyBytes_FromString("Hello!");
   31|   114k|            break;
   32|  1.04M|
   33|  1.04M|        default:
   34|   774k|            res_p = PyLong_FromLong(0);
   35|   774k|            break;
   36|      0|        }
   37|      0|    } else {
   38|      0|        Py_INCREF(Py_None);
   39|      0|        res_p = Py_None;
   40|      0|    }
   41|  1.04M|
   42|  1.04M|    return (res_p);
   43|  1.04M|}
   44|       |
   45|       |static struct PyMethodDef methods[] = {
   46|       |    { "tell", m_tell, METH_O, tell_doc},
   47|       |    { NULL }
   48|       |};
   49|       |
   50|       |static PyModuleDef module = {
   51|       |    PyModuleDef_HEAD_INIT,
   52|       |    .m_name = "hello_world",
   53|       |    .m_size = -1,
   54|       |    .m_methods = methods
   55|       |};
   56|       |
   57|       |PyMODINIT_FUNC PyInit_hello_world(void)
   58|      1|{
   59|      1|    return (PyModule_Create(&module));
   60|      1|}

Use a custom mutator when testing the module hello_world.

Testing with a custom mutator is often more efficient then using a generic.

$ cd examples/hello_world
$ pyfuzzer -m mutator.py hello_world hello_world.c
...

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Files for pyfuzzer, version 0.6.0
Filename, size File type Python version Upload date Hashes
Filename, size pyfuzzer-0.6.0.tar.gz (6.2 kB) File type Source Python version None Upload date Hashes View

Supported by

AWS AWS Cloud computing Datadog Datadog Monitoring DigiCert DigiCert EV certificate Facebook / Instagram Facebook / Instagram PSF Sponsor Fastly Fastly CDN Google Google Object Storage and Download Analytics Pingdom Pingdom Monitoring Salesforce Salesforce PSF Sponsor Sentry Sentry Error logging StatusPage StatusPage Status page