Skip to content

sqlite3: Connection.close() inside callback UAF #158908

Closed as duplicate
Closed as duplicate

Description

@error-3317

Crash report

PoC

import sqlite3
con = sqlite3.connect(":memory:")
con.execute("create table t(a)")
con.executemany("insert into t values (?)", [(i,) for i in range(10)])
def handler():
    con.close()      # runs while sqlite3_step() is on the C stack
    return 0         # "keep going": the zombie VDBE keeps executing
con.set_progress_handler(handler, 1)
list(con.execute("select * from t"))   # Segmentation fault
print("NO CRASH")

Output

$ python3 -X faulthandler run.py
Fatal Python error: Segmentation fault

Current thread 0x00007f3e81776740 [python3.15] (most recent call first):
  File "<stdin>", line 9 in <module>

Current thread's C stack trace (most recent call first):
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at _Py_DumpStack+0x30 [0x4f0b80]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x59968b]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x5995de]
  Binary file "/lib/x86_64-linux-gnu/libc.so.6", at +0x3c050 [0x7f3e814b5050]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1a8c265]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1b94cb4]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1be0a8d]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1ae890e]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1b0289c]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1b018d8]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1a2d33f]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1a72484]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at PyEval_EvalCode+0xa6 [0x1a72182]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1ac87bb]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c7184d]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c71767]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c712c6]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1c6fc45]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at Py_RunMain+0x422 [0x1b8d062]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1b8cc1d]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15" [0x1b8ca6e]
  Binary file "/lib/x86_64-linux-gnu/libc.so.6", at +0x2724a [0x7f3e814a024a]
  Binary file "/lib/x86_64-linux-gnu/libc.so.6", at __libc_start_main+0x85 [0x7f3e814a0305]
  Binary file "/home/user/.local/share/uv/python/cpython-3.15-linux-x86_64-gnu/bin/python3.15", at _start+0x29 [0x1be5437]

Root Cause

Modules/_sqlite/connection.c:441-467 (connection_close frees callback contexts via free_callback_contexts at :465 while statements are still stepping) and :1487-1502 (progress_callback: incref_callback_context at :1487 is a UAF write; PyObject_CallNoArgs(ctx->callable) at :1490 calls a freed pointer; decref at :1502 is a double-free-class primitive)
sqlite3_close_v2() produces a zombie connection when statements are busy (by design), but connection_close immediately frees the registered callback contexts, the zombie VDBE keeps invoking progress_callback, which increfs/calls/decrefs the freed ctx. Deregistration (remove_callbacks) exists but is only invoked from the interpreter-teardown finalizer, not from close — proving the module considers deregistration its own job and simply misses the close path.

CPython versions tested on:

3.15

Operating systems tested on:

Linux

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

Python 3.15.0rc3 (main, Oct 3 2026, 01:07:55) [Clang 22.1.3 ]

Activity

  1. added
    type-crashA hard crash of the interpreter, possibly with a core dump
    on Oct 6, 2026
  2. picnixz commented on Oct 6, 2026

    @picnixz
    Member

    This is already known. Please avoid duplicate reports: #145040.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    extension-modulesC modules in the Modules dirtopic-sqlite3type-crashA hard crash of the interpreter, possibly with a core dump

    Projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions