python / python/cpython

Use-after-free in lsprof `initContext` via re-entrant external timer `__index__`

Đang mở
#143,545 2 bình luận 1 reaction 0 người được giao Xem trên GitHub

Chưa có ai nhận issue này.

extension-modules topic-profiling type-bug
Ngôn ngữ chính
Python
Star
77.2k
Fork
35.9k
Chỉ số merge pull request
Chỉ số pull request đang chờ

Mô tả

What happened?

prof._pystart_callback installs a new ProfilerContext and immediately calls the external timer. If the timer’s __index__ clears the profiler, it frees currentProfilerContext while initContext still writes to it, leading to a heap use-after-free.

Proof of Concept:

import cProfile

class Timer:
    def __call__(self):
        return self

    def __index__(self):
        prof.clear()
        return 0

prof = cProfile.Profile(timer=Timer())

def victim():
    pass

prof._pystart_callback(victim.__code__, 0)

Vulnerable Code Snippet:

Click to expand
/* Buggy Re-entrant Path */
op(_DO_CALL, (callable, self_or_null, args[oparg] -- res)) {
    /* ... */
    PyObject *res_o = PyObject_Vectorcall(
        callable_o, args_o,
        total_args | PY_VECTORCALL_ARGUMENTS_OFFSET,
        NULL);
    /* ... */
}

static void
initContext(ProfilerObject *pObj, ProfilerContext *self, ProfilerEntry *entry)
{
    self->ctxEntry = entry;
    self->subt = 0;
    self->previous = pObj->currentProfilerContext;
    pObj->currentProfilerContext = self;  /* crashing pointer derived */
    /* ... */
    self->t0 = call_timer(pObj);  /* Reentrant call site */ /* Crash site */
}

static PyTime_t
CallExternalTimer(ProfilerObject *pObj)
{
    PyObject *o;
    /* ... */
    o = _PyObject_CallNoArgs(pObj->externalTimer);
    /* ... */
    err = _PyTime_FromSecondsObject(&result, o, _PyTime_ROUND_FLOOR);
    /* ... */
    return result;
}

static inline PyObject*
vectorcall_unbound(PyThreadState *tstate, int unbound, PyObject *func,
                   PyObject *const *args, Py_ssize_t nargs)
{
    /* ... */
    return _PyObject_VectorcallTstate(tstate, func, args, nargsf, NULL);  /* Reentrant call site */
}

/* Clobbering Path */
static void clearEntries(ProfilerObject *pObj)
{
    /* ... */
    if (pObj->currentProfilerContext) {
        PyMem_Free(pObj->currentProfilerContext);  /* state mutate site */
        pObj->currentProfilerContext = NULL;
    }
    /* ... */
}

Sanitizer Output:

Click to expand
=================================================================
==287983==ERROR: AddressSanitizer: heap-use-after-free on address 0x50300001dc80 at pc 0x78e4bf424a0a bp 0x7ffd850cf040 sp 0x7ffd850cf030
WRITE of size 8 at 0x50300001dc80 thread T0
    #0 0x78e4bf424a09 in initContext Modules/_lsprof.c:324
    #1 0x78e4bf424a09 in ptrace_enter_call Modules/_lsprof.c:393
    #2 0x78e4bf424c51 in _lsprof_Profiler__pystart_callback_impl Modules/_lsprof.c:631
    #3 0x78e4bf424c51 in _lsprof_Profiler__pystart_callback Modules/clinic/_lsprof.c.h:88
    #4 0x5f5f549183e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
    #5 0x5f5f549183e7 in PyObject_Vectorcall Objects/call.c:327
    #6 0x5f5f547cc5a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
    #7 0x5f5f54c96ad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
    #8 0x5f5f54c96ad6 in _PyEval_Vector Python/ceval.c:2001
    #9 0x5f5f54c96ad6 in PyEval_EvalCode Python/ceval.c:884
    #10 0x5f5f54ddc16e in run_eval_code_obj Python/pythonrun.c:1365
    #11 0x5f5f54ddc16e in run_mod Python/pythonrun.c:1459
    #12 0x5f5f54de0e17 in pyrun_file Python/pythonrun.c:1293
    #13 0x5f5f54de0e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521
    #14 0x5f5f54de193c in _PyRun_AnyFileObject Python/pythonrun.c:81
    #15 0x5f5f54e54e3c in pymain_run_file_obj Modules/main.c:410
    #16 0x5f5f54e54e3c in pymain_run_file Modules/main.c:429
    #17 0x5f5f54e54e3c in pymain_run_python Modules/main.c:691
    #18 0x5f5f54e5671e in Py_RunMain Modules/main.c:772
    #19 0x5f5f54e5671e in pymain_main Modules/main.c:802
    #20 0x5f5f54e5671e in Py_BytesMain Modules/main.c:826
    #21 0x78e4bf22a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #22 0x78e4bf22a28a in __libc_start_main_impl ../csu/libc-start.c:360
    #23 0x5f5f547f0634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)

0x50300001dc80 is located 0 bytes inside of 32-byte region [0x50300001dc80,0x50300001dca0)
freed by thread T0 here:
    #0 0x78e4bf6fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52
    #1 0x78e4bf425706 in clearEntries Modules/_lsprof.c:296
    #2 0x78e4bf425706 in _lsprof_Profiler_clear_impl Modules/_lsprof.c:954
    #3 0x78e4bf425706 in _lsprof_Profiler_clear Modules/clinic/_lsprof.c.h:370
    #4 0x5f5f549183e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
    #5 0x5f5f549183e7 in PyObject_Vectorcall Objects/call.c:327
    #6 0x5f5f547cc5a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
    #7 0x5f5f54c972a5 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
    #8 0x5f5f54c972a5 in _PyEval_Vector Python/ceval.c:2001
    #9 0x5f5f54ad3607 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
    #10 0x5f5f54ad3607 in vectorcall_unbound Objects/typeobject.c:3033
    #11 0x5f5f54ad3607 in vectorcall_method Objects/typeobject.c:3104
    #12 0x5f5f54ad3607 in slot_nb_index Objects/typeobject.c:10507
    #13 0x5f5f548c413f in _PyNumber_Index Objects/abstract.c:1418
    #14 0x5f5f549cc267 in PyLong_AsLongLong Objects/longobject.c:1592
    #15 0x5f5f54de599a in pytime_from_object Python/pytime.c:593
    #16 0x5f5f54de599a in pytime_from_object Python/pytime.c:589
    #17 0x5f5f54de599a in _PyTime_FromSecondsObject Python/pytime.c:630
    #18 0x78e4bf4232f3 in CallExternalTimer Modules/_lsprof.c:120
    #19 0x78e4bf423f91 in call_timer Modules/_lsprof.c:135
    #20 0x78e4bf423f91 in initContext Modules/_lsprof.c:324
    #21 0x78e4bf423f91 in ptrace_enter_call Modules/_lsprof.c:393
    #22 0x78e4bf424c51 in _lsprof_Profiler__pystart_callback_impl Modules/_lsprof.c:631
    #23 0x78e4bf424c51 in _lsprof_Profiler__pystart_callback Modules/clinic/_lsprof.c.h:88
    #24 0x5f5f549183e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
    #25 0x5f5f549183e7 in PyObject_Vectorcall Objects/call.c:327
    #26 0x5f5f547cc5a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
    #27 0x5f5f54c96ad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
    #28 0x5f5f54c96ad6 in _PyEval_Vector Python/ceval.c:2001
    #29 0x5f5f54c96ad6 in PyEval_EvalCode Python/ceval.c:884
    #30 0x5f5f54ddc16e in run_eval_code_obj Python/pythonrun.c:1365
    #31 0x5f5f54ddc16e in run_mod Python/pythonrun.c:1459
    #32 0x5f5f54de0e17 in pyrun_file Python/pythonrun.c:1293
    #33 0x5f5f54de0e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521
    #34 0x5f5f54de193c in _PyRun_AnyFileObject Python/pythonrun.c:81
    #35 0x5f5f54e54e3c in pymain_run_file_obj Modules/main.c:410
    #36 0x5f5f54e54e3c in pymain_run_file Modules/main.c:429
    #37 0x5f5f54e54e3c in pymain_run_python Modules/main.c:691
    #38 0x5f5f54e5671e in Py_RunMain Modules/main.c:772
    #39 0x5f5f54e5671e in pymain_main Modules/main.c:802
    #40 0x5f5f54e5671e in Py_BytesMain Modules/main.c:826
    #41 0x78e4bf22a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #42 0x78e4bf22a28a in __libc_start_main_impl ../csu/libc-start.c:360
CPython versions tested on:
Python Version Status Exit Code
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 28 2025, 16:51:20) Exception 1
Python 3.10.19+ (heads/3.10:014261980b1, Oct 28 2025, 16:52:08) [Clang 18.1.3 (1ubuntu1)] Exception 1
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 28 2025, 16:53:08) [Clang 18.1.3 (1ubuntu1)] Exception 1
Python 3.12.12+ (heads/3.12:8cb2092bd8c, Oct 28 2025, 16:54:14) [Clang 18.1.3 (1ubuntu1)] ASAN 1
Python 3.13.9+ (heads/3.13:9c8eade20c6, Oct 28 2025, 16:55:18) [Clang 18.1.3 (1ubuntu1)] ASAN 1
Python 3.14.0+ (heads/3.14:2e216728038, Oct 28 2025, 16:56:16) [Clang 18.1.3 (1ubuntu1)] ASAN 1
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 28 2025, 19:29:54) [GCC 13.3.0] ASAN 1
Operating systems tested on:

Linux

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

Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 28 2025, 19:29:54) [GCC 13.3.0]

Linked PRs
  • gh-143550

Hướng dẫn đóng góp

Mở hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Hướng nghiên cứu

Bắt đầu trong Modules/_lsprof.c tại initContext, CallExternalTimer, clearEntries và đường dẫn __pystart_callback. Tái hiện ví dụ Timer được cung cấp trên bản build ASAN, sau đó kiểm tra công việc liên quan gh-143550. Hoàn tất khi callback re-entrant không còn gây ra use-after-free và một bài kiểm thử hồi quy bao quát hành vi này.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Đánh giá

Công nghệ
c, python
Lĩnh vực
devtools, performance
Loại issue
Lỗi
Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức độ hoạt động
Đình trệ
Độ rõ ràng
Khá rõ ràng
Mức phù hợp với người mới
25/100

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.