Skip to content

Commit c40ffaa

Browse files
committed
add PRAGMA cipher_memory_security to control settings; lock/unlock memory in manager
1 parent 37270bd commit c40ffaa

5 files changed

Lines changed: 129 additions & 70 deletions

File tree

src/crypto.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -425,6 +425,15 @@ int sqlcipher_codec_pragma(sqlite3* db, int iDb, Parse *pParse, const char *zLef
425425
codec_vdbe_return_static_string(pParse, "cipher_default_kdf_algorithm", SQLCIPHER_PBKDF2_HMAC_SHA512_LABEL);
426426
}
427427
}
428+
}else
429+
if( sqlite3StrICmp(zLeft,"cipher_memory_security")==0 ){
430+
if( zRight ) {
431+
sqlcipher_set_mem_security(sqlite3GetBoolean(zRight,1));
432+
} else {
433+
char *on = sqlite3_mprintf("%d", sqlcipher_get_mem_security());
434+
codec_vdbe_return_static_string(pParse, "cipher_memory_security", on);
435+
sqlite3_free(on);
436+
}
428437
}else {
429438
return 0;
430439
}

src/crypto.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -291,6 +291,8 @@ int sqlcipher_get_default_kdf_algorithm();
291291
int sqlcipher_codec_ctx_set_kdf_algorithm(codec_ctx *ctx, int algorithm);
292292
int sqlcipher_codec_ctx_get_kdf_algorithm(codec_ctx *ctx);
293293

294+
void sqlcipher_set_mem_security(int);
295+
int sqlcipher_get_mem_security();
294296

295297
#endif
296298
#endif

src/crypto_impl.c

Lines changed: 91 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -44,14 +44,17 @@
4444
#endif
4545
#endif
4646

47-
static unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
48-
static unsigned char hmac_salt_mask = HMAC_SALT_MASK;
49-
static int default_kdf_iter = PBKDF2_ITER;
50-
static int default_page_size = 4096;
51-
static int default_plaintext_header_sz = 0;
52-
static int default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
53-
static int default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
54-
static unsigned int sqlcipher_activate_count = 0;
47+
static volatile unsigned int default_flags = DEFAULT_CIPHER_FLAGS;
48+
static volatile unsigned char hmac_salt_mask = HMAC_SALT_MASK;
49+
static volatile int default_kdf_iter = PBKDF2_ITER;
50+
static volatile int default_page_size = 4096;
51+
static volatile int default_plaintext_header_sz = 0;
52+
static volatile int default_hmac_algorithm = SQLCIPHER_HMAC_SHA512;
53+
static volatile int default_kdf_algorithm = SQLCIPHER_PBKDF2_HMAC_SHA512;
54+
static volatile int mem_security_on = 1;
55+
static volatile int mem_security_activated = 0;
56+
static volatile unsigned int sqlcipher_activate_count = 0;
57+
static volatile sqlite3_mem_methods default_mem_methods;
5558
static sqlite3_mutex* sqlcipher_provider_mutex = NULL;
5659
static sqlcipher_provider *default_provider = NULL;
5760

@@ -96,24 +99,33 @@ struct codec_ctx {
9699
void *provider_ctx;
97100
};
98101

99-
static sqlite3_mem_methods default_mem_methods;
100-
101102
static int sqlcipher_mem_init(void *pAppData) {
102103
return default_mem_methods.xInit(pAppData);
103104
}
104105
static void sqlcipher_mem_shutdown(void *pAppData) {
105106
default_mem_methods.xShutdown(pAppData);
106107
}
107108
static void *sqlcipher_mem_malloc(int n) {
108-
return default_mem_methods.xMalloc(n);
109+
void *ptr = default_mem_methods.xMalloc(n);
110+
if(mem_security_on) {
111+
CODEC_TRACE("sqlcipher_mem_malloc: calling sqlcipher_mlock(%p,%d)\n", ptr, sz);
112+
sqlcipher_mlock(ptr, n);
113+
if(!mem_security_activated) mem_security_activated = 1;
114+
}
115+
return ptr;
109116
}
110117
static int sqlcipher_mem_size(void *p) {
111118
return default_mem_methods.xSize(p);
112119
}
113120
static void sqlcipher_mem_free(void *p) {
114-
int sz = sqlcipher_mem_size(p);
115-
CODEC_TRACE("sqlcipher_mem_free: calling sqlcipher_memset(%p,0,%d)\n", p, sz);
116-
sqlcipher_memset(p, 0, sz);
121+
int sz;
122+
if(mem_security_on) {
123+
sz = sqlcipher_mem_size(p);
124+
CODEC_TRACE("sqlcipher_mem_free: calling sqlcipher_memset(%p,0,%d) and sqlcipher_munlock(%p, %d) \n", p, sz, p, sz);
125+
sqlcipher_memset(p, 0, sz);
126+
sqlcipher_munlock(p, sz);
127+
if(!mem_security_activated) mem_security_activated = 1;
128+
}
117129
default_mem_methods.xFree(p);
118130
}
119131
static void *sqlcipher_mem_realloc(void *p, int n) {
@@ -288,45 +300,71 @@ int sqlcipher_memcmp(const void *v0, const void *v1, int len) {
288300
return (result != 0);
289301
}
290302

291-
/**
292-
* Free and wipe memory. Uses SQLites internal sqlite3_free so that memory
293-
* can be countend and memory leak detection works in the test suite.
294-
* If ptr is not null memory will be freed.
295-
* If sz is greater than zero, the memory will be overwritten with zero before it is freed
296-
* If sz is > 0, and not compiled with OMIT_MEMLOCK, system will attempt to unlock the
297-
* memory segment so it can be paged
298-
*/
299-
void sqlcipher_free(void *ptr, int sz) {
300-
if(ptr) {
301-
if(sz > 0) {
303+
void sqlcipher_mlock(void *ptr, int sz) {
302304
#ifndef OMIT_MEMLOCK
303-
int rc;
305+
int rc;
304306
#if defined(__unix__) || defined(__APPLE__)
305-
unsigned long pagesize = sysconf(_SC_PAGESIZE);
306-
unsigned long offset = (unsigned long) ptr % pagesize;
307+
unsigned long pagesize = sysconf(_SC_PAGESIZE);
308+
unsigned long offset = (unsigned long) ptr % pagesize;
309+
310+
if(ptr == NULL || sz == 0) return;
311+
312+
CODEC_TRACE("sqlcipher_mem_lock: calling mlock(%p,%lu); _SC_PAGESIZE=%lu\n", ptr - offset, sz + offset, pagesize);
313+
rc = mlock(ptr - offset, sz + offset);
314+
if(rc!=0) {
315+
CODEC_TRACE("sqlcipher_mem_lock: mlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
316+
}
317+
#elif defined(_WIN32)
318+
#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
319+
CODEC_TRACE("sqlcipher_mem_lock: calling VirtualLock(%p,%d)\n", ptr, sz);
320+
rc = VirtualLock(ptr, sz);
321+
if(rc==0) {
322+
CODEC_TRACE("sqlcipher_mem_lock: VirtualLock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
323+
}
307324
#endif
308325
#endif
309-
CODEC_TRACE("sqlcipher_free: calling sqlcipher_memset(%p,0,%d)\n", ptr, sz);
310-
sqlcipher_memset(ptr, 0, sz);
326+
#endif
327+
}
328+
329+
void sqlcipher_munlock(void *ptr, int sz) {
311330
#ifndef OMIT_MEMLOCK
331+
int rc;
312332
#if defined(__unix__) || defined(__APPLE__)
313-
CODEC_TRACE("sqlcipher_free: calling munlock(%p,%lu)\n", ptr - offset, sz + offset);
314-
rc = munlock(ptr - offset, sz + offset);
315-
if(rc!=0) {
316-
CODEC_TRACE("sqlcipher_free: munlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
317-
}
333+
unsigned long pagesize = sysconf(_SC_PAGESIZE);
334+
unsigned long offset = (unsigned long) ptr % pagesize;
335+
336+
if(ptr == NULL || sz == 0) return;
337+
338+
CODEC_TRACE("sqlcipher_mem_unlock: calling munlock(%p,%lu)\n", ptr - offset, sz + offset);
339+
rc = munlock(ptr - offset, sz + offset);
340+
if(rc!=0) {
341+
CODEC_TRACE("sqlcipher_mem_unlock: munlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
342+
}
318343
#elif defined(_WIN32)
319344
#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
320-
rc = VirtualUnlock(ptr, sz);
321-
if(!rc) {
322-
CODEC_TRACE("sqlcipher_free: VirtualUnlock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
323-
}
345+
CODEC_TRACE("sqlcipher_mem_lock: calling VirtualUnlock(%p,%d)\n", ptr, sz);
346+
rc = VirtualUnlock(ptr, sz);
347+
if(!rc) {
348+
CODEC_TRACE("sqlcipher_mem_unlock: VirtualUnlock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
349+
}
324350
#endif
325351
#endif
326352
#endif
327-
}
328-
sqlite3_free(ptr);
329-
}
353+
}
354+
355+
/**
356+
* Free and wipe memory. Uses SQLites internal sqlite3_free so that memory
357+
* can be countend and memory leak detection works in the test suite.
358+
* If ptr is not null memory will be freed.
359+
* If sz is greater than zero, the memory will be overwritten with zero before it is freed
360+
* If sz is > 0, and not compiled with OMIT_MEMLOCK, system will attempt to unlock the
361+
* memory segment so it can be paged
362+
*/
363+
void sqlcipher_free(void *ptr, int sz) {
364+
CODEC_TRACE("sqlcipher_free: calling sqlcipher_memset(%p,0,%d)\n", ptr, sz);
365+
sqlcipher_memset(ptr, 0, sz);
366+
sqlcipher_munlock(ptr, sz);
367+
sqlite3_free(ptr);
330368
}
331369

332370
/**
@@ -340,31 +378,10 @@ void* sqlcipher_malloc(int sz) {
340378
ptr = sqlite3Malloc(sz);
341379
CODEC_TRACE("sqlcipher_malloc: calling sqlcipher_memset(%p,0,%d)\n", ptr, sz);
342380
sqlcipher_memset(ptr, 0, sz);
343-
#ifndef OMIT_MEMLOCK
344-
if(ptr) {
345-
int rc;
346-
#if defined(__unix__) || defined(__APPLE__)
347-
unsigned long pagesize = sysconf(_SC_PAGESIZE);
348-
unsigned long offset = (unsigned long) ptr % pagesize;
349-
CODEC_TRACE("sqlcipher_malloc: calling mlock(%p,%lu); _SC_PAGESIZE=%lu\n", ptr - offset, sz + offset, pagesize);
350-
rc = mlock(ptr - offset, sz + offset);
351-
if(rc!=0) {
352-
CODEC_TRACE("sqlcipher_malloc: mlock(%p,%lu) returned %d errno=%d\n", ptr - offset, sz + offset, rc, errno);
353-
}
354-
#elif defined(_WIN32)
355-
#if !(defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP || WINAPI_FAMILY == WINAPI_FAMILY_APP))
356-
rc = VirtualLock(ptr, sz);
357-
if(rc==0) {
358-
CODEC_TRACE("sqlcipher_malloc: VirtualLock(%p,%d) returned %d LastError=%d\n", ptr, sz, rc, GetLastError());
359-
}
360-
#endif
361-
#endif
362-
}
363-
#endif
381+
sqlcipher_mlock(ptr, sz);
364382
return ptr;
365383
}
366384

367-
368385
/**
369386
* Initialize new cipher_ctx struct. This function will allocate memory
370387
* for the cipher context and for the key
@@ -800,6 +817,16 @@ int sqlcipher_get_default_pagesize() {
800817
return default_page_size;
801818
}
802819

820+
void sqlcipher_set_mem_security(int on) {
821+
mem_security_on = on;
822+
mem_security_activated = 0;
823+
}
824+
825+
int sqlcipher_get_mem_security() {
826+
return mem_security_on && mem_security_activated;
827+
}
828+
829+
803830
int sqlcipher_codec_ctx_init(codec_ctx **iCtx, Db *pDb, Pager *pPager, sqlite3_file *fd, const void *zKey, int nKey) {
804831
int rc;
805832
codec_ctx *ctx;

src/sqlcipher.h

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -75,15 +75,17 @@ typedef struct {
7575
} sqlcipher_provider;
7676

7777
/* utility functions */
78-
void sqlcipher_free(void *ptr, int sz);
79-
void* sqlcipher_malloc(int sz);
80-
void* sqlcipher_memset(void *v, unsigned char value, int len);
81-
int sqlcipher_ismemset(const void *v, unsigned char value, int len);
82-
int sqlcipher_memcmp(const void *v0, const void *v1, int len);
78+
void sqlcipher_free(void *, int);
79+
void* sqlcipher_malloc(int);
80+
void sqlcipher_mlock(void *, int);
81+
void sqlcipher_munlock(void *, int);
82+
void* sqlcipher_memset(void *, unsigned char, int);
83+
int sqlcipher_ismemset(const void *, unsigned char, int);
84+
int sqlcipher_memcmp(const void *, const void *, int);
8385
void sqlcipher_free(void *, int);
8486

8587
/* provider interfaces */
86-
int sqlcipher_register_provider(sqlcipher_provider *p);
88+
int sqlcipher_register_provider(sqlcipher_provider *);
8789
sqlcipher_provider* sqlcipher_get_provider();
8890

8991
#endif

test/crypto.test

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2790,5 +2790,24 @@ do_test verify-pragma-cipher-default-kdf-algorithm {
27902790
db close
27912791
file delete -force test.db
27922792

2793+
# verify memory security behavior
2794+
# initially should report ON
2795+
# then disable, check that it is off
2796+
# turn it back on, then check.
2797+
do_test verify-memory-security {
2798+
sqlite_orig db test.db
2799+
execsql {
2800+
PRAGMA cipher_memory_security;
2801+
PRAGMA cipher_memory_security = OFF;
2802+
PRAGMA cipher_memory_security;
2803+
PRAGMA cipher_memory_security = ON;
2804+
PRAGMA cipher_memory_security;
2805+
2806+
}
2807+
} {1 0 1}
2808+
db close
2809+
file delete -force test.db
2810+
2811+
27932812
sqlite3_test_control_pending_byte $old_pending_byte
27942813
finish_test

0 commit comments

Comments
 (0)