1 // Copyright 2019 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "sql/sandboxed_vfs.h"
14 #include "base/check_op.h"
15 #include "base/files/file.h"
16 #include "base/no_destructor.h"
17 #include "base/notreached.h"
18 #include "base/threading/platform_thread.h"
19 #include "build/build_config.h"
20 #include "sql/initialization.h"
21 #include "sql/sandboxed_vfs_file.h"
22 #include "third_party/sqlite/sqlite3.h"
28 // Extracts the SandboxedVfs* stashed in a SQLite VFS structure.
29 SandboxedVfs& SandboxedVfsFromSqliteVfs(sqlite3_vfs& vfs) {
30 return *reinterpret_cast<SandboxedVfs*>(vfs.pAppData);
33 int SandboxedVfsOpen(sqlite3_vfs* vfs,
34 const char* full_path,
35 sqlite3_file* result_file,
38 return SandboxedVfsFromSqliteVfs(*vfs).Open(full_path, *result_file,
39 requested_flags, granted_flags);
41 int SandboxedVfsDelete(sqlite3_vfs* vfs, const char* full_path, int sync_dir) {
42 return SandboxedVfsFromSqliteVfs(*vfs).Delete(full_path, sync_dir);
44 int SandboxedVfsAccess(sqlite3_vfs* vfs,
45 const char* full_path,
48 return SandboxedVfsFromSqliteVfs(*vfs).Access(full_path, flags, *result);
50 int SandboxedVfsFullPathname(sqlite3_vfs* vfs,
51 const char* file_path,
54 return SandboxedVfsFromSqliteVfs(*vfs).FullPathname(file_path, result_size,
57 int SandboxedVfsRandomness(sqlite3_vfs* vfs, int result_size, char* result) {
58 return SandboxedVfsFromSqliteVfs(*vfs).Randomness(result_size, result);
60 int SandboxedVfsSleep(sqlite3_vfs* vfs, int microseconds) {
61 return SandboxedVfsFromSqliteVfs(*vfs).Sleep(microseconds);
63 int SandboxedVfsGetLastError(sqlite3_vfs* vfs,
66 return SandboxedVfsFromSqliteVfs(*vfs).GetLastError(message_size, message);
68 int SandboxedVfsCurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* result_ms) {
69 return SandboxedVfsFromSqliteVfs(*vfs).CurrentTimeInt64(result_ms);
72 sqlite3_vfs SqliteVfsFor(SandboxedVfs* sandboxed_vfs, const char* name) {
73 DCHECK_EQ(sandboxed_vfs, reinterpret_cast<SandboxedVfs*>(
74 reinterpret_cast<void*>(sandboxed_vfs)))
75 << "This implementation round-trips SandboxedVfs* via void*";
77 // VFS API entry points are listed at https://www.sqlite.org/c3ref/vfs.html
78 static constexpr int kSqliteVfsApiVersion = 3;
80 // Maximum file path size.
81 // TODO(pwnall): Obtain this from //base or some other good place.
82 static constexpr int kSqliteMaxPathSize = 512;
86 sizeof(SandboxedVfsFileSqliteBridge),
90 /*pAppData=*/reinterpret_cast<void*>(sandboxed_vfs),
94 SandboxedVfsFullPathname,
99 SandboxedVfsRandomness,
101 /*xCurrentTime=*/nullptr, // Deprecated in API versions 2 and above.
102 SandboxedVfsGetLastError,
103 SandboxedVfsCurrentTimeInt64,
104 /*xSetSystemCall=*/nullptr,
105 /*xGetSystemCall=*/nullptr,
106 /*xNextSystemCall=*/nullptr,
110 // SQLite measures time according to the Julian calendar.
111 base::Time SqliteEpoch() {
112 // The ".5" is intentional -- days in the Julian calendar start at noon.
113 // The offset is in the SQLite source code (os_unix.c) multiplied by 10.
114 constexpr const double kUnixEpochAsJulianDay = 2440587.5;
116 return base::Time::FromMillisecondsSinceUnixEpoch(
117 -kUnixEpochAsJulianDay * base::Time::kMillisecondsPerDay);
121 // `full_path_cstr` must be a filename argument passed to the VFS from SQLite.
122 SandboxedVfsFileType VfsFileTypeFromPath(const char* full_path_cstr) {
123 base::StringPiece full_path(full_path_cstr);
125 const char* database_file_cstr = sqlite3_filename_database(full_path_cstr);
126 base::StringPiece database_file(database_file_cstr);
127 if (full_path == database_file)
128 return SandboxedVfsFileType::kDatabase;
130 const char* journal_file_cstr = sqlite3_filename_journal(full_path_cstr);
131 base::StringPiece journal_file(journal_file_cstr);
132 if (full_path == journal_file)
133 return SandboxedVfsFileType::kJournal;
135 const char* wal_file_cstr = sqlite3_filename_wal(full_path_cstr);
136 base::StringPiece wal_file(wal_file_cstr);
137 if (full_path == wal_file)
138 return SandboxedVfsFileType::kWal;
141 << "Argument is not a file name buffer passed from SQLite to a VFS: "
143 return SandboxedVfsFileType::kDatabase;
145 #endif // DCHECK_IS_ON()
150 void SandboxedVfs::Register(const char* name,
151 std::unique_ptr<Delegate> delegate,
153 static base::NoDestructor<std::vector<SandboxedVfs*>>
154 registered_vfs_instances;
155 sql::EnsureSqliteInitialized();
156 registered_vfs_instances->push_back(
157 new SandboxedVfs(name, std::move(delegate), make_default));
160 int SandboxedVfs::Open(const char* full_path,
161 sqlite3_file& result_file,
163 int* granted_flags) {
164 base::FilePath file_path = base::FilePath::FromUTF8Unsafe(full_path);
165 base::File file = delegate_->OpenFile(file_path, requested_flags);
166 if (!file.IsValid()) {
167 // TODO(pwnall): Figure out if we can remove the fallback to read-only.
168 if (!(requested_flags & SQLITE_OPEN_READWRITE)) {
169 // The SQLite API requires that pMethods is set to null even if the open
170 // call returns a failure status.
171 result_file.pMethods = nullptr;
172 return SQLITE_CANTOPEN;
176 (requested_flags & ~SQLITE_OPEN_READWRITE) | SQLITE_OPEN_READONLY;
177 return Open(full_path, result_file, new_flags, granted_flags);
180 SandboxedVfsFile::Create(std::move(file), std::move(file_path),
182 VfsFileTypeFromPath(full_path),
183 #endif // DCHECK_IS_ON()
186 *granted_flags = requested_flags;
190 int SandboxedVfs::Delete(const char* full_path, int sync_dir) {
192 return delegate_->DeleteFile(base::FilePath::FromUTF8Unsafe(full_path),
196 int SandboxedVfs::Access(const char* full_path, int flags, int& result) {
198 absl::optional<PathAccessInfo> access =
199 delegate_->GetPathAccess(base::FilePath::FromUTF8Unsafe(full_path));
206 case SQLITE_ACCESS_EXISTS:
209 case SQLITE_ACCESS_READ:
210 result = access->can_read ? 1 : 0;
212 case SQLITE_ACCESS_READWRITE:
213 result = (access->can_read && access->can_write) ? 1 : 0;
216 NOTREACHED() << "Unsupported xAccess flags: " << flags;
222 int SandboxedVfs::FullPathname(const char* file_path,
226 DCHECK_GT(result_size, 0);
229 // Renderer processes cannot access files directly, so it doesn't make sense
230 // to expose full paths here.
231 size_t file_path_size = std::strlen(file_path) + 1;
232 if (static_cast<size_t>(result_size) < file_path_size)
233 return SQLITE_CANTOPEN;
234 std::memcpy(result, file_path, file_path_size);
238 int SandboxedVfs::Randomness(int result_size, char* result) {
239 DCHECK_GT(result_size, 0);
242 // TODO(pwnall): Figure out if we need a real implementation.
243 std::memset(result, 0, result_size);
247 int SandboxedVfs::Sleep(int microseconds) {
248 DCHECK_GE(microseconds, 0);
249 base::PlatformThread::Sleep(base::Microseconds(microseconds));
253 int SandboxedVfs::GetLastError(int message_size, char* message) const {
254 DCHECK_GE(message_size, 0);
255 DCHECK(message_size == 0 || message);
257 std::string error_string = base::File::ErrorToString(last_error_);
258 size_t error_string_size = error_string.length() + 1;
260 std::min(static_cast<size_t>(message_size), error_string_size);
261 std::memcpy(message, error_string.c_str(), copy_length);
262 // The return value is zero if the message fits in the buffer, and non-zero if
264 return copy_length != error_string_size;
267 int SandboxedVfs::CurrentTimeInt64(sqlite3_int64* result_ms) {
270 base::TimeDelta delta = base::Time::Now() - sqlite_epoch_;
271 *result_ms = delta.InMilliseconds();
275 SandboxedVfs::SandboxedVfs(const char* name,
276 std::unique_ptr<Delegate> delegate,
278 : sandboxed_vfs_(SqliteVfsFor(this, name)),
279 sqlite_epoch_(SqliteEpoch()),
280 delegate_(std::move(delegate)),
281 last_error_(base::File::FILE_OK) {
282 // The register function returns a SQLite status as an int. The status is
283 // ignored here. If registration fails, we'd want to report the error while
284 // attempting to open a database. This is exactly what will happen, because
285 // SQLite won't find the VFS we're asking for.
286 sqlite3_vfs_register(&sandboxed_vfs_, make_default ? 1 : 0);