SQLite Forum

heap-buffer-overflow at sessionfuzz
Login

heap-buffer-overflow at sessionfuzz

(1) By qbit (junwha0511) on 2023-09-07 09:21:56 [link] [source]

Hi we found a heap-buffer-overflow bug from SQLite3 with our custom tool.

OS: Ubuntu 22.04 SQLite3 fossil-version: da4b7385 bug location: sqlite3.c:220260:11

you can also trigger the bug with Addreses Sanitizer, with following commands

export CC=/usr/bin/clang-15
export CFLAGS="-DSQLITE_OMIT_LOOKASIDE -fsanitize=address -g"
export LDFLAGS=$CFLAGS
export ASAN_OPTIONS=detect_leaks=0

mkdir build && cd build
../configure
make -j`nproc` sessionfuzz
./sessionfuzz run -v ../test/sessionfuzz-data1.db

The root cause is that it doesn't validate the pIn->iNext on reading aVal. (but we couldn't identify what is the reason invalid eType is there)

static int sessionReadRecord(
  SessionInput *pIn,              /* Input data */
  int nCol,                       /* Number of values in record */
  u8 *abPK,                       /* Array of primary key flags, or NULL */
  sqlite3_value **apOut,          /* Write values to this array */
  int *pbEmpty
){
	...
    if( rc==SQLITE_OK ){
      u8 *aVal = &pIn->aData[pIn->iNext]; //! [A] pIn->iNext must be validated
      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
        int nByte;
        pIn->iNext += sessionVarintGet(aVal, &nByte);
        rc = sessionInputBuffer(pIn, nByte);
        if( rc==SQLITE_OK ){
          if( nByte<0 || nByte>pIn->nData-pIn->iNext ){
            rc = SQLITE_CORRUPT_BKPT;
          }else{
            u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
            rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
            pIn->iNext += nByte;
          }
        }
      }
      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
        sqlite3_int64 v = sessionGetI64(aVal); //! [B] bug triggered**
        if( eType==SQLITE_INTEGER ){
          sqlite3VdbeMemSetInt64(apOut[i], v);
        }else{
          double d;
          memcpy(&d, &v, 8);
          sqlite3VdbeMemSetDouble(apOut[i], d);
        }
        pIn->iNext += 8;
      }
    }
	...

Here, it reads 8-bytes region from pIn->aData[pIn->iNext], but it was out-of-bound access on 1-byte accessible area because here pIn->iNext is 0x25, and pIn->nData is 0x26.

The patch can be as follows.

static int sessionReadRecord(
  SessionInput *pIn,              /* Input data */
  int nCol,                       /* Number of values in record */
  u8 *abPK,                       /* Array of primary key flags, or NULL */
  sqlite3_value **apOut,          /* Write values to this array */
  int *pbEmpty
){
	...
    if( rc==SQLITE_OK ){
      u8 *aVal = &pIn->aData[pIn->iNext]; 
      if( eType==SQLITE_TEXT || eType==SQLITE_BLOB ){
        int nByte;
        pIn->iNext += sessionVarintGet(aVal, &nByte);
        rc = sessionInputBuffer(pIn, nByte);
        if( rc==SQLITE_OK ){
          if( nByte<0 || nByte>pIn->nData-pIn->iNext ){
            rc = SQLITE_CORRUPT_BKPT;
          }else{
            u8 enc = (eType==SQLITE_TEXT ? SQLITE_UTF8 : 0);
            rc = sessionValueSetStr(apOut[i],&pIn->aData[pIn->iNext],nByte,enc);
            pIn->iNext += nByte;
          }
        }
      }
      if( eType==SQLITE_INTEGER || eType==SQLITE_FLOAT ){
      #ifndef DISABLE_PATCH
        if( pIn->iNext+sizeof(sqlite3_int64)>pIn->nData ){ 
            rc = SQLITE_CORRUPT_BKPT;
        } else {
      #endif
        sqlite3_int64 v = sessionGetI64(aVal);
        if( eType==SQLITE_INTEGER ){
          sqlite3VdbeMemSetInt64(apOut[i], v);
        }else{
          double d;
          memcpy(&d, &v, 8);
          sqlite3VdbeMemSetDouble(apOut[i], d);
        }
        pIn->iNext += 8;
      }
    #ifndef DISABLE_PATCH
     }
    #endif
    }
	...

---------- ASAN report -----------

==3125996==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6120000482f8 at pc 0x555555ad569f bp 0x7fffffffcb40 sp 0x7fffffffcb38
READ of size 1 at 0x6120000482f8 thread T0
    #0 0x555555ad569e in sessionGetI64 /home/qbit/SQLite-da4b7385/build/./sqlite3.c:220260:11
    #1 0x555555adf5a8 in sessionReadRecord /home/qbit/SQLite-da4b7385/build/./sqlite3.c:223159:27
    #2 0x555555adbc82 in sessionChangesetNextOne /home/qbit/SQLite-da4b7385/build/./sqlite3.c:223414:15
    #3 0x55555572da8d in sessionChangesetNext /home/qbit/SQLite-da4b7385/build/./sqlite3.c:223483:10
    #4 0x55555572d93e in sqlite3changeset_next /home/qbit/SQLite-da4b7385/build/./sqlite3.c:223497:10
    #5 0x555555731744 in sessionChangesetApply /home/qbit/SQLite-da4b7385/build/./sqlite3.c:224809:39
    #6 0x555555731198 in sqlite3changeset_apply_v2 /home/qbit/SQLite-da4b7385/build/./sqlite3.c:224993:10
    #7 0x5555557332d7 in sqlite3changeset_apply /home/qbit/SQLite-da4b7385/build/./sqlite3.c:225020:10
    #8 0x555555739bd9 in main /home/qbit/SQLite-da4b7385/build/../test/sessionfuzz.c:972:16
    #9 0x7ffff7c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16
    #10 0x7ffff7c29e3f in __libc_start_main csu/../csu/libc-start.c:392:3
    #11 0x555555600404 in _start (/home/qbit/SQLite-da4b7385/build/sessionfuzz+0xac404) (BuildId: 00776f96c0e0db6f20fbbb083d69175ab983a6e5)

0x6120000482f8 is located 0 bytes to the right of 312-byte region [0x6120000481c0,0x6120000482f8)
allocated by thread T0 here:
    #0 0x555555685e2e in __interceptor_malloc (/home/qbit/SQLite-da4b7385/build/sessionfuzz+0x131e2e) (BuildId: 00776f96c0e0db6f20fbbb083d69175ab983a6e5)
    #1 0x555555abfaa6 in sqlite3MemMalloc /home/qbit/SQLite-da4b7385/build/./sqlite3.c:26160:7
    #2 0x55555573b410 in mallocWithAlarm /home/qbit/SQLite-da4b7385/build/./sqlite3.c:29862:7
    #3 0x5555556c4383 in sqlite3Malloc /home/qbit/SQLite-da4b7385/build/./sqlite3.c:29908:5
    #4 0x55555573c6dc in dbMallocRawFinish /home/qbit/SQLite-da4b7385/build/./sqlite3.c:30213:7
    #5 0x55555573c564 in sqlite3DbMallocRawNN /home/qbit/SQLite-da4b7385/build/./sqlite3.c:30295:10
    #6 0x5555556f8657 in sqlite3DbMallocRaw /home/qbit/SQLite-da4b7385/build/./sqlite3.c:30244:19
    #7 0x5555557c327e in sqlite3VdbeMemGrow /home/qbit/SQLite-da4b7385/build/./sqlite3.c:82021:21
    #8 0x5555557c5bce in vdbeMemAddTerminator /home/qbit/SQLite-da4b7385/build/./sqlite3.c:82115:7
    #9 0x5555556ea5b3 in sqlite3VdbeMemMakeWriteable /home/qbit/SQLite-da4b7385/build/./sqlite3.c:82138:16
    #10 0x5555556ed6b9 in sqlite3VdbeMemCopy /home/qbit/SQLite-da4b7385/build/./sqlite3.c:82859:12
    #11 0x5555556ed425 in sqlite3_result_value /home/qbit/SQLite-da4b7385/build/./sqlite3.c:89812:3
    #12 0x55555573b07d in sqlarUncompressFunc /home/qbit/SQLite-da4b7385/build/../test/sessionfuzz.c:730:5
    #13 0x555555819a09 in sqlite3VdbeExec /home/qbit/SQLite-da4b7385/build/./sqlite3.c:100392:3
    #14 0x5555556ef780 in sqlite3Step /home/qbit/SQLite-da4b7385/build/./sqlite3.c:90003:10
    #15 0x5555556dbe25 in sqlite3_step /home/qbit/SQLite-da4b7385/build/./sqlite3.c:90064:16
    #16 0x555555739934 in main /home/qbit/SQLite-da4b7385/build/../test/sessionfuzz.c:964:28
    #17 0x7ffff7c29d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /home/qbit/SQLite-da4b7385/build/./sqlite3.c:220260:11 in sessionGetI64
Shadow bytes around the buggy address:
  0x0c2480001000: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c2480001010: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c2480001020: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
  0x0c2480001030: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00
  0x0c2480001040: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c2480001050: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00[fa]
  0x0c2480001060: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c2480001070: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
  0x0c2480001080: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fa
  0x0c2480001090: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd fd
  0x0c24800010a0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
==3125996==ABORTING

Thank you

(2) By Dan Kennedy (dan) on 2023-09-07 15:10:41 in reply to 1 [source]

Thanks for reporting this. Should now be fixed here:

https://sqlite.org/src/info/0e4e7a05c4204b47

Dan.

(3) By qbit (junwha0511) on 2023-09-12 07:43:05 in reply to 2 [link] [source]

Thanks for quickly addressing the heap-buffer-overflow I reported!:)

Could I kindly ask you to register this as a CVE, similar to prior buffer-overflow issues like CVE-2022-35737?

(4) By Richard Hipp (drh) on 2023-09-12 11:31:02 in reply to 3 [link] [source]

Thank you for reporting the issue.

We do not do CVEs. If you want to issue a CVE, that is your business and we will not try to stop you. But we do not participate in the CVE system. See https://www.sqlite.org/cves.html for additional information.