summaryrefslogtreecommitdiff
path: root/chromium/sql/sandboxed_vfs.h
blob: b07465973640ce8f6325622ba1261aa308135b7a (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// 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.

#ifndef SQL_SANDBOXED_VFS_H_
#define SQL_SANDBOXED_VFS_H_

#include <stdint.h>

#include <memory>

#include "base/component_export.h"
#include "base/files/file.h"
#include "base/files/file_path.h"
#include "base/time/time.h"
#include "third_party/abseil-cpp/absl/types/optional.h"
#include "third_party/sqlite/sqlite3.h"

namespace sql {

// SQLite VFS file implementation that works in a sandboxed process.
//
// Instances are thread-friendly.
class COMPONENT_EXPORT(SQL) SandboxedVfs {
 public:
  // Describes access rights for a path, used by Delegate::GetPathAccess below.
  struct PathAccessInfo {
    bool can_read = false;
    bool can_write = false;
  };

  // Environment-specific SandboxedVfs implementation details.
  //
  // This abstracts a handful of operations that don't typically work in a
  // sandbox environment given a typical naive implementation. Instances must be
  // thread-safe.
  class Delegate {
   public:
    virtual ~Delegate() = default;

    // Opens a file.
    //
    // `file_path` is the parsed version of a path passed by SQLite to Open().
    // `sqlite_requested_flags` is a bitwise combination SQLite flags used when
    // opening files. Returns the opened File on success, or an invalid File on
    // failure.
    virtual base::File OpenFile(const base::FilePath& file_path,
                                int sqlite_requested_flags) = 0;

    // Deletes a file.
    //
    // `file_path` is the parsed version of a path passed by SQLite to Delete().
    // If `sync_dir` is true, the implementation should attempt to flush to disk
    // the changes to the file's directory, to ensure that the deletion is
    // reflected after a power failure. Returns an SQLite error code indicating
    // the status of the operation.
    virtual int DeleteFile(const base::FilePath& file_path, bool sync_dir) = 0;

    // Queries path access information for `file_path`. Returns null if the
    // given path does not exist.
    virtual absl::optional<PathAccessInfo> GetPathAccess(
        const base::FilePath& file_path) = 0;

    // Resizes a file.
    //
    // `file` is the result of a previous call to Delegate::OpenFile() with
    // `file_path`. `size` is the new desired size in bytes, and may be smaller
    // or larger than the current file size. Returns true if successful and
    // false otherwise.
    //
    // Implementations can modify `file` directly, or operate on the filesystem
    // via `file_path`.
    //
    // This is only called after the direct approach of base::File::SetLength()
    // fails. So, the implementation should not bother trying to call
    // SetLength() on `file`. This currently only happens on macOS < 10.15.
    virtual bool SetFileLength(const base::FilePath& file_path,
                               base::File& file,
                               size_t size) = 0;
  };

  // We don't allow SandboxedVfs instances to be destroyed. Once created, they
  // are permanently registered in the calling process.
  ~SandboxedVfs() = delete;

  // Constructs a new instance of ths object using `delegate` to support various
  // operations from within the sandbox. The VFS is registered with SQLite under
  // `name` and if `make_default` is true then the VFS is also set as the global
  // default for new database instances within the calling process.
  //
  // Note that `name` must be globally unique to the calling process.
  static void Register(const char* name,
                       std::unique_ptr<Delegate> delegate,
                       bool make_default);

  Delegate* delegate() const { return delegate_.get(); }

  // sqlite3_vfs implementation.
  int Open(const char* full_path,
           sqlite3_file& result_file,
           int requested_flags,
           int* granted_flags);
  int Delete(const char* full_path, int sync_dir);
  int Access(const char* full_path, int flags, int& result);
  int FullPathname(const char* file_path, int result_size, char* result);
  int Randomness(int result_size, char* result);
  int Sleep(int microseconds);
  int GetLastError(int message_size, char* message) const;
  int CurrentTimeInt64(sqlite3_int64* result_ms);

  // Used by SandboxedVfsFile.
  void SetLastError(base::File::Error error) { this->last_error_ = error; }

 private:
  SandboxedVfs(const char* name,
               std::unique_ptr<Delegate> delegate,
               bool make_default);

  sqlite3_vfs sandboxed_vfs_;
  const base::Time sqlite_epoch_;
  const std::unique_ptr<Delegate> delegate_;
  base::File::Error last_error_;
};

}  // namespace sql

#endif  // SQL_SANDBOXED_VFS_H_