From 4856e930c59435c62da1e002f875acacbc07e31e Mon Sep 17 00:00:00 2001 From: utelle Date: Sun, 9 Jun 2024 22:27:41 +0200 Subject: [PATCH] Improve VFS error reporting, fix issue #167 If decrypting a page failed due to a wrong passphrase, the error was detected at VFS level, but not communicated properly to higher level SQLite functions. In debug mode that could lead to raising an assertion, although the error was detected and handled by SQLite later on. --- src/cipher_common.c | 27 +++++++++++++++++++++++---- src/cipher_common.h | 4 ++++ src/codecext.c | 16 +++++++++++++--- src/sqlite3mc_vfs.c | 6 ++++++ 4 files changed, 46 insertions(+), 7 deletions(-) diff --git a/src/cipher_common.c b/src/cipher_common.c index bf7ae17..43ff369 100644 --- a/src/cipher_common.c +++ b/src/cipher_common.c @@ -207,6 +207,7 @@ sqlite3mcCodecInit(Codec* codec) memset(codec->m_page, 0, sizeof(codec->m_page)); codec->m_pageSize = 0; codec->m_reserved = 0; + codec->m_lastError = SQLITE_OK; codec->m_hasKeySalt = 0; memset(codec->m_keySalt, 0, sizeof(codec->m_keySalt)); } @@ -428,25 +429,40 @@ sqlite3mcGetPageSizeWriteCipher(Codec* codec) SQLITE_PRIVATE int sqlite3mcGetReservedReadCipher(Codec* codec) { - int reserved = (codec->m_hasReadCipher && codec->m_readCipher != NULL) ? globalCodecDescriptorTable[codec->m_readCipherType-1].m_getReserved(codec->m_readCipher) : 0; + int reserved = (codec->m_hasReadCipher && codec->m_readCipher != NULL) ? globalCodecDescriptorTable[codec->m_readCipherType-1].m_getReserved(codec->m_readCipher) : -1; return reserved; } SQLITE_PRIVATE int sqlite3mcGetReservedWriteCipher(Codec* codec) { - int reserved = (codec->m_hasWriteCipher && codec->m_writeCipher != NULL) ? globalCodecDescriptorTable[codec->m_writeCipherType-1].m_getReserved(codec->m_writeCipher) : 0; + int reserved = (codec->m_hasWriteCipher && codec->m_writeCipher != NULL) ? globalCodecDescriptorTable[codec->m_writeCipherType-1].m_getReserved(codec->m_writeCipher) : -1; return reserved; } SQLITE_PRIVATE int sqlite3mcReservedEqual(Codec* codec) { - int readReserved = (codec->m_hasReadCipher && codec->m_readCipher != NULL) ? globalCodecDescriptorTable[codec->m_readCipherType-1].m_getReserved(codec->m_readCipher) : 0; - int writeReserved = (codec->m_hasWriteCipher && codec->m_writeCipher != NULL) ? globalCodecDescriptorTable[codec->m_writeCipherType-1].m_getReserved(codec->m_writeCipher) : 0; + int readReserved = (codec->m_hasReadCipher && codec->m_readCipher != NULL) ? globalCodecDescriptorTable[codec->m_readCipherType-1].m_getReserved(codec->m_readCipher) : -1; + int writeReserved = (codec->m_hasWriteCipher && codec->m_writeCipher != NULL) ? globalCodecDescriptorTable[codec->m_writeCipherType-1].m_getReserved(codec->m_writeCipher) : -1; return (readReserved == writeReserved); } +SQLITE_PRIVATE void +sqlite3mcSetCodecLastError(Codec* codec, int error) +{ + if (codec) + { + codec->m_lastError = error; + } +} + +SQLITE_PRIVATE int +sqlite3mcGetCodecLastError(Codec* codec) +{ + return codec ? codec->m_lastError : SQLITE_OK; +} + SQLITE_PRIVATE unsigned char* sqlite3mcGetSaltWriteCipher(Codec* codec) { @@ -500,6 +516,9 @@ sqlite3mcCodecCopy(Codec* codec, Codec* other) codec->m_bt = other->m_bt; #endif codec->m_btShared = other->m_btShared; + + codec->m_lastError = SQLITE_OK; + return rc; } diff --git a/src/cipher_common.h b/src/cipher_common.h index a1bae21..15bee4c 100644 --- a/src/cipher_common.h +++ b/src/cipher_common.h @@ -87,6 +87,7 @@ typedef struct _Codec unsigned char m_page[SQLITE_MAX_PAGE_SIZE + 24]; int m_pageSize; int m_reserved; + int m_lastError; int m_hasKeySalt; unsigned char m_keySalt[KEYSALT_LENGTH]; } Codec; @@ -158,6 +159,9 @@ SQLITE_PRIVATE int sqlite3mcGetReservedWriteCipher(Codec* codec); SQLITE_PRIVATE int sqlite3mcReservedEqual(Codec* codec); +SQLITE_PRIVATE void sqlite3mcSetCodecLastError(Codec* codec, int error); +SQLITE_PRIVATE int sqlite3mcGetCodecLastError(Codec* codec); + SQLITE_PRIVATE unsigned char* sqlite3mcGetSaltWriteCipher(Codec* codec); SQLITE_PRIVATE int sqlite3mcCodecCopy(Codec* codec, Codec* other); diff --git a/src/codecext.c b/src/codecext.c index 3cdf196..b29b96f 100644 --- a/src/codecext.c +++ b/src/codecext.c @@ -89,12 +89,15 @@ mcReportCodecError(BtShared* pBt, int error) { pBt->pPager->eState = PAGER_ERROR; } - setGetterMethod(pBt->pPager); if (error == SQLITE_OK) { /* Clear cache to force reread of database after a new passphrase has been set */ sqlite3PagerClearCache(pBt->pPager); + /* unlock required? + pager_unlock(pBt->pPager); + */ } + setGetterMethod(pBt->pPager); } /* @@ -113,6 +116,7 @@ sqlite3mcCodec(void* pCodecArg, void* data, Pgno nPageNum, int nMode) codec = (Codec*) pCodecArg; if (!sqlite3mcIsEncrypted(codec)) { + sqlite3mcSetCodecLastError(codec, rc); return data; } @@ -126,7 +130,11 @@ sqlite3mcCodec(void* pCodecArg, void* data, Pgno nPageNum, int nMode) if (sqlite3mcHasReadCipher(codec)) { rc = sqlite3mcDecrypt(codec, nPageNum, (unsigned char*) data, pageSize); - if (rc != SQLITE_OK) mcReportCodecError(sqlite3mcGetBtShared(codec), rc); + if (rc != SQLITE_OK) + { + mcReportCodecError(sqlite3mcGetBtShared(codec), rc); + memset(data, 0, pageSize); + } } break; @@ -160,6 +168,7 @@ sqlite3mcCodec(void* pCodecArg, void* data, Pgno nPageNum, int nMode) } break; } + sqlite3mcSetCodecLastError(codec, rc); return data; } @@ -184,11 +193,12 @@ mcAdjustBtree(Btree* pBt, int nPageSize, int nReserved, int isLegacy) /* Adjust the page size and the reserved area */ if (pager->pageSize != pagesize || pager->nReserve != nReserved) { + int reserved = (nReserved >= 0) ? nReserved : 0; if (isLegacy != 0) { pBt->pBt->btsFlags &= ~BTS_PAGESIZE_FIXED; } - rc = sqlite3BtreeSetPageSize(pBt, pagesize, nReserved, 0); + rc = sqlite3BtreeSetPageSize(pBt, pagesize, reserved, 0); } return rc; } diff --git a/src/sqlite3mc_vfs.c b/src/sqlite3mc_vfs.c index 7ba6277..4d28c20 100644 --- a/src/sqlite3mc_vfs.c +++ b/src/sqlite3mc_vfs.c @@ -656,6 +656,7 @@ static int mcReadMainDb(sqlite3_file* pFile, void* buffer, int count, sqlite3_in */ pageNo = prevOffset / pageSize + 1; bufferDecrypted = sqlite3mcCodec(mcFile->codec, pageBuffer, pageNo, 3); + rc = sqlite3mcGetCodecLastError(mcFile->codec); /* ** Return the requested content @@ -684,6 +685,7 @@ static int mcReadMainDb(sqlite3_file* pFile, void* buffer, int count, sqlite3_in for (iPage = 0; iPage < nPages; ++iPage) { void* bufferDecrypted = sqlite3mcCodec(mcFile->codec, data, pageNo, 3); + rc = sqlite3mcGetCodecLastError(mcFile->codec); data += pageSize; offset += pageSize; ++pageNo; @@ -712,6 +714,7 @@ static int mcReadMainJournal(sqlite3_file* pFile, const void* buffer, int count, ** Decrypt the page buffer, but only if the page number is valid */ void* bufferDecrypted = sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 3); + rc = sqlite3mcGetCodecLastError(codec); mcFile->pageNo = 0; } else if (count == 4) @@ -745,6 +748,7 @@ static int mcReadSubJournal(sqlite3_file* pFile, const void* buffer, int count, ** Decrypt the page buffer, but only if the page number is valid */ void* bufferDecrypted = sqlite3mcCodec(codec, (char*) buffer, mcFile->pageNo, 3); + rc = sqlite3mcGetCodecLastError(codec); } else if (count == 4) { @@ -793,6 +797,7 @@ static int mcReadWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3 if (pageNo != 0) { void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer, pageNo, 3); + rc = sqlite3mcGetCodecLastError(codec); } } else if (codec->m_walLegacy != 0 && count == pageSize + walFrameHeaderSize) @@ -805,6 +810,7 @@ static int mcReadWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3 if (pageNo != 0) { void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 3); + rc = sqlite3mcGetCodecLastError(codec); } } }