SQLite Forum

Timeline
Login

1 forum post by user wmhfzh

2020-09-28
12:06 Post: SQLite 3.33.0 has an integer overflow leading to heap out of bound access on 32-bit systems (artifact: 10a2892377 user: wmhfzh)

SQLite 3.33.0 has an integer overflow leading to out of bound access to heap on 32-bit systems when handling sqlite3 -pagecache SIZE N command.

How to Trigger the Bug

SQLite 3.33.0 has an integer overflow that can further lead to heap out of bound access. The bug is effective on 32 bit OS systems. We’ve verified it with clang AddressSanitizer as follows.

First, use clang to compile the sqlite with ‘-fsanitize=address -fsanitize=undefined”:

CC=clang CFLAGS="-fsanitize=address -fsanitize=undefined -m32” ../configure

Then, make;

Finally, run: ./sqlite3 -pagecache 70000 70000.

It finally gave us the following output with error information.

shell.c:20470:46: runtime error: signed integer overflow: 70000 * 70000 cannot be represented in type 'int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior shell.c:20470:46 in
shell.c:20472:45: runtime error: signed integer overflow: 70000 * 70000 cannot be represented in type 'int'
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior shell.c:20472:45 in
AddressSanitizer:DEADLYSIGNAL
=================================================================
==21440==ERROR: AddressSanitizer: SEGV on unknown address 0xf580a750 (pc 0x082e08eb bp 0xffa6c3a8 sp 0xffa6c340 T0)
==21440==The signal is caused by a WRITE memory access.
    #0 0x82e08ea in sqlite3PCacheBufferSetup /home/tony/Documents/projects/ikos/fv_test/sqlite-src-3330000/bld-poc/sqlite3.c
    #1 0x8266e48 in sqlite3_initialize /home/tony/Documents/projects/ikos/fv_test/sqlite-src-3330000/bld-poc/sqlite3.c:161315:7
    #2 0x812b1ef in main /home/tony/Documents/projects/ikos/fv_test/sqlite-src-3330000/bld-poc/shell.c:20549:3
    #3 0xf7c56f20 in __libc_start_main (/lib32/libc.so.6+0x18f20)
    #4 0x8065291 in _start (/home/tony/Documents/projects/ikos/fv_test/sqlite-src-3330000/bld-poc/sqlite3+0x8065291)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /home/tony/Documents/projects/ikos/fv_test/sqlite-src-3330000/bld-poc/sqlite3.c in sqlite3PCacheBufferSetup
==21440==ABORTING

Root Cause of Bug:

From following snippet of shell.c.in, we see that sqlite3_config(SQLITE_CONFIG_PAGECACHE, …) is called to setup page cache for sqlite. At (2), 'n * sz' would be the param of malloc, where ’n’ as shown at (1) is actually given by an user input, and it could cause n * sz to be overflowed.

For the command ./sqlite3 -pagecache 70000 70000, sz was 70000, n was 70000 and n * sz was actually 5600 after calling sqlite3_config as shown at (3)~(5). (70000 * 70000 exceeds INT32_MAX) .

/// shell.c.in
int SQLITE_CDECL main(int argc, char **argv){
    ...
    ...
    }else if( strcmp(z,"-pagecache")==0 ){
      int n, sz;
      sz = (int)integerValue(cmdline_option_value(argc,argv,++i));
      if( sz>70000 ) sz = 70000;
      if( sz<0 ) sz = 0;
      n = (int)integerValue(cmdline_option_value(argc,argv,++i));   // (1) n comes from the user input, which can be arbitrary.
      printf("[+] n: %d\n", n);
      printf("[+] n * sz: %lu\n", (size_t)(n * sz));
      sqlite3_config(SQLITE_CONFIG_PAGECACHE,
                    (n>0 && sz>0) ? malloc(n*sz) : 0, sz, n);     // (2)  n * sz could be overflowed. 
     ...
     ...
     sqlite3_initialize();  
     ...
    }
}

/// sqlite3.c
SQLITE_API int sqlite3_config(int op, ...){
    ......
    case SQLITE_CONFIG_PAGECACHE: {
      /* EVIDENCE-OF: R-18761-36601 There are three arguments to
      ** SQLITE_CONFIG_PAGECACHE: A pointer to 8-byte aligned memory (pMem),
      ** the size of each page cache line (sz), and the number of cache lines
      ** (N). */
      sqlite3GlobalConfig.pPage = va_arg(ap, void*);        // (3) malloc(5600)
      sqlite3GlobalConfig.szPage = va_arg(ap, int);         // (4) 7000
      sqlite3GlobalConfig.nPage = va_arg(ap, int);          // (5) 7000
      break;
    }
    ......
}

After that, sqlite3_initialize() is called and it further calls sqlite3PCacheBufferSetup, as show in the following snippet. The param sqlite3GlobalConfig.szPage is 70000, sqlite3GlobalConfig.nPage is 70000, and sqlite3GlobalConfig.pPage is the heap allocated by malloc(5600), as shown at (6).

When the execution goes in sqlite3PCacheBufferSetup, we can know that out of bound access to the allocated heap would be occurred, as shown at (7).

/// sqlite3.c
SQLITE_API int sqlite3_initialize(void){
    ...
    ...
    if( rc==SQLITE_OK ){
    sqlite3PCacheBufferSetup(sqlite3GlobalConfig.pPage, sqlite3GlobalConfig.szPage, sqlite3GlobalConfig.nPage);  // (6) The arg would be 'malloc(5600)', 70000, 70000 respectively. 
    sqlite3MemoryBarrier();
    sqlite3GlobalConfig.isInit = 1;
    ...
    ....
}
/// sqlite3.c
SQLITE_PRIVATE void sqlite3PCacheBufferSetup(void *pBuf, int sz, int n){
  if( pcache1.isInit ){
    PgFreeslot *p;
    if( pBuf==0 ) sz = n = 0;
    if( n==0 ) sz = 0;
    sz = ROUNDDOWN8(sz);
    pcache1.szSlot = sz;
    pcache1.nSlot = pcache1.nFreeSlot = n;
    pcache1.nReserve = n>90 ? 10 : (n/10 + 1);
    pcache1.pStart = pBuf;
    pcache1.pFree = 0;
    pcache1.bUnderPressure = 0;
    while( n-- ){                           // (7) Out of bound access to heap occured inside this loop and it caused the heap corrpution.
      p = (PgFreeslot*)pBuf;                
      p->pNext = pcache1.pFree;
      pcache1.pFree = p;
      pBuf = (void*)&((char*)pBuf)[sz];
    }
    pcache1.pEnd = pBuf;
  }
}