vfs_wrapper.cc 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. // Copyright (c) 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "sql/vfs_wrapper.h"
  5. #include <algorithm>
  6. #include <string>
  7. #include <vector>
  8. #include "base/check_op.h"
  9. #include "base/debug/leak_annotations.h"
  10. #include "base/files/file_path.h"
  11. #include "base/memory/ptr_util.h"
  12. #include "base/metrics/histogram_macros.h"
  13. #include "base/notreached.h"
  14. #include "base/strings/string_piece.h"
  15. #include "build/build_config.h"
  16. #if BUILDFLAG(IS_APPLE)
  17. #include "base/mac/backup_util.h"
  18. #endif
  19. #if BUILDFLAG(IS_FUCHSIA)
  20. #include "sql/vfs_wrapper_fuchsia.h"
  21. #endif
  22. namespace sql {
  23. namespace {
  24. // https://www.sqlite.org/vfs.html - documents the overall VFS system.
  25. //
  26. // https://www.sqlite.org/c3ref/vfs.html - VFS methods. This code tucks the
  27. // wrapped VFS pointer into the wrapper's pAppData pointer.
  28. //
  29. // https://www.sqlite.org/c3ref/file.html - instance of an open file. This code
  30. // allocates a VfsFile for this, which contains a pointer to the wrapped file.
  31. // Idiomatic SQLite would take the wrapped VFS szOsFile and increase it to store
  32. // additional data as a prefix.
  33. sqlite3_vfs* GetWrappedVfs(sqlite3_vfs* wrapped_vfs) {
  34. return static_cast<sqlite3_vfs*>(wrapped_vfs->pAppData);
  35. }
  36. VfsFile* AsVfsFile(sqlite3_file* wrapper_file) {
  37. return reinterpret_cast<VfsFile*>(wrapper_file);
  38. }
  39. sqlite3_file* GetWrappedFile(sqlite3_file* wrapper_file) {
  40. return AsVfsFile(wrapper_file)->wrapped_file;
  41. }
  42. int Close(sqlite3_file* sqlite_file) {
  43. #if BUILDFLAG(IS_FUCHSIA)
  44. // Other platforms automatically unlock when the file descriptor is closed,
  45. // but the fuchsia virtual implementation doesn't have that so it needs an
  46. // explicit unlock on close.
  47. Unlock(sqlite_file, SQLITE_LOCK_NONE);
  48. #endif
  49. VfsFile* file = AsVfsFile(sqlite_file);
  50. int r = file->wrapped_file->pMethods->xClose(file->wrapped_file);
  51. sqlite3_free(file->wrapped_file);
  52. // Memory will be freed with sqlite3_free(), so the destructor needs to be
  53. // called explicitly.
  54. file->~VfsFile();
  55. memset(file, '\0', sizeof(*file));
  56. return r;
  57. }
  58. int Read(sqlite3_file* sqlite_file, void* buf, int amt, sqlite3_int64 ofs)
  59. {
  60. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  61. return wrapped_file->pMethods->xRead(wrapped_file, buf, amt, ofs);
  62. }
  63. int Write(sqlite3_file* sqlite_file, const void* buf, int amt,
  64. sqlite3_int64 ofs)
  65. {
  66. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  67. return wrapped_file->pMethods->xWrite(wrapped_file, buf, amt, ofs);
  68. }
  69. int Truncate(sqlite3_file* sqlite_file, sqlite3_int64 size)
  70. {
  71. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  72. return wrapped_file->pMethods->xTruncate(wrapped_file, size);
  73. }
  74. int Sync(sqlite3_file* sqlite_file, int flags)
  75. {
  76. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  77. return wrapped_file->pMethods->xSync(wrapped_file, flags);
  78. }
  79. int FileSize(sqlite3_file* sqlite_file, sqlite3_int64* size)
  80. {
  81. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  82. return wrapped_file->pMethods->xFileSize(wrapped_file, size);
  83. }
  84. #if !BUILDFLAG(IS_FUCHSIA)
  85. int Lock(sqlite3_file* sqlite_file, int file_lock)
  86. {
  87. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  88. return wrapped_file->pMethods->xLock(wrapped_file, file_lock);
  89. }
  90. int Unlock(sqlite3_file* sqlite_file, int file_lock)
  91. {
  92. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  93. return wrapped_file->pMethods->xUnlock(wrapped_file, file_lock);
  94. }
  95. int CheckReservedLock(sqlite3_file* sqlite_file, int* result)
  96. {
  97. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  98. return wrapped_file->pMethods->xCheckReservedLock(wrapped_file, result);
  99. }
  100. #endif // !BUILDFLAG(IS_FUCHSIA)
  101. // Else these functions are imported via vfs_wrapper_fuchsia.h.
  102. int FileControl(sqlite3_file* sqlite_file, int op, void* arg)
  103. {
  104. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  105. return wrapped_file->pMethods->xFileControl(wrapped_file, op, arg);
  106. }
  107. int SectorSize(sqlite3_file* sqlite_file)
  108. {
  109. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  110. return wrapped_file->pMethods->xSectorSize(wrapped_file);
  111. }
  112. int DeviceCharacteristics(sqlite3_file* sqlite_file)
  113. {
  114. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  115. return wrapped_file->pMethods->xDeviceCharacteristics(wrapped_file);
  116. }
  117. int ShmMap(sqlite3_file *sqlite_file, int region, int size,
  118. int extend, void volatile **pp) {
  119. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  120. return wrapped_file->pMethods->xShmMap(
  121. wrapped_file, region, size, extend, pp);
  122. }
  123. int ShmLock(sqlite3_file *sqlite_file, int ofst, int n, int flags) {
  124. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  125. return wrapped_file->pMethods->xShmLock(wrapped_file, ofst, n, flags);
  126. }
  127. void ShmBarrier(sqlite3_file *sqlite_file) {
  128. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  129. wrapped_file->pMethods->xShmBarrier(wrapped_file);
  130. }
  131. int ShmUnmap(sqlite3_file *sqlite_file, int del) {
  132. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  133. return wrapped_file->pMethods->xShmUnmap(wrapped_file, del);
  134. }
  135. int Fetch(sqlite3_file *sqlite_file, sqlite3_int64 off, int amt, void **pp) {
  136. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  137. return wrapped_file->pMethods->xFetch(wrapped_file, off, amt, pp);
  138. }
  139. int Unfetch(sqlite3_file *sqlite_file, sqlite3_int64 off, void *p) {
  140. sqlite3_file* wrapped_file = GetWrappedFile(sqlite_file);
  141. return wrapped_file->pMethods->xUnfetch(wrapped_file, off, p);
  142. }
  143. int Open(sqlite3_vfs* vfs, const char* file_name, sqlite3_file* wrapper_file,
  144. int desired_flags, int* used_flags) {
  145. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  146. sqlite3_file* wrapped_file = static_cast<sqlite3_file*>(
  147. sqlite3_malloc(wrapped_vfs->szOsFile));
  148. if (!wrapped_file)
  149. return SQLITE_NOMEM;
  150. // NOTE(shess): SQLite's unixOpen() makes assumptions about the structure of
  151. // |file_name|. Do not pass a local copy, here, only the passed-in value.
  152. int rc = wrapped_vfs->xOpen(wrapped_vfs,
  153. file_name, wrapped_file,
  154. desired_flags, used_flags);
  155. if (rc != SQLITE_OK) {
  156. sqlite3_free(wrapped_file);
  157. return rc;
  158. }
  159. // NOTE(shess): Any early exit from here needs to call xClose() on
  160. // |wrapped_file|.
  161. #if BUILDFLAG(IS_APPLE)
  162. // When opening journal files, propagate backup exclusion from db.
  163. static int kJournalFlags =
  164. SQLITE_OPEN_MAIN_JOURNAL | SQLITE_OPEN_TEMP_JOURNAL |
  165. SQLITE_OPEN_SUBJOURNAL | SQLITE_OPEN_MASTER_JOURNAL;
  166. if (file_name && (desired_flags & kJournalFlags)) {
  167. // https://www.sqlite.org/c3ref/vfs.html indicates that the journal path
  168. // will have a suffix separated by "-" from the main database file name.
  169. base::StringPiece file_name_string_piece(file_name);
  170. size_t dash_index = file_name_string_piece.rfind('-');
  171. if (dash_index != base::StringPiece::npos) {
  172. base::StringPiece db_name(file_name, dash_index);
  173. if (base::mac::GetBackupExclusion(base::FilePath(db_name))) {
  174. base::mac::SetBackupExclusion(base::FilePath(file_name_string_piece));
  175. }
  176. }
  177. }
  178. #endif
  179. // |iVersion| determines what methods SQLite may call on the instance.
  180. // Having the methods which can't be proxied return an error may cause SQLite
  181. // to operate differently than if it didn't call those methods at all. To be
  182. // on the safe side, the wrapper sqlite3_io_methods version perfectly matches
  183. // the version of the wrapped files.
  184. //
  185. // At a first glance, it might be tempting to simplify the code by
  186. // restricting wrapping support to VFS version 3. However, this might fail on
  187. // Mac.
  188. //
  189. // On Mac, SQLite built with SQLITE_ENABLE_LOCKING_STYLE ends up using a VFS
  190. // that dynamically dispatches between a few variants of sqlite3_io_methods,
  191. // based on whether the opened database is on a local or on a remote (AFS,
  192. // NFS) filesystem. Some variants return a VFS version 1 structure.
  193. VfsFile* file = AsVfsFile(wrapper_file);
  194. // Call constructor explicitly since the memory is already allocated.
  195. new (file) VfsFile();
  196. file->wrapped_file = wrapped_file;
  197. #if BUILDFLAG(IS_FUCHSIA)
  198. file->file_name = file_name;
  199. #endif
  200. if (wrapped_file->pMethods->iVersion == 1) {
  201. static const sqlite3_io_methods io_methods = {
  202. 1,
  203. Close,
  204. Read,
  205. Write,
  206. Truncate,
  207. Sync,
  208. FileSize,
  209. Lock,
  210. Unlock,
  211. CheckReservedLock,
  212. FileControl,
  213. SectorSize,
  214. DeviceCharacteristics,
  215. };
  216. file->methods = &io_methods;
  217. } else if (wrapped_file->pMethods->iVersion == 2) {
  218. static const sqlite3_io_methods io_methods = {
  219. 2,
  220. Close,
  221. Read,
  222. Write,
  223. Truncate,
  224. Sync,
  225. FileSize,
  226. Lock,
  227. Unlock,
  228. CheckReservedLock,
  229. FileControl,
  230. SectorSize,
  231. DeviceCharacteristics,
  232. // Methods above are valid for version 1.
  233. ShmMap,
  234. ShmLock,
  235. ShmBarrier,
  236. ShmUnmap,
  237. };
  238. file->methods = &io_methods;
  239. } else {
  240. static const sqlite3_io_methods io_methods = {
  241. 3,
  242. Close,
  243. Read,
  244. Write,
  245. Truncate,
  246. Sync,
  247. FileSize,
  248. Lock,
  249. Unlock,
  250. CheckReservedLock,
  251. FileControl,
  252. SectorSize,
  253. DeviceCharacteristics,
  254. // Methods above are valid for version 1.
  255. ShmMap,
  256. ShmLock,
  257. ShmBarrier,
  258. ShmUnmap,
  259. // Methods above are valid for version 2.
  260. Fetch,
  261. Unfetch,
  262. };
  263. file->methods = &io_methods;
  264. }
  265. return SQLITE_OK;
  266. }
  267. int Delete(sqlite3_vfs* vfs, const char* file_name, int sync_dir) {
  268. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  269. return wrapped_vfs->xDelete(wrapped_vfs, file_name, sync_dir);
  270. }
  271. int Access(sqlite3_vfs* vfs, const char* file_name, int flag, int* res) {
  272. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  273. return wrapped_vfs->xAccess(wrapped_vfs, file_name, flag, res);
  274. }
  275. int FullPathname(sqlite3_vfs* vfs, const char* relative_path,
  276. int buf_size, char* absolute_path) {
  277. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  278. return wrapped_vfs->xFullPathname(
  279. wrapped_vfs, relative_path, buf_size, absolute_path);
  280. }
  281. int Randomness(sqlite3_vfs* vfs, int buf_size, char* buffer) {
  282. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  283. return wrapped_vfs->xRandomness(wrapped_vfs, buf_size, buffer);
  284. }
  285. int Sleep(sqlite3_vfs* vfs, int microseconds) {
  286. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  287. return wrapped_vfs->xSleep(wrapped_vfs, microseconds);
  288. }
  289. int GetLastError(sqlite3_vfs* vfs, int e, char* s) {
  290. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  291. return wrapped_vfs->xGetLastError(wrapped_vfs, e, s);
  292. }
  293. int CurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* now) {
  294. sqlite3_vfs* wrapped_vfs = GetWrappedVfs(vfs);
  295. return wrapped_vfs->xCurrentTimeInt64(wrapped_vfs, now);
  296. }
  297. } // namespace
  298. sqlite3_vfs* VFSWrapper() {
  299. static constexpr char kVFSName[] = "VFSWrapper";
  300. // Return existing version if already registered.
  301. {
  302. sqlite3_vfs* vfs = sqlite3_vfs_find(kVFSName);
  303. if (vfs)
  304. return vfs;
  305. }
  306. // Get the default VFS on all platforms except Fuchsia.
  307. static constexpr const char* kBaseVfsName =
  308. #if BUILDFLAG(IS_FUCHSIA)
  309. "unix-none";
  310. #else
  311. nullptr;
  312. #endif
  313. sqlite3_vfs* wrapped_vfs = sqlite3_vfs_find(kBaseVfsName);
  314. // Give up if there is no VFS implementation for the current platform.
  315. if (!wrapped_vfs) {
  316. NOTREACHED();
  317. return nullptr;
  318. }
  319. std::unique_ptr<sqlite3_vfs, std::function<void(sqlite3_vfs*)>> wrapper_vfs(
  320. static_cast<sqlite3_vfs*>(sqlite3_malloc(sizeof(sqlite3_vfs))),
  321. [](sqlite3_vfs* v) {
  322. sqlite3_free(v);
  323. });
  324. memset(wrapper_vfs.get(), '\0', sizeof(sqlite3_vfs));
  325. // VFS implementations should always work with a SQLite that only knows about
  326. // earlier versions.
  327. constexpr int kSqliteVfsApiVersion = 3;
  328. wrapper_vfs->iVersion = kSqliteVfsApiVersion;
  329. // All the SQLite VFS implementations used by Chrome should support the
  330. // version proxied here.
  331. DCHECK_GE(wrapped_vfs->iVersion, kSqliteVfsApiVersion);
  332. // Caller of xOpen() allocates this much space.
  333. wrapper_vfs->szOsFile = sizeof(VfsFile);
  334. wrapper_vfs->mxPathname = wrapped_vfs->mxPathname;
  335. wrapper_vfs->pNext = nullptr; // Field used by SQLite.
  336. wrapper_vfs->zName = kVFSName;
  337. // Keep a reference to the wrapped vfs for use in methods.
  338. wrapper_vfs->pAppData = wrapped_vfs;
  339. // VFS methods.
  340. wrapper_vfs->xOpen = &Open;
  341. wrapper_vfs->xDelete = &Delete;
  342. wrapper_vfs->xAccess = &Access;
  343. wrapper_vfs->xFullPathname = &FullPathname;
  344. // SQLite's dynamic extension loading is disabled in Chrome. Not proxying
  345. // these methods lets us ship less logic and provides a tiny bit of extra
  346. // security, as we know for sure that SQLite will not dynamically load code.
  347. wrapper_vfs->xDlOpen = nullptr;
  348. wrapper_vfs->xDlError = nullptr;
  349. wrapper_vfs->xDlSym = nullptr;
  350. wrapper_vfs->xDlClose = nullptr;
  351. wrapper_vfs->xRandomness = &Randomness;
  352. wrapper_vfs->xSleep = &Sleep;
  353. // |xCurrentTime| is null when SQLite is built with SQLITE_OMIT_DEPRECATED, so
  354. // it does not need to be proxied.
  355. wrapper_vfs->xCurrentTime = nullptr;
  356. wrapper_vfs->xGetLastError = &GetLastError;
  357. // The methods above are in version 1 of SQLite's VFS API.
  358. DCHECK(wrapped_vfs->xCurrentTimeInt64 != nullptr);
  359. wrapper_vfs->xCurrentTimeInt64 = &CurrentTimeInt64;
  360. // The methods above are in version 2 of SQLite's VFS API.
  361. // The VFS system call interception API is intended for very low-level SQLite
  362. // testing and tweaks. Proxying these methods is not necessary because Chrome
  363. // does not do very low-level SQLite testing, and the VFS wrapper supports all
  364. // the needed tweaks.
  365. wrapper_vfs->xSetSystemCall = nullptr;
  366. wrapper_vfs->xGetSystemCall = nullptr;
  367. wrapper_vfs->xNextSystemCall = nullptr;
  368. // The methods above are in version 3 of sqlite_vfs.
  369. if (SQLITE_OK == sqlite3_vfs_register(wrapper_vfs.get(), 0)) {
  370. ANNOTATE_LEAKING_OBJECT_PTR(wrapper_vfs.get());
  371. wrapper_vfs.release();
  372. }
  373. return sqlite3_vfs_find(kVFSName);
  374. }
  375. } // namespace sql