SQLite User Forum

The setupLookaside function contains an integer overflow bug
Login

The setupLookaside function contains an integer overflow bug

(1) By violin (yuelinwang) on 2025-02-17 04:49:31 [source]

Abstract

​ I discovered an integer overflow bug in the sqlite3.c file at line 182342 using code auditing techniques. This line is in the setupLookaside function, with the following code: nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;. The result of sz*nBig can potentially cause an integer overflow.

Function Description

​ The function's purpose is to divide the incoming lookaside buffer block into large and small memory chunks, with specific memory size allocation based on the provided sz and cnt parameters. Here, sz is the size of the lookaside buffer block defined by the user, and cnt is the number of such blocks. The user defines sz and cnt when calling the SQL function sqlite3_db_config(db, SQLITE_DBCONFIG_LOOKASIDE, NULL , sz , cnt, NULL);. After sz and cnt are passed to the sqlite3 program, the program proceeds to execute the code near line 182342:

#define LOOKASIDE_SMALL 128

...
sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;
...
if( sz>=LOOKASIDE_SMALL*3 ){
    nBig = szAlloc/(3*LOOKASIDE_SMALL+sz);
    nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL;
}
...

​ This portion of the code calculates the number of large memory blocks nBig first using szAlloc/(3*LOOKASIDE_SMALL+sz), where szAlloc is the total memory to be allocated, i.e., sz*cnt, LOOKASIDE_SMALL is a defined constant of 128, and sz is the passed value. After calculating the large memory blocks, the remaining memory is divided into small chunks of size LOOKASIDE_SMALL, determining the number of small blocks. The calculation is done by subtracting the allocated large memory size (sz * nBig) from the total memory (szAlloc) and then dividing by LOOKASIDE_SMALL: (szAlloc - sz*nBig)/LOOKASIDE_SMALL. This gives the number of small blocks to allocate.

Integer Overflow Bug

​ When calculating sz*nBig, the result was not cast to sqlite3_int64, leading to an integer overflow vulnerability. In normal cases, with sz = 1200 and cnt = 100, the value of szAlloc would be sz*cnt = 1200*100 = 120,000. Since sz = 1200 is greater than LOOKASIDE_SMALL*3 = 128*3 = 384, the program calculates nBig as 120000/(3*128 + 1200) = 75.75, which is rounded down to 75. Next, nSm is calculated as (szAlloc - sz*nBig)/LOOKASIDE_SMALL = (120000 - 1200*75)/128 = 234.

​ However, when sz = 1200 and cnt = 2500000, an integer overflow occurs. First, calculating szAlloc results in sz*cnt = 1200*2500000 = 3000000000. Similarly, since sz = 1200 is still greater than LOOKASIDE_SMALL*3, nBig is computed as 3000000000/(3*128 + 1200), which gives nBig = 1893939. Next, the calculation for nSm theoretically should be (3000000000 - 1200*1893939)/128 = 5681821. However, due to the overflow when calculating 1200*1893939, the actual result in gdb debugging is 39236253. Here is the gdb output:

...
(gdb) next
182340    if( sz>=LOOKASIDE_SMALL*3 ){
(gdb) step
182341      nBig = szAlloc/(3*LOOKASIDE_SMALL+sz);
(gdb) step
182345      nSm = (szAlloc - sz*nBig)/LOOKASIDE_SMALL; //LOOKASIDE_SMALL is 128
(gdb) step
182354    db->lookaside.pStart = pStart;
(gdb) print nBig
$1 = 1893939
(gdb) print nSm
$2 = 39236253
...

Potential Impact and Suggested Fix

​ Your code accounted for the possibility that the total allocated space might exceed the size of an int, using (sqlite3_int64) to cast the result of sz*cnt to sqlite3_int64: sqlite3_int64 szAlloc = sz*(sqlite3_int64)cnt;. However, when allocating the memory blocks, this casting was not applied, leading to potential issues where the lookaside buffer might fail to divide correctly, and the allocated memory may exceed the intended size. This could cause crashes or even allow attackers to exploit the bug for arbitrary memory writes, potentially leading to remote code execution vulnerabilities.

​ I recommend adding the same type casting to sz*nBig during the calculation of nSm, as follows:

nSm = (szAlloc - sz*(sqlite3_int64)nBig)/LOOKASIDE_SMALL; 

​ This will resolve the overflow bug.