python / python/cpython

Null pointer dereference in `cursor.fetchone` after re-entrant `text_factory` closes connection

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

@picnixz đang làm issue này rồi.

Từ ngày 10/1/2026.

extension-modules topic-sqlite3 type-crash
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ả

A user-provided text_factory runs while _pysqlite_fetch_one_row converts TEXT columns. If it calls Connection.close, connection->db is set to NULL, but pysqlite_cursor_iternext still calls sqlite3_changes(self->connection->db) once iteration advances. The SQLite helper dereferences the cleared pointer and segfaults.

Proof of Concept:

import sqlite3

conn = sqlite3.connect(":memory:")
conn.execute("create table t(x)")
cur = conn.cursor()
cur.execute("insert into t values ('a') returning x")

def text_factory(val, _conn=conn):
    if not getattr(text_factory, "armed", False):
        text_factory.armed = True
        _conn.close()
    return "x"

conn.text_factory = text_factory
cur.fetchone()

Vulnerable Code Snippet:

Click to expand
/* Buggy Re-entrant Path */
static PyObject *
pysqlite_cursor_fetchone_impl(pysqlite_Cursor *self)
{
    return pysqlite_cursor_iternext((PyObject *)self);
}

static PyObject *
pysqlite_cursor_iternext(PyObject *op)
{
    pysqlite_Cursor *self = _pysqlite_Cursor_CAST(op);
    /* ... */
    PyObject *row = _pysqlite_fetch_one_row(self);
    /* ... */
    if (rc == SQLITE_DONE) {
        if (self->statement->is_dml) {
            sqlite3 *db = self->connection->db;  /* crashing pointer derived */
            self->rowcount = (long)sqlite3_changes(db);  /* Crash site */
        }
        /* ... */
    }
    return row;
}

static PyObject *
_pysqlite_fetch_one_row(pysqlite_Cursor* self)
{
    /* ... */
    converted = PyObject_CallFunction(self->connection->text_factory,
                                      "y#", text, nbytes);  /* Reentrant call site */
    /* ... */
}

/* Clobbering Path */
static int
connection_close(pysqlite_Connection *self)
{
    sqlite3 *db = self->db;
    self->db = NULL;  /* state mutate site */
    (void)sqlite3_close_v2(db);
    /* ... */
    return rc;
}

Sanitizer Output:

Click to expand
AddressSanitizer:DEADLYSIGNAL
=================================================================
==431550==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000078 (pc 0x7fbfd133c1b4 bp 0x7ffed0387610 sp 0x7ffed0387608 T0)
==431550==The signal is caused by a READ memory access.
==431550==Hint: address points to the zero page.
    #0 0x7fbfd133c1b4 in sqlite3_changes64 (/lib/x86_64-linux-gnu/libsqlite3.so.0+0xa41b4) (BuildId: ac2bec9c45eec6feab0928b3b1373b467aa51339)
    #1 0x7fbfd133c1cc in sqlite3_changes (/lib/x86_64-linux-gnu/libsqlite3.so.0+0xa41cc) (BuildId: ac2bec9c45eec6feab0928b3b1373b467aa51339)
    #2 0x7fbfd3bdbb1c in pysqlite_cursor_iternext Modules/_sqlite/cursor.c:1121
    #3 0x7fbfd3bdbb1c in pysqlite_cursor_fetchone_impl Modules/_sqlite/cursor.c:1154
    #4 0x7fbfd3bdbb1c in pysqlite_cursor_fetchone Modules/_sqlite/clinic/cursor.c.h:169
    #5 0x6390ee26e3e7 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169
    #6 0x6390ee26e3e7 in PyObject_Vectorcall Objects/call.c:327
    #7 0x6390ee1225a2 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620
    #8 0x6390ee5ecad6 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121
    #9 0x6390ee5ecad6 in _PyEval_Vector Python/ceval.c:2001
    #10 0x6390ee5ecad6 in PyEval_EvalCode Python/ceval.c:884
    #11 0x6390ee73216e in run_eval_code_obj Python/pythonrun.c:1365
    #12 0x6390ee73216e in run_mod Python/pythonrun.c:1459
    #13 0x6390ee736e17 in pyrun_file Python/pythonrun.c:1293
    #14 0x6390ee736e17 in _PyRun_SimpleFileObject Python/pythonrun.c:521
    #15 0x6390ee73793c in _PyRun_AnyFileObject Python/pythonrun.c:81
    #16 0x6390ee7aae3c in pymain_run_file_obj Modules/main.c:410
    #17 0x6390ee7aae3c in pymain_run_file Modules/main.c:429
    #18 0x6390ee7aae3c in pymain_run_python Modules/main.c:691
    #19 0x6390ee7ac71e in Py_RunMain Modules/main.c:772
    #20 0x6390ee7ac71e in pymain_main Modules/main.c:802
    #21 0x6390ee7ac71e in Py_BytesMain Modules/main.c:826
    #22 0x7fbfd442a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
    #23 0x7fbfd442a28a in __libc_start_main_impl ../csu/libc-start.c:360
    #24 0x6390ee146634 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x206634) (BuildId: 4d105290d0ad566a4d6f4f7b2f05fbc9e317b533)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/lib/x86_64-linux-gnu/libsqlite3.so.0+0xa41b4) (BuildId: ac2bec9c45eec6feab0928b3b1373b467aa51339) in sqlite3_changes64
==431550==ABORTING
Affected Versions:
Python Version Status Exit Code
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 28 2025, 16:51:20) OK 0
Python 3.10.19+ (heads/3.10:014261980b1, Oct 28 2025, 16:52:08) [Clang 18.1.3 (1ubuntu1)] OK 0
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 28 2025, 16:53:08) [Clang 18.1.3 (1ubuntu1)] ASAN 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
CPython versions tested on:

CPython main branch

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]

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.

Đánh giá

Issue này chưa được đánh giá.

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.