1 // Copyright 2019 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
5 #include "sql/sandboxed_vfs.h"
6
7 #include <algorithm>
8 #include <cstring>
9 #include <string>
10 #include <utility>
11 #include <vector>
12
13 #include "base/check_op.h"
14 #include "base/files/file.h"
15 #include "base/no_destructor.h"
16 #include "base/notreached.h"
17 #include "base/stl_util.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"
23
24 namespace sql {
25
26 namespace {
27
28 // Extracts the SandboxedVfs* stashed in a SQLite VFS structure.
SandboxedVfsFromSqliteVfs(sqlite3_vfs & vfs)29 SandboxedVfs& SandboxedVfsFromSqliteVfs(sqlite3_vfs& vfs) {
30 return *reinterpret_cast<SandboxedVfs*>(vfs.pAppData);
31 }
32
SandboxedVfsOpen(sqlite3_vfs * vfs,const char * full_path,sqlite3_file * result_file,int requested_flags,int * granted_flags)33 int SandboxedVfsOpen(sqlite3_vfs* vfs,
34 const char* full_path,
35 sqlite3_file* result_file,
36 int requested_flags,
37 int* granted_flags) {
38 return SandboxedVfsFromSqliteVfs(*vfs).Open(full_path, *result_file,
39 requested_flags, granted_flags);
40 }
SandboxedVfsDelete(sqlite3_vfs * vfs,const char * full_path,int sync_dir)41 int SandboxedVfsDelete(sqlite3_vfs* vfs, const char* full_path, int sync_dir) {
42 return SandboxedVfsFromSqliteVfs(*vfs).Delete(full_path, sync_dir);
43 }
SandboxedVfsAccess(sqlite3_vfs * vfs,const char * full_path,int flags,int * result)44 int SandboxedVfsAccess(sqlite3_vfs* vfs,
45 const char* full_path,
46 int flags,
47 int* result) {
48 return SandboxedVfsFromSqliteVfs(*vfs).Access(full_path, flags, *result);
49 }
SandboxedVfsFullPathname(sqlite3_vfs * vfs,const char * file_path,int result_size,char * result)50 int SandboxedVfsFullPathname(sqlite3_vfs* vfs,
51 const char* file_path,
52 int result_size,
53 char* result) {
54 return SandboxedVfsFromSqliteVfs(*vfs).FullPathname(file_path, result_size,
55 result);
56 }
SandboxedVfsRandomness(sqlite3_vfs * vfs,int result_size,char * result)57 int SandboxedVfsRandomness(sqlite3_vfs* vfs, int result_size, char* result) {
58 return SandboxedVfsFromSqliteVfs(*vfs).Randomness(result_size, result);
59 }
SandboxedVfsSleep(sqlite3_vfs * vfs,int microseconds)60 int SandboxedVfsSleep(sqlite3_vfs* vfs, int microseconds) {
61 return SandboxedVfsFromSqliteVfs(*vfs).Sleep(microseconds);
62 }
SandboxedVfsGetLastError(sqlite3_vfs * vfs,int message_size,char * message)63 int SandboxedVfsGetLastError(sqlite3_vfs* vfs,
64 int message_size,
65 char* message) {
66 return SandboxedVfsFromSqliteVfs(*vfs).GetLastError(message_size, message);
67 }
SandboxedVfsCurrentTimeInt64(sqlite3_vfs * vfs,sqlite3_int64 * result_ms)68 int SandboxedVfsCurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* result_ms) {
69 return SandboxedVfsFromSqliteVfs(*vfs).CurrentTimeInt64(result_ms);
70 }
71
SqliteVfsFor(SandboxedVfs * sandboxed_vfs,const char * name)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*";
76
77 // VFS API entry points are listed at https://www.sqlite.org/c3ref/vfs.html
78 static constexpr int kSqliteVfsApiVersion = 3;
79
80 // Maximum file path size.
81 // TODO(pwnall): Obtain this from //base or some other good place.
82 static constexpr int kSqliteMaxPathSize = 512;
83
84 return {
85 kSqliteVfsApiVersion,
86 sizeof(SandboxedVfsFileSqliteBridge),
87 kSqliteMaxPathSize,
88 /*pNext=*/nullptr,
89 name,
90 /*pAppData=*/reinterpret_cast<void*>(sandboxed_vfs),
91 SandboxedVfsOpen,
92 SandboxedVfsDelete,
93 SandboxedVfsAccess,
94 SandboxedVfsFullPathname,
95 /*xDlOpen=*/nullptr,
96 /*xDlError=*/nullptr,
97 /*xDlSym=*/nullptr,
98 /*xDlClose=*/nullptr,
99 SandboxedVfsRandomness,
100 SandboxedVfsSleep,
101 /*xCurrentTime=*/nullptr, // Deprecated in API versions 2 and above.
102 SandboxedVfsGetLastError,
103 SandboxedVfsCurrentTimeInt64,
104 /*xSetSystemCall=*/nullptr,
105 /*xGetSystemCall=*/nullptr,
106 /*xNextSystemCall=*/nullptr,
107 };
108 }
109
110 // SQLite measures time according to the Julian calendar.
SqliteEpoch()111 base::Time SqliteEpoch() {
112 constexpr const double kMicroSecondsPerDay = 24 * 60 * 60 * 1000;
113 // The ".5" is intentional -- days in the Julian calendar start at noon.
114 // The offset is in the SQLite source code (os_unix.c) multiplied by 10.
115 constexpr const double kUnixEpochAsJulianDay = 2440587.5;
116
117 return base::Time::FromJsTime(-kUnixEpochAsJulianDay * kMicroSecondsPerDay);
118 }
119
120 } // namespace
121
122 // static
Register(const char * name,std::unique_ptr<Delegate> delegate,bool make_default)123 void SandboxedVfs::Register(const char* name,
124 std::unique_ptr<Delegate> delegate,
125 bool make_default) {
126 static base::NoDestructor<std::vector<SandboxedVfs*>>
127 registered_vfs_instances;
128 sql::EnsureSqliteInitialized();
129 registered_vfs_instances->push_back(
130 new SandboxedVfs(name, std::move(delegate), make_default));
131 }
132
Open(const char * full_path,sqlite3_file & result_file,int requested_flags,int * granted_flags)133 int SandboxedVfs::Open(const char* full_path,
134 sqlite3_file& result_file,
135 int requested_flags,
136 int* granted_flags) {
137 base::FilePath file_path = base::FilePath::FromUTF8Unsafe(full_path);
138 base::File file = delegate_->OpenFile(file_path, requested_flags);
139 if (!file.IsValid()) {
140 // TODO(pwnall): Figure out if we can remove the fallback to read-only.
141 if (!(requested_flags & SQLITE_OPEN_READWRITE)) {
142 // The SQLite API requires that pMethods is set to null even if the open
143 // call returns a failure status.
144 result_file.pMethods = nullptr;
145 return SQLITE_CANTOPEN;
146 }
147
148 int new_flags =
149 (requested_flags & ~SQLITE_OPEN_READWRITE) | SQLITE_OPEN_READONLY;
150 return Open(full_path, result_file, new_flags, granted_flags);
151 }
152
153 SandboxedVfsFile::Create(std::move(file), std::move(file_path), this,
154 result_file);
155 if (granted_flags)
156 *granted_flags = requested_flags;
157 return SQLITE_OK;
158 }
159
Delete(const char * full_path,int sync_dir)160 int SandboxedVfs::Delete(const char* full_path, int sync_dir) {
161 DCHECK(full_path);
162 return delegate_->DeleteFile(base::FilePath::FromUTF8Unsafe(full_path),
163 sync_dir == 1);
164 }
165
Access(const char * full_path,int flags,int & result)166 int SandboxedVfs::Access(const char* full_path, int flags, int& result) {
167 DCHECK(full_path);
168 base::Optional<PathAccessInfo> access =
169 delegate_->GetPathAccess(base::FilePath::FromUTF8Unsafe(full_path));
170 if (!access) {
171 result = 0;
172 return SQLITE_OK;
173 }
174
175 switch (flags) {
176 case SQLITE_ACCESS_EXISTS:
177 result = 1;
178 break;
179 case SQLITE_ACCESS_READ:
180 result = access->can_read ? 1 : 0;
181 break;
182 case SQLITE_ACCESS_READWRITE:
183 result = (access->can_read && access->can_write) ? 1 : 0;
184 break;
185 default:
186 NOTREACHED() << "Unsupported xAccess flags: " << flags;
187 return SQLITE_ERROR;
188 }
189 return SQLITE_OK;
190 }
191
FullPathname(const char * file_path,int result_size,char * result)192 int SandboxedVfs::FullPathname(const char* file_path,
193 int result_size,
194 char* result) {
195 DCHECK(file_path);
196 DCHECK_GT(result_size, 0);
197 DCHECK(result);
198
199 // Renderer processes cannot access files directly, so it doesn't make sense
200 // to expose full paths here.
201 size_t file_path_size = std::strlen(file_path) + 1;
202 if (static_cast<size_t>(result_size) < file_path_size)
203 return SQLITE_CANTOPEN;
204 std::memcpy(result, file_path, file_path_size);
205 return SQLITE_OK;
206 }
207
Randomness(int result_size,char * result)208 int SandboxedVfs::Randomness(int result_size, char* result) {
209 DCHECK_GT(result_size, 0);
210 DCHECK(result);
211
212 // TODO(pwnall): Figure out if we need a real implementation.
213 std::memset(result, 0, result_size);
214 return result_size;
215 }
216
Sleep(int microseconds)217 int SandboxedVfs::Sleep(int microseconds) {
218 DCHECK_GE(microseconds, 0);
219 base::PlatformThread::Sleep(base::TimeDelta::FromMicroseconds(microseconds));
220 return SQLITE_OK;
221 }
222
GetLastError(int message_size,char * message) const223 int SandboxedVfs::GetLastError(int message_size, char* message) const {
224 DCHECK_GE(message_size, 0);
225 DCHECK(message_size == 0 || message);
226
227 std::string error_string = base::File::ErrorToString(last_error_);
228 size_t error_string_size = error_string.length() + 1;
229 size_t copy_length =
230 std::min(static_cast<size_t>(message_size), error_string_size);
231 std::memcpy(message, error_string.c_str(), copy_length);
232 // The return value is zero if the message fits in the buffer, and non-zero if
233 // it does not fit.
234 return copy_length != error_string_size;
235 }
236
CurrentTimeInt64(sqlite3_int64 * result_ms)237 int SandboxedVfs::CurrentTimeInt64(sqlite3_int64* result_ms) {
238 DCHECK(result_ms);
239
240 base::TimeDelta delta = base::Time::Now() - sqlite_epoch_;
241 *result_ms = delta.InMilliseconds();
242 return SQLITE_OK;
243 }
244
SandboxedVfs(const char * name,std::unique_ptr<Delegate> delegate,bool make_default)245 SandboxedVfs::SandboxedVfs(const char* name,
246 std::unique_ptr<Delegate> delegate,
247 bool make_default)
248 : sandboxed_vfs_(SqliteVfsFor(this, name)),
249 sqlite_epoch_(SqliteEpoch()),
250 delegate_(std::move(delegate)),
251 last_error_(base::File::FILE_OK) {
252 // The register function returns a SQLite status as an int. The status is
253 // ignored here. If registration fails, we'd want to report the error while
254 // attempting to open a database. This is exactly what will happen, because
255 // SQLite won't find the VFS we're asking for.
256 sqlite3_vfs_register(&sandboxed_vfs_, make_default ? 1 : 0);
257 }
258
259 } // namespace sql
260