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

[3.14] gh-143228: Fix UAF in perf trampoline during finalization (GH-143233)#143247

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Merged
pablogsal merged 1 commit intopython:3.14frompablogsal:backport-3ccc76f-3.14
Dec 28, 2025
Merged
Show file tree
Hide file tree
Changes fromall commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2,333 changes: 1,177 additions & 1,156 deletionsDoc/data/python3.14.abi
View file
Open in desktop

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletionInclude/internal/pycore_ceval.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -105,7 +105,6 @@ extern int _PyPerfTrampoline_SetCallbacks(_PyPerf_Callbacks *);
extern void _PyPerfTrampoline_GetCallbacks(_PyPerf_Callbacks *);
extern int _PyPerfTrampoline_Init(int activate);
extern int _PyPerfTrampoline_Fini(void);
extern void _PyPerfTrampoline_FreeArenas(void);
extern int _PyIsPerfTrampolineActive(void);
extern PyStatus _PyPerfTrampoline_AfterFork_Child(void);
#ifdef PY_HAVE_PERF_TRAMPOLINE
Expand Down
3 changes: 3 additions & 0 deletionsInclude/internal/pycore_interp_structs.h
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -87,6 +87,9 @@ struct _ceval_runtime_state {
struct trampoline_api_st trampoline_api;
FILE *map_file;
Py_ssize_t persist_after_fork;
_PyFrameEvalFunction prev_eval_frame;
Py_ssize_t trampoline_refcount;
int code_watcher_id;
#else
int _not_used;
#endif
Expand Down
View file
Open in desktop
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
Fix use-after-free in perf trampoline when toggling profiling while
threads are running or during interpreter finalization with daemon threads
active. The fix uses reference counting to ensure trampolines are not freed
while any code object could still reference them. Pach by Pablo Galindo
68 changes: 60 additions & 8 deletionsPython/perf_trampoline.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -204,6 +204,43 @@ enum perf_trampoline_type {
#define perf_map_file _PyRuntime.ceval.perf.map_file
#define persist_after_fork _PyRuntime.ceval.perf.persist_after_fork
#define perf_trampoline_type _PyRuntime.ceval.perf.perf_trampoline_type
#define prev_eval_frame _PyRuntime.ceval.perf.prev_eval_frame
#define trampoline_refcount _PyRuntime.ceval.perf.trampoline_refcount
#define code_watcher_id _PyRuntime.ceval.perf.code_watcher_id

static void free_code_arenas(void);

static void
perf_trampoline_reset_state(void)
{
free_code_arenas();
if (code_watcher_id >= 0) {
PyCode_ClearWatcher(code_watcher_id);
code_watcher_id = -1;
}
extra_code_index = -1;
}

static int
perf_trampoline_code_watcher(PyCodeEvent event, PyCodeObject *co)
{
if (event != PY_CODE_EVENT_DESTROY) {
return 0;
}
if (extra_code_index == -1) {
return 0;
}
py_trampoline f = NULL;
int ret = _PyCode_GetExtra((PyObject *)co, extra_code_index, (void **)&f);
if (ret != 0 || f == NULL) {
return 0;
}
trampoline_refcount--;
if (trampoline_refcount == 0) {
perf_trampoline_reset_state();
}
return 0;
}

static void
perf_map_write_entry(void *state, const void *code_addr,
Expand DownExpand Up@@ -405,6 +442,7 @@ py_trampoline_evaluator(PyThreadState *ts, _PyInterpreterFrame *frame,
perf_code_arena->code_size, co);
_PyCode_SetExtra((PyObject *)co, extra_code_index,
(void *)new_trampoline);
trampoline_refcount++;
f = new_trampoline;
}
assert(f != NULL);
Expand All@@ -428,6 +466,7 @@ int PyUnstable_PerfTrampoline_CompileCode(PyCodeObject *co)
}
trampoline_api.write_state(trampoline_api.state, new_trampoline,
perf_code_arena->code_size, co);
trampoline_refcount++;
return _PyCode_SetExtra((PyObject *)co, extra_code_index,
(void *)new_trampoline);
}
Expand DownExpand Up@@ -482,6 +521,10 @@ _PyPerfTrampoline_Init(int activate)
{
#ifdef PY_HAVE_PERF_TRAMPOLINE
PyThreadState *tstate = _PyThreadState_GET();
if (code_watcher_id == 0) {
// Initialize to -1 since 0 is a valid watcher ID
code_watcher_id = -1;
}
if (tstate->interp->eval_frame &&
tstate->interp->eval_frame != py_trampoline_evaluator) {
PyErr_SetString(PyExc_RuntimeError,
Expand All@@ -505,6 +548,13 @@ _PyPerfTrampoline_Init(int activate)
if (new_code_arena() < 0) {
return -1;
}
code_watcher_id = PyCode_AddWatcher(perf_trampoline_code_watcher);
if (code_watcher_id < 0) {
PyErr_FormatUnraisable("Failed to register code watcher for perf trampoline");
free_code_arenas();
return -1;
}
trampoline_refcount = 1; // Base refcount held by the system
perf_status = PERF_STATUS_OK;
}
#endif
Expand All@@ -526,17 +576,19 @@ _PyPerfTrampoline_Fini(void)
trampoline_api.free_state(trampoline_api.state);
perf_trampoline_type = PERF_TRAMPOLINE_UNSET;
}
extra_code_index = -1;

// Prevent new trampolines from being created
perf_status = PERF_STATUS_NO_INIT;
#endif
return 0;
}

void _PyPerfTrampoline_FreeArenas(void) {
#ifdef PY_HAVE_PERF_TRAMPOLINE
free_code_arenas();
// Decrement base refcount. If refcount reaches 0, all code objects are already
// dead so clean up now. Otherwise, watcher remains active to clean up when last
// code object dies; extra_code_index stays valid so watcher can identify them.
trampoline_refcount--;
if (trampoline_refcount == 0) {
perf_trampoline_reset_state();
}
#endif
return;
return 0;
}

int
Expand Down
1 change: 0 additions & 1 deletionPython/pylifecycle.c
View file
Open in desktop
Original file line numberDiff line numberDiff line change
Expand Up@@ -1923,7 +1923,6 @@ finalize_interp_clear(PyThreadState *tstate)
_PyArg_Fini();
_Py_ClearFileSystemEncoding();
_PyPerfTrampoline_Fini();
_PyPerfTrampoline_FreeArenas();
}

finalize_interp_types(tstate->interp);
Expand Down
Loading

[8]ページ先頭

©2009-2026 Movatter.jp