CPython UaF during index callbacks
Chưa có ai nhận issue này.
- 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ả
Bug report
Bug description:
The _PyNumber_Index, PyFloat_AsDouble and PyNumber_Long functions use a borrowed reference for error formatting after calling Python slots (index/float), but the slot's frame cleanup can free the object before the error is formatted.
A use-after-free vulnerability exists in CPython's type conversion functions (_PyNumber_Index, PyFloat_AsDouble and PyNumber_Long) where a borrowed reference is used for error message formatting after a Python callback that can free the referenced object.
For example, the vulnerable code pattern could be observed in _PyNumber_Index implementation (Objects/abstract.c):
PyObject *
_PyNumber_Index(PyObject *item) // item is a BORROWED reference
{
if (item == NULL) {
return null_error();
}
if (PyLong_Check(item)) {
return Py_NewRef(item);
}
if (!_PyIndex_Check(item)) {
PyErr_Format(PyExc_TypeError,
"'%.200s' object cannot be interpreted "
"as an integer", Py_TYPE(item)->tp_name);
return NULL;
}
// === PYTHON CODE EXECUTES HERE ===
PyObject *result = Py_TYPE(item)->tp_as_number->nb_index(item);
// === item MAY NOW BE FREED ===
if (!result || PyLong_CheckExact(result)) {
return result;
}
if (!PyLong_Check(result)) {
PyErr_Format(PyExc_TypeError,
"%T.__index__() must return an int, not %T",
item, result); // <== UAF: item may be freed
Py_DECREF(result);
return NULL;
}
// ... similar pattern continues
}
Similar patterns can be found in the PyFloat_AsDouble and PyNumber_Long functions.
The Python array.fromlist() method provides an ideal attack vector because it:
Iterates over a list using PyList_GET_ITEM() (returns borrowed reference)
Passes the borrowed reference directly to type-specific setitem functions
These functions call _PyNumber_Index() or PyFloat_AsDouble() for conversion.
Running with a python interpreter compiled with ASAN (./configure --with-address-sanitizer):
import array
class Evil:
def __init__(self, lst):
self.lst = lst
def __index__(self):
self.lst.clear()
return "not an int"
lst = []
e = Evil(lst)
lst.append(e)
del e
arr = array.array('I')
arr.fromlist(lst)
You'll get the following:
==73525==ERROR: AddressSanitizer: heap-use-after-free on address 0x6130000300b8 at pc 0x0001013458a4 bp 0x00016ee396f0 sp 0x00016ee396e8
READ of size 8 at 0x6130000300b8 thread T0
#0 0x0001013458a0 in unicode_from_format unicodeobject.c:3075
#1 0x0001013436a8 in PyUnicode_FromFormatV unicodeobject.c:3109
#2 0x00010154d5c8 in PyErr_Format errors.c:1243
#3 0x0001010fe4e8 in _PyNumber_Index abstract.c:1433
#4 0x000109338334 in II_setitem arraymodule.c:411
#5 0x0001093427d4 in array_array_fromlist arraymodule.c.h:495
#6 0x00010114aeb0 in _PyObject_VectorcallTstate pycore_call.h:136
#7 0x0001014828ac in _Py_VectorCallInstrumentation_StackRefSteal ceval.c:1094
#8 0x0001014b4718 in _PyEval_EvalFrameDefault generated_cases.c.h:1785
#9 0x00010148180c in _PyEval_Vector ceval.c:2516
#10 0x00010148105c in PyEval_EvalCode ceval.c:1005
#11 0x000101646118 in run_mod pythonrun.c:1469
#12 0x00010163e6a0 in _PyRun_SimpleFileObject pythonrun.c:518
#13 0x00010163da30 in _PyRun_AnyFileObject pythonrun.c:81
#14 0x0001016ac948 in pymain_run_file main.c:429
#15 0x0001016aabcc in Py_RunMain main.c:772
#16 0x0001016ab9fc in pymain_main main.c:802
#17 0x0001016abba8 in Py_BytesMain main.c:826
#18 0x00019e4edd50 (<unknown module>)
CPython versions tested on:
3.15
Operating systems tested on:
macOS
Linked PRs
- gh-144138
Hướng dẫn đóng góp
Bắt đầu từ đâu
- Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
- 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.
- Fork repository và làm thay đổi trên một nhánh.
- Mở pull request có tham chiếu số hiệu của issue.
Hướng nghiên cứu
Bắt đầu trong Objects/abstract.c tại _PyNumber_Index, PyFloat_AsDouble và PyNumber_Long, sau đó kiểm tra đường dẫn gọi trong arraymodule.c và tái hiện bằng ví dụ ASAN. So sánh cách xử lý liên quan và các bài kiểm thử trong cây hiện tại; hoàn tất có nghĩa là use-after-free đã được báo cáo được xử lý trên tất cả các hàm chuyển đổi đã nêu và trình tái hiện ASAN không còn thất bại.
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
- security
- 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
- Đặc tả rõ ràng
- Mức phù hợp với người mới
- 25/100