
Advisory e reproducer AddressSanitizer per un heap-buffer-overflow in SQLite SQLAR innescato da un valore SZ appositamente predisposto che causa un'allocazione troncata e una scrittura out-of-bounds in zlib.
CVE-2026-39113 è un overflow del buffer heap nell'estensione SQLAR opzionale di SQLite. In un'applicazione che ha caricato l'estensione, un attaccante in grado di invocare sqlar_uncompress() con un blob compresso e una dimensione controllati può indurre zlib a scrivere oltre un'allocazione heap su un sistema LP64. Si tratta di una violazione dei limiti di sicurezza della memoria all'interno del processo host; non è un problema di parsing dei file di database SQLite, un bypass dell'autenticazione o una falla raggiungibile in ogni installazione SQLite predefinita.
Il comportamento vulnerabile è stato introdotto il 2026-03-11 dal commit Git 169f68e (check-in Fossil 8bdc0d485e3ad0c7...) e corretto il 2026-04-01 dal commit Git 34e139d (check-in Fossil 6194f3b5314ef98b...). Il perimetro interessato comprende gli snapshot del codice sorgente e le build personalizzate da 169f68e fino al genitore di 34e139d. Nessuna release ufficiale di SQLite è stata verificata vulnerabile: SQLite 3.52.0 precede l'introduzione, e SQLite 3.53.0 contiene sia la modifica che ha introdotto il problema sia la correzione. SQLite 3.53.0 è quindi la prima release ufficiale contenente il codice corretto, non una release interessata.
Ho esaminato la revisione vulnerabile esatta, le modifiche introduttiva e correttiva e gli snapshot delle release 3.52.0 e 3.53.0. Ho inoltre ispezionato l'output preservato di un'esecuzione autorizzata in un ambiente WSL2 Ubuntu 24.04 monouso. AddressSanitizer ha rilevato un heap-buffer-overflow seguito dalla terminazione del processo, accertando la corruzione nativa dell'heap e il denial of service. L'esecuzione di codice non è stata dimostrata.
SQLAR è un formato di archivio di SQLite. L'estensione opzionale in ext/misc/sqlar.c registra sqlar_compress() e sqlar_uncompress() come funzioni SQL. Non fa parte di ogni applicazione che utilizza SQLite; il percorso vulnerabile richiede che l'estensione sia presente e caricata.
Per questo report, Mallory controlla i parametri blob e SZ forniti a:
SELECT sqlar_uncompress(?1, ?2);
L'ambiente testato aveva un int a 32 bit e sqlite3_int64 e zlib uLongf a 64 bit. La funzione dovrebbe allocare almeno tanta memoria quanta zlib è autorizzato a scrivere. Invece, il sorgente vulnerabile converte la dimensione a 64 bit nel tipo di parametro a 32 bit di sqlite3_malloc() mantenendo il valore completo per uncompress().
Lo snapshot del sorgente vulnerabile stampava Configuring SQLite version 3.53.0 durante la configurazione. Questa stringa di versione di sviluppo non deve essere confusa con la release ufficiale SQLite 3.53.0 datata 2026-04-09, il cui sorgente contiene la correzione.
Alla revisione valutata, sqlarUncompressFunc() in ext/misc/sqlar.c legge la dimensione controllata dall'attaccante come intero a 64 bit:
sqlite3_int64 sz;
sz = sqlite3_value_int64(argv[1]);
Se sz è positivo e diverso dalla lunghezza del blob di input, lo stesso valore viene usato in due modi incompatibili:
uLongf szf = sz;
const Bytef *pData = sqlite3_value_blob(argv[0]);
Bytef *pOut = sqlite3_malloc(sz);
if( pOut==0 ){
sqlite3_result_error_nomem(context);
}else if( Z_OK!=uncompress(pOut, &szf, pData, nData) ){
sqlite3_result_error(context, "error in uncompress()", -1);
}
A questa revisione, SQLite dichiara sqlite3_malloc(int). Nella build LP64 testata, il valore PoC 4294967328 (0x100000020) è diventato 32 quando passato a questa API, mentre szf manteneva il valore completo a 64 bit. SQLite quindi ha effettuato una piccola allocazione, ma a zlib è stato comunicato che il buffer di output poteva contenere più di 4 GiB. La decompressione di un blob di 42 byte che rappresenta 4096 byte di dati ha quindi superato il limite dell'allocazione.
La discrepanza è entrata nel progetto quando la modifica del 2026-03-11 ha sostituito sqlite3_value_int() con sqlite3_value_int64() senza modificare l'API di allocazione. L'analisi del codice sorgente di SQLite 3.52.0 mostra la precedente lettura a 32 bit, quindi la discrepanza tra valore a larghezza piena e allocazione ridotta non era presente lì. La correzione del 2026-04-01 ha modificato l'allocazione in sqlite3_malloc64(sz). L'analisi del codice sorgente del tag ufficiale 3.53.0 conferma quella chiamata corretta.
La primitiva dimostrata è una scrittura heap fuori dai limiti nel processo che ospita SQLite. L'esecuzione preservata mostra AddressSanitizer che rileva la prima scrittura non valida di un byte immediatamente dopo una regione heap di 40 byte allocata tramite sqlite3_malloc(), seguita da un abort. Questo supporta direttamente il crash del processo e il denial of service.
Lo sfruttamento richiede tutte le seguenti condizioni:
sqlar_uncompress() con un blob e un valore SZ controllati;int è a 32 bit mentre sqlite3_int64 e zlib uLongf sono a 64 bit; eIl PoC controlla i byte decompressi, il che è rilevante per la gravità della corruzione nativa dell'heap. Tuttavia, trasformare questa primitiva in esecuzione di codice dipenderebbe dal layout dell'allocatore, dallo stato circostante del processo, dalle mitigazioni e da un'opportuna via a livello applicativo. Nessuna catena di questo tipo è stata testata o dimostrata, pertanto questo report non rivendica l'esecuzione di codice.
L'esecuzione preservata non includeva un controllo negativo a runtime rispetto alla revisione corretta. Due controlli a livello di codice sorgente restringono la spiegazione: SQLite 3.52.0 legge la dimensione con l'API a 32 bit, e il sorgente ufficiale 3.53.0 alloca con sqlite3_malloc64(). Questi controlli supportano l'introduzione e la correzione identificate, ma non sono presentati come test eseguiti contro la versione corretta. La diffusione delle applicazioni che caricano questa estensione opzionale è sconosciuta.
Il repository include:
poc/verify_sqlar_poc.c, che crea un payload di 4096 byte, lo comprime, carica sqlar.so e imposta SZ = 4294967328;poc/reproduce.sh, che clona revisioni fissate di SQLite e zlib, le compila con AddressSanitizer, compila l'estensione e l'harness ed esegue il trigger; eevidence/asan-summary.txt, un sommario con percorsi normalizzati dell'esecuzione autorizzata osservata.Esegui il reproducer solo in un ambiente Linux o WSL monouso. Innesca intenzionalmente la corruzione della memoria e un abort di AddressSanitizer. Lo script richiede git, make, un compilatore C, strumenti di build standard e accesso alla rete:
chmod +x poc/reproduce.sh
./poc/reproduce.sh
Il reproducer è stato eseguito di nuovo il 2026-08-21 su Ubuntu 24.04 in WSL2 e ha prodotto lo stesso riscontro di AddressSanitizer. Il suo output rilevante era:
env: sizeof(int)=4 sizeof(sqlite3_int64)=8 sizeof(uLongf)=8
payload: plain=4096 compressed=42 evil_sz=4294967328 low32=32
ERROR: AddressSanitizer: heap-buffer-overflow
WRITE of size 1
#0 inflate_fast zlib/inffast.c:252
#4 uncompress zlib/uncompr.c:100
#5 sqlarUncompressFunc sqlite/ext/misc/sqlar.c:97
The write occurred immediately after a 40-byte heap region.
SUMMARY: AddressSanitizer: heap-buffer-overflow in inflate_fast
ABORTING
PoC exit status: 1
Questo output mostra le larghezze di tipo incompatibili e la dimensione costruita, la scrittura di zlib, la chiamata da sqlarUncompressFunc() e la violazione del limite di allocazione. Lo script di riproduzione elimina la sua directory di build temporanea all'uscita a meno che non sia impostato KEEP_BUILD=1.
Upstream ha corretto l'allocazione vulnerabile nel commit 34e139d:
- Bytef *pOut = sqlite3_malloc(sz);
+ Bytef *pOut = sqlite3_malloc64(sz);
Questo mantiene la larghezza dell'allocazione coerente con il valore positivo a 64 bit di sz conservato in uLongf szf e passato a zlib. Il codice corretto è presente nella SQLite 3.53.0 ufficiale. Gli utenti di snapshot del codice sorgente o build personalizzate contenenti l'intervallo vulnerabile dovrebbero aggiornare a 34e139d o successivo. Le applicazioni che non richiedono SQLAR dovrebbero evitare di caricare l'estensione, e quelle che la utilizzano dovrebbero impedire a chiamanti non fidati di fornire argomenti arbitrari a sqlar_uncompress().
Un test di regressione mirato dovrebbe esercitare la funzione SQL con un blob compresso valido e un valore SZ superiore a INT_MAX i cui 32 bit bassi siano piccoli. Dovrebbe verificare che la build corretta non esegua un'allocazione troncata e dovrebbe conservare come controlli i casi ordinari di decompressione riuscita e di errore per input non valido.
CVE-2026-39113 interessa solo gli snapshot del codice sorgente di SQLite e le build personalizzate da 169f68e fino al genitore di 34e139d quando l'estensione SQLAR opzionale è caricata e chiamate controllate dall'attaccante raggiungono sqlar_uncompress() su una build LP64. Una dimensione a 64 bit è stata ristretta da sqlite3_malloc(int) mentre zlib manteneva il valore completo, producendo un heap-buffer-overflow confermato da AddressSanitizer e un abort del processo. Nessuna release ufficiale di SQLite è stata verificata vulnerabile e l'esecuzione di codice non è stata dimostrata. La modifica upstream a sqlite3_malloc64(sz) è presente nella SQLite 3.53.0 ufficiale e rimuove la discrepanza di larghezza dell'allocazione.