Pillow icon indicating copy to clipboard operation
Pillow copied to clipboard

Memory leak in function `fname2char` due to new reference is not decreased (static analyzer report)

Open Snape3058 opened this issue 3 years ago • 4 comments

  1. A new reference is returned and assigned to bytes. https://github.com/python-pillow/Pillow/blob/68e39cba431680105c0e0f1a54371b7028e8da9a/src/Tk/tkImaging.c#L371

  2. Function returns without decreasing the refcnt of bytes. https://github.com/python-pillow/Pillow/blob/68e39cba431680105c0e0f1a54371b7028e8da9a/src/Tk/tkImaging.c#L375

Internal Report ID: c6d448

Snape3058 avatar May 23 '22 06:05 Snape3058

Would you mind providing some detail on how you ran the static analyzer? What tool did you use specifically?

radarhere avatar May 23 '22 09:05 radarhere

It is an experimental analyzer of my unpublished research, which is developed on the top of the clang static analyzer.

Snape3058 avatar May 23 '22 14:05 Snape3058

https://github.com/python-pillow/Pillow/pull/6326#issuecomment-1135809007

I believe this change will cause undefined behaviour by reading deallocated memory.

From https://docs.python.org/3/c-api/bytes.html#c.PyBytes_AsString (emphasis mine):

char *PyBytes_AsString(PyObject *o) Part of the Stable ABI. Return a pointer to the contents of o. The pointer refers to the internal buffer of o, which consists of len(o) + 1 bytes. The last byte in the buffer is always null, regardless of whether there are any other null bytes. The data must not be modified in any way, unless the object was just created using PyBytes_FromStringAndSize(NULL, size). It must not be deallocated. If o is not a bytes object at all, PyBytes_AsString() returns NULL and raises TypeError.

My understanding of this is that the returned buffer will be freed with the decref call.

This would not be picked up by the Valgrind CI run as it is missing a display:

Tests/test_imagetk.py::test_kw SKIPPED (TCL Error: no display name and no $DISPLAY environment variable) [ 63%] Tests/test_imagetk.py::test_photoimage SKIPPED (TCL Error: no display name and no $DISPLAY environment variable) [ 63%] Tests/test_imagetk.py::test_photoimage_blank SKIPPED (TCL Error: no display name and no $DISPLAY environment variable) [ 63%] Tests/test_imagetk.py::test_box_deprecation SKIPPED (TCL Error: no display name and no $DISPLAY environment variable) [ 63%] Tests/test_imagetk.py::test_bitmapimage SKIPPED (TCL Error: no display name and no $DISPLAY environment variable) [ 63%]

radarhere avatar May 24 '22 13:05 radarhere

@radarhere

I agree with this comment. It will lead to a UaF bug if the refcnt is decreased. However, it is also a fact that the PyObject is definitely leaked.

Maybe a better solution is required. Such as copying the content of the string into a temporary buffer, or just returning the PyObject directly, and using the getter function at the places where the content is used.

Snape3058 avatar May 24 '22 14:05 Snape3058