Skip to content

Use after free in PyDict_Clear() due to re-entrancy #130555

Open
@colesbury

Description

@colesbury

Crash report

The implementation of PyDict_Clear() isn't safe for dictionaries with values that are embedded in an object:

The calls to Py_CLEAR(oldvalues->values[i]) can execute arbitrary code via object destructors. oldvalues may no longer be valid because the object its embedded in may be freed during the Py_CLEAR() call.

cpython/Objects/dictobject.c

Lines 2868 to 2880 in 0ef4ffe

n = oldkeys->dk_nentries;
for (i = 0; i < n; i++) {
Py_CLEAR(oldvalues->values[i]);
}
if (oldvalues->embedded) {
oldvalues->size = 0;
}
else {
set_values(mp, NULL);
set_keys(mp, Py_EMPTY_KEYS);
free_values(oldvalues, IS_DICT_SHARED(mp));
dictkeys_decref(interp, oldkeys, false);
}

Repro

./configure --with-address-sanitizer --with-pydebug --without-pymalloc
class MyObj:
    pass

class DelXOnDelete:
    def __del__(self):
        global x
        del x

x = MyObj()
x.a = DelXOnDelete()

d = x.__dict__
d.clear()
==3794958==ERROR: AddressSanitizer: heap-use-after-free on address 0x513000022ec2 at pc 0x56320dddb439 bp 0x7fff8205bb90 sp 0x7fff8205bb88
READ of size 1 at 0x513000022ec2 thread T0
    #0 0x56320dddb438 in clear_lock_held /raid/sgross/cpython/Objects/dictobject.c:2872:24
    #1 0x56320dddb438 in PyDict_Clear /raid/sgross/cpython/Objects/dictobject.c:2889:5
    #2 0x56320ddf7e38 in dict_clear_impl /raid/sgross/cpython/Objects/dictobject.c:4452:5
    #3 0x56320ddf7e38 in dict_clear /raid/sgross/cpython/Objects/clinic/dictobject.c.h:157:12
...

freed by thread T0 here:
    #0 0x56320db400e6 in free (/raid/sgross/cpython/python+0x2fd0e6) (BuildId: f9a13329ff2de3d6fd6a01eae843cc226d0d8f7c)
    #1 0x56320de99e6a in subtype_dealloc /raid/sgross/cpython/Objects/typeobject.c:2611:5
    #2 0x56320de31448 in _Py_Dealloc /raid/sgross/cpython/Objects/object.c:3004:5
    #3 0x56320dddc0e6 in Py_DECREF /raid/sgross/cpython/./Include/refcount.h:393:9
    #4 0x56320dddc0e6 in _PyDict_Pop_KnownHash /raid/sgross/cpython/Objects/dictobject.c:3028:9
    #5 0x56320e064bd4 in _PyEval_EvalFrameDefault /raid/sgross/cpython/Python/generated_cases.c.h:5006:23
...

cc @DinoV @markshannon

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixes3.14new features, bugs and security fixesinterpreter-core(Objects, Python, Grammar, and Parser dirs)type-crashA 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