4 ** The author disclaims copyright to this source code. In place of
5 ** a legal notice, here is a blessing:
7 ** May you do good and not evil.
8 ** May you find forgiveness for yourself and forgive others.
9 ** May you share freely, never taking more than you give.
11 ******************************************************************************
13 ** This file implements a VFS shim that obfuscates database content
14 ** written to disk by applying a CipherStrategy.
18 ** This extension requires SQLite 3.32.0 or later.
23 ** Initialize it using a single API call as follows:
25 ** sqlite3_obfsvfs_init();
27 ** Obfsvfs is a VFS Shim. When loaded, "obfsvfs" becomes the new
28 ** default VFS and it uses the prior default VFS as the next VFS
29 ** down in the stack. This is normally what you want. However, it
30 ** complex situations where multiple VFS shims are being loaded,
31 ** it might be important to ensure that obfsvfs is loaded in the
32 ** correct order so that it sequences itself into the default VFS
33 ** Shim stack in the right order.
37 ** Open database connections using the sqlite3_open_v2() with
38 ** the SQLITE_OPEN_URI flag and using a URI filename that includes
39 ** the query parameter "key=XXXXXXXXXXX..." where the XXXX... consists
40 ** of 64 hexadecimal digits (32 bytes of content).
42 ** Create a new encrypted database by opening a file that does not
43 ** yet exist using the key= query parameter.
47 ** * An obfuscated database must be created as such. There is
48 ** no way to convert an existing database file into an
49 ** obfuscated database file other than to run ".dump" on the
50 ** older database and reimport the SQL text into a new
51 ** obfuscated database.
53 ** * There is no way to change the key value, other than to
54 ** ".dump" and restore the database
56 ** * The database page size must be exactly 8192 bytes. No other
57 ** database page sizes are currently supported.
59 ** * Memory-mapped I/O does not work for obfuscated databases.
60 ** If you think about it, memory-mapped I/O doesn't make any
61 ** sense for obfuscated databases since you have to make a
62 ** copy of the content to deobfuscate anyhow - you might as
63 ** well use normal read()/write().
65 ** * Only the main database, the rollback journal, and WAL file
66 ** are obfuscated. Other temporary files used for things like
67 ** SAVEPOINTs or as part of a large external sort remain
70 ** * Requires SQLite 3.32.0 or later.
75 #include <stdio.h> /* For debugging only */
77 #include "mozilla/dom/quota/IPCStreamCipherStrategy.h"
78 #include "mozilla/ScopeExit.h"
79 #include "nsPrintfCString.h"
82 ** Forward declaration of objects used by this utility
84 using ObfsVfs
= sqlite3_vfs
;
87 ** Useful datatype abbreviations
89 #if !defined(SQLITE_CORE)
90 using u8
= unsigned char;
93 /* Access to a lower-level VFS that (might) implement dynamic loading,
94 ** access to randomness, etc.
96 #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData))
97 #define ORIGFILE(p) ((sqlite3_file*)(((ObfsFile*)(p)) + 1))
100 ** Database page size for obfuscated databases
102 #define OBFS_PGSZ 8192
104 using namespace mozilla
;
105 using namespace mozilla::dom::quota
;
109 sqlite3_file base
; /* IO methods */
110 const char* zFName
; /* Original name of the file */
111 bool inCkpt
; /* Currently doing a checkpoint */
112 ObfsFile
* pPartner
; /* Ptr from WAL to main-db, or from main-db to WAL */
113 void* pTemp
; /* Temporary storage for encoded pages */
114 IPCStreamCipherStrategy
*
115 encryptCipherStrategy
; /* CipherStrategy for encryption */
116 IPCStreamCipherStrategy
*
117 decryptCipherStrategy
; /* CipherStrategy for decryption */
121 ** Methods for ObfsFile
123 static int obfsClose(sqlite3_file
*);
124 static int obfsRead(sqlite3_file
*, void*, int iAmt
, sqlite3_int64 iOfst
);
125 static int obfsWrite(sqlite3_file
*, const void*, int iAmt
, sqlite3_int64 iOfst
);
126 static int obfsTruncate(sqlite3_file
*, sqlite3_int64 size
);
127 static int obfsSync(sqlite3_file
*, int flags
);
128 static int obfsFileSize(sqlite3_file
*, sqlite3_int64
* pSize
);
129 static int obfsLock(sqlite3_file
*, int);
130 static int obfsUnlock(sqlite3_file
*, int);
131 static int obfsCheckReservedLock(sqlite3_file
*, int* pResOut
);
132 static int obfsFileControl(sqlite3_file
*, int op
, void* pArg
);
133 static int obfsSectorSize(sqlite3_file
*);
134 static int obfsDeviceCharacteristics(sqlite3_file
*);
135 static int obfsShmMap(sqlite3_file
*, int iPg
, int pgsz
, int, void volatile**);
136 static int obfsShmLock(sqlite3_file
*, int offset
, int n
, int flags
);
137 static void obfsShmBarrier(sqlite3_file
*);
138 static int obfsShmUnmap(sqlite3_file
*, int deleteFlag
);
139 static int obfsFetch(sqlite3_file
*, sqlite3_int64 iOfst
, int iAmt
, void** pp
);
140 static int obfsUnfetch(sqlite3_file
*, sqlite3_int64 iOfst
, void* p
);
143 ** Methods for ObfsVfs
145 static int obfsOpen(sqlite3_vfs
*, const char*, sqlite3_file
*, int, int*);
146 static int obfsDelete(sqlite3_vfs
*, const char* zPath
, int syncDir
);
147 static int obfsAccess(sqlite3_vfs
*, const char* zPath
, int flags
, int*);
148 static int obfsFullPathname(sqlite3_vfs
*, const char* zPath
, int, char* zOut
);
149 static void* obfsDlOpen(sqlite3_vfs
*, const char* zPath
);
150 static void obfsDlError(sqlite3_vfs
*, int nByte
, char* zErrMsg
);
151 static void (*obfsDlSym(sqlite3_vfs
* pVfs
, void* p
, const char* zSym
))(void);
152 static void obfsDlClose(sqlite3_vfs
*, void*);
153 static int obfsRandomness(sqlite3_vfs
*, int nByte
, char* zBufOut
);
154 static int obfsSleep(sqlite3_vfs
*, int nMicroseconds
);
155 static int obfsCurrentTime(sqlite3_vfs
*, double*);
156 static int obfsGetLastError(sqlite3_vfs
*, int, char*);
157 static int obfsCurrentTimeInt64(sqlite3_vfs
*, sqlite3_int64
*);
158 static int obfsSetSystemCall(sqlite3_vfs
*, const char*, sqlite3_syscall_ptr
);
159 static sqlite3_syscall_ptr
obfsGetSystemCall(sqlite3_vfs
*, const char* z
);
160 static const char* obfsNextSystemCall(sqlite3_vfs
*, const char* zName
);
162 static const sqlite3_io_methods obfs_io_methods
= {
164 obfsClose
, /* xClose */
165 obfsRead
, /* xRead */
166 obfsWrite
, /* xWrite */
167 obfsTruncate
, /* xTruncate */
168 obfsSync
, /* xSync */
169 obfsFileSize
, /* xFileSize */
170 obfsLock
, /* xLock */
171 obfsUnlock
, /* xUnlock */
172 obfsCheckReservedLock
, /* xCheckReservedLock */
173 obfsFileControl
, /* xFileControl */
174 obfsSectorSize
, /* xSectorSize */
175 obfsDeviceCharacteristics
, /* xDeviceCharacteristics */
176 obfsShmMap
, /* xShmMap */
177 obfsShmLock
, /* xShmLock */
178 obfsShmBarrier
, /* xShmBarrier */
179 obfsShmUnmap
, /* xShmUnmap */
180 obfsFetch
, /* xFetch */
181 obfsUnfetch
/* xUnfetch */
184 static constexpr int kKeyBytes
= 32;
185 static constexpr int kIvBytes
= IPCStreamCipherStrategy::BlockPrefixLength
;
186 static constexpr int kClearTextPrefixBytesOnFirstPage
= 32;
187 static constexpr int kReservedBytes
= 32;
188 static constexpr int kBasicBlockSize
= IPCStreamCipherStrategy::BasicBlockSize
;
189 static_assert(kClearTextPrefixBytesOnFirstPage
% kBasicBlockSize
== 0);
190 static_assert(kReservedBytes
% kBasicBlockSize
== 0);
192 /* Obfuscate a page using p->encryptCipherStrategy.
194 ** A new random nonce is created and stored in the last 32 bytes
195 ** of the page. All other bytes of the page are obfuscasted using the
196 ** CipherStrategy. Except, for page-1 (including the SQLite
197 ** database header) the first 32 bytes are not obfuscated
199 ** Return a pointer to the obfuscated content, which is held in the
200 ** p->pTemp buffer. Or return a NULL pointer if something goes wrong.
201 ** Errors are reported using NS_WARNING().
203 static void* obfsEncode(ObfsFile
* p
, /* File containing page to be obfuscated */
204 u8
* a
, /* database page to be obfuscated */
205 int nByte
/* Bytes of content in a[]. Must be a multiple
206 of kBasicBlockSize. */
212 static_assert((kIvBytes
& (kIvBytes
- 1)) == 0);
213 sqlite3_randomness(kIvBytes
, aIv
);
214 pOut
= (u8
*)p
->pTemp
;
215 if (pOut
== nullptr) {
216 pOut
= static_cast<u8
*>(sqlite3_malloc64(nByte
));
217 if (pOut
== nullptr) {
218 NS_WARNING(nsPrintfCString("unable to allocate a buffer in which to"
219 " write obfuscated database content for %s",
226 if (memcmp(a
, "SQLite format 3", 16) == 0) {
227 i
= kClearTextPrefixBytesOnFirstPage
;
228 if (a
[20] != kReservedBytes
) {
229 NS_WARNING(nsPrintfCString("obfuscated database must have reserved-bytes"
235 memcpy(pOut
, a
, kClearTextPrefixBytesOnFirstPage
);
239 const int payloadLength
= nByte
- kReservedBytes
- i
;
240 MOZ_ASSERT(payloadLength
> 0);
241 // XXX I guess this can be done in-place as well, then we don't need the
242 // temporary page at all, I guess?
243 p
->encryptCipherStrategy
->Cipher(
244 Span
{aIv
}, Span
{a
+ i
, static_cast<unsigned>(payloadLength
)},
245 Span
{pOut
+ i
, static_cast<unsigned>(payloadLength
)});
246 memcpy(pOut
+ nByte
- kReservedBytes
, aIv
, kIvBytes
);
251 /* De-obfuscate a page using p->decryptCipherStrategy.
253 ** The deobfuscation is done in-place.
255 ** For pages that begin with the SQLite header text, the first
256 ** 32 bytes are not deobfuscated.
258 static void obfsDecode(ObfsFile
* p
, /* File containing page to be obfuscated */
259 u8
* a
, /* database page to be obfuscated */
260 int nByte
/* Bytes of content in a[]. Must be a multiple
261 of kBasicBlockSize. */
265 if (memcmp(a
, "SQLite format 3", 16) == 0) {
266 i
= kClearTextPrefixBytesOnFirstPage
;
270 const int payloadLength
= nByte
- kReservedBytes
- i
;
271 MOZ_ASSERT(payloadLength
> 0);
272 p
->decryptCipherStrategy
->Cipher(
273 Span
{a
+ nByte
- kReservedBytes
, kIvBytes
},
274 Span
{a
+ i
, static_cast<unsigned>(payloadLength
)},
275 Span
{a
+ i
, static_cast<unsigned>(payloadLength
)});
279 ** Close an obfsucated file.
281 static int obfsClose(sqlite3_file
* pFile
) {
282 ObfsFile
* p
= (ObfsFile
*)pFile
;
284 MOZ_ASSERT(p
->pPartner
->pPartner
== p
);
285 p
->pPartner
->pPartner
= nullptr;
286 p
->pPartner
= nullptr;
288 sqlite3_free(p
->pTemp
);
290 delete p
->decryptCipherStrategy
;
291 delete p
->encryptCipherStrategy
;
293 pFile
= ORIGFILE(pFile
);
294 return pFile
->pMethods
->xClose(pFile
);
298 ** Read data from an obfuscated file.
300 ** If the file is less than one full page in length, then return
301 ** a substitute "prototype" page-1. This prototype page one
302 ** specifies a database in WAL mode with an 8192-byte page size
303 ** and a 32-byte reserved-bytes value. Those settings are necessary
304 ** for obfuscation to function correctly.
306 static int obfsRead(sqlite3_file
* pFile
, void* zBuf
, int iAmt
,
307 sqlite_int64 iOfst
) {
309 ObfsFile
* p
= (ObfsFile
*)pFile
;
310 pFile
= ORIGFILE(pFile
);
311 rc
= pFile
->pMethods
->xRead(pFile
, zBuf
, iAmt
, iOfst
);
312 if (rc
== SQLITE_OK
) {
313 if (iAmt
== OBFS_PGSZ
&& !p
->inCkpt
) {
314 obfsDecode(p
, (u8
*)zBuf
, iAmt
);
316 } else if (SQLITE_IOERR_SHORT_READ
&& iOfst
== 0 && iAmt
>= 100) {
317 static const unsigned char aEmptyDb
[] = {
318 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66,
319 0x6f, 0x72, 0x6d, 0x61, 0x74, 0x20, 0x33, 0x00,
320 0x20, 0x00, 0x02, 0x02, kReservedBytes
, 0x40, 0x20, 0x20,
321 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01};
322 memcpy(zBuf
, aEmptyDb
, sizeof(aEmptyDb
));
323 memset(((u8
*)zBuf
) + sizeof(aEmptyDb
), 0, iAmt
- sizeof(aEmptyDb
));
330 ** Write data to an obfuscated file or journal.
332 static int obfsWrite(sqlite3_file
* pFile
, const void* zBuf
, int iAmt
,
333 sqlite_int64 iOfst
) {
334 ObfsFile
* p
= (ObfsFile
*)pFile
;
335 pFile
= ORIGFILE(pFile
);
336 if (iAmt
== OBFS_PGSZ
&& !p
->inCkpt
) {
337 zBuf
= obfsEncode(p
, (u8
*)zBuf
, iAmt
);
338 if (zBuf
== nullptr) {
342 return pFile
->pMethods
->xWrite(pFile
, zBuf
, iAmt
, iOfst
);
346 ** Truncate an obfuscated file.
348 static int obfsTruncate(sqlite3_file
* pFile
, sqlite_int64 size
) {
349 pFile
= ORIGFILE(pFile
);
350 return pFile
->pMethods
->xTruncate(pFile
, size
);
354 ** Sync an obfuscated file.
356 static int obfsSync(sqlite3_file
* pFile
, int flags
) {
357 pFile
= ORIGFILE(pFile
);
358 return pFile
->pMethods
->xSync(pFile
, flags
);
362 ** Return the current file-size of an obfuscated file.
364 static int obfsFileSize(sqlite3_file
* pFile
, sqlite_int64
* pSize
) {
365 ObfsFile
* p
= (ObfsFile
*)pFile
;
367 return pFile
->pMethods
->xFileSize(pFile
, pSize
);
371 ** Lock an obfuscated file.
373 static int obfsLock(sqlite3_file
* pFile
, int eLock
) {
374 pFile
= ORIGFILE(pFile
);
375 return pFile
->pMethods
->xLock(pFile
, eLock
);
379 ** Unlock an obfuscated file.
381 static int obfsUnlock(sqlite3_file
* pFile
, int eLock
) {
382 pFile
= ORIGFILE(pFile
);
383 return pFile
->pMethods
->xUnlock(pFile
, eLock
);
387 ** Check if another file-handle holds a RESERVED lock on an obfuscated file.
389 static int obfsCheckReservedLock(sqlite3_file
* pFile
, int* pResOut
) {
390 pFile
= ORIGFILE(pFile
);
391 return pFile
->pMethods
->xCheckReservedLock(pFile
, pResOut
);
395 ** File control method. For custom operations on an obfuscated file.
397 static int obfsFileControl(sqlite3_file
* pFile
, int op
, void* pArg
) {
399 ObfsFile
* p
= (ObfsFile
*)pFile
;
400 pFile
= ORIGFILE(pFile
);
401 if (op
== SQLITE_FCNTL_PRAGMA
) {
402 char** azArg
= (char**)pArg
;
403 MOZ_ASSERT(azArg
[1] != nullptr);
404 if (azArg
[2] != nullptr && sqlite3_stricmp(azArg
[1], "page_size") == 0) {
405 /* Do not allow page size changes on an obfuscated database */
408 } else if (op
== SQLITE_FCNTL_CKPT_START
|| op
== SQLITE_FCNTL_CKPT_DONE
) {
409 p
->inCkpt
= op
== SQLITE_FCNTL_CKPT_START
;
411 p
->pPartner
->inCkpt
= p
->inCkpt
;
414 rc
= pFile
->pMethods
->xFileControl(pFile
, op
, pArg
);
415 if (rc
== SQLITE_OK
&& op
== SQLITE_FCNTL_VFSNAME
) {
416 *(char**)pArg
= sqlite3_mprintf("obfs/%z", *(char**)pArg
);
422 ** Return the sector-size in bytes for an obfuscated file.
424 static int obfsSectorSize(sqlite3_file
* pFile
) {
425 pFile
= ORIGFILE(pFile
);
426 return pFile
->pMethods
->xSectorSize(pFile
);
430 ** Return the device characteristic flags supported by an obfuscated file.
432 static int obfsDeviceCharacteristics(sqlite3_file
* pFile
) {
433 pFile
= ORIGFILE(pFile
);
434 return pFile
->pMethods
->xDeviceCharacteristics(pFile
);
437 /* Create a shared memory file mapping */
438 static int obfsShmMap(sqlite3_file
* pFile
, int iPg
, int pgsz
, int bExtend
,
439 void volatile** pp
) {
440 pFile
= ORIGFILE(pFile
);
441 return pFile
->pMethods
->xShmMap(pFile
, iPg
, pgsz
, bExtend
, pp
);
444 /* Perform locking on a shared-memory segment */
445 static int obfsShmLock(sqlite3_file
* pFile
, int offset
, int n
, int flags
) {
446 pFile
= ORIGFILE(pFile
);
447 return pFile
->pMethods
->xShmLock(pFile
, offset
, n
, flags
);
450 /* Memory barrier operation on shared memory */
451 static void obfsShmBarrier(sqlite3_file
* pFile
) {
452 pFile
= ORIGFILE(pFile
);
453 pFile
->pMethods
->xShmBarrier(pFile
);
456 /* Unmap a shared memory segment */
457 static int obfsShmUnmap(sqlite3_file
* pFile
, int deleteFlag
) {
458 pFile
= ORIGFILE(pFile
);
459 return pFile
->pMethods
->xShmUnmap(pFile
, deleteFlag
);
462 /* Fetch a page of a memory-mapped file */
463 static int obfsFetch(sqlite3_file
* pFile
, sqlite3_int64 iOfst
, int iAmt
,
469 /* Release a memory-mapped page */
470 static int obfsUnfetch(sqlite3_file
* pFile
, sqlite3_int64 iOfst
, void* pPage
) {
471 pFile
= ORIGFILE(pFile
);
472 return pFile
->pMethods
->xUnfetch(pFile
, iOfst
, pPage
);
476 ** Translate a single byte of Hex into an integer.
477 ** This routine only works if h really is a valid hexadecimal
478 ** character: 0..9a..fA..F
480 static u8
obfsHexToInt(int h
) {
481 MOZ_ASSERT((h
>= '0' && h
<= '9') || (h
>= 'a' && h
<= 'f') ||
482 (h
>= 'A' && h
<= 'F'));
484 h
+= 9 * (1 & (h
>> 6));
486 h
+= 9 * (1 & ~(h
>> 4));
488 return (u8
)(h
& 0xf);
494 ** If the file is an ordinary database file, or a rollback or WAL journal
495 ** file, and if the key=XXXX parameter exists, then try to open the file
496 ** as an obfuscated database. All other open attempts fall through into
497 ** the lower-level VFS shim.
499 ** If the key=XXXX parameter exists but is not 64-bytes of hex key, then
500 ** put an error message in NS_WARNING() and return SQLITE_CANTOPEN.
502 static int obfsOpen(sqlite3_vfs
* pVfs
, const char* zName
, sqlite3_file
* pFile
,
503 int flags
, int* pOutFlags
) {
505 sqlite3_file
* pSubFile
;
506 sqlite3_vfs
* pSubVfs
;
510 pSubVfs
= ORIGVFS(pVfs
);
512 (SQLITE_OPEN_MAIN_DB
| SQLITE_OPEN_WAL
| SQLITE_OPEN_MAIN_JOURNAL
)) {
513 zKey
= sqlite3_uri_parameter(zName
, "key");
517 if (zKey
== nullptr) {
518 return pSubVfs
->xOpen(pSubVfs
, zName
, pFile
, flags
, pOutFlags
);
521 i
< kKeyBytes
&& isxdigit(zKey
[i
* 2]) && isxdigit(zKey
[i
* 2 + 1]);
523 aKey
[i
] = (obfsHexToInt(zKey
[i
* 2]) << 4) | obfsHexToInt(zKey
[i
* 2 + 1]);
525 if (i
!= kKeyBytes
) {
527 nsPrintfCString("invalid query parameter on %s: key=%s", zName
, zKey
)
529 return SQLITE_CANTOPEN
;
531 p
= (ObfsFile
*)pFile
;
532 memset(p
, 0, sizeof(*p
));
534 auto encryptCipherStrategy
= MakeUnique
<IPCStreamCipherStrategy
>();
535 auto decryptCipherStrategy
= MakeUnique
<IPCStreamCipherStrategy
>();
537 auto resetMethods
= MakeScopeExit([pFile
] { pFile
->pMethods
= nullptr; });
539 if (NS_WARN_IF(NS_FAILED(encryptCipherStrategy
->Init(
540 CipherMode::Encrypt
, Span
{aKey
, sizeof(aKey
)},
541 IPCStreamCipherStrategy::MakeBlockPrefix())))) {
545 if (NS_WARN_IF(NS_FAILED(decryptCipherStrategy
->Init(
546 CipherMode::Decrypt
, Span
{aKey
, sizeof(aKey
)})))) {
550 pSubFile
= ORIGFILE(pFile
);
551 p
->base
.pMethods
= &obfs_io_methods
;
552 rc
= pSubVfs
->xOpen(pSubVfs
, zName
, pSubFile
, flags
, pOutFlags
);
557 resetMethods
.release();
559 if (flags
& (SQLITE_OPEN_WAL
| SQLITE_OPEN_MAIN_JOURNAL
)) {
560 sqlite3_file
* pDb
= sqlite3_database_file_object(zName
);
561 p
->pPartner
= (ObfsFile
*)pDb
;
562 MOZ_ASSERT(p
->pPartner
->pPartner
== nullptr);
563 p
->pPartner
->pPartner
= p
;
567 p
->encryptCipherStrategy
= encryptCipherStrategy
.release();
568 p
->decryptCipherStrategy
= decryptCipherStrategy
.release();
574 ** All other VFS methods are pass-thrus.
576 static int obfsDelete(sqlite3_vfs
* pVfs
, const char* zPath
, int syncDir
) {
577 return ORIGVFS(pVfs
)->xDelete(ORIGVFS(pVfs
), zPath
, syncDir
);
579 static int obfsAccess(sqlite3_vfs
* pVfs
, const char* zPath
, int flags
,
581 return ORIGVFS(pVfs
)->xAccess(ORIGVFS(pVfs
), zPath
, flags
, pResOut
);
583 static int obfsFullPathname(sqlite3_vfs
* pVfs
, const char* zPath
, int nOut
,
585 return ORIGVFS(pVfs
)->xFullPathname(ORIGVFS(pVfs
), zPath
, nOut
, zOut
);
587 static void* obfsDlOpen(sqlite3_vfs
* pVfs
, const char* zPath
) {
588 return ORIGVFS(pVfs
)->xDlOpen(ORIGVFS(pVfs
), zPath
);
590 static void obfsDlError(sqlite3_vfs
* pVfs
, int nByte
, char* zErrMsg
) {
591 ORIGVFS(pVfs
)->xDlError(ORIGVFS(pVfs
), nByte
, zErrMsg
);
593 static void (*obfsDlSym(sqlite3_vfs
* pVfs
, void* p
, const char* zSym
))(void) {
594 return ORIGVFS(pVfs
)->xDlSym(ORIGVFS(pVfs
), p
, zSym
);
596 static void obfsDlClose(sqlite3_vfs
* pVfs
, void* pHandle
) {
597 ORIGVFS(pVfs
)->xDlClose(ORIGVFS(pVfs
), pHandle
);
599 static int obfsRandomness(sqlite3_vfs
* pVfs
, int nByte
, char* zBufOut
) {
600 return ORIGVFS(pVfs
)->xRandomness(ORIGVFS(pVfs
), nByte
, zBufOut
);
602 static int obfsSleep(sqlite3_vfs
* pVfs
, int nMicroseconds
) {
603 return ORIGVFS(pVfs
)->xSleep(ORIGVFS(pVfs
), nMicroseconds
);
605 static int obfsCurrentTime(sqlite3_vfs
* pVfs
, double* pTimeOut
) {
606 return ORIGVFS(pVfs
)->xCurrentTime(ORIGVFS(pVfs
), pTimeOut
);
608 static int obfsGetLastError(sqlite3_vfs
* pVfs
, int a
, char* b
) {
609 return ORIGVFS(pVfs
)->xGetLastError(ORIGVFS(pVfs
), a
, b
);
611 static int obfsCurrentTimeInt64(sqlite3_vfs
* pVfs
, sqlite3_int64
* p
) {
612 return ORIGVFS(pVfs
)->xCurrentTimeInt64(ORIGVFS(pVfs
), p
);
614 static int obfsSetSystemCall(sqlite3_vfs
* pVfs
, const char* zName
,
615 sqlite3_syscall_ptr pCall
) {
616 return ORIGVFS(pVfs
)->xSetSystemCall(ORIGVFS(pVfs
), zName
, pCall
);
618 static sqlite3_syscall_ptr
obfsGetSystemCall(sqlite3_vfs
* pVfs
,
620 return ORIGVFS(pVfs
)->xGetSystemCall(ORIGVFS(pVfs
), zName
);
622 static const char* obfsNextSystemCall(sqlite3_vfs
* pVfs
, const char* zName
) {
623 return ORIGVFS(pVfs
)->xNextSystemCall(ORIGVFS(pVfs
), zName
);
629 const char* GetObfuscatingVFSName() { return "obfsvfs"; }
631 UniquePtr
<sqlite3_vfs
> ConstructObfuscatingVFS(const char* aBaseVFSName
) {
632 MOZ_ASSERT(aBaseVFSName
);
634 if (sqlite3_vfs_find(GetObfuscatingVFSName()) != nullptr) {
637 sqlite3_vfs
* const pOrig
= sqlite3_vfs_find(aBaseVFSName
);
638 if (pOrig
== nullptr) {
643 // If the VFS version is higher than the last known one, you should update
644 // this VFS adding appropriate methods for any methods added in the version
646 static constexpr int kLastKnownVfsVersion
= 3;
647 MOZ_ASSERT(pOrig
->iVersion
<= kLastKnownVfsVersion
);
650 const sqlite3_vfs obfs_vfs
= {
651 pOrig
->iVersion
, /* iVersion */
652 static_cast<int>(pOrig
->szOsFile
+ sizeof(ObfsFile
)), /* szOsFile */
653 1024, /* mxPathname */
655 GetObfuscatingVFSName(), /* zName */
656 pOrig
, /* pAppData */
657 obfsOpen
, /* xOpen */
658 obfsDelete
, /* xDelete */
659 obfsAccess
, /* xAccess */
660 obfsFullPathname
, /* xFullPathname */
661 obfsDlOpen
, /* xDlOpen */
662 obfsDlError
, /* xDlError */
663 obfsDlSym
, /* xDlSym */
664 obfsDlClose
, /* xDlClose */
665 obfsRandomness
, /* xRandomness */
666 obfsSleep
, /* xSleep */
667 obfsCurrentTime
, /* xCurrentTime */
668 obfsGetLastError
, /* xGetLastError */
669 obfsCurrentTimeInt64
, /* xCurrentTimeInt64 */
670 obfsSetSystemCall
, /* xSetSystemCall */
671 obfsGetSystemCall
, /* xGetSystemCall */
672 obfsNextSystemCall
/* xNextSystemCall */
675 return MakeUnique
<sqlite3_vfs
>(obfs_vfs
);
678 } // namespace storage
679 } // namespace mozilla