Skip to content

PRAGMA cipher_default_settings returns successful NULL rows when formatting allocation fails #618

Description

@DBFuzz

Version and environment

Reproduced from SQLCipher commit 810db22f575ee7cf94ea96a3e91622b5fcece3dc on Linux amd64. The fresh build reported SQLite 3.53.3 / SQLCipher 4.17.0 Community.

Describe the bug

PRAGMA cipher_default_settings formats six setting strings with sqlite3_mprintf() and passes each result to sqlcipher_vdbe_return_string() without checking for allocation failure. Under controlled memory pressure, prepare succeeds and stepping returns six SQL NULL rows followed by SQLITE_DONE, rather than valid setting strings or SQLITE_NOMEM.

Minimal reproduction

Run the supplied C harness:

bash sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a/poc/run_revalidation.sh

The trigger logic in revalidate_cipher_default_settings_oom.c is:

sqlite3_open(":memory:", &db);
sqlite3_status64(SQLITE_STATUS_MEMORY_USED, &used, &highwater, 0);
sqlite3_hard_heap_limit64(used);
sqlite3_prepare_v2(db, "PRAGMA cipher_default_settings;", -1, &stmt, 0);
while ((rc = sqlite3_step(stmt)) == SQLITE_ROW) {
  printf("type=%d value=%s\n", sqlite3_column_type(stmt, 0),
         sqlite3_column_text(stmt, 0));
}

The harness first runs the same PRAGMA without the hard limit as a control.

Actual behavior/output

The control returned six non-NULL strings and finished with step_rc=101. Under the hard limit:

prepare_rc=0
row1=(null)
row2=(null)
row3=(null)
row4=(null)
row5=(null)
row6=(null)
step_rc=101 msg=no more rows available rows=6 nulls=6

Expected behavior

The statement should either return all six non-NULL setting strings or surface SQLITE_NOMEM. Allocation failure must not be represented as a successful result set containing NULL values.

Impact and scope

Callers cannot distinguish genuine settings from internal allocation failure and may accept incomplete configuration state. The focused test covers cipher_default_settings; other PRAGMA branches using the same helper may need review.

Relevant source/root cause

sqlcipher_vdbe_return_string() at src/sqlcipher.c:2690-2695 does not validate value. The cipher_default_settings branch around src/sqlcipher.c:3310-3340 passes unchecked sqlite3_mprintf() results to it. The resulting OP_String8 path produces NULL columns without propagating OOM.

Suggested regression test

Use SQLite's deterministic allocation-failure mechanism around every formatted cipher_default_settings row and assert that the statement returns SQLITE_NOMEM, never SQLITE_ROW with a NULL column followed by SQLITE_DONE.

Reproduction bundle

Attached: sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a_attachment.zip. It contains the focused PoC, validation evidence, and candidate metadata.

sqlcipher-005-unchecked-sqlcipher-pragma-formatting-returns-null-row-5002b91a_attachment.zip

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions