Skip to content

Heap-buffer-overflow in _decimal_exec via overriding collections.namedtuple #142595

@jackfromeast

Description

@jackfromeast

What happened?

_decimal_exec calls collections.namedtuple("DecimalTuple", ...) and assumes it returns a type. If collections.namedtuple has been set to return a non-type object, the code casts it to PyTypeObject* and writes to tp_dict (__module__), causing type confusion and a heap buffer overflow during module initialization.

Proof of Concept:

import collections
collections.namedtuple = lambda *a, **k: object()
import _decimal

Affected Versions:

Python Version Status Exit Code
Python 3.9.24+ (heads/3.9:9c4638d, Oct 17 2025, 11:19:30) ASAN 1
Python 3.10.19+ (heads/3.10:0142619, Oct 17 2025, 11:20:05) [GCC 13.3.0] ASAN 1
Python 3.11.14+ (heads/3.11:88f3f5b, Oct 17 2025, 11:20:44) [GCC 13.3.0] ASAN 1
Python 3.12.12+ (heads/3.12:8cb2092, Oct 17 2025, 11:21:35) [GCC 13.3.0] ASAN 1
Python 3.13.9+ (heads/3.13:0760a57, Oct 17 2025, 11:22:25) [GCC 13.3.0] ASAN 1
Python 3.14.0+ (heads/3.14:889e918, Oct 17 2025, 11:23:02) [GCC 13.3.0] ASAN 1
Python 3.15.0a1+ (heads/main:fbf0843, Oct 17 2025, 11:23:37) [GCC 13.3.0] Exception 1

Vulnerable Code:

cpython/Modules/_decimal/_decimal.c:7646-7651
ASSIGN_PTR(state->DecimalTuple, (PyTypeObject *)PyObject_CallMethod(collections,
                             "namedtuple", "(ss)", "DecimalTuple",
                             "sign digits exponent"));

ASSIGN_PTR(obj, PyUnicode_FromString("decimal"));
CHECK_INT(PyDict_SetItemString(state->DecimalTuple->tp_dict, "__module__", obj));
Py_CLEAR(obj);

Sanitizer Output

(base) jackfromeast@blue-sea:~/Desktop/entropy/tasks/grammar-afl++-latest/targets/cpython$ /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython-afl/bin/python3 /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-latest/inputs/decimal_poc.py
=================================================================
==863339==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x504000004c68 at pc 0x728e1ca00bd7 bp 0x7ffe94ca42c0 sp 0x7ffe94ca42b8
READ of size 8 at 0x504000004c68 thread T0
    #0 0x728e1ca00bd6 in _decimal_exec /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Modules/_decimal/_decimal.c:6001:5
    #1 0x5d68c379ab3f in PyModule_ExecDef /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/moduleobject.c:495:23
    #2 0x5d68c3dbab12 in exec_builtin_or_dynamic /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:817:12
    #3 0x5d68c3dbab12 in _imp_exec_dynamic_impl /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:4745:12
    #4 0x5d68c3dbab12 in _imp_exec_dynamic /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/clinic/import.c.h:514:21
    #5 0x5d68c3790ab8 in cfunction_vectorcall_O /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/methodobject.c:523:24
    #6 0x5d68c3c0493f in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/generated_cases.c.h:1758:32
    #7 0x5d68c3bdfd22 in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_ceval.h:116:16
    #8 0x5d68c3bdfd22 in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:1911:12
    #9 0x5d68c35a05be in _PyObject_VectorcallTstate /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_call.h:167:11
    #10 0x5d68c35a05be in object_vacall /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c:819:14
    #11 0x5d68c359faa4 in PyObject_CallMethodObjArgs /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c:880:24
    #12 0x5d68c3da6987 in import_find_and_load /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:3681:11
    #13 0x5d68c3da6987 in PyImport_ImportModuleLevelObject /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:3763:15
    #14 0x5d68c3c4f02a in _PyEval_ImportName /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:2812:16
    #15 0x5d68c3be2937 in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/generated_cases.c.h:4359:31
    #16 0x5d68c3bdfd22 in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_ceval.h:116:16
    #17 0x5d68c3bdfd22 in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:1911:12
    #18 0x5d68c3bdedf8 in PyEval_EvalCode /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:658:21
    #19 0x5d68c3ed05b7 in run_eval_code_obj /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:1338:9
    #20 0x5d68c3ece010 in run_mod /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:1423:19
    #21 0x5d68c3ebfca1 in pyrun_file /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:1256:15
    #22 0x5d68c3ebfca1 in _PyRun_SimpleFileObject /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:491:13
    #23 0x5d68c3ebe49f in _PyRun_AnyFileObject /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:78:15
    #24 0x5d68c3f99e97 in pymain_run_file_obj /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:410:15
    #25 0x5d68c3f99e97 in pymain_run_file /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:429:15
    #26 0x5d68c3f957b9 in pymain_run_python /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:697:21
    #27 0x5d68c3f957b9 in Py_RunMain /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:776:5
    #28 0x5d68c3f9740c in pymain_main /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:806:12
    #29 0x5d68c3f975d6 in Py_BytesMain /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:830:12
    #30 0x728e1ec2a1c9 in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #31 0x728e1ec2a28a in __libc_start_main csu/../csu/libc-start.c:360:3
    #32 0x5d68c3225144 in _start (/home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython-afl/bin/python3.14+0x259144) (BuildId: 4a021c7c2d7561e34d5f3a67f13e279fba070d79)

0x504000004c68 is located 240 bytes after 40-byte region [0x504000004b50,0x504000004b78)
allocated by thread T0 here:
    #0 0x5d68c32bff93 in malloc (/home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython-afl/bin/python3.14+0x2f3f93) (BuildId: 4a021c7c2d7561e34d5f3a67f13e279fba070d79)
    #1 0x5d68c381ab3e in _PyMem_DebugRawAlloc /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/obmalloc.c:2733:24
    #2 0x5d68c381ab3e in _PyMem_DebugRawMalloc /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/obmalloc.c:2766:12
    #3 0x5d68c381ab3e in _PyMem_DebugMalloc /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/obmalloc.c:2930:12
    #4 0x5d68c388bb49 in _PyObject_MallocWithType /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_object_alloc.h:46:17
    #5 0x5d68c388bb49 in _PyType_AllocNoTrack /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/typeobject.c:2229:19
    #6 0x5d68c388b8ac in PyType_GenericAlloc /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/typeobject.c:2258:21
    #7 0x5d68c38a0c89 in type_call /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/typeobject.c:2173:11
    #8 0x5d68c3596a76 in _PyObject_MakeTpCall /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c:242:18
    #9 0x5d68c3c181a7 in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/generated_cases.c.h:960:35
    #10 0x5d68c3bdfd22 in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_ceval.h:116:16
    #11 0x5d68c3bdfd22 in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:1911:12
    #12 0x5d68c359c14a in _PyObject_VectorcallTstate /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_call.h:167:11
    #13 0x5d68c359c14a in _PyObject_CallFunctionVa /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c
    #14 0x5d68c359cf14 in callmethod /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c:626:12
    #15 0x5d68c359cf14 in PyObject_CallMethod /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c:645:24
    #16 0x728e1c9fe3a2 in _decimal_exec /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Modules/_decimal/_decimal.c:5996:5
    #17 0x5d68c379ab3f in PyModule_ExecDef /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/moduleobject.c:495:23
    #18 0x5d68c3dbab12 in exec_builtin_or_dynamic /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:817:12
    #19 0x5d68c3dbab12 in _imp_exec_dynamic_impl /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:4745:12
    #20 0x5d68c3dbab12 in _imp_exec_dynamic /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/clinic/import.c.h:514:21
    #21 0x5d68c3790ab8 in cfunction_vectorcall_O /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/methodobject.c:523:24
    #22 0x5d68c3c0493f in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/generated_cases.c.h:1758:32
    #23 0x5d68c3bdfd22 in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_ceval.h:116:16
    #24 0x5d68c3bdfd22 in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:1911:12
    #25 0x5d68c35a05be in _PyObject_VectorcallTstate /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_call.h:167:11
    #26 0x5d68c35a05be in object_vacall /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c:819:14
    #27 0x5d68c359faa4 in PyObject_CallMethodObjArgs /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Objects/call.c:880:24
    #28 0x5d68c3da6987 in import_find_and_load /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:3681:11
    #29 0x5d68c3da6987 in PyImport_ImportModuleLevelObject /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/import.c:3763:15
    #30 0x5d68c3c4f02a in _PyEval_ImportName /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:2812:16
    #31 0x5d68c3be2937 in _PyEval_EvalFrameDefault /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/generated_cases.c.h:4359:31
    #32 0x5d68c3bdfd22 in _PyEval_EvalFrame /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Include/internal/pycore_ceval.h:116:16
    #33 0x5d68c3bdfd22 in _PyEval_Vector /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:1911:12
    #34 0x5d68c3bdedf8 in PyEval_EvalCode /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/ceval.c:658:21
    #35 0x5d68c3ed05b7 in run_eval_code_obj /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:1338:9
    #36 0x5d68c3ece010 in run_mod /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:1423:19
    #37 0x5d68c3ebfca1 in pyrun_file /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:1256:15
    #38 0x5d68c3ebfca1 in _PyRun_SimpleFileObject /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:491:13
    #39 0x5d68c3ebe49f in _PyRun_AnyFileObject /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Python/pythonrun.c:78:15
    #40 0x5d68c3f99e97 in pymain_run_file_obj /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:410:15
    #41 0x5d68c3f99e97 in pymain_run_file /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:429:15
    #42 0x5d68c3f957b9 in pymain_run_python /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:697:21
    #43 0x5d68c3f957b9 in Py_RunMain /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:776:5
    #44 0x5d68c3f9740c in pymain_main /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/Modules/main.c:806:12

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/jackfromeast/Desktop/entropy/tasks/grammar-afl++-issue-128049/targets/cpython/./Modules/_decimal/_decimal.c:6001:5 in _decimal_exec
Shadow bytes around the buggy address:
  0x504000004980: fa fa 00 00 00 00 00 fa fa fa 00 00 00 00 00 07
  0x504000004a00: fa fa 00 00 00 00 00 00 fa fa fd fd fd fd fd fd
  0x504000004a80: fa fa fd fd fd fd fd fa fa fa fd fd fd fd fd fd
  0x504000004b00: fa fa fd fd fd fd fd fa fa fa 00 00 00 00 00 fa
  0x504000004b80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
=>0x504000004c00: fa fa fa fa fa fa fa fa fa fa fa fa fa[fa]fa fa
  0x504000004c80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x504000004d00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x504000004d80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x504000004e00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x504000004e80: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
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
==863339==ABORTING

Linked PRs

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-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