add PRAGMA cipher_memory_security to control settings; lock/unlock memory in manager

This commit is contained in:
Stephen Lombardo 2018-09-11 12:56:45 -04:00
parent 37270bd069
commit c40ffaa964
5 changed files with 131 additions and 72 deletions

View File

@ -425,6 +425,15 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
codec_vdbe_return_static_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
}
}
}else
if( sqlite3StrICmp(zLeft,"cipher_memory_security")==0 ){
if( zRight ) {
sqlcipher_set_mem_security(sqlite3GetBoolean(zRight,1));
} else {
char *on = sqlite3_mprintf("%d", sqlcipher_get_mem_security());
codec_vdbe_return_static_string(pParse, "cipher_memory_security", on);
sqlite3_free(on);
}
}else {
return 0;
}

View File

@ -291,6 +291,8 @@ int sqlcipher_get_default_kdf_algorithm();
int sqlcipher_codec_ctx_set_kdf_algorithm(codec_ctx *ctx, int algorithm);
int sqlcipher_codec_ctx_get_kdf_algorithm(codec_ctx *ctx);
void sqlcipher_set_mem_security(int);
int sqlcipher_get_mem_security();
#endif
#endif

View File

@ -44,14 +44,17 @@
#endif
#endif
static unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
static unsigned char hmac_salt_mask = HMAC_SALT_MASK;
static int default_kdf_iter = PBKDF2_ITER;
static int default_page_size = 4096;
static int default_plaintext_header_sz = 0;
static int default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
static int default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
static unsigned int sqlcipher_activate_count = 0;
static volatile unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
static volatile unsigned char hmac_salt_mask = HMAC_SALT_MASK;
static volatile int default_kdf_iter = PBKDF2_ITER;
static volatile int default_page_size = 4096;
static volatile int default_plaintext_header_sz = 0;
static volatile int default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
static volatile int default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
static volatile int mem_security_on = 1;
static volatile int mem_security_activated = 0;
static volatile unsigned int sqlcipher_activate_count = 0;
static volatile sqlite3_mem_methods default_mem_methods;
static sqlite3_mutex* sqlcipher_provider_mutex = NULL;
static sqlcipher_provider *default_provider = NULL;
@ -96,8 +99,6 @@ struct codec_ctx {
void *provider_ctx;
};
static sqlite3_mem_methods default_mem_methods;
static int sqlcipher_mem_init(void *pAppData) {
return default_mem_methods.xInit(pAppData);
}
@ -105,15 +106,26 @@ static void sqlcipher_mem_shutdown(void *pAppData) {
default_mem_methods.xShutdown(pAppData);
}
static void *sqlcipher_mem_malloc(int n) {
return default_mem_methods.xMalloc(n);
void *ptr = default_mem_methods.xMalloc(n);
if(mem_security_on) {
CODEC_TRACE("sqlcipher_mem_malloc: calling sqlcipher_mlock(%p,%d)\n", ptr, sz);
sqlcipher_mlock(ptr, n);
if(!mem_security_activated) mem_security_activated = 1;
}
return ptr;
}
static int sqlcipher_mem_size(void *p) {
return default_mem_methods.xSize(p);
}
static void sqlcipher_mem_free(void *p) {
int sz = sqlcipher_mem_size(p);
CODEC_TRACE("sqlcipher_mem_free: calling sqlcipher_memset(%p,0,%d)\n", p, sz);
sqlcipher_memset(p, 0, sz);
int sz;
if(mem_security_on) {
sz = sqlcipher_mem_size(p);
CODEC_TRACE("sqlcipher_mem_free: calling sqlcipher_memset(%p,0,%d) and sqlcipher_munlock(%p, %d) \n", p, sz, p, sz);
sqlcipher_memset(p, 0, sz);
sqlcipher_munlock(p, sz);
if(!mem_security_activated) mem_security_activated = 1;
}
default_mem_methods.xFree(p);
}
static void *sqlcipher_mem_realloc(void *p, int n) {
@ -288,6 +300,58 @@ int sqlcipher_memcmp(const void *v0, const void *v1, int len) {
return (result != 0);
}
void sqlcipher_mlock(void *ptr, int sz) {
#ifndef OMIT_MEMLOCK
int rc;
#if defined(__unix__) || defined(__APPLE__)
unsigned long pagesize = sysconf(_SC_PAGESIZE);
unsigned long offset = (unsigned long) ptr % pagesize;
if(ptr == NULL || sz == 0) return;
CODEC_TRACE("sqlcipher_mem_lock: calling mlock(%p,%lu); _SC_PAGESIZE=%lu\n", ptr - offset, sz + offset, pagesize);
rc = mlock(ptr - offset, sz + offset);
if(rc!=0) {
CODEC_TRACE("sqlcipher_mem_lock: mlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
}
#elif defined(_WIN32)
#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
CODEC_TRACE("sqlcipher_mem_lock: calling VirtualLock(%p,%d)\n", ptr, sz);
rc = VirtualLock(ptr, sz);
if(rc==0) {
CODEC_TRACE("sqlcipher_mem_lock: VirtualLock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
}
#endif
#endif
#endif
}
void sqlcipher_munlock(void *ptr, int sz) {
#ifndef OMIT_MEMLOCK
int rc;
#if defined(__unix__) || defined(__APPLE__)
unsigned long pagesize = sysconf(_SC_PAGESIZE);
unsigned long offset = (unsigned long) ptr % pagesize;
if(ptr == NULL || sz == 0) return;
CODEC_TRACE("sqlcipher_mem_unlock: calling munlock(%p,%lu)\n", ptr - offset, sz + offset);
rc = munlock(ptr - offset, sz + offset);
if(rc!=0) {
CODEC_TRACE("sqlcipher_mem_unlock: munlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
}
#elif defined(_WIN32)
#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
CODEC_TRACE("sqlcipher_mem_lock: calling VirtualUnlock(%p,%d)\n", ptr, sz);
rc = VirtualUnlock(ptr, sz);
if(!rc) {
CODEC_TRACE("sqlcipher_mem_unlock: VirtualUnlock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
}
#endif
#endif
#endif
}
/**
* Free and wipe memory. Uses SQLites internal sqlite3_free so that memory
* can be countend and memory leak detection works in the test suite.
@ -297,36 +361,10 @@ int sqlcipher_memcmp(const void *v0, const void *v1, int len) {
* memory segment so it can be paged
*/
void sqlcipher_free(void *ptr, int sz) {
if(ptr) {
if(sz > 0) {
#ifndef OMIT_MEMLOCK
int rc;
#if defined(__unix__) || defined(__APPLE__)
unsigned long pagesize = sysconf(_SC_PAGESIZE);
unsigned long offset = (unsigned long) ptr % pagesize;
#endif
#endif
CODEC_TRACE("sqlcipher_free: calling sqlcipher_memset(%p,0,%d)\n", ptr, sz);
sqlcipher_memset(ptr, 0, sz);
#ifndef OMIT_MEMLOCK
#if defined(__unix__) || defined(__APPLE__)
CODEC_TRACE("sqlcipher_free: calling munlock(%p,%lu)\n", ptr - offset, sz + offset);
rc = munlock(ptr - offset, sz + offset);
if(rc!=0) {
CODEC_TRACE("sqlcipher_free: munlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
}
#elif defined(_WIN32)
#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
rc = VirtualUnlock(ptr, sz);
if(!rc) {
CODEC_TRACE("sqlcipher_free: VirtualUnlock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
}
#endif
#endif
#endif
}
sqlite3_free(ptr);
}
CODEC_TRACE("sqlcipher_free: calling sqlcipher_memset(%p,0,%d)\n", ptr, sz);
sqlcipher_memset(ptr, 0, sz);
sqlcipher_munlock(ptr, sz);
sqlite3_free(ptr);
}
/**
@ -340,31 +378,10 @@ void* sqlcipher_malloc(int sz) {
ptr = sqlite3Malloc(sz);
CODEC_TRACE("sqlcipher_malloc: calling sqlcipher_memset(%p,0,%d)\n", ptr, sz);
sqlcipher_memset(ptr, 0, sz);
#ifndef OMIT_MEMLOCK
if(ptr) {
int rc;
#if defined(__unix__) || defined(__APPLE__)
unsigned long pagesize = sysconf(_SC_PAGESIZE);
unsigned long offset = (unsigned long) ptr % pagesize;
CODEC_TRACE("sqlcipher_malloc: calling mlock(%p,%lu); _SC_PAGESIZE=%lu\n", ptr - offset, sz + offset, pagesize);
rc = mlock(ptr - offset, sz + offset);
if(rc!=0) {
CODEC_TRACE("sqlcipher_malloc: mlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
}
#elif defined(_WIN32)
#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
rc = VirtualLock(ptr, sz);
if(rc==0) {
CODEC_TRACE("sqlcipher_malloc: VirtualLock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
}
#endif
#endif
}
#endif
sqlcipher_mlock(ptr, sz);
return ptr;
}
/**
* Initialize new cipher_ctx struct. This function will allocate memory
* for the cipher context and for the key
@ -800,6 +817,16 @@ int sqlcipher_get_default_pagesize() {
return default_page_size;
}
void sqlcipher_set_mem_security(int on) {
mem_security_on = on;
mem_security_activated = 0;
}
int sqlcipher_get_mem_security() {
return mem_security_on && mem_security_activated;
}
int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_file *fd, const void *zKey, int nKey) {
int rc;
codec_ctx *ctx;

View File

@ -75,15 +75,17 @@ typedef struct {
} sqlcipher_provider;
/* utility functions */
void sqlcipher_free(void *ptr, int sz);
void* sqlcipher_malloc(int sz);
void* sqlcipher_memset(void *v, unsigned char value, int len);
int sqlcipher_ismemset(const void *v, unsigned char value, int len);
int sqlcipher_memcmp(const void *v0, const void *v1, int len);
void sqlcipher_free(void *, int);
void* sqlcipher_malloc(int);
void sqlcipher_mlock(void *, int);
void sqlcipher_munlock(void *, int);
void* sqlcipher_memset(void *, unsigned char, int);
int sqlcipher_ismemset(const void *, unsigned char, int);
int sqlcipher_memcmp(const void *, const void *, int);
void sqlcipher_free(void *, int);
/* provider interfaces */
int sqlcipher_register_provider(sqlcipher_provider *p);
int sqlcipher_register_provider(sqlcipher_provider *);
sqlcipher_provider* sqlcipher_get_provider();
#endif

View File

@ -2790,5 +2790,24 @@ do_test verify-pragma-cipher-default-kdf-algorithm {
db close
file delete -force test.db
# verify memory security behavior
# initially should report ON
# then disable, check that it is off
# turn it back on, then check.
do_test verify-memory-security {
sqlite_orig db test.db
execsql {
PRAGMA cipher_memory_security;
PRAGMA cipher_memory_security = OFF;
PRAGMA cipher_memory_security;
PRAGMA cipher_memory_security = ON;
PRAGMA cipher_memory_security;
}
} {1 0 1}
db close
file delete -force test.db
sqlite3_test_control_pending_byte $old_pending_byte
finish_test