RLBox
rlbox_noop_sandbox.hpp
1 #pragma once
2 
3 #include <cstdint>
4 #include <cstdlib>
5 #include <mutex>
6 #ifndef RLBOX_USE_CUSTOM_SHARED_LOCK
7 # include <shared_mutex>
8 #endif
9 #include <utility>
10 
11 #include "rlbox_helpers.hpp"
12 
13 namespace rlbox {
14 
15 class rlbox_noop_sandbox;
16 
18 {
19  rlbox_noop_sandbox* sandbox;
20  uint32_t last_callback_invoked;
21 };
22 
23 #ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
24 
25 rlbox_noop_sandbox_thread_data* get_rlbox_noop_sandbox_thread_data();
26 # define RLBOX_NOOP_SANDBOX_STATIC_VARIABLES() \
27  thread_local rlbox::rlbox_noop_sandbox_thread_data \
28  rlbox_noop_sandbox_thread_info{ 0, 0 }; \
29  namespace rlbox { \
30  rlbox_noop_sandbox_thread_data* get_rlbox_noop_sandbox_thread_data() \
31  { \
32  return &rlbox_noop_sandbox_thread_info; \
33  } \
34  } \
35  static_assert(true, "Enforce semi-colon")
36 
37 #endif
38 
45 {
46 public:
47  // Stick with the system defaults
48  using T_LongLongType = long long;
49  using T_LongType = long;
50  using T_IntType = int;
51  using T_PointerType = void*;
52  using T_ShortType = short;
53  // no-op sandbox can transfer buffers as there is no sandboxings
54  // Thus transfer is a noop
55  using can_grant_deny_access = void;
56 
57 private:
58  RLBOX_SHARED_LOCK(callback_mutex);
59  static inline const uint32_t MAX_CALLBACKS = 64;
60  void* callback_unique_keys[MAX_CALLBACKS]{ 0 };
61  void* callbacks[MAX_CALLBACKS]{ 0 };
62 
63 #ifndef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
64  thread_local static inline rlbox_noop_sandbox_thread_data thread_data{ 0, 0 };
65 #endif
66 
67  template<uint32_t N, typename T_Ret, typename... T_Args>
68  static T_Ret callback_trampoline(T_Args... params)
69  {
70 #ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
71  auto& thread_data = *get_rlbox_noop_sandbox_thread_data();
72 #endif
73  thread_data.last_callback_invoked = N;
74  using T_Func = T_Ret (*)(T_Args...);
75  T_Func func;
76  {
77  RLBOX_ACQUIRE_SHARED_GUARD(lock, thread_data.sandbox->callback_mutex);
78  func = reinterpret_cast<T_Func>(thread_data.sandbox->callbacks[N]);
79  }
80  // Callbacks are invoked through function pointers, cannot use std::forward
81  // as we don't have caller context for T_Args, which means they are all
82  // effectively passed by value
83  return func(params...);
84  }
85 
86 protected:
87  inline void impl_create_sandbox() {}
88 
89  inline void impl_destroy_sandbox() {}
90 
91  template<typename T>
92  inline void* impl_get_unsandboxed_pointer(T_PointerType p) const
93  {
94  return p;
95  }
96 
97  template<typename T>
98  inline T_PointerType impl_get_sandboxed_pointer(const void* p) const
99  {
100  return const_cast<T_PointerType>(p);
101  }
102 
103  template<typename T>
104  static inline void* impl_get_unsandboxed_pointer_no_ctx(
105  T_PointerType p,
106  const void* /* example_unsandboxed_ptr */,
108  * // Func ptr
109  /* param: expensive_sandbox_finder */)(const void*
110  example_unsandboxed_ptr))
111  {
112  return p;
113  }
114 
115  template<typename T>
116  static inline T_PointerType impl_get_sandboxed_pointer_no_ctx(
117  const void* p,
118  const void* /* example_unsandboxed_ptr */,
120  * // Func ptr
121  /* param: expensive_sandbox_finder */)(const void*
122  example_unsandboxed_ptr))
123  {
124  return const_cast<T_PointerType>(p);
125  }
126 
127  inline T_PointerType impl_malloc_in_sandbox(size_t size)
128  {
129  void* p = malloc(size);
130  return p;
131  }
132 
133  inline void impl_free_in_sandbox(T_PointerType p) { free(p); }
134 
135  static inline bool impl_is_in_same_sandbox(const void*, const void*)
136  {
137  return true;
138  }
139 
140  inline bool impl_is_pointer_in_sandbox_memory(const void*) { return true; }
141  inline bool impl_is_pointer_in_app_memory(const void*) { return true; }
142 
143  inline size_t impl_get_total_memory()
144  {
145  return std::numeric_limits<size_t>::max();
146  }
147 
148  inline void* impl_get_memory_location()
149  {
150  // There isn't any sandbox memory for the noop_sandbox as we just redirect
151  // to the app. Also, this is mostly used for pointer swizzling or sandbox
152  // bounds checks which is also not present/not required. So we can just
153  // return null
154  return nullptr;
155  }
156 
157  // adding a template so that we can use static_assert to fire only if this
158  // function is invoked
159  template<typename T = void>
160  void* impl_lookup_symbol(const char* /* func_name */)
161  {
162  // Will fire if this impl_lookup_symbol is ever called for the static
163  // sandbox
164  constexpr bool fail = std::is_same_v<T, void>;
165  rlbox_detail_static_fail_because(
166  fail,
167  "The no_op_sandbox uses static calls and thus developers should add\n\n"
168  "#define RLBOX_USE_STATIC_CALLS() rlbox_noop_sandbox_lookup_symbol\n\n"
169  "to their code, to ensure that static calls are handled correctly.");
170 
171  return nullptr;
172  }
173 
174 #define rlbox_noop_sandbox_lookup_symbol(func_name) \
175  reinterpret_cast<void*>(&func_name) /* NOLINT */
176 
177  template<typename T, typename T_Converted, typename... T_Args>
178  auto impl_invoke_with_func_ptr(T_Converted* func_ptr, T_Args&&... params)
179  {
180 #ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
181  auto& thread_data = *get_rlbox_noop_sandbox_thread_data();
182 #endif
183  thread_data.sandbox = this;
184  return (*func_ptr)(params...);
185  }
186 
187  template<typename T_Ret, typename... T_Args>
188  inline T_PointerType impl_register_callback(void* key, void* callback)
189  {
190  RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex);
191 
192  void* chosen_trampoline = nullptr;
193 
194  // need a compile time for loop as we we need I to be a compile time value
195  // this is because we are returning the I'th callback trampoline
196  detail::compile_time_for<MAX_CALLBACKS>([&](auto I) {
197  if (!chosen_trampoline && callback_unique_keys[I.value] == nullptr) {
198  callback_unique_keys[I.value] = key;
199  callbacks[I.value] = callback;
200  chosen_trampoline = reinterpret_cast<void*>(
201  callback_trampoline<I.value, T_Ret, T_Args...>);
202  }
203  });
204 
205  return reinterpret_cast<T_PointerType>(chosen_trampoline);
206  }
207 
208  static inline std::pair<rlbox_noop_sandbox*, void*>
209  impl_get_executed_callback_sandbox_and_key()
210  {
211 #ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES
212  auto& thread_data = *get_rlbox_noop_sandbox_thread_data();
213 #endif
214  auto sandbox = thread_data.sandbox;
215  auto callback_num = thread_data.last_callback_invoked;
216  void* key = sandbox->callback_unique_keys[callback_num];
217  return std::make_pair(sandbox, key);
218  }
219 
220  template<typename T_Ret, typename... T_Args>
221  inline void impl_unregister_callback(void* key)
222  {
223  RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex);
224  for (uint32_t i = 0; i < MAX_CALLBACKS; i++) {
225  if (callback_unique_keys[i] == key) {
226  callback_unique_keys[i] = nullptr;
227  callbacks[i] = nullptr;
228  break;
229  }
230  }
231  }
232 
233  template<typename T>
234  inline T* impl_grant_access(T* src, size_t num, bool& success)
235  {
236  RLBOX_UNUSED(num);
237  success = true;
238  return src;
239  }
240 
241  template<typename T>
242  inline T* impl_deny_access(T* src, size_t num, bool& success)
243  {
244  RLBOX_UNUSED(num);
245  success = true;
246  return src;
247  }
248 };
249 
250 }
Class that implements the null sandbox. This sandbox doesn't actually provide any isolation and only ...
Definition: rlbox_noop_sandbox.hpp:45
Definition: rlbox_noop_sandbox.hpp:18