Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions 1 Modules/_xxtestfuzz/fuzz_tests.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,4 @@ fuzz_sre_compile
fuzz_sre_match
fuzz_csv_reader
fuzz_struct_unpack
fuzz_pickle_loads
81 changes: 81 additions & 0 deletions 81 Modules/_xxtestfuzz/fuzzer.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,74 @@ static int fuzz_struct_unpack(const char* data, size_t size) {
}


PyObject* pickle_loads_method = NULL;
Comment thread
gpshead marked this conversation as resolved.
PyObject* pickle_error = NULL;
PyObject* pickling_error = NULL;
PyObject* unpickling_error = NULL;
/* Called by LLVMFuzzerTestOneInput for initialization */
static int init_pickle_loads() {
/* Import pickle.loads */
PyObject* pickle_module = PyImport_ImportModule("pickle");
if (pickle_module == NULL) {
return 0;
}
pickle_error = PyObject_GetAttrString(pickle_module, "PickleError");
if (pickle_error == NULL) {
return 0;
}
pickling_error = PyObject_GetAttrString(pickle_module, "PicklingError");
if (pickling_error == NULL) {
return 0;
}
unpickling_error = PyObject_GetAttrString(pickle_module, "UnpicklingError");
if (unpickling_error == NULL) {
return 0;
}
pickle_loads_method = PyObject_GetAttrString(pickle_module, "loads");
return pickle_loads_method != NULL;
}

#define MAX_PICKLE_TEST_SIZE 0x10000
/* Fuzz pickle.loads(x) */
static int fuzz_pickle_loads(const char* data, size_t size) {
if (size > MAX_PICKLE_TEST_SIZE) {
return 0;
}
PyObject* input_bytes = PyBytes_FromStringAndSize(data, size);
if (input_bytes == NULL) {
return 0;
}
PyObject* parsed = PyObject_CallOneArg(pickle_loads_method, input_bytes);
if (parsed == NULL &&
(PyErr_ExceptionMatches(PyExc_ValueError) ||
PyErr_ExceptionMatches(PyExc_AttributeError) ||
PyErr_ExceptionMatches(PyExc_KeyError) ||
PyErr_ExceptionMatches(PyExc_TypeError) ||
PyErr_ExceptionMatches(PyExc_OverflowError) ||
PyErr_ExceptionMatches(PyExc_EOFError) ||
PyErr_ExceptionMatches(PyExc_MemoryError) ||
PyErr_ExceptionMatches(PyExc_ModuleNotFoundError) ||
PyErr_ExceptionMatches(PyExc_IndexError) ||
PyErr_ExceptionMatches(PyExc_RecursionError) ||
PyErr_ExceptionMatches(PyExc_UnicodeDecodeError)))
{
PyErr_Clear();
}

if (parsed == NULL && (
PyErr_ExceptionMatches(pickle_error) ||
PyErr_ExceptionMatches(pickling_error) ||
PyErr_ExceptionMatches(unpickling_error)

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not simply PyErr_ExceptionMatches(PyExc_Exception)? We don't really care which exact exception is raised.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

other fuzzers in this module also work like this, but if we're going to list exceptions to ignore, we should at least add comments as to why for each or at least each class.

I assume this being a pickle.loads test is really looking for process crashes.

unfortunately... I expect the results of this as a fuzzer to be pretty bad, pickle is explicitly documented as not being suitable for untrusted data. it may execute arbitrary code or crash in that situation. i asked this broader question on the bug.

))
{
PyErr_Clear();
}
Py_DECREF(input_bytes);
Py_XDECREF(parsed);
return 0;
}


#define MAX_JSON_TEST_SIZE 0x10000

PyObject* json_loads_method = NULL;
Expand Down Expand Up @@ -452,6 +520,19 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
}
rv |= _run_fuzz(data, size, fuzz_struct_unpack);
#endif

#if !defined(_Py_FUZZ_ONE) || defined(_Py_FUZZ_fuzz_pickle_loads)
static int PICKLE_LOADS_INITIALIZED = 0;
if (!PICKLE_LOADS_INITIALIZED && !init_pickle_loads()) {
PyErr_Print();
abort();
} else {
PICKLE_LOADS_INITIALIZED = 1;
}

rv |= _run_fuzz(data, size, fuzz_pickle_loads);
#endif

#if !defined(_Py_FUZZ_ONE) || defined(_Py_FUZZ_fuzz_json_loads)
static int JSON_LOADS_INITIALIZED = 0;
if (!JSON_LOADS_INITIALIZED && !init_json_loads()) {
Expand Down
Morty Proxy This is a proxified and sanitized view of the page, visit original site.