SQLite User Forum

Potentially dangerous negative size term in sqlite3WhereCodeOneLoopStart allocation
Login

Potentially dangerous negative size term in sqlite3WhereCodeOneLoopStart allocation

(1) By anonymous on 2023-12-19 14:22:52 [source]

Version: 3.44.0

I am chasing a corruption of sqlite data structures. One of the rarer stacktraces that have been captured reads:

#0  sqlite3WhereCodeOneLoopStart (notReady=18446744073709551615, pLevel=<optimized out>, iLevel=0, pWInfo=0x7f14dc0b7370, v=<optimized out>, pParse=0x7f14d2ffd1c0) at sqlite3.c:158072
158072        if( pTerm->wtFlags & (TERM_VIRTUAL|TERM_CODED) ) continue;
(gdb) p pTerm
$1 = (WhereTerm *) 0x0
(gdb) bt
#0  sqlite3WhereCodeOneLoopStart (notReady=18446744073709551615, pLevel=<optimized out>, iLevel=0, pWInfo=0x7f14dc0b7370, v=<optimized out>, pParse=0x7f14d2ffd1c0) at sqlite3.c:158072
#1  sqlite3WhereBegin (pParse=pParse@entry=0x7f14d2ffd1c0, pTabList=pTabList@entry=0x7f14dc0c10b0, pWhere=pWhere@entry=0x7f14dc0c1430, pOrderBy=<optimized out>, pResultSet=<optimized out>, pSelect=pSelect@entry=0x7f14dc0c1eb0, wctrlFlags=<optimized out>, iAuxArg=320) at sqlite3.c:35739
#2  0x00007f159994c8f6 in sqlite3Select (pParse=pParse@entry=0x7f14d2ffd1c0, p=<optimized out>, pDest=pDest@entry=0x7f14d2ffc760) at sqlite3.c:149126
#3  0x00007f159997f13f in yy_reduce (yypParser=0x7f14d2ffc7c0, yyLookahead=<optimized out>, pParse=0x7f14d2ffd1c0, yyLookaheadToken=..., yyruleno=84) at sqlite3.c:174205
#4  sqlite3Parser (yyminor=..., yymajor=<optimized out>, yyp=0x7f14d2ffc7c0) at sqlite3.c:44579
#5  sqlite3RunParser (pParse=pParse@entry=0x7f14d2ffd1c0, zSql=<optimized out>, zSql@entry=0x7f1598ddaa50 "SELECT proptag, propval FROM folder_properties WHERE folder_id=? AND proptag=?") at sqlite3.c:45879
#6  0x00007f1599984d29 in sqlite3Prepare (db=db@entry=0x7f14dc0f4a50, zSql=zSql@entry=0x7f1598ddaa50 "SELECT proptag, propval FROM folder_properties WHERE folder_id=? AND proptag=?", nBytes=nBytes@entry=-1, prepFlags=prepFlags@entry=128, pReprepare=pReprepare@entry=0x0, ppStmt=ppStmt@entry=0x7f14d2ffd460, pzTail=0x0) at sqlite3.c:140941
#7  0x00007f159998518f in sqlite3LockAndPrepare (db=0x7f14dc0f4a50, zSql=0x7f1598ddaa50 "SELECT proptag, propval FROM folder_properties WHERE folder_id=? AND proptag=?", nBytes=-1, prepFlags=128, pOld=0x0, ppStmt=0x7f14d2ffd460, pzTail=0x0) at sqlite3.c:141016
#8  0x00007f1599989926 in sqlite3_prepare_v2 (db=db@entry=0x7f14dc0f4a50, zSql=zSql@entry=0x7f1598ddaa50 "SELECT proptag, propval FROM folder_properties WHERE folder_id=? AND proptag=?", nBytes=nBytes@entry=-1, ppStmt=ppStmt@entry=0x7f14d2ffd460, pzTail=pzTail@entry=0x0) at sqlite3.c:141102

Either way, this nullptr seems to originate in pWInfo->sWC.a=0x0.

So I went reading aimlessy for a bit in source code in the hope of finding something/anything. Have a peek at

  SQLITE_PRIVATE WhereInfo *sqlite3WhereBegin(...)

In this function, one finds:

    /* Special case: No FROM clause
    */
    if( nTabList==0 ){

This suggests nTabList can be reasonably 0. Now, this function also has this line above the nTabList check:

  nByteWInfo = ROUND8P(sizeof(WhereInfo)+(nTabList-1)*sizeof(WhereLevel));
  pWInfo = sqlite3DbMallocRawNN(db, nByteWInfo + sizeof(WhereLoop));

So if nTabList does happen to be zero, what this spells is

  <=> nByteWInfo = ROUND8P(sizeof(WhereInfo) + 18446744073709551504);

  <=> nByteWInfo = ROUND8P(856)

  <=> nByteWInfo = ROUND8P( offsetof(WhereInfo::a from WhereInfo) )

which means accessing pWInfo->a[0] is now undefined behavior. While pWInfo->a[0] shouldn't ideally be accessed under normal circumstances (because nTabList does spell 0), the fact that WhereInfo::a was declared as WhereLevel a[1]; rather than WhereLevel a[0]; means it is susceptible to a problem of that kind, e.g. if something somewhere did

  memset(pWInfo, 0, sizeof(WhereInfo)); or
  memcpy(another_winfo, pWInfo, sizeof(*pWInfo));