Bug 591747 - python: corrupted double-linked list when running pylint on certain scripts
Summary: python: corrupted double-linked list when running pylint on certain scripts
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Security Response
Classification: Other
Component: vulnerability
Version: unspecified
Hardware: All
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Red Hat Product Security
QA Contact:
URL:
Whiteboard:
Depends On:
Blocks:
TreeView+ depends on / blocked
 
Reported: 2010-05-12 23:18 UTC by Vincent Danen
Modified: 2019-09-29 12:36 UTC (History)
1 user (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2010-08-10 18:52:52 UTC


Attachments (Terms of Use)

Description Vincent Danen 2010-05-12 23:18:40 UTC
A Debian bug report [1] indicated a memory corruption issue when pylint is run on a script that just imports numpy. I've tried this on Fedora 12 and 13 and it is reproducable:


$cat test.py
#!/usr/bin/env python
import numpy
$ pylint test.py
...
*** glibc detected *** /usr/bin/python: corrupted double-linked list: 0x0000000001a2f740 ***

I would be ready to write this off as a "don't do that" kind of thing, but I don't know if the issue is with numpy or with python itself.  Running it through valgrind I see:

==17765== Invalid read of size 8
==17765==    at 0x3E6B07CDB9: insertdict (dictobject.c:459)
==17765==    by 0x3E6B07F87F: PyDict_SetItem (dictobject.c:701)
==17765==    by 0x3E6B08138C: _PyModule_Clear (moduleobject.c:138)
==17765==    by 0x3E6B0F1FB1: PyImport_Cleanup (import.c:492)
==17765==    by 0x3E6B0FB1D7: Py_Finalize (pythonrun.c:434)
==17765==    by 0x3E6B0FB2E7: Py_Exit (pythonrun.c:1714)
==17765==    by 0x3E6B0FB417: handle_system_exit (pythonrun.c:1116)
==17765==    by 0x3E6B0FB65C: PyErr_PrintEx (pythonrun.c:1126)
==17765==    by 0x3E6B0FBB26: PyRun_SimpleFileExFlags (pythonrun.c:935)
==17765==    by 0x3E6B10833C: Py_Main (main.c:599)
==17765==    by 0x3E5801EC5C: (below main) (libc-start.c:226)
==17765==  Address 0xf9a44f0 is 0 bytes inside a block of size 144 free'd
==17765==    at 0x4A04D72: free (vg_replace_malloc.c:325)
==17765==    by 0x3E6B07CDFE: insertdict (dictobject.c:459)
==17765==    by 0x3E6B07F87F: PyDict_SetItem (dictobject.c:701)
==17765==    by 0x3E6B08138C: _PyModule_Clear (moduleobject.c:138)
==17765==    by 0x3E6B0F1FB1: PyImport_Cleanup (import.c:492)
==17765==    by 0x3E6B0FB1D7: Py_Finalize (pythonrun.c:434)
==17765==    by 0x3E6B0FB2E7: Py_Exit (pythonrun.c:1714)
==17765==    by 0x3E6B0FB417: handle_system_exit (pythonrun.c:1116)
==17765==    by 0x3E6B0FB65C: PyErr_PrintEx (pythonrun.c:1126)
==17765==    by 0x3E6B0FBB26: PyRun_SimpleFileExFlags (pythonrun.c:935)
==17765==    by 0x3E6B10833C: Py_Main (main.c:599)
==17765==    by 0x3E5801EC5C: (below main) (libc-start.c:226)

and:

==17765== Invalid read of size 8
==17765==    at 0x3E6B07E869: dict_dealloc (dictobject.c:911)
==17765==    by 0x3E6B0A0E1F: subtype_dealloc (typeobject.c:1009)
==17765==    by 0x3E6B07CDFE: insertdict (dictobject.c:459)
==17765==    by 0x3E6B07F87F: PyDict_SetItem (dictobject.c:701)
==17765==    by 0x3E6B08138C: _PyModule_Clear (moduleobject.c:138)
==17765==    by 0x3E6B0F1FB1: PyImport_Cleanup (import.c:492)
==17765==    by 0x3E6B0FB1D7: Py_Finalize (pythonrun.c:434)
==17765==    by 0x3E6B0FB2E7: Py_Exit (pythonrun.c:1714)
==17765==    by 0x3E6B0FB417: handle_system_exit (pythonrun.c:1116)
==17765==    by 0x3E6B0FB65C: PyErr_PrintEx (pythonrun.c:1126)
==17765==    by 0x3E6B0FBB26: PyRun_SimpleFileExFlags (pythonrun.c:935)
==17765==    by 0x3E6B10833C: Py_Main (main.c:599)
==17765==  Address 0xf9a55b0 is 0 bytes inside a block of size 144 free'd
==17765==    at 0x4A04D72: free (vg_replace_malloc.c:325)
==17765==    by 0x3E6B07CDFE: insertdict (dictobject.c:459)
==17765==    by 0x3E6B07F87F: PyDict_SetItem (dictobject.c:701)
==17765==    by 0x3E6B08138C: _PyModule_Clear (moduleobject.c:138)
==17765==    by 0x3E6B0F1FB1: PyImport_Cleanup (import.c:492)
==17765==    by 0x3E6B0FB1D7: Py_Finalize (pythonrun.c:434)
==17765==    by 0x3E6B0FB2E7: Py_Exit (pythonrun.c:1714)
==17765==    by 0x3E6B0FB417: handle_system_exit (pythonrun.c:1116)
==17765==    by 0x3E6B0FB65C: PyErr_PrintEx (pythonrun.c:1126)
==17765==    by 0x3E6B0FBB26: PyRun_SimpleFileExFlags (pythonrun.c:935)
==17765==    by 0x3E6B10833C: Py_Main (main.c:599)
==17765==    by 0x3E5801EC5C: (below main) (libc-start.c:226)


Which made me look at the python source for Objects/dictobject.c, which has:

459         Py_DECREF(old_value); /* which **CAN** re-enter */
...
911             Py_XDECREF(ep->me_value);

This is about as far as I can take it.  I have concerns that this would be a python issue, and not a numpy issue.  Can someone take a closer look at this to determine if that is the case?  I'm also unsure as to whether or not this is exploitable, or if it is just a crash (making pylint crash is not what I would consider a security issue, but if this is something in python there may be other avenues).

Comment 1 Vincent Danen 2010-05-12 23:20:37 UTC
Ooops, forgot to note the Debian bug:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=581058

Comment 2 Josh Bressers 2010-08-10 18:52:52 UTC
This isn't a security flaw. From reading the upstream bug:
http://projects.scipy.org/numpy/ticket/1464

It's trying to free an invalid pointer on exit. Even if we didn't have the various memory protections, this isn't going to be exploitable, as if the pointer is being freed during python cleanup, the attacker has lost control over memory at that point.

There is no potential for arbitrary code execution, and since it crashes at script exit, it's not a DoS either.


Note You need to log in before you can comment on or make changes to this bug.