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
 }
 

Reply via email to