package: src:matplotlib version: 0.99.3-1 severity: serious tag: security, patch
Matt Giuca reported a matplotlib buffer overrun to the private security team request tracker in 2013, which ended up falling through the cracks at the time. See below for the original message and a proposed patch attached. On Wed, Jan 23, 2013 at 11:21:14PM +0000, Matt Giuca via RT wrote: > The bug is in > src/mplutils.cpp<https://github.com/matplotlib/matplotlib/blob/master/src/mplutils.cpp>. > The Printf::Printf constructor accepts an arbitrary format string and > values, and dumps it into a 1024-byte buffer with vsprintf. This is > obviously not safe, as the user can simply supply enough bytes to overflow > the 1024-byte buffer. > > The bug can be exploited from Python code, through a number of > Python-exposed functions that call Printf. The most obvious entry-point I > can find is ft2font.FT2Font constructor: > > >>> from matplotlib import ft2font > >>> ft2font.FT2Font('x' * 2048) > *** glibc detected *** python: free(): invalid next size (normal): > 0x00000000029f1480 *** > > There are several other Python functions that call Printf with > user-supplied data, but this is the cleanest one. > > As for what this can be used for: I'm not an expert in exploiting > vulnerabilities, but it allows any user who can supply either Python code > to be executed, or certain specific strings such as the name of a font, to > write an arbitrary number of bytes to a location on the heap, and I know > that that can potentially be used to compromise a machine.
diff --git a/lib/matplotlib/__init__.py b/lib/matplotlib/__init__.py index c7e3141..37feb20 100644 --- a/lib/matplotlib/__init__.py +++ b/lib/matplotlib/__init__.py @@ -1114,6 +1114,7 @@ default_test_modules = [ 'matplotlib.tests.test_lines', 'matplotlib.tests.test_mathtext', 'matplotlib.tests.test_mlab', + 'matplotlib.tests.test_mplutils', 'matplotlib.tests.test_patches', 'matplotlib.tests.test_pickle', 'matplotlib.tests.test_rcparams', diff --git a/lib/matplotlib/tests/test_mplutils.py b/lib/matplotlib/tests/test_mplutils.py new file mode 100644 index 0000000..e37e41c --- /dev/null +++ b/lib/matplotlib/tests/test_mplutils.py @@ -0,0 +1,12 @@ +from __future__ import print_function +from nose.tools import assert_raises +from matplotlib import ft2font +from matplotlib.testing.decorators import knownfailureif +import sys + +def test_printf_buffer(): + """Tests Printf for buffer overrun.""" + # Use ft2font.FT2Font, which indirectly calls the Printf function in + # mplutils.cpp. + # Expect a RuntimeError, since the font is not found. + assert_raises(RuntimeError, ft2font.FT2Font, 'x' * 2048) diff --git a/src/mplutils.cpp b/src/mplutils.cpp index febb97a..af3a2f3 100644 --- a/src/mplutils.cpp +++ b/src/mplutils.cpp @@ -18,7 +18,10 @@ Printf::Printf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); - vsprintf(buffer, fmt, ap); + vsnprintf(buffer, 1024, fmt, ap); + // Null-terminate the string. Non-standard C implementations (e.g., + // Microsoft Visual C++) do not do this automatically. + buffer[1023] = '\0'; va_end(ap); // look ma - I rememberd it this time }