ObfuscatingVFS.cpp (24846B)
1 /* 2 ** 2020-04-20 3 ** 4 ** The author disclaims copyright to this source code. In place of 5 ** a legal notice, here is a blessing: 6 ** 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. 10 ** 11 ****************************************************************************** 12 ** 13 ** This file implements a VFS shim that obfuscates database content 14 ** written to disk by applying a CipherStrategy. 15 ** 16 ** COMPILING 17 ** 18 ** This extension requires SQLite 3.32.0 or later. 19 ** 20 ** 21 ** LOADING 22 ** 23 ** Initialize it using a single API call as follows: 24 ** 25 ** sqlite3_obfsvfs_init(); 26 ** 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. 34 ** 35 ** USING 36 ** 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). 41 ** 42 ** Create a new encrypted database by opening a file that does not 43 ** yet exist using the key= query parameter. 44 ** 45 ** LIMITATIONS: 46 ** 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. 52 ** 53 ** * There is no way to change the key value, other than to 54 ** ".dump" and restore the database 55 ** 56 ** * The database page size must be exactly 8192 bytes. No other 57 ** database page sizes are currently supported. 58 ** 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(). 64 ** 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 68 ** unobfuscated. 69 ** 70 ** * Requires SQLite 3.32.0 or later. 71 */ 72 #include "ObfuscatingVFS.h" 73 74 #include <string.h> 75 #include <ctype.h> 76 #include <stdio.h> /* For debugging only */ 77 78 #include "mozilla/dom/quota/IPCStreamCipherStrategy.h" 79 #include "mozilla/ScopeExit.h" 80 #include "nsPrintfCString.h" 81 #include "QuotaVFS.h" 82 #include "sqlite3.h" 83 84 /* 85 ** Forward declaration of objects used by this utility 86 */ 87 using ObfsVfs = sqlite3_vfs; 88 89 /* 90 ** Useful datatype abbreviations 91 */ 92 #if !defined(SQLITE_CORE) 93 using u8 = unsigned char; 94 #endif 95 96 /* Access to a lower-level VFS that (might) implement dynamic loading, 97 ** access to randomness, etc. 98 */ 99 #define ORIGVFS(p) ((sqlite3_vfs*)((p)->pAppData)) 100 #define ORIGFILE(p) ((sqlite3_file*)(((ObfsFile*)(p)) + 1)) 101 102 /* 103 ** Database page size for obfuscated databases 104 */ 105 #define OBFS_PGSZ 8192 106 107 #define WAL_FRAMEHDRSIZE 24 108 109 using namespace mozilla; 110 using namespace mozilla::dom::quota; 111 112 /* An open file */ 113 struct ObfsFile { 114 sqlite3_file base; /* IO methods */ 115 const char* zFName; /* Original name of the file */ 116 bool inCkpt; /* Currently doing a checkpoint */ 117 ObfsFile* pPartner; /* Ptr from WAL to main-db, or from main-db to WAL */ 118 void* pTemp; /* Temporary storage for encoded pages */ 119 IPCStreamCipherStrategy* 120 encryptCipherStrategy; /* CipherStrategy for encryption */ 121 IPCStreamCipherStrategy* 122 decryptCipherStrategy; /* CipherStrategy for decryption */ 123 }; 124 125 /* 126 ** Methods for ObfsFile 127 */ 128 static int obfsClose(sqlite3_file*); 129 static int obfsRead(sqlite3_file*, void*, int iAmt, sqlite3_int64 iOfst); 130 static int obfsWrite(sqlite3_file*, const void*, int iAmt, sqlite3_int64 iOfst); 131 static int obfsTruncate(sqlite3_file*, sqlite3_int64 size); 132 static int obfsSync(sqlite3_file*, int flags); 133 static int obfsFileSize(sqlite3_file*, sqlite3_int64* pSize); 134 static int obfsLock(sqlite3_file*, int); 135 static int obfsUnlock(sqlite3_file*, int); 136 static int obfsCheckReservedLock(sqlite3_file*, int* pResOut); 137 static int obfsFileControl(sqlite3_file*, int op, void* pArg); 138 static int obfsSectorSize(sqlite3_file*); 139 static int obfsDeviceCharacteristics(sqlite3_file*); 140 static int obfsShmMap(sqlite3_file*, int iPg, int pgsz, int, void volatile**); 141 static int obfsShmLock(sqlite3_file*, int offset, int n, int flags); 142 static void obfsShmBarrier(sqlite3_file*); 143 static int obfsShmUnmap(sqlite3_file*, int deleteFlag); 144 static int obfsFetch(sqlite3_file*, sqlite3_int64 iOfst, int iAmt, void** pp); 145 static int obfsUnfetch(sqlite3_file*, sqlite3_int64 iOfst, void* p); 146 147 /* 148 ** Methods for ObfsVfs 149 */ 150 static int obfsOpen(sqlite3_vfs*, const char*, sqlite3_file*, int, int*); 151 static int obfsDelete(sqlite3_vfs*, const char* zPath, int syncDir); 152 static int obfsAccess(sqlite3_vfs*, const char* zPath, int flags, int*); 153 static int obfsFullPathname(sqlite3_vfs*, const char* zPath, int, char* zOut); 154 static void* obfsDlOpen(sqlite3_vfs*, const char* zPath); 155 static void obfsDlError(sqlite3_vfs*, int nByte, char* zErrMsg); 156 static void (*obfsDlSym(sqlite3_vfs* pVfs, void* p, const char* zSym))(void); 157 static void obfsDlClose(sqlite3_vfs*, void*); 158 static int obfsRandomness(sqlite3_vfs*, int nByte, char* zBufOut); 159 static int obfsSleep(sqlite3_vfs*, int nMicroseconds); 160 static int obfsCurrentTime(sqlite3_vfs*, double*); 161 static int obfsGetLastError(sqlite3_vfs*, int, char*); 162 static int obfsCurrentTimeInt64(sqlite3_vfs*, sqlite3_int64*); 163 static int obfsSetSystemCall(sqlite3_vfs*, const char*, sqlite3_syscall_ptr); 164 static sqlite3_syscall_ptr obfsGetSystemCall(sqlite3_vfs*, const char* z); 165 static const char* obfsNextSystemCall(sqlite3_vfs*, const char* zName); 166 167 static const sqlite3_io_methods obfs_io_methods = { 168 3, /* iVersion */ 169 obfsClose, /* xClose */ 170 obfsRead, /* xRead */ 171 obfsWrite, /* xWrite */ 172 obfsTruncate, /* xTruncate */ 173 obfsSync, /* xSync */ 174 obfsFileSize, /* xFileSize */ 175 obfsLock, /* xLock */ 176 obfsUnlock, /* xUnlock */ 177 obfsCheckReservedLock, /* xCheckReservedLock */ 178 obfsFileControl, /* xFileControl */ 179 obfsSectorSize, /* xSectorSize */ 180 obfsDeviceCharacteristics, /* xDeviceCharacteristics */ 181 obfsShmMap, /* xShmMap */ 182 obfsShmLock, /* xShmLock */ 183 obfsShmBarrier, /* xShmBarrier */ 184 obfsShmUnmap, /* xShmUnmap */ 185 obfsFetch, /* xFetch */ 186 obfsUnfetch /* xUnfetch */ 187 }; 188 189 static constexpr int kKeyBytes = 32; 190 static constexpr int kIvBytes = IPCStreamCipherStrategy::BlockPrefixLength; 191 static constexpr int kClearTextPrefixBytesOnFirstPage = 32; 192 static constexpr int kReservedBytes = 32; 193 static constexpr int kBasicBlockSize = IPCStreamCipherStrategy::BasicBlockSize; 194 static_assert(kClearTextPrefixBytesOnFirstPage % kBasicBlockSize == 0); 195 static_assert(kReservedBytes % kBasicBlockSize == 0); 196 197 /* Obfuscate a page using p->encryptCipherStrategy. 198 ** 199 ** A new random nonce is created and stored in the last 32 bytes 200 ** of the page. All other bytes of the page are obfuscasted using the 201 ** CipherStrategy. Except, for page-1 (including the SQLite 202 ** database header) the first 32 bytes are not obfuscated 203 ** 204 ** Return a pointer to the obfuscated content, which is held in the 205 ** p->pTemp buffer. Or return a NULL pointer if something goes wrong. 206 ** Errors are reported using NS_WARNING(). 207 */ 208 static void* obfsEncode(ObfsFile* p, /* File containing page to be obfuscated */ 209 u8* a, /* database page to be obfuscated */ 210 int nByte /* Bytes of content in a[]. Must be a multiple 211 of kBasicBlockSize. */ 212 ) { 213 u8 aIv[kIvBytes]; 214 u8* pOut; 215 int i; 216 217 static_assert((kIvBytes & (kIvBytes - 1)) == 0); 218 sqlite3_randomness(kIvBytes, aIv); 219 pOut = (u8*)p->pTemp; 220 if (pOut == nullptr) { 221 pOut = static_cast<u8*>(sqlite3_malloc64(nByte)); 222 if (pOut == nullptr) { 223 NS_WARNING(nsPrintfCString("unable to allocate a buffer in which to" 224 " write obfuscated database content for %s", 225 p->zFName) 226 .get()); 227 return nullptr; 228 } 229 p->pTemp = pOut; 230 } 231 if (memcmp(a, "SQLite format 3", 16) == 0) { 232 i = kClearTextPrefixBytesOnFirstPage; 233 if (a[20] != kReservedBytes) { 234 NS_WARNING(nsPrintfCString("obfuscated database must have reserved-bytes" 235 " set to %d", 236 kReservedBytes) 237 .get()); 238 return nullptr; 239 } 240 memcpy(pOut, a, kClearTextPrefixBytesOnFirstPage); 241 } else { 242 i = 0; 243 } 244 const int payloadLength = nByte - kReservedBytes - i; 245 MOZ_ASSERT(payloadLength > 0); 246 // XXX I guess this can be done in-place as well, then we don't need the 247 // temporary page at all, I guess? 248 p->encryptCipherStrategy->Cipher( 249 Span{aIv}, Span{a + i, static_cast<unsigned>(payloadLength)}, 250 Span{pOut + i, static_cast<unsigned>(payloadLength)}); 251 memcpy(pOut + nByte - kReservedBytes, aIv, kIvBytes); 252 253 return pOut; 254 } 255 256 /* De-obfuscate a page using p->decryptCipherStrategy. 257 ** 258 ** The deobfuscation is done in-place. 259 ** 260 ** For pages that begin with the SQLite header text, the first 261 ** 32 bytes are not deobfuscated. 262 */ 263 static void obfsDecode(ObfsFile* p, /* File containing page to be obfuscated */ 264 u8* a, /* database page to be obfuscated */ 265 int nByte /* Bytes of content in a[]. Must be a multiple 266 of kBasicBlockSize. */ 267 ) { 268 int i; 269 270 if (memcmp(a, "SQLite format 3", 16) == 0) { 271 i = kClearTextPrefixBytesOnFirstPage; 272 } else { 273 i = 0; 274 } 275 const int payloadLength = nByte - kReservedBytes - i; 276 MOZ_ASSERT(payloadLength > 0); 277 p->decryptCipherStrategy->Cipher( 278 Span{a + nByte - kReservedBytes, kIvBytes}, 279 Span{a + i, static_cast<unsigned>(payloadLength)}, 280 Span{a + i, static_cast<unsigned>(payloadLength)}); 281 memset(a + nByte - kReservedBytes, 0, kIvBytes); 282 } 283 284 /* 285 ** Close an obfsucated file. 286 */ 287 static int obfsClose(sqlite3_file* pFile) { 288 ObfsFile* p = (ObfsFile*)pFile; 289 if (p->pPartner) { 290 MOZ_ASSERT(p->pPartner->pPartner == p); 291 p->pPartner->pPartner = nullptr; 292 p->pPartner = nullptr; 293 } 294 sqlite3_free(p->pTemp); 295 296 delete p->decryptCipherStrategy; 297 delete p->encryptCipherStrategy; 298 299 pFile = ORIGFILE(pFile); 300 return pFile->pMethods->xClose(pFile); 301 } 302 303 /* 304 ** Read data from an obfuscated file. 305 ** 306 ** If the file is less than one full page in length, then return 307 ** a substitute "prototype" page-1. This prototype page one 308 ** specifies a database in WAL mode with an 8192-byte page size 309 ** and a 32-byte reserved-bytes value. Those settings are necessary 310 ** for obfuscation to function correctly. 311 */ 312 static int obfsRead(sqlite3_file* pFile, void* zBuf, int iAmt, 313 sqlite_int64 iOfst) { 314 int rc; 315 ObfsFile* p = (ObfsFile*)pFile; 316 pFile = ORIGFILE(pFile); 317 rc = pFile->pMethods->xRead(pFile, zBuf, iAmt, iOfst); 318 if (rc == SQLITE_OK) { 319 if ((iAmt == OBFS_PGSZ || iAmt == OBFS_PGSZ + WAL_FRAMEHDRSIZE) && 320 !p->inCkpt) { 321 obfsDecode(p, ((u8*)zBuf) + iAmt - OBFS_PGSZ, OBFS_PGSZ); 322 } 323 } else if (rc == SQLITE_IOERR_SHORT_READ && iOfst == 0 && iAmt >= 100) { 324 static const unsigned char aEmptyDb[] = { 325 // Offset 0, Size 16, The header string: "SQLite format 3\000" 326 0x53, 0x51, 0x4c, 0x69, 0x74, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x61, 327 0x74, 0x20, 0x33, 0x00, 328 // XXX Add description for other fields 329 0x20, 0x00, 0x02, 0x02, kReservedBytes, 0x40, 0x20, 0x20, 0x00, 0x00, 330 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 331 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 332 0x00, 0x00, 333 // Offset 52, Size 4, The page number of the largest root b-tree page 334 // when in auto-vacuum or incremental-vacuum modes, or zero otherwise. 335 0x00, 0x00, 0x00, 0x01}; 336 337 memcpy(zBuf, aEmptyDb, sizeof(aEmptyDb)); 338 memset(((u8*)zBuf) + sizeof(aEmptyDb), 0, iAmt - sizeof(aEmptyDb)); 339 rc = SQLITE_OK; 340 } 341 return rc; 342 } 343 344 /* 345 ** Write data to an obfuscated file or journal. 346 */ 347 static int obfsWrite(sqlite3_file* pFile, const void* zBuf, int iAmt, 348 sqlite_int64 iOfst) { 349 ObfsFile* p = (ObfsFile*)pFile; 350 pFile = ORIGFILE(pFile); 351 if (iAmt == OBFS_PGSZ && !p->inCkpt) { 352 zBuf = obfsEncode(p, (u8*)zBuf, iAmt); 353 if (zBuf == nullptr) { 354 return SQLITE_IOERR; 355 } 356 } 357 return pFile->pMethods->xWrite(pFile, zBuf, iAmt, iOfst); 358 } 359 360 /* 361 ** Truncate an obfuscated file. 362 */ 363 static int obfsTruncate(sqlite3_file* pFile, sqlite_int64 size) { 364 pFile = ORIGFILE(pFile); 365 return pFile->pMethods->xTruncate(pFile, size); 366 } 367 368 /* 369 ** Sync an obfuscated file. 370 */ 371 static int obfsSync(sqlite3_file* pFile, int flags) { 372 pFile = ORIGFILE(pFile); 373 return pFile->pMethods->xSync(pFile, flags); 374 } 375 376 /* 377 ** Return the current file-size of an obfuscated file. 378 */ 379 static int obfsFileSize(sqlite3_file* pFile, sqlite_int64* pSize) { 380 ObfsFile* p = (ObfsFile*)pFile; 381 pFile = ORIGFILE(p); 382 return pFile->pMethods->xFileSize(pFile, pSize); 383 } 384 385 /* 386 ** Lock an obfuscated file. 387 */ 388 static int obfsLock(sqlite3_file* pFile, int eLock) { 389 pFile = ORIGFILE(pFile); 390 return pFile->pMethods->xLock(pFile, eLock); 391 } 392 393 /* 394 ** Unlock an obfuscated file. 395 */ 396 static int obfsUnlock(sqlite3_file* pFile, int eLock) { 397 pFile = ORIGFILE(pFile); 398 return pFile->pMethods->xUnlock(pFile, eLock); 399 } 400 401 /* 402 ** Check if another file-handle holds a RESERVED lock on an obfuscated file. 403 */ 404 static int obfsCheckReservedLock(sqlite3_file* pFile, int* pResOut) { 405 pFile = ORIGFILE(pFile); 406 return pFile->pMethods->xCheckReservedLock(pFile, pResOut); 407 } 408 409 /* 410 ** File control method. For custom operations on an obfuscated file. 411 */ 412 static int obfsFileControl(sqlite3_file* pFile, int op, void* pArg) { 413 int rc; 414 ObfsFile* p = (ObfsFile*)pFile; 415 pFile = ORIGFILE(pFile); 416 if (op == SQLITE_FCNTL_PRAGMA) { 417 char** azArg = (char**)pArg; 418 MOZ_ASSERT(azArg[1] != nullptr); 419 if (azArg[2] != nullptr && sqlite3_stricmp(azArg[1], "page_size") == 0) { 420 /* Do not allow page size changes on an obfuscated database */ 421 return SQLITE_OK; 422 } 423 } else if (op == SQLITE_FCNTL_CKPT_START || op == SQLITE_FCNTL_CKPT_DONE) { 424 p->inCkpt = op == SQLITE_FCNTL_CKPT_START; 425 if (p->pPartner) { 426 p->pPartner->inCkpt = p->inCkpt; 427 } 428 } 429 rc = pFile->pMethods->xFileControl(pFile, op, pArg); 430 if (rc == SQLITE_OK && op == SQLITE_FCNTL_VFSNAME) { 431 *(char**)pArg = sqlite3_mprintf("obfs/%z", *(char**)pArg); 432 } 433 return rc; 434 } 435 436 /* 437 ** Return the sector-size in bytes for an obfuscated file. 438 */ 439 static int obfsSectorSize(sqlite3_file* pFile) { 440 pFile = ORIGFILE(pFile); 441 return pFile->pMethods->xSectorSize(pFile); 442 } 443 444 /* 445 ** Return the device characteristic flags supported by an obfuscated file. 446 */ 447 static int obfsDeviceCharacteristics(sqlite3_file* pFile) { 448 int dc; 449 pFile = ORIGFILE(pFile); 450 dc = pFile->pMethods->xDeviceCharacteristics(pFile); 451 return dc & ~SQLITE_IOCAP_SUBPAGE_READ; /* All except the 452 SQLITE_IOCAP_SUBPAGE_READ bit */ 453 } 454 455 /* Create a shared memory file mapping */ 456 static int obfsShmMap(sqlite3_file* pFile, int iPg, int pgsz, int bExtend, 457 void volatile** pp) { 458 pFile = ORIGFILE(pFile); 459 return pFile->pMethods->xShmMap(pFile, iPg, pgsz, bExtend, pp); 460 } 461 462 /* Perform locking on a shared-memory segment */ 463 static int obfsShmLock(sqlite3_file* pFile, int offset, int n, int flags) { 464 pFile = ORIGFILE(pFile); 465 return pFile->pMethods->xShmLock(pFile, offset, n, flags); 466 } 467 468 /* Memory barrier operation on shared memory */ 469 static void obfsShmBarrier(sqlite3_file* pFile) { 470 pFile = ORIGFILE(pFile); 471 pFile->pMethods->xShmBarrier(pFile); 472 } 473 474 /* Unmap a shared memory segment */ 475 static int obfsShmUnmap(sqlite3_file* pFile, int deleteFlag) { 476 pFile = ORIGFILE(pFile); 477 return pFile->pMethods->xShmUnmap(pFile, deleteFlag); 478 } 479 480 /* Fetch a page of a memory-mapped file */ 481 static int obfsFetch(sqlite3_file* pFile, sqlite3_int64 iOfst, int iAmt, 482 void** pp) { 483 *pp = nullptr; 484 return SQLITE_OK; 485 } 486 487 /* Release a memory-mapped page */ 488 static int obfsUnfetch(sqlite3_file* pFile, sqlite3_int64 iOfst, void* pPage) { 489 pFile = ORIGFILE(pFile); 490 return pFile->pMethods->xUnfetch(pFile, iOfst, pPage); 491 } 492 493 /* 494 ** Translate a single byte of Hex into an integer. 495 ** This routine only works if h really is a valid hexadecimal 496 ** character: 0..9a..fA..F 497 */ 498 static u8 obfsHexToInt(int h) { 499 MOZ_ASSERT((h >= '0' && h <= '9') || (h >= 'a' && h <= 'f') || 500 (h >= 'A' && h <= 'F')); 501 #if 1 /* ASCII */ 502 h += 9 * (1 & (h >> 6)); 503 #else /* EBCDIC */ 504 h += 9 * (1 & ~(h >> 4)); 505 #endif 506 return (u8)(h & 0xf); 507 } 508 509 /* 510 ** Open a new file. 511 ** 512 ** If the file is an ordinary database file, or a rollback or WAL journal 513 ** file, and if the key=XXXX parameter exists, then try to open the file 514 ** as an obfuscated database. All other open attempts fall through into 515 ** the lower-level VFS shim. 516 ** 517 ** If the key=XXXX parameter exists but is not 64-bytes of hex key, then 518 ** put an error message in NS_WARNING() and return SQLITE_CANTOPEN. 519 */ 520 static int obfsOpen(sqlite3_vfs* pVfs, const char* zName, sqlite3_file* pFile, 521 int flags, int* pOutFlags) { 522 ObfsFile* p; 523 sqlite3_file* pSubFile; 524 sqlite3_vfs* pSubVfs; 525 int rc, i; 526 const char* zKey; 527 u8 aKey[kKeyBytes]; 528 pSubVfs = ORIGVFS(pVfs); 529 if (flags & 530 (SQLITE_OPEN_MAIN_DB | SQLITE_OPEN_WAL | SQLITE_OPEN_MAIN_JOURNAL)) { 531 zKey = sqlite3_uri_parameter(zName, "key"); 532 } else { 533 zKey = nullptr; 534 } 535 if (zKey == nullptr) { 536 return pSubVfs->xOpen(pSubVfs, zName, pFile, flags, pOutFlags); 537 } 538 for (i = 0; 539 i < kKeyBytes && isxdigit(zKey[i * 2]) && isxdigit(zKey[i * 2 + 1]); 540 i++) { 541 aKey[i] = (obfsHexToInt(zKey[i * 2]) << 4) | obfsHexToInt(zKey[i * 2 + 1]); 542 } 543 if (i != kKeyBytes) { 544 NS_WARNING( 545 nsPrintfCString("invalid query parameter on %s: key=%s", zName, zKey) 546 .get()); 547 return SQLITE_CANTOPEN; 548 } 549 p = (ObfsFile*)pFile; 550 memset(p, 0, sizeof(*p)); 551 552 auto encryptCipherStrategy = MakeUnique<IPCStreamCipherStrategy>(); 553 auto decryptCipherStrategy = MakeUnique<IPCStreamCipherStrategy>(); 554 555 auto resetMethods = MakeScopeExit([pFile] { pFile->pMethods = nullptr; }); 556 557 if (NS_WARN_IF(NS_FAILED(encryptCipherStrategy->Init( 558 CipherMode::Encrypt, Span{aKey, sizeof(aKey)}, 559 IPCStreamCipherStrategy::MakeBlockPrefix())))) { 560 return SQLITE_ERROR; 561 } 562 563 if (NS_WARN_IF(NS_FAILED(decryptCipherStrategy->Init( 564 CipherMode::Decrypt, Span{aKey, sizeof(aKey)})))) { 565 return SQLITE_ERROR; 566 } 567 568 pSubFile = ORIGFILE(pFile); 569 p->base.pMethods = &obfs_io_methods; 570 rc = pSubVfs->xOpen(pSubVfs, zName, pSubFile, flags, pOutFlags); 571 if (rc) { 572 return rc; 573 } 574 575 resetMethods.release(); 576 577 if (flags & (SQLITE_OPEN_WAL | SQLITE_OPEN_MAIN_JOURNAL)) { 578 sqlite3_file* pDb = sqlite3_database_file_object(zName); 579 p->pPartner = (ObfsFile*)pDb; 580 MOZ_ASSERT(p->pPartner->pPartner == nullptr); 581 p->pPartner->pPartner = p; 582 } 583 p->zFName = zName; 584 585 p->encryptCipherStrategy = encryptCipherStrategy.release(); 586 p->decryptCipherStrategy = decryptCipherStrategy.release(); 587 588 return SQLITE_OK; 589 } 590 591 /* 592 ** All other VFS methods are pass-thrus. 593 */ 594 static int obfsDelete(sqlite3_vfs* pVfs, const char* zPath, int syncDir) { 595 return ORIGVFS(pVfs)->xDelete(ORIGVFS(pVfs), zPath, syncDir); 596 } 597 static int obfsAccess(sqlite3_vfs* pVfs, const char* zPath, int flags, 598 int* pResOut) { 599 return ORIGVFS(pVfs)->xAccess(ORIGVFS(pVfs), zPath, flags, pResOut); 600 } 601 static int obfsFullPathname(sqlite3_vfs* pVfs, const char* zPath, int nOut, 602 char* zOut) { 603 return ORIGVFS(pVfs)->xFullPathname(ORIGVFS(pVfs), zPath, nOut, zOut); 604 } 605 static void* obfsDlOpen(sqlite3_vfs* pVfs, const char* zPath) { 606 return ORIGVFS(pVfs)->xDlOpen(ORIGVFS(pVfs), zPath); 607 } 608 static void obfsDlError(sqlite3_vfs* pVfs, int nByte, char* zErrMsg) { 609 ORIGVFS(pVfs)->xDlError(ORIGVFS(pVfs), nByte, zErrMsg); 610 } 611 static void (*obfsDlSym(sqlite3_vfs* pVfs, void* p, const char* zSym))(void) { 612 return ORIGVFS(pVfs)->xDlSym(ORIGVFS(pVfs), p, zSym); 613 } 614 static void obfsDlClose(sqlite3_vfs* pVfs, void* pHandle) { 615 ORIGVFS(pVfs)->xDlClose(ORIGVFS(pVfs), pHandle); 616 } 617 static int obfsRandomness(sqlite3_vfs* pVfs, int nByte, char* zBufOut) { 618 return ORIGVFS(pVfs)->xRandomness(ORIGVFS(pVfs), nByte, zBufOut); 619 } 620 static int obfsSleep(sqlite3_vfs* pVfs, int nMicroseconds) { 621 return ORIGVFS(pVfs)->xSleep(ORIGVFS(pVfs), nMicroseconds); 622 } 623 static int obfsCurrentTime(sqlite3_vfs* pVfs, double* pTimeOut) { 624 return ORIGVFS(pVfs)->xCurrentTime(ORIGVFS(pVfs), pTimeOut); 625 } 626 static int obfsGetLastError(sqlite3_vfs* pVfs, int a, char* b) { 627 return ORIGVFS(pVfs)->xGetLastError(ORIGVFS(pVfs), a, b); 628 } 629 static int obfsCurrentTimeInt64(sqlite3_vfs* pVfs, sqlite3_int64* p) { 630 return ORIGVFS(pVfs)->xCurrentTimeInt64(ORIGVFS(pVfs), p); 631 } 632 static int obfsSetSystemCall(sqlite3_vfs* pVfs, const char* zName, 633 sqlite3_syscall_ptr pCall) { 634 return ORIGVFS(pVfs)->xSetSystemCall(ORIGVFS(pVfs), zName, pCall); 635 } 636 static sqlite3_syscall_ptr obfsGetSystemCall(sqlite3_vfs* pVfs, 637 const char* zName) { 638 return ORIGVFS(pVfs)->xGetSystemCall(ORIGVFS(pVfs), zName); 639 } 640 static const char* obfsNextSystemCall(sqlite3_vfs* pVfs, const char* zName) { 641 return ORIGVFS(pVfs)->xNextSystemCall(ORIGVFS(pVfs), zName); 642 } 643 644 namespace mozilla::storage::obfsvfs { 645 646 const char* GetVFSName() { return "obfsvfs"; } 647 648 UniquePtr<sqlite3_vfs> ConstructVFS(const char* aBaseVFSName) { 649 MOZ_ASSERT(aBaseVFSName); 650 651 if (sqlite3_vfs_find(GetVFSName()) != nullptr) { 652 return nullptr; 653 } 654 sqlite3_vfs* const pOrig = sqlite3_vfs_find(aBaseVFSName); 655 if (pOrig == nullptr) { 656 return nullptr; 657 } 658 659 #ifdef DEBUG 660 // If the VFS version is higher than the last known one, you should update 661 // this VFS adding appropriate methods for any methods added in the version 662 // change. 663 static constexpr int kLastKnownVfsVersion = 3; 664 MOZ_ASSERT(pOrig->iVersion <= kLastKnownVfsVersion); 665 #endif 666 667 const sqlite3_vfs obfs_vfs = { 668 pOrig->iVersion, /* iVersion */ 669 static_cast<int>(pOrig->szOsFile + sizeof(ObfsFile)), /* szOsFile */ 670 pOrig->mxPathname, /* mxPathname */ 671 nullptr, /* pNext */ 672 GetVFSName(), /* zName */ 673 pOrig, /* pAppData */ 674 obfsOpen, /* xOpen */ 675 obfsDelete, /* xDelete */ 676 obfsAccess, /* xAccess */ 677 obfsFullPathname, /* xFullPathname */ 678 obfsDlOpen, /* xDlOpen */ 679 obfsDlError, /* xDlError */ 680 obfsDlSym, /* xDlSym */ 681 obfsDlClose, /* xDlClose */ 682 obfsRandomness, /* xRandomness */ 683 obfsSleep, /* xSleep */ 684 obfsCurrentTime, /* xCurrentTime */ 685 obfsGetLastError, /* xGetLastError */ 686 obfsCurrentTimeInt64, /* xCurrentTimeInt64 */ 687 obfsSetSystemCall, /* xSetSystemCall */ 688 obfsGetSystemCall, /* xGetSystemCall */ 689 obfsNextSystemCall /* xNextSystemCall */ 690 }; 691 692 return MakeUnique<sqlite3_vfs>(obfs_vfs); 693 } 694 695 already_AddRefed<QuotaObject> GetQuotaObjectForFile(sqlite3_file* pFile) { 696 return quotavfs::GetQuotaObjectForFile(ORIGFILE(pFile)); 697 } 698 699 } // namespace mozilla::storage::obfsvfs