Summary
sqlite3_rekey_v2() computes the new-key length with nKey = strlen(pKey) whenever pKey is non-NULL and nKey < 0, without verifying that pKey is NUL-terminated. Passing a non-NUL-terminated key buffer with a negative nKey makes strlen() scan past the end of the heap buffer, producing an ASan heap-buffer-overflow (READ of size 6 past a 13-byte region). Same root cause as sqlite3_key_v2 (sqlite3.c:114458), here at sqlite3.c:114482.
- Affected versions: SQLCipher 4.17.0 (SQLite kernel 3.53.3), commit
810db22f575ee7cf94ea96a3e91622b5fcece3dc
- Severity: High (heap out-of-bounds read; DoS + potential heap info disclosure)
- CWE: CWE-125 (Out-of-bounds Read)
Detail Gifferent from #605
Affected code
/* src/sqlcipher.c:3736 / amalgamation sqlite3.c:114482 (sqlite3_rekey_v2) */
SQLITE_API int sqlite3_rekey_v2(sqlite3 *db, const char *zDb, const void *pKey, int nKey) {
sqlcipher_log(...);
if(pKey && nKey < 0) {
nKey = strlen(pKey); /* <-- unbounded strlen on possibly non-NUL-terminated pKey */
}
...
}
Identical pattern to sqlite3_key_v2 (sqlite3.c:114458). All four entry points sqlite3_key / sqlite3_key_v2 / sqlite3_rekey / sqlite3_rekey_v2 are affected.
Root cause
A key buffer that is not NUL-terminated (binary key material from file/network/hardware-token) combined with nKey = -1 drives strlen(pKey) past the heap allocation boundary, returning a bogus length that is then used by sqlcipher_cipher_ctx_set_pass() in a memcpy(ctx->pass, zKey, L) — a second OOB read of the rekey path.
POC (tested on the unmodified source)
A 44-byte input (MD5 6622bc8768c32fe7cc1320da3a1a9118) triggers the sqlite3_rekey_v2 path. Recreate it byte-for-byte:
printf '%s' '0500ffffff84796b65790a505241474d41206369706865725f2d656d6f72795f73656375726974793d4f4e3b' | xxd -r -p > poc2.bin
ASAN_OPTIONS=detect_leaks=0:abort_on_error=1 ./sqlcipher_key_fuzzer poc2.bin
Trigger result
==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x7b95cf8e005d
READ of size 6 at 0x7b95cf8e005d thread T0
#0 ... in strlen sanitizer_common_interceptors.inc:425:5
#1 ... in sqlite3_rekey_v2 /src/sqlcipher/sqlite3.c:114482:12
#2 ... in LLVMFuzzerTestOneInput /work/harness.c:164:5
0x7b95cf8e005d is located 0 bytes after 13-byte region [0x7b95cf8e0050,0x7b95cf8e005d)
SUMMARY: AddressSanitizer: heap-buffer-overflow /src/sqlcipher/sqlite3.c:114482:12 in sqlite3_rekey_v2
- Replay exit code:
134 (SIGABRT), deterministic
- Stability: reproduced on 2 independent replays
Suggested fix
Same as for sqlite3_key_v2: do not call unbounded strlen() on pKey when nKey < 0; reject or use a bounded-length check, and validate nKey against the source-buffer size before the memcpy in sqlcipher_cipher_ctx_set_pass.
Summary
sqlite3_rekey_v2()computes the new-key length withnKey = strlen(pKey)wheneverpKeyis non-NULL andnKey < 0, without verifying thatpKeyis NUL-terminated. Passing a non-NUL-terminated key buffer with a negativenKeymakesstrlen()scan past the end of the heap buffer, producing an ASan heap-buffer-overflow (READ of size 6 past a 13-byte region). Same root cause assqlite3_key_v2(sqlite3.c:114458), here at sqlite3.c:114482.810db22f575ee7cf94ea96a3e91622b5fcece3dcDetail Gifferent from #605
Affected code
Identical pattern to
sqlite3_key_v2(sqlite3.c:114458). All four entry pointssqlite3_key / sqlite3_key_v2 / sqlite3_rekey / sqlite3_rekey_v2are affected.Root cause
A key buffer that is not NUL-terminated (binary key material from file/network/hardware-token) combined with
nKey = -1drivesstrlen(pKey)past the heap allocation boundary, returning a bogus length that is then used bysqlcipher_cipher_ctx_set_pass()in amemcpy(ctx->pass, zKey, L)— a second OOB read of the rekey path.POC (tested on the unmodified source)
A 44-byte input (MD5
6622bc8768c32fe7cc1320da3a1a9118) triggers thesqlite3_rekey_v2path. Recreate it byte-for-byte:Trigger result
134(SIGABRT), deterministicSuggested fix
Same as for
sqlite3_key_v2: do not call unboundedstrlen()onpKeywhennKey < 0; reject or use a bounded-length check, and validatenKeyagainst the source-buffer size before thememcpyinsqlcipher_cipher_ctx_set_pass.