Avi Drissman | 69b874f | 2022-09-15 19:11:14 | [diff] [blame] | 1 | // Copyright 2019 The Chromium Authors |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 2 | // Use of this source code is governed by a BSD-style license that can be |
| 3 | // found in the LICENSE file. |
| 4 | |
| 5 | #ifndef SQL_SANDBOXED_VFS_H_ |
| 6 | #define SQL_SANDBOXED_VFS_H_ |
| 7 | |
| 8 | #include <stdint.h> |
| 9 | |
| 10 | #include <memory> |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 11 | #include <optional> |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 12 | |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 13 | #include <optional> |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 14 | #include "base/component_export.h" |
| 15 | #include "base/files/file.h" |
| 16 | #include "base/files/file_path.h" |
Gabriel Charette | d87f10f | 2022-03-31 00:44:22 | [diff] [blame] | 17 | #include "base/time/time.h" |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 18 | #include "third_party/sqlite/sqlite3.h" |
| 19 | |
| 20 | namespace sql { |
| 21 | |
Victor Costan | 959eab0 | 2020-08-17 18:33:56 | [diff] [blame] | 22 | // SQLite VFS file implementation that works in a sandboxed process. |
| 23 | // |
| 24 | // Instances are thread-friendly. |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 25 | class COMPONENT_EXPORT(SQL) SandboxedVfs { |
| 26 | public: |
| 27 | // Describes access rights for a path, used by Delegate::GetPathAccess below. |
| 28 | struct PathAccessInfo { |
| 29 | bool can_read = false; |
| 30 | bool can_write = false; |
| 31 | }; |
| 32 | |
Victor Costan | 959eab0 | 2020-08-17 18:33:56 | [diff] [blame] | 33 | // Environment-specific SandboxedVfs implementation details. |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 34 | // |
Victor Costan | 959eab0 | 2020-08-17 18:33:56 | [diff] [blame] | 35 | // This abstracts a handful of operations that don't typically work in a |
| 36 | // sandbox environment given a typical naive implementation. Instances must be |
| 37 | // thread-safe. |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 38 | class Delegate { |
| 39 | public: |
| 40 | virtual ~Delegate() = default; |
| 41 | |
Victor Costan | 959eab0 | 2020-08-17 18:33:56 | [diff] [blame] | 42 | // Opens a file. |
| 43 | // |
| 44 | // `file_path` is the parsed version of a path passed by SQLite to Open(). |
| 45 | // `sqlite_requested_flags` is a bitwise combination SQLite flags used when |
| 46 | // opening files. Returns the opened File on success, or an invalid File on |
| 47 | // failure. |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 48 | virtual base::File OpenFile(const base::FilePath& file_path, |
| 49 | int sqlite_requested_flags) = 0; |
| 50 | |
Victor Costan | 959eab0 | 2020-08-17 18:33:56 | [diff] [blame] | 51 | // Deletes a file. |
| 52 | // |
| 53 | // `file_path` is the parsed version of a path passed by SQLite to Delete(). |
| 54 | // If `sync_dir` is true, the implementation should attempt to flush to disk |
| 55 | // the changes to the file's directory, to ensure that the deletion is |
| 56 | // reflected after a power failure. Returns an SQLite error code indicating |
| 57 | // the status of the operation. |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 58 | virtual int DeleteFile(const base::FilePath& file_path, bool sync_dir) = 0; |
| 59 | |
| 60 | // Queries path access information for `file_path`. Returns null if the |
| 61 | // given path does not exist. |
Arthur Sonzogni | 59ac822 | 2023-11-10 09:46:54 | [diff] [blame] | 62 | virtual std::optional<PathAccessInfo> GetPathAccess( |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 63 | const base::FilePath& file_path) = 0; |
| 64 | |
Victor Costan | 959eab0 | 2020-08-17 18:33:56 | [diff] [blame] | 65 | // Resizes a file. |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 66 | // |
Victor Costan | 959eab0 | 2020-08-17 18:33:56 | [diff] [blame] | 67 | // `file` is the result of a previous call to Delegate::OpenFile() with |
| 68 | // `file_path`. `size` is the new desired size in bytes, and may be smaller |
| 69 | // or larger than the current file size. Returns true if successful and |
| 70 | // false otherwise. |
| 71 | // |
| 72 | // Implementations can modify `file` directly, or operate on the filesystem |
| 73 | // via `file_path`. |
| 74 | // |
| 75 | // This is only called after the direct approach of base::File::SetLength() |
| 76 | // fails. So, the implementation should not bother trying to call |
| 77 | // SetLength() on `file`. This currently only happens on macOS < 10.15. |
Ken Rockot | 7655fcb6 | 2020-08-12 19:22:40 | [diff] [blame] | 78 | virtual bool SetFileLength(const base::FilePath& file_path, |
| 79 | base::File& file, |
| 80 | size_t size) = 0; |
| 81 | }; |
| 82 | |
| 83 | // We don't allow SandboxedVfs instances to be destroyed. Once created, they |
| 84 | // are permanently registered in the calling process. |
| 85 | ~SandboxedVfs() = delete; |
| 86 | |
| 87 | // Constructs a new instance of ths object using `delegate` to support various |
| 88 | // operations from within the sandbox. The VFS is registered with SQLite under |
| 89 | // `name` and if `make_default` is true then the VFS is also set as the global |
| 90 | // default for new database instances within the calling process. |
| 91 | // |
| 92 | // Note that `name` must be globally unique to the calling process. |
| 93 | static void Register(const char* name, |
| 94 | std::unique_ptr<Delegate> delegate, |
| 95 | bool make_default); |
| 96 | |
| 97 | Delegate* delegate() const { return delegate_.get(); } |
| 98 | |
| 99 | // sqlite3_vfs implementation. |
| 100 | int Open(const char* full_path, |
| 101 | sqlite3_file& result_file, |
| 102 | int requested_flags, |
| 103 | int* granted_flags); |
| 104 | int Delete(const char* full_path, int sync_dir); |
| 105 | int Access(const char* full_path, int flags, int& result); |
| 106 | int FullPathname(const char* file_path, int result_size, char* result); |
| 107 | int Randomness(int result_size, char* result); |
| 108 | int Sleep(int microseconds); |
| 109 | int GetLastError(int message_size, char* message) const; |
| 110 | int CurrentTimeInt64(sqlite3_int64* result_ms); |
| 111 | |
| 112 | // Used by SandboxedVfsFile. |
| 113 | void SetLastError(base::File::Error error) { this->last_error_ = error; } |
| 114 | |
| 115 | private: |
| 116 | SandboxedVfs(const char* name, |
| 117 | std::unique_ptr<Delegate> delegate, |
| 118 | bool make_default); |
| 119 | |
| 120 | sqlite3_vfs sandboxed_vfs_; |
| 121 | const base::Time sqlite_epoch_; |
| 122 | const std::unique_ptr<Delegate> delegate_; |
| 123 | base::File::Error last_error_; |
| 124 | }; |
| 125 | |
| 126 | } // namespace sql |
| 127 | |
| 128 | #endif // SQL_SANDBOXED_VFS_H_ |