Movatterモバイル変換


[0]ホーム

URL:


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

Sign up
Appearance settings

_hashlib: Use-After-Free + Double Free in_hashopenssl.cpy_hashentry_table_new() #145301

Open
Labels
3.13bugs and security fixes3.14bugs and security fixes3.15new features, bugs and security fixeseasyextension-modulesC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dump
@raminfp

Description

@raminfp

Crash report

What happened?

Inpy_hashentry_table_new(), when_Py_hashtable_set() fails for an alias key (line 270),entry is explicitly freed viaPyMem_Free(entry) at line 271. However, this sameentry was already successfully inserted into the hashtable underpy_name at line 263. Thegoto error path then calls_Py_hashtable_destroy(ht) (line 280), which invokes the destroy callbackpy_hashentry_t_destroy_value() on the already-freed entry.

// Modules/_hashopenssl.c - py_hashentry_table_new()for (constpy_hashentry_t*h=py_hashes;h->py_name!=NULL;h++) {py_hashentry_t*entry= (py_hashentry_t*)PyMem_Malloc(sizeof(py_hashentry_t));if (entry==NULL) {        gotoerror;    }memcpy(entry,h,sizeof(py_hashentry_t));// [line 263] entry inserted into hashtable under py_name - hashtable now owns itif (_Py_hashtable_set(ht, (constvoid*)entry->py_name, (void*)entry)<0) {PyMem_Free(entry);        gotoerror;    }entry->refcnt=1;if (h->py_alias!=NULL) {// [line 270] second insert fails (e.g. OOM)if (_Py_hashtable_set(ht, (constvoid*)entry->py_alias, (void*)entry)<0) {PyMem_Free(entry);// [line 271] BUG: entry freed, but still in hashtable under py_name            gotoerror;// [line 272] jumps to error path        }entry->refcnt++;    }}returnht;error:_Py_hashtable_destroy(ht);// [line 280] destroy callback called on already-freed entryreturnNULL;

Build

mkdir build-asan&&cd build-asan../configure --with-pydebug --with-address-sanitizer --without-pymallocmake -j$(nproc)
importsubprocessimportsyscode= ("import sys, _testcapi\n""if '_hashlib' in sys.modules:\n""    del sys.modules['_hashlib']\n""_testcapi.set_nomemory(40, 41)\n""try:\n""    import _hashlib\n""except (MemoryError, ImportError):\n""    pass\n""finally:\n""    _testcapi.remove_mem_hooks()\n")result=subprocess.run(    [sys.executable,'-c',code],capture_output=True,text=True,timeout=10)ifresult.returncode!=0:print(f"[*] CRASH confirmed (rc={result.returncode})")print(f"[*]{result.stderr.strip().split(chr(10))[-1]}")else:print("[*] No crash (try different start values)")
$ ./build-asan/python uaf_asan.py[*] CRASH confirmed (rc=-6)[*] python: ../Include/internal/pycore_stackref.h:554: PyStackRef_FromPyObjectSteal: Assertion`obj!= NULL' failed.

GDB backtrace

$ gdb -batch -ex run -ex bt --args ./build-asan/python -c"import sys, _testcapiif '_hashlib' in sys.modules:    del sys.modules['_hashlib']_testcapi.set_nomemory(40, 41)try:    import _hashlibexcept (MemoryError, ImportError):    passfinally:    _testcapi.remove_mem_hooks()"
python: ../Include/internal/pycore_stackref.h:554: PyStackRef_FromPyObjectSteal: Assertion `obj != NULL' failed.Program received signal SIGABRT, Aborted.#0  __pthread_kill_implementation at ./nptl/pthread_kill.c:44#1  __pthread_kill_internal at ./nptl/pthread_kill.c:78#2  __GI___pthread_kill at ./nptl/pthread_kill.c:89#3  __GI_raise at ../sysdeps/posix/raise.c:26#4  __GI_abort at ./stdlib/abort.c:79#5  __assert_fail_base — Assertion `obj != NULL' failed.#6  __assert_fail at ./assert/assert.c:105#7  PyStackRef_FromPyObjectSteal at ../Include/internal/pycore_stackref.h:554#8  _PyEval_EvalFrameDefault at ../Python/generated_cases.c.h:292...#15 import_find_and_load — importing _hashlib...#19 _PyEval_EvalFrameDefault at ../Python/generated_cases.c.h:6424

The assertion fires because memory corruption during_hashlib module init (caused by the UAF/double-free) propagates a NULL into the eval loop.

Suggested Fix

RemovePyMem_Free(entry) at line 271. Theentry is already owned by the hashtable (underpy_name withrefcnt=1), so_Py_hashtable_destroy() in the error path will correctly clean it up via the destroy callback.

     if (h->py_alias != NULL) {         if (_Py_hashtable_set(ht, (const void*)entry->py_alias, (void*)entry) < 0) {-            PyMem_Free(entry);             goto error;         }         entry->refcnt++;     }

CPython versions tested on:

CPython main branch

Operating systems tested on:

Linux

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

Python 3.15.0a6+

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    3.13bugs and security fixes3.14bugs and security fixes3.15new features, bugs and security fixeseasyextension-modulesC modules in the Modules dirtype-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


      [8]ページ先頭

      ©2009-2026 Movatter.jp