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