Skip to content

Commit

Permalink
Introduce WAL compatibility configuration parameter
Browse files Browse the repository at this point in the history
Unfortunately WAL journal mode was in fact broken in all versions <= 1.2.5. To allow to recover a hot WAL journal left behind by an application using a version <= 1.2.5, the global configuration parameter mc_legacy_wal has been introduced. It should be noted that parallel use of the new version and a version <= 1.2.5 will most likely not work. For recovery of a hot WAL journal use mc_legacy_wal=1.
  • Loading branch information
utelle committed May 12, 2021
1 parent 43bd436 commit b8e0cd7
Show file tree
Hide file tree
Showing 5 changed files with 54 additions and 7 deletions.
5 changes: 5 additions & 0 deletions src/cipher_common.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ static CipherParams commonParams[] =
{
{ "cipher", CODEC_TYPE, CODEC_TYPE, 1, CODEC_TYPE_MAX },
{ "hmac_check", 1, 1, 0, 1 },
{ "mc_legacy_wal", 0, 0, 0, 1 },
CIPHER_PARAMS_SENTINEL
};

Expand Down Expand Up @@ -205,6 +206,7 @@ sqlite3mcCodecInit(Codec* codec)
{
codec->m_isEncrypted = 0;
codec->m_hmacCheck = 1;
codec->m_walLegacy = 0;

codec->m_hasReadCipher = 0;
codec->m_readCipherType = CODEC_TYPE_UNKNOWN;
Expand Down Expand Up @@ -264,6 +266,7 @@ sqlite3mcCodecSetup(Codec* codec, int cipherType, char* userPassword, int passwo
CipherParams* globalParams = sqlite3mcGetCipherParams(codec->m_db, 0);
codec->m_isEncrypted = 1;
codec->m_hmacCheck = sqlite3mcGetCipherParameter(globalParams, "hmac_check");
codec->m_walLegacy = sqlite3mcGetCipherParameter(globalParams, "mc_legacy_wal");
codec->m_hasReadCipher = 1;
codec->m_hasWriteCipher = 1;
codec->m_readCipherType = cipherType;
Expand Down Expand Up @@ -292,6 +295,7 @@ sqlite3mcSetupWriteCipher(Codec* codec, int cipherType, char* userPassword, int
}
codec->m_isEncrypted = 1;
codec->m_hmacCheck = sqlite3mcGetCipherParameter(globalParams, "hmac_check");
codec->m_walLegacy = sqlite3mcGetCipherParameter(globalParams, "mc_legacy_wal");
codec->m_hasWriteCipher = 1;
codec->m_writeCipherType = cipherType;
codec->m_writeCipher = codecDescriptorTable[codec->m_writeCipherType-1]->m_allocateCipher(codec->m_db);
Expand Down Expand Up @@ -475,6 +479,7 @@ sqlite3mcCodecCopy(Codec* codec, Codec* other)
int rc = SQLITE_OK;
codec->m_isEncrypted = other->m_isEncrypted;
codec->m_hmacCheck = other->m_hmacCheck;
codec->m_walLegacy = other->m_walLegacy;
codec->m_hasReadCipher = other->m_hasReadCipher;
codec->m_hasWriteCipher = other->m_hasWriteCipher;
codec->m_readCipherType = other->m_readCipherType;
Expand Down
1 change: 1 addition & 0 deletions src/cipher_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ typedef struct _Codec
{
int m_isEncrypted;
int m_hmacCheck;
int m_walLegacy;
/* Read cipher */
int m_hasReadCipher;
int m_readCipherType;
Expand Down
9 changes: 9 additions & 0 deletions src/cipher_config.c
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault)
int skipLegacy = 0;
/* Set global parameters (cipher and hmac_check) */
int hmacCheck = sqlite3_uri_boolean(dbFileName, "hmac_check", 1);
int walLegacy = sqlite3_uri_boolean(dbFileName, "mc_legacy_wal", 0);
if (configDefault)
{
sqlite3mc_config(db, "default:cipher", globalCodecParameterTable[j].m_id);
Expand All @@ -668,6 +669,7 @@ sqlite3mcConfigureFromUri(sqlite3* db, const char *zDbName, int configDefault)
{
sqlite3mc_config(db, "hmac_check", hmacCheck);
}
sqlite3mc_config(db, "mc_legacy_wal", walLegacy);

#if HAVE_CIPHER_SQLCIPHER
/* Special handling for SQLCipher */
Expand Down Expand Up @@ -794,6 +796,13 @@ sqlite3mcFileControlPragma(sqlite3* db, const char* zDbName, int op, void* pArg)
((char**)pArg)[0] = sqlite3_mprintf("%d", value);
rc = SQLITE_OK;
}
else if (sqlite3StrICmp(pragmaName, "mc_legacy_wal") == 0)
{
int walLegacy = (pragmaValue != NULL) ? sqlite3GetBoolean(pragmaValue, 0) : -1;
int value = sqlite3mc_config(db, "mc_legacy_wal", walLegacy);
((char**)pArg)[0] = sqlite3_mprintf("%d", value);
rc = SQLITE_OK;
}
else if (sqlite3StrICmp(pragmaName, "key") == 0)
{
rc = sqlite3_key_v2(db, zDbName, pragmaValue, -1);
Expand Down
4 changes: 2 additions & 2 deletions src/sqlite3mc_version.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

#define SQLITE3MC_VERSION_MAJOR 1
#define SQLITE3MC_VERSION_MINOR 3
#define SQLITE3MC_VERSION_RELEASE 1
#define SQLITE3MC_VERSION_RELEASE 2
#define SQLITE3MC_VERSION_SUBRELEASE 0
#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.3.1"
#define SQLITE3MC_VERSION_STRING "SQLite3 Multiple Ciphers 1.3.2"

#endif /* SQLITE3MC_VERSION_H_ */
42 changes: 37 additions & 5 deletions src/sqlite3mc_vfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -281,7 +281,7 @@ SQLITE_PRIVATE void* sqlite3mcPagerCodec(PgHdr* pPg)
{
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = mcFile->codec;
if (codec != 0 && sqlite3mcIsEncrypted(codec))
if (codec != 0 && codec->m_walLegacy == 0 && sqlite3mcIsEncrypted(codec))
{
aData = sqlite3mcCodec(codec, pPg->pData, pPg->pgno, 6);
}
Expand Down Expand Up @@ -676,7 +676,19 @@ static int mcReadWal(sqlite3_file* pFile, const void* buffer, int count, sqlite3
*/
if (pageNo != 0)
{
void* bufferDecrypted = sqlite3mcCodec(codec, (char*) buffer, pageNo, 3);
void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer, pageNo, 3);
}
}
else if (codec->m_walLegacy != 0 && count == pageSize + walFrameHeaderSize)
{
int pageNo = sqlite3Get4byte(buffer);

/*
** Decrypt page content if page number is valid
*/
if (pageNo != 0)
{
void* bufferDecrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 3);
}
}
}
Expand Down Expand Up @@ -905,7 +917,7 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite
sqlite3mc_file* mcFile = (sqlite3mc_file*) pFile;
Codec* codec = (mcFile->pMainDb) ? mcFile->pMainDb->codec : 0;

if (codec != 0 && sqlite3mcIsEncrypted(codec))
if (codec != 0 && codec->m_walLegacy != 0 && sqlite3mcIsEncrypted(codec))
{
const int pageSize = sqlite3mcGetPageSize(codec);

Expand All @@ -921,7 +933,7 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite
** immediately before writing the corresponding page content.
** Page numbers and checksums are written to file independently.
** Therefore it is necessary to explicitly read the page number
** on writing to file the contetn of a page.
** on writing to file the content of a page.
*/
rc = REALFILE(pFile)->pMethods->xRead(REALFILE(pFile), ac, 4, offset - walFrameHeaderSize);
if (rc == SQLITE_OK)
Expand All @@ -945,6 +957,26 @@ static int mcWriteWal(sqlite3_file* pFile, const void* buffer, int count, sqlite
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
}
else if (count == pageSize + walFrameHeaderSize)
{
int pageNo = sqlite3Get4byte(buffer);
if (pageNo != 0)
{
/*
** Encrypt the page buffer, but only if the page number is valid
*/
void* bufferEncrypted = sqlite3mcCodec(codec, (char*)buffer+walFrameHeaderSize, pageNo, 7);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, walFrameHeaderSize, offset);
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), bufferEncrypted, pageSize, offset+walFrameHeaderSize);
}
else
{
/*
** Write buffer without encryption if the page number could not be determined
*/
rc = REALFILE(pFile)->pMethods->xWrite(REALFILE(pFile), buffer, count, offset);
}
}
else
{
/*
Expand Down Expand Up @@ -1014,7 +1046,7 @@ static int mcIoWrite(sqlite3_file* pFile, const void* buffer, int count, sqlite3
*/
}
#endif
#if 0
#if 1
/*
** The page content is encrypted in memory in the WAL journal handler.
** This provides for compatibility with legacy applications using the
Expand Down

0 comments on commit b8e0cd7

Please sign in to comment.