Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Use After Free in deque_index_impl #115243

Copy link
Copy link
Closed
@kcatss

Description

@kcatss
Issue body actions

Crash report

What happened?

Version

Python 3.13.0a3+ (heads/v3.13.0a2:e2c4038924, Feb 10 2024, 12:05:47) [GCC 11.4.0]
bisect from commit 32ea165

Root cause

the deque_index_impl function retrieves an element from the deque using b→data. However, the reference count of the item may decrease due to PyObject_RichCompareBool, leading to a use-after-free

static PyObject *
deque_index_impl(dequeobject *deque, PyObject *v, Py_ssize_t start,
                 Py_ssize_t stop){
...
	while (n--) {
            CHECK_NOT_END(b);
            item = b->data[index]; // <---  don't raise reference count using Py_NewRef
            cmp = PyObject_RichCompareBool(item, v, Py_EQ); //  <---  arbitrary call to __eq__
            if (cmp > 0)
                return PyLong_FromSsize_t(stop - (n + 1));
            else if (cmp < 0)
                return NULL;
            if (start_state != deque->state) {
                PyErr_SetString(PyExc_RuntimeError,
                                "deque mutated during iteration");
                return NULL;
           }
}

POC

import collections

class evil_pre1(object):
    def __eq__(self,o):
        deq.clear()
        return NotImplemented

deq = collections.deque([evil_pre1()])

deq.index(3)

ASAN

asan
=================================================================
==246599==ERROR: AddressSanitizer: heap-use-after-free on address 0xffffb086b3c8 at pc 0xaaaabb857308 bp 0xffffc5757c40 sp 0xffffc5757c50
READ of size 8 at 0xffffb086b3c8 thread T0
    #0 0xaaaabb857304 in Py_TYPE Include/object.h:333
    #1 0xaaaabb857304 in long_richcompare Objects/longobject.c:3265
    #2 0xaaaabb8c1158 in do_richcompare Objects/object.c:922
    #3 0xaaaabb8c1438 in PyObject_RichCompare Objects/object.c:965
    #4 0xaaaabb8c1578 in PyObject_RichCompareBool Objects/object.c:987
    #5 0xaaaabbcc1a5c in deque_index_impl Modules/_collectionsmodule.c:1222
    #6 0xaaaabbcc1c94 in deque_index Modules/clinic/_collectionsmodule.c.h:248
    #7 0xaaaabb7f4ee4 in method_vectorcall_FASTCALL Objects/descrobject.c:401
    #8 0xaaaabb7ccb84 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:168
    #9 0xaaaabb7cccc0 in PyObject_Vectorcall Objects/call.c:327
    #10 0xaaaabbab73e4 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:815
    #11 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115
    #12 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788
    #13 0xaaaabbb00abc in PyEval_EvalCode Python/ceval.c:592
    #14 0xaaaabbc02aec in run_eval_code_obj Python/pythonrun.c:1294
    #15 0xaaaabbc059e0 in run_mod Python/pythonrun.c:1379
    #16 0xaaaabbc0677c in pyrun_file Python/pythonrun.c:1215
    #17 0xaaaabbc08c3c in _PyRun_SimpleFileObject Python/pythonrun.c:464
    #18 0xaaaabbc08ff4 in _PyRun_AnyFileObject Python/pythonrun.c:77
    #19 0xaaaabbc66e68 in pymain_run_file_obj Modules/main.c:357
    #20 0xaaaabbc693d8 in pymain_run_file Modules/main.c:376
    #21 0xaaaabbc69de0 in pymain_run_python Modules/main.c:628
    #22 0xaaaabbc6a084 in Py_RunMain Modules/main.c:707
    #23 0xaaaabbc6a274 in pymain_main Modules/main.c:737
    #24 0xaaaabbc6a5b0 in Py_BytesMain Modules/main.c:761
    #25 0xaaaabb63145c in main Programs/python.c:15
    #26 0xffffb93d73f8 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #27 0xffffb93d74c8 in __libc_start_main_impl ../csu/libc-start.c:392
    #28 0xaaaabb63136c in _start (/home/kk/projects/cpython/python+0x27136c)

0xffffb086b3c8 is located 56 bytes inside of 72-byte region [0xffffb086b390,0xffffb086b3d8)
freed by thread T0 here:
    #0 0xffffb96a9fe8 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127
    #1 0xaaaabb8c9744 in _PyMem_RawFree Objects/obmalloc.c:84
    #2 0xaaaabb8cc580 in _PyMem_DebugRawFree Objects/obmalloc.c:2398
    #3 0xaaaabb8ccd74 in _PyMem_DebugFree Objects/obmalloc.c:2531
    #4 0xaaaabb8f0f78 in PyObject_Free Objects/obmalloc.c:995
    #5 0xaaaabbb7087c in PyObject_GC_Del Python/gc.c:1903
    #6 0xaaaabb914e1c in object_dealloc Objects/typeobject.c:5569
    #7 0xaaaabb938da8 in subtype_dealloc Objects/typeobject.c:2092
    #8 0xaaaabb8bf0b8 in _Py_Dealloc Objects/object.c:2889
    #9 0xaaaabbb69bc4 in Py_DECREF Include/object.h:922
    #10 0xaaaabbb69bc4 in Py_XDECREF Include/object.h:1030
    #11 0xaaaabbb69bc4 in _PyFrame_ClearExceptCode Python/frame.c:140
    #12 0xaaaabbaa276c in clear_thread_frame Python/ceval.c:1652
    #13 0xaaaabbaab750 in _PyEval_FrameClearAndPop Python/ceval.c:1679
    #14 0xaaaabbadc91c in _PyEval_EvalFrameDefault Python/generated_cases.c.h:4914
    #15 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115
    #16 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788
    #17 0xaaaabb7cc2fc in _PyFunction_Vectorcall Objects/call.c:413
    #18 0xaaaabb94bfe0 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:168
    #19 0xaaaabb94bfe0 in vectorcall_unbound Objects/typeobject.c:2271
    #20 0xaaaabb94bfe0 in slot_tp_richcompare Objects/typeobject.c:8983
    #21 0xaaaabb8c1058 in do_richcompare Objects/object.c:916
    #22 0xaaaabb8c1438 in PyObject_RichCompare Objects/object.c:965
    #23 0xaaaabb8c1578 in PyObject_RichCompareBool Objects/object.c:987
    #24 0xaaaabbcc1a5c in deque_index_impl Modules/_collectionsmodule.c:1222
    #25 0xaaaabbcc1c94 in deque_index Modules/clinic/_collectionsmodule.c.h:248
    #26 0xaaaabb7f4ee4 in method_vectorcall_FASTCALL Objects/descrobject.c:401
    #27 0xaaaabb7ccb84 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:168
    #28 0xaaaabb7cccc0 in PyObject_Vectorcall Objects/call.c:327
    #29 0xaaaabbab73e4 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:815
    #30 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115
    #31 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788
    #32 0xaaaabbb00abc in PyEval_EvalCode Python/ceval.c:592
    #33 0xaaaabbc02aec in run_eval_code_obj Python/pythonrun.c:1294
    #34 0xaaaabbc059e0 in run_mod Python/pythonrun.c:1379
    #35 0xaaaabbc0677c in pyrun_file Python/pythonrun.c:1215

previously allocated by thread T0 here:
    #0 0xffffb96aa2f4 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145
    #1 0xaaaabb8cb160 in _PyMem_RawMalloc Objects/obmalloc.c:56
    #2 0xaaaabb8c9028 in _PyMem_DebugRawAlloc Objects/obmalloc.c:2331
    #3 0xaaaabb8c9084 in _PyMem_DebugRawMalloc Objects/obmalloc.c:2364
    #4 0xaaaabb8ccdc0 in _PyMem_DebugMalloc Objects/obmalloc.c:2516
    #5 0xaaaabb8f0df0 in PyObject_Malloc Objects/obmalloc.c:966
    #6 0xaaaabb92e22c in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46
    #7 0xaaaabb92e22c in _PyType_AllocNoTrack Objects/typeobject.c:1739
    #8 0xaaaabb92e538 in PyType_GenericAlloc Objects/typeobject.c:1763
    #9 0xaaaabb92830c in object_new Objects/typeobject.c:5555
    #10 0xaaaabb92ec48 in type_call Objects/typeobject.c:1682
    #11 0xaaaabb7cc64c in _PyObject_MakeTpCall Objects/call.c:242
    #12 0xaaaabb7ccc90 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:166
    #13 0xaaaabb7cccc0 in PyObject_Vectorcall Objects/call.c:327
    #14 0xaaaabbab73e4 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:815
    #15 0xaaaabbb008f4 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:115
    #16 0xaaaabbb008f4 in _PyEval_Vector Python/ceval.c:1788
    #17 0xaaaabbb00abc in PyEval_EvalCode Python/ceval.c:592
    #18 0xaaaabbc02aec in run_eval_code_obj Python/pythonrun.c:1294
    #19 0xaaaabbc059e0 in run_mod Python/pythonrun.c:1379
    #20 0xaaaabbc0677c in pyrun_file Python/pythonrun.c:1215
    #21 0xaaaabbc08c3c in _PyRun_SimpleFileObject Python/pythonrun.c:464
    #22 0xaaaabbc08ff4 in _PyRun_AnyFileObject Python/pythonrun.c:77
    #23 0xaaaabbc66e68 in pymain_run_file_obj Modules/main.c:357
    #24 0xaaaabbc693d8 in pymain_run_file Modules/main.c:376
    #25 0xaaaabbc69de0 in pymain_run_python Modules/main.c:628
    #26 0xaaaabbc6a084 in Py_RunMain Modules/main.c:707
    #27 0xaaaabbc6a274 in pymain_main Modules/main.c:737
    #28 0xaaaabbc6a5b0 in Py_BytesMain Modules/main.c:761
    #29 0xaaaabb63145c in main Programs/python.c:15
    #30 0xffffb93d73f8 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #31 0xffffb93d74c8 in __libc_start_main_impl ../csu/libc-start.c:392

SUMMARY: AddressSanitizer: heap-use-after-free Include/object.h:333 in Py_TYPE
Shadow bytes around the buggy address:
  0x200ff610d620: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x200ff610d630: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x200ff610d640: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x200ff610d650: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x200ff610d660: fa fa fa fa fd fd fd fd fd fd fd fd fd fa fa fa
=>0x200ff610d670: fa fa fd fd fd fd fd fd fd[fd]fd fa fa fa fa fa
  0x200ff610d680: fd fd fd fd fd fd fd fd fd fd fa fa fa fa fd fd
  0x200ff610d690: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd
  0x200ff610d6a0: fd fd fd fd fd fd fa fa fa fa 00 00 00 00 00 00
  0x200ff610d6b0: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00
  0x200ff610d6c0: 00 00 fa fa fa fa 00 00 00 00 00 00 00 00 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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  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
  Shadow gap:              cc
==246599==ABORTING

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

Output from running 'python -VV' on the command line:

Python 3.13.0a3+ (heads/v3.13.0a2:e2c4038924, Feb 10 2024, 12:05:47) [GCC 11.4.0]

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.11only security fixesonly security fixes3.12only security fixesonly security fixes3.13bugs and security fixesbugs and security fixesextension-modulesC modules in the Modules dirC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

      Morty Proxy This is a proxified and sanitized view of the page, visit original site.