RLBox
rlbox_policy_types.hpp
1 #pragma once
2 // IWYU pragma: private, include "rlbox.hpp"
3 // IWYU pragma: friend "rlbox_.*\.hpp"
4 
5 #include <type_traits>
6 #include <utility>
7 
8 #include "rlbox_helpers.hpp"
9 #include "rlbox_struct_support.hpp"
10 #include "rlbox_types.hpp"
11 
12 namespace rlbox {
13 
14 namespace callback_detail {
15 
16  // Compute the expected type of the callback
17  template<typename T_Sbx, typename T_Ret, typename... T_Args>
18  using T_Cb =
19  std::conditional_t<std::is_void_v<T_Ret>, void, tainted<T_Ret, T_Sbx>> (*)(
20  rlbox_sandbox<T_Sbx>&,
21  tainted<T_Args, T_Sbx>...);
22 
23  template<typename T_Sbx, typename T_Ret, typename... T_Args>
24  T_Cb<T_Sbx, T_Ret, T_Args...> callback_type_helper(T_Ret (*)(T_Args...));
25 
26  // Compute the expected type of the interceptor
27  template<typename T_Sbx, typename T_Ret, typename... T_Args>
28  using T_I = detail::convert_to_sandbox_equivalent_t<T_Ret, T_Sbx> (*)(
29  detail::convert_to_sandbox_equivalent_t<T_Args, T_Sbx>...);
30 
31  template<typename T_Sbx, typename T_Ret, typename... T_Args>
32  T_I<T_Sbx, T_Ret, T_Args...> interceptor_type_helper(T_Ret (*)(T_Args...));
33 }
34 
35 template<typename T, typename T_Sbx>
37 {
38  KEEP_CLASSES_FRIENDLY
39 
40 private:
41  rlbox_sandbox<T_Sbx>* sandbox;
42 
43  using T_Callback =
44  decltype(callback_detail::callback_type_helper<T_Sbx>(std::declval<T>()));
45  T_Callback callback;
46 
47  // The interceptor is the function that runs between the sandbox invoking the
48  // callback and the actual callback running The interceptor is responsible for
49  // wrapping and converting callback arguments, returns etc. to their
50  // appropriate representations
51  using T_Interceptor =
52  decltype(callback_detail::interceptor_type_helper<T_Sbx>(
53  std::declval<T>()));
54  T_Interceptor callback_interceptor;
55 
56  // The trampoline is the internal sandbox representation of the callback
57  // Depending on the sandbox type, this could be the callback pointer directly
58  // or a trampoline function that gates exits from the sandbox.
59  using T_Trampoline = detail::convert_to_sandbox_equivalent_t<T, T_Sbx>;
60  T_Trampoline callback_trampoline;
61 
62  // The unique key representing the callback to pass to unregister_callback on
63  // destruction
64  void* key;
65 
66  inline void move_obj(sandbox_callback&& other)
67  {
68  sandbox = other.sandbox;
69  callback = other.callback;
70  callback_interceptor = other.callback_interceptor;
71  callback_trampoline = other.callback_trampoline;
72  key = other.key;
73  other.sandbox = nullptr;
74  other.callback = nullptr;
75  other.callback_interceptor = nullptr;
76  other.callback_trampoline = 0;
77  other.key = nullptr;
78  }
79 
80  template<typename T_Ret, typename... T_Args>
81  inline void unregister_helper(T_Ret (*)(T_Args...))
82  {
83  if (callback != nullptr) {
84  // Don't need to worry about race between unregister and move as
85  // 1) this will not happen in a correctly written program
86  // 2) if this does happen, the worst that can happen is an invocation of a
87  // null function pointer, which causes a crash that cannot be exploited
88  // for RCE
89  sandbox->template unregister_callback<T_Ret, T_Args...>(key);
90  sandbox = nullptr;
91  callback = nullptr;
92  callback_interceptor = nullptr;
93  callback_trampoline = 0;
94  key = nullptr;
95  }
96  }
97 
98  inline T_Callback get_raw_value() const noexcept { return callback; }
99  inline T_Trampoline get_raw_sandbox_value() const noexcept
100  {
101  return callback_trampoline;
102  }
103  inline T_Callback get_raw_value() noexcept { return callback; }
104  inline T_Trampoline get_raw_sandbox_value() noexcept
105  {
106  return callback_trampoline;
107  }
108 
109  // Keep constructor private as only rlbox_sandbox should be able to create
110  // this object
112  T_Callback p_callback,
113  T_Interceptor p_callback_interceptor,
114  T_Trampoline p_callback_trampoline,
115  void* p_key)
116  : sandbox(p_sandbox)
117  , callback(p_callback)
118  , callback_interceptor(p_callback_interceptor)
119  , callback_trampoline(p_callback_trampoline)
120  , key(p_key)
121  {
122  detail::dynamic_check(sandbox != nullptr,
123  "Unexpected null sandbox when creating a callback");
124  }
125 
126 public:
128  : sandbox(nullptr)
129  , callback(nullptr)
130  , callback_interceptor(nullptr)
131  , callback_trampoline(0)
132  , key(nullptr)
133  {}
134 
136  {
137  move_obj(std::forward<sandbox_callback>(other));
138  }
139 
140  inline sandbox_callback& operator=(sandbox_callback&& other)
141  {
142  if (this != &other) {
143  move_obj(std::forward<sandbox_callback>(other));
144  }
145  return *this;
146  }
147 
148  void unregister()
149  {
150  T dummy = nullptr;
151  unregister_helper(dummy);
152  }
153 
154  ~sandbox_callback() { unregister(); }
155 
160  inline auto UNSAFE_unverified() const noexcept { return get_raw_value(); }
167  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const noexcept
168  {
169  RLBOX_UNUSED(sandbox);
170  return get_raw_sandbox_value();
171  }
172  inline auto UNSAFE_unverified() noexcept { return get_raw_value(); }
173  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) noexcept
174  {
175  RLBOX_UNUSED(sandbox);
176  return get_raw_sandbox_value();
177  }
178 };
179 
180 template<typename T, typename T_Sbx>
182 {
183  KEEP_CLASSES_FRIENDLY
184 
185 private:
187  typename T_Sbx::T_PointerType idx;
188  T idx_unsandboxed;
189 
190  inline void move_obj(app_pointer&& other)
191  {
192  map = other.map;
193  idx = other.idx;
194  idx_unsandboxed = other.idx_unsandboxed;
195  other.map = nullptr;
196  other.idx = 0;
197  other.idx_unsandboxed = nullptr;
198  }
199 
200  inline T get_raw_value() const noexcept
201  {
202  return to_tainted().get_raw_value();
203  }
204  inline typename T_Sbx::T_PointerType get_raw_sandbox_value() const noexcept
205  {
206  return idx;
207  }
208  inline T get_raw_value() noexcept { return to_tainted().get_raw_value(); }
209  inline typename T_Sbx::T_PointerType get_raw_sandbox_value() noexcept
210  {
211  return idx;
212  }
213 
215  typename T_Sbx::T_PointerType a_idx,
216  T a_idx_unsandboxed)
217  : map(a_map)
218  , idx(a_idx)
219  , idx_unsandboxed(a_idx_unsandboxed)
220  {}
221 
222 public:
223  app_pointer()
224  : map(nullptr)
225  , idx(0)
226  , idx_unsandboxed(0)
227  {}
228 
229  ~app_pointer() { unregister(); }
230 
231  app_pointer(app_pointer&& other)
232  {
233  move_obj(std::forward<app_pointer>(other));
234  }
235 
236  inline app_pointer& operator=(app_pointer&& other)
237  {
238  if (this != &other) {
239  move_obj(std::forward<app_pointer>(other));
240  }
241  return *this;
242  }
243 
244  void unregister()
245  {
246  if (idx != 0) {
247  map->remove_app_ptr(idx);
248  map = nullptr;
249  idx = 0;
250  idx_unsandboxed = nullptr;
251  }
252  }
253 
254  tainted<T, T_Sbx> to_tainted()
255  {
257  reinterpret_cast<T>(idx_unsandboxed));
258  }
259 
264  inline auto UNSAFE_unverified() const noexcept { return get_raw_value(); }
271  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const noexcept
272  {
273  RLBOX_UNUSED(sandbox);
274  return get_raw_sandbox_value();
275  }
276  inline auto UNSAFE_unverified() noexcept { return get_raw_value(); }
277  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) noexcept
278  {
279  RLBOX_UNUSED(sandbox);
280  return get_raw_sandbox_value();
281  }
282 };
283 
284 }
Definition: rlbox_policy_types.hpp:182
auto UNSAFE_sandboxed(rlbox_sandbox< T_Sbx > &sandbox) const noexcept
Like UNSAFE_unverified, but get the underlying sandbox representation.
Definition: rlbox_policy_types.hpp:271
auto UNSAFE_unverified() const noexcept
Unwrap a callback without verification. This is an unsafe operation and should be used with care.
Definition: rlbox_policy_types.hpp:264
Encapsulation for sandboxes.
Definition: rlbox_sandbox.hpp:95
Definition: rlbox_policy_types.hpp:37
auto UNSAFE_sandboxed(rlbox_sandbox< T_Sbx > &sandbox) const noexcept
Like UNSAFE_unverified, but get the underlying sandbox representation.
Definition: rlbox_policy_types.hpp:167
auto UNSAFE_unverified() const noexcept
Unwrap a callback without verification. This is an unsafe operation and should be used with care.
Definition: rlbox_policy_types.hpp:160
Definition: rlbox_types.hpp:22