From: Ken Jin Date: Sun, 4 Jan 2026 13:10:39 +0000 (+0800) Subject: gh-143403: Fix a UAF in `_BINARY_OP_INPLACE_ADD_UNICODE` (GH-143404) X-Git-Tag: v3.15.0a5~11^2~130 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6116d70bbd3f4d8886e55f586b2b9a1bc5c58e54;p=thirdparty%2FPython%2Fcpython.git gh-143403: Fix a UAF in `_BINARY_OP_INPLACE_ADD_UNICODE` (GH-143404) Fix a UAF in `_BINARY_OP_INPLACE_ADD_UNICODE` --- diff --git a/Python/bytecodes.c b/Python/bytecodes.c index 366bca44f83f..2e86e11e140e 100644 --- a/Python/bytecodes.c +++ b/Python/bytecodes.c @@ -802,15 +802,18 @@ dummy_func( */ assert(Py_REFCNT(left_o) >= 2 || !PyStackRef_IsHeapSafe(left)); PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - PyUnicode_Append(&temp, right_o); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - DEAD(right); + PyObject *right_o = PyStackRef_AsPyObjectSteal(right); + /* gh-143403: It's critical to close this reference *before* + * we append. Otherwise, append can move the underlying + * unicode object, which will cause a use after free! + */ PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); DEAD(left); + PyUnicode_Append(&temp, right_o); + _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); + *target_local = PyStackRef_NULL; ERROR_IF(temp == NULL); res = PyStackRef_FromPyObjectSteal(temp); - *target_local = PyStackRef_NULL; } op(_GUARD_BINARY_OP_EXTEND, (descr/4, left, right -- left, right)) { diff --git a/Python/executor_cases.c.h b/Python/executor_cases.c.h index 3fe7a3200269..def627204b4b 100644 --- a/Python/executor_cases.c.h +++ b/Python/executor_cases.c.h @@ -4957,30 +4957,22 @@ STAT_INC(BINARY_OP, hit); assert(Py_REFCNT(left_o) >= 2 || !PyStackRef_IsHeapSafe(left)); PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); - stack_pointer[0] = left; - stack_pointer[1] = right; - stack_pointer += 2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); + PyObject *right_o = PyStackRef_AsPyObjectSteal(right); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); _PyFrame_SetStackPointer(frame, stack_pointer); PyUnicode_Append(&temp, right_o); + _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + *target_local = PyStackRef_NULL; if (temp == NULL) { - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); SET_CURRENT_CACHED_VALUES(0); JUMP_TO_ERROR(); } res = PyStackRef_FromPyObjectSteal(temp); - *target_local = PyStackRef_NULL; _tos_cache0 = res; _tos_cache1 = PyStackRef_ZERO_BITS; _tos_cache2 = PyStackRef_ZERO_BITS; SET_CURRENT_CACHED_VALUES(1); - stack_pointer += -2; - ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); assert(WITHIN_STACK_BOUNDS_IGNORING_CACHE()); break; } diff --git a/Python/generated_cases.c.h b/Python/generated_cases.c.h index a1d5a98255c4..a0a1e94921b9 100644 --- a/Python/generated_cases.c.h +++ b/Python/generated_cases.c.h @@ -428,20 +428,22 @@ STAT_INC(BINARY_OP, hit); assert(Py_REFCNT(left_o) >= 2 || !PyStackRef_IsHeapSafe(left)); PyObject *temp = PyStackRef_AsPyObjectSteal(*target_local); - PyObject *right_o = PyStackRef_AsPyObjectBorrow(right); + PyObject *right_o = PyStackRef_AsPyObjectSteal(right); + PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + stack_pointer += -2; + ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); _PyFrame_SetStackPointer(frame, stack_pointer); PyUnicode_Append(&temp, right_o); + _Py_DECREF_SPECIALIZED(right_o, _PyUnicode_ExactDealloc); stack_pointer = _PyFrame_GetStackPointer(frame); - PyStackRef_CLOSE_SPECIALIZED(right, _PyUnicode_ExactDealloc); - PyStackRef_CLOSE_SPECIALIZED(left, _PyUnicode_ExactDealloc); + *target_local = PyStackRef_NULL; if (temp == NULL) { - JUMP_TO_LABEL(pop_2_error); + JUMP_TO_LABEL(error); } res = PyStackRef_FromPyObjectSteal(temp); - *target_local = PyStackRef_NULL; } - stack_pointer[-2] = res; - stack_pointer += -1; + stack_pointer[0] = res; + stack_pointer += 1; ASSERT_WITHIN_STACK_BOUNDS(__FILE__, __LINE__); DISPATCH(); }