123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288 |
- // Copyright 2019 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #include "sql/sandboxed_vfs.h"
- #include <algorithm>
- #include <cstring>
- #include <string>
- #include <utility>
- #include <vector>
- #include "base/check_op.h"
- #include "base/files/file.h"
- #include "base/no_destructor.h"
- #include "base/notreached.h"
- #include "base/threading/platform_thread.h"
- #include "build/build_config.h"
- #include "sql/initialization.h"
- #include "sql/sandboxed_vfs_file.h"
- #include "third_party/sqlite/sqlite3.h"
- namespace sql {
- namespace {
- // Extracts the SandboxedVfs* stashed in a SQLite VFS structure.
- SandboxedVfs& SandboxedVfsFromSqliteVfs(sqlite3_vfs& vfs) {
- return *reinterpret_cast<SandboxedVfs*>(vfs.pAppData);
- }
- int SandboxedVfsOpen(sqlite3_vfs* vfs,
- const char* full_path,
- sqlite3_file* result_file,
- int requested_flags,
- int* granted_flags) {
- return SandboxedVfsFromSqliteVfs(*vfs).Open(full_path, *result_file,
- requested_flags, granted_flags);
- }
- int SandboxedVfsDelete(sqlite3_vfs* vfs, const char* full_path, int sync_dir) {
- return SandboxedVfsFromSqliteVfs(*vfs).Delete(full_path, sync_dir);
- }
- int SandboxedVfsAccess(sqlite3_vfs* vfs,
- const char* full_path,
- int flags,
- int* result) {
- return SandboxedVfsFromSqliteVfs(*vfs).Access(full_path, flags, *result);
- }
- int SandboxedVfsFullPathname(sqlite3_vfs* vfs,
- const char* file_path,
- int result_size,
- char* result) {
- return SandboxedVfsFromSqliteVfs(*vfs).FullPathname(file_path, result_size,
- result);
- }
- int SandboxedVfsRandomness(sqlite3_vfs* vfs, int result_size, char* result) {
- return SandboxedVfsFromSqliteVfs(*vfs).Randomness(result_size, result);
- }
- int SandboxedVfsSleep(sqlite3_vfs* vfs, int microseconds) {
- return SandboxedVfsFromSqliteVfs(*vfs).Sleep(microseconds);
- }
- int SandboxedVfsGetLastError(sqlite3_vfs* vfs,
- int message_size,
- char* message) {
- return SandboxedVfsFromSqliteVfs(*vfs).GetLastError(message_size, message);
- }
- int SandboxedVfsCurrentTimeInt64(sqlite3_vfs* vfs, sqlite3_int64* result_ms) {
- return SandboxedVfsFromSqliteVfs(*vfs).CurrentTimeInt64(result_ms);
- }
- sqlite3_vfs SqliteVfsFor(SandboxedVfs* sandboxed_vfs, const char* name) {
- DCHECK_EQ(sandboxed_vfs, reinterpret_cast<SandboxedVfs*>(
- reinterpret_cast<void*>(sandboxed_vfs)))
- << "This implementation round-trips SandboxedVfs* via void*";
- // VFS API entry points are listed at https://www.sqlite.org/c3ref/vfs.html
- static constexpr int kSqliteVfsApiVersion = 3;
- // Maximum file path size.
- // TODO(pwnall): Obtain this from //base or some other good place.
- static constexpr int kSqliteMaxPathSize = 512;
- return {
- kSqliteVfsApiVersion,
- sizeof(SandboxedVfsFileSqliteBridge),
- kSqliteMaxPathSize,
- /*pNext=*/nullptr,
- name,
- /*pAppData=*/reinterpret_cast<void*>(sandboxed_vfs),
- SandboxedVfsOpen,
- SandboxedVfsDelete,
- SandboxedVfsAccess,
- SandboxedVfsFullPathname,
- /*xDlOpen=*/nullptr,
- /*xDlError=*/nullptr,
- /*xDlSym=*/nullptr,
- /*xDlClose=*/nullptr,
- SandboxedVfsRandomness,
- SandboxedVfsSleep,
- /*xCurrentTime=*/nullptr, // Deprecated in API versions 2 and above.
- SandboxedVfsGetLastError,
- SandboxedVfsCurrentTimeInt64,
- /*xSetSystemCall=*/nullptr,
- /*xGetSystemCall=*/nullptr,
- /*xNextSystemCall=*/nullptr,
- };
- }
- // SQLite measures time according to the Julian calendar.
- base::Time SqliteEpoch() {
- constexpr const double kMicroSecondsPerDay = 24 * 60 * 60 * 1000;
- // The ".5" is intentional -- days in the Julian calendar start at noon.
- // The offset is in the SQLite source code (os_unix.c) multiplied by 10.
- constexpr const double kUnixEpochAsJulianDay = 2440587.5;
- return base::Time::FromJsTime(-kUnixEpochAsJulianDay * kMicroSecondsPerDay);
- }
- #if DCHECK_IS_ON()
- // `full_path_cstr` must be a filename argument passed to the VFS from SQLite.
- SandboxedVfsFileType VfsFileTypeFromPath(const char* full_path_cstr) {
- base::StringPiece full_path(full_path_cstr);
- const char* database_file_cstr = sqlite3_filename_database(full_path_cstr);
- base::StringPiece database_file(database_file_cstr);
- if (full_path == database_file)
- return SandboxedVfsFileType::kDatabase;
- const char* journal_file_cstr = sqlite3_filename_journal(full_path_cstr);
- base::StringPiece journal_file(journal_file_cstr);
- if (full_path == journal_file)
- return SandboxedVfsFileType::kJournal;
- const char* wal_file_cstr = sqlite3_filename_wal(full_path_cstr);
- base::StringPiece wal_file(wal_file_cstr);
- if (full_path == wal_file)
- return SandboxedVfsFileType::kWal;
- NOTREACHED()
- << "Argument is not a file name buffer passed from SQLite to a VFS: "
- << full_path;
- return SandboxedVfsFileType::kDatabase;
- }
- #endif // DCHECK_IS_ON()
- } // namespace
- // static
- void SandboxedVfs::Register(const char* name,
- std::unique_ptr<Delegate> delegate,
- bool make_default) {
- static base::NoDestructor<std::vector<SandboxedVfs*>>
- registered_vfs_instances;
- sql::EnsureSqliteInitialized();
- registered_vfs_instances->push_back(
- new SandboxedVfs(name, std::move(delegate), make_default));
- }
- int SandboxedVfs::Open(const char* full_path,
- sqlite3_file& result_file,
- int requested_flags,
- int* granted_flags) {
- base::FilePath file_path = base::FilePath::FromUTF8Unsafe(full_path);
- base::File file = delegate_->OpenFile(file_path, requested_flags);
- if (!file.IsValid()) {
- // TODO(pwnall): Figure out if we can remove the fallback to read-only.
- if (!(requested_flags & SQLITE_OPEN_READWRITE)) {
- // The SQLite API requires that pMethods is set to null even if the open
- // call returns a failure status.
- result_file.pMethods = nullptr;
- return SQLITE_CANTOPEN;
- }
- int new_flags =
- (requested_flags & ~SQLITE_OPEN_READWRITE) | SQLITE_OPEN_READONLY;
- return Open(full_path, result_file, new_flags, granted_flags);
- }
- SandboxedVfsFile::Create(std::move(file), std::move(file_path),
- #if DCHECK_IS_ON()
- VfsFileTypeFromPath(full_path),
- #endif // DCHECK_IS_ON()
- this, result_file);
- if (granted_flags)
- *granted_flags = requested_flags;
- return SQLITE_OK;
- }
- int SandboxedVfs::Delete(const char* full_path, int sync_dir) {
- DCHECK(full_path);
- return delegate_->DeleteFile(base::FilePath::FromUTF8Unsafe(full_path),
- sync_dir == 1);
- }
- int SandboxedVfs::Access(const char* full_path, int flags, int& result) {
- DCHECK(full_path);
- absl::optional<PathAccessInfo> access =
- delegate_->GetPathAccess(base::FilePath::FromUTF8Unsafe(full_path));
- if (!access) {
- result = 0;
- return SQLITE_OK;
- }
- switch (flags) {
- case SQLITE_ACCESS_EXISTS:
- result = 1;
- break;
- case SQLITE_ACCESS_READ:
- result = access->can_read ? 1 : 0;
- break;
- case SQLITE_ACCESS_READWRITE:
- result = (access->can_read && access->can_write) ? 1 : 0;
- break;
- default:
- NOTREACHED() << "Unsupported xAccess flags: " << flags;
- return SQLITE_ERROR;
- }
- return SQLITE_OK;
- }
- int SandboxedVfs::FullPathname(const char* file_path,
- int result_size,
- char* result) {
- DCHECK(file_path);
- DCHECK_GT(result_size, 0);
- DCHECK(result);
- // Renderer processes cannot access files directly, so it doesn't make sense
- // to expose full paths here.
- size_t file_path_size = std::strlen(file_path) + 1;
- if (static_cast<size_t>(result_size) < file_path_size)
- return SQLITE_CANTOPEN;
- std::memcpy(result, file_path, file_path_size);
- return SQLITE_OK;
- }
- int SandboxedVfs::Randomness(int result_size, char* result) {
- DCHECK_GT(result_size, 0);
- DCHECK(result);
- // TODO(pwnall): Figure out if we need a real implementation.
- std::memset(result, 0, result_size);
- return result_size;
- }
- int SandboxedVfs::Sleep(int microseconds) {
- DCHECK_GE(microseconds, 0);
- base::PlatformThread::Sleep(base::Microseconds(microseconds));
- return SQLITE_OK;
- }
- int SandboxedVfs::GetLastError(int message_size, char* message) const {
- DCHECK_GE(message_size, 0);
- DCHECK(message_size == 0 || message);
- std::string error_string = base::File::ErrorToString(last_error_);
- size_t error_string_size = error_string.length() + 1;
- size_t copy_length =
- std::min(static_cast<size_t>(message_size), error_string_size);
- std::memcpy(message, error_string.c_str(), copy_length);
- // The return value is zero if the message fits in the buffer, and non-zero if
- // it does not fit.
- return copy_length != error_string_size;
- }
- int SandboxedVfs::CurrentTimeInt64(sqlite3_int64* result_ms) {
- DCHECK(result_ms);
- base::TimeDelta delta = base::Time::Now() - sqlite_epoch_;
- *result_ms = delta.InMilliseconds();
- return SQLITE_OK;
- }
- SandboxedVfs::SandboxedVfs(const char* name,
- std::unique_ptr<Delegate> delegate,
- bool make_default)
- : sandboxed_vfs_(SqliteVfsFor(this, name)),
- sqlite_epoch_(SqliteEpoch()),
- delegate_(std::move(delegate)),
- last_error_(base::File::FILE_OK) {
- // The register function returns a SQLite status as an int. The status is
- // ignored here. If registration fails, we'd want to report the error while
- // attempting to open a database. This is exactly what will happen, because
- // SQLite won't find the VFS we're asking for.
- sqlite3_vfs_register(&sandboxed_vfs_, make_default ? 1 : 0);
- }
- } // namespace sql
|