Skip to content

autoinit is broken for libsql_open_v3 #2169

@hgarrereyn

Description

@hgarrereyn

Hi, its documented that calling sqlite3_initialize is required before using certain other functions.

However the library also supports "autoinit" whereby, when necessary, sqlite3_initialize is automatically called in the process of executing those functions:

** This routine must be called to initialize the memory allocation,
** VFS, and mutex subsystems prior to doing any serious work with
** SQLite. But as long as you do not compile with SQLITE_OMIT_AUTOINIT
** this routine will be called automatically by key routines such as
** sqlite3_open().

One such function is openDatabase which is used by the sqlite3_open* and libsql_open* APIs.

However, there is a potential issue with libsql_open_v3 as it tries to perform memory allocation before invoking openDatabase via a call to make_ref_counted_wal_manager:

int libsql_open_v3(
const char *filename, /* Database filename (UTF-8) */
sqlite3 **ppDb, /* OUT: SQLite db handle */
int flags, /* Flags */
const char *zVfs, /* Name of VFS module to use, NULL for default */
libsql_wal_manager wal_manager /* wal_manager implemetation */
) {
RefCountedWalManager *wal_manager_rc;
int rc = make_ref_counted_wal_manager(wal_manager, &wal_manager_rc);
if (rc) {
wal_manager.xDestroy(wal_manager.pData);
return rc;
}
return openDatabase(filename, ppDb, (unsigned int)flags, zVfs, wal_manager_rc);
}

Thus, while libsql_open_v3 intends to automatically initialize, it actually does it too late, leading to a crash.

(found via automated fuzzing)

The following testcase demonstrates the issue:

testcase.cpp

#include <cstdint>
extern "C" {
#include "sqlite3.h"
#include "sqlite3ext.h"
}
int main(){
  libsql_wal_manager wm{};
  wm.bUsesShm = 0;
  // Provide non-NULL stubs for required callbacks
  wm.xOpen = +[](wal_manager_impl*, sqlite3_vfs*, sqlite3_file*, int, long long, const char*, libsql_wal*)->int{return 1; };
  wm.xClose = +[](wal_manager_impl*, wal_impl*, sqlite3*, int, int, unsigned char*)->int{ return 0; };
  wm.xLogDestroy = +[](wal_manager_impl*, sqlite3_vfs*, const char*)->int{ return 0; };
  wm.xLogExists = +[](wal_manager_impl*, sqlite3_vfs*, const char*, int *pResOut)->int{ if(!pResOut) return 1; *pResOut=0; return 0; };
  wm.xDestroy = +[](wal_manager_impl*){};
  wm.pData = nullptr;
  const char *fname = ":memory:";
  sqlite3 *db=nullptr;
  int flags = SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE;
  // This call crashes inside libsql_open_v3 with pc=0x0
  int rc = libsql_open_v3(fname, &db, flags, nullptr, wm);
  (void)rc; (void)db;
  return 0;
}

crash report

==12==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x000000000000 bp 0x7ffd3c874770 sp 0x7ffd3c8746a8 T0)
==12==Hint: pc points to the zero page.
==12==The signal is caused by a READ memory access.
==12==Hint: address points to the zero page.
    #0 0x0  (<unknown module>)
    #1 0x5650461d476e in main /fuzz/workspace/test.cpp:22:12
    #2 0x7faec1d67d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (<unknown module>)

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