Skip to content

OOM: SQLAllocHandle(SQL_HANDLE_STMT) can segfault if ARD_AllocBookmark malloc fails #177

Description

@jarvis24young

OOM: SQLAllocHandle(SQL_HANDLE_STMT) can segfault if ARD_AllocBookmark malloc fails

Summary

While doing defensive robustness testing of psqlODBC, I found a NULL-dereference crash on the statement allocation path when an internal bookmark allocation fails.

This is an OOM/robustness issue. I am not claiming a practical remote exploit; the reproducer uses malloc-failure injection to force the allocation failure deterministically. The expected behavior would be to return an ODBC error/diagnostic instead of crashing the hosting process.

Affected path

SQLAllocHandle(SQL_HANDLE_STMT, ...) reaches PGAPI_AllocStmt(), which calls ARD_AllocBookmark():

BindInfoClass *
ARD_AllocBookmark(ARDFields *ardopts)
{
    if (!ardopts->bookmark)
    {
        ardopts->bookmark = (BindInfoClass *) malloc(sizeof(BindInfoClass));
        pg_memset(ardopts->bookmark, 0, sizeof(BindInfoClass));
    }
    return ardopts->bookmark;
}

If malloc(sizeof(BindInfoClass)) returns NULL, pg_memset() is called with a NULL pointer.

Observed call chain:

SQLAllocHandle(SQL_HANDLE_STMT)
  -> PGAPI_AllocStmt              statement.c:232
     -> ARD_AllocBookmark         descriptor.c:345
        -> malloc(sizeof(BindInfoClass)) returns NULL
        -> pg_memset(NULL, ...)

On my x86_64 Linux build, sizeof(BindInfoClass) was 40 bytes.

Reproducer

Environment used:

  • Linux under WSL2
  • unixODBC
  • PostgreSQL test database
  • psqlODBC built with debug/gcov flags, no ASan for this OOM injection run

A minimal black-box test only uses public ODBC APIs:

SQLDriverConnect(...);
SQLAllocHandle(SQL_HANDLE_STMT, conn, &hstmt);

I forced the relevant allocation to fail with an LD_PRELOAD malloc shim that returns NULL on the Nth 40-byte allocation:

PODBC_FAIL_MALLOC_SIZE=40 PODBC_FAIL_MALLOC_N=178 \
LD_PRELOAD=./exe/malloc_fail_shim.so \
ODBCSYSINI=. ODBCINSTINI=./odbcinst.ini ODBCINI=./odbc.ini \
  ./exe/ard-bookmark-oom-bugwatch-test

Observed output:

connected
allocating statement handle through SQLAllocHandle(SQL_HANDLE_STMT)
malloc-fail-shim: failing malloc(40) occurrence 178
../.libs/psqlodbcw.so(+0x8f5e9)
../.libs/psqlodbcw.so(+0x7cea0)
../.libs/psqlodbcw.so(SQLAllocHandle+0x20e)
oom_rc=139

Address mapping:

driver +0x8f5e9:
ARD_AllocBookmark
.../descriptor.c:345

driver +0x7cea0:
PGAPI_AllocStmt
.../statement.c:232

Normal run without malloc failure completes successfully:

connected
allocating statement handle through SQLAllocHandle(SQL_HANDLE_STMT)
SQLAllocHandle stmt rc=0 hstmt=...
disconnecting
statement allocation completed without crashing

Expected behavior

If bookmark allocation fails during statement allocation, the driver should return an ODBC error, ideally with a memory-allocation diagnostic, rather than dereferencing NULL and crashing.

Suggested fix direction

ARD_AllocBookmark() could return NULL when allocation fails, and callers that require the bookmark should handle that by setting an appropriate diagnostic and returning SQL_ERROR.

Known direct callers worth checking:

  • statement.c::PGAPI_AllocStmt()
  • bind.c::PGAPI_BindCol()
  • descriptor.c::ARDFields_copy()

I can provide the regression test and malloc-failure shim if that would be useful.

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