RLBox
rlbox_struct_support.hpp
1 #pragma once
2 // IWYU pragma: private, include "rlbox.hpp"
3 // IWYU pragma: friend "rlbox_.*\.hpp"
4 
5 #include <cstring>
6 #include <functional>
7 #include <type_traits>
8 
9 #include "rlbox_conversion.hpp"
10 #include "rlbox_helpers.hpp"
11 #include "rlbox_types.hpp"
12 #include "rlbox_wrapper_traits.hpp"
13 
14 namespace rlbox::detail {
15 
16 template<typename T, typename T_Sbx, typename T_Enable = void>
18 
19 template<typename T, typename T_Sbx>
21  T,
22  T_Sbx,
23  std::enable_if_t<!std::is_class_v<T>>>
24 {
25  using type = typename rlbox_sandbox<
26  T_Sbx>::template convert_to_sandbox_equivalent_nonclass_t<T>;
27 };
28 
29 template<typename T, typename T_Sbx>
30 using convert_to_sandbox_equivalent_t =
32 
33 }
34 
35 #define helper_create_converted_field(fieldType, fieldName, isFrozen) \
36  typename detail::convert_to_sandbox_equivalent_t<fieldType, T_Sbx> fieldName;
37 
38 #define helper_no_op()
39 
40 #define sandbox_equivalent_specialization(T, libId) \
41  template<typename T_Sbx> \
42  struct Sbx_##libId##_##T \
43  { \
44  sandbox_fields_reflection_##libId##_class_##T( \
45  helper_create_converted_field, \
46  helper_no_op) \
47  }; \
48  \
49  /* add convert_to_sandbox_equivalent_t specialization for new struct */ \
50  namespace detail { \
51  template<typename T_Template, typename T_Sbx> \
52  struct convert_to_sandbox_equivalent_helper< \
53  T_Template, \
54  T_Sbx, \
55  std::enable_if_t<std::is_same_v<T_Template, T>>> \
56  { \
57  using type = Sbx_##libId##_##T<T_Sbx>; \
58  }; \
59  }
60 
61 #define helper_create_tainted_field( \
62  fieldType, fieldName, isFrozen, MaybeConst) \
63  MaybeConst tainted<fieldType, T_Sbx> fieldName;
64 
65 #define helper_create_tainted_vol_field( \
66  fieldType, fieldName, isFrozen, MaybeConst) \
67  MaybeConst tainted_volatile<fieldType, T_Sbx> fieldName;
68 
69 #define helper_convert_type(fieldType, fieldName, isFrozen) \
70  ::rlbox::detail::convert_type<T_Sbx, Direction, Context>( \
71  lhs.fieldName, rhs.fieldName, example_unsandboxed_ptr, sandbox_ptr);
72 
73 #define helper_find_example_pointer_or_null(fieldType, fieldName, isFrozen) \
74  { \
75  const void* ret = fieldName.find_example_pointer_or_null(); \
76  if (ret != nullptr) { \
77  return ret; \
78  } \
79  }
80 
81 #define tainted_data_specialization_helper(MaybeConst, T, libId) \
82  \
83  template<typename T_Sbx> \
84  class tainted_volatile<MaybeConst T, T_Sbx> \
85  { \
86  KEEP_CLASSES_FRIENDLY \
87  KEEP_CAST_FRIENDLY \
88  \
89  private: \
90  inline MaybeConst Sbx_##libId##_##T<T_Sbx>& \
91  get_sandbox_value_ref() noexcept \
92  { \
93  return *reinterpret_cast<MaybeConst Sbx_##libId##_##T<T_Sbx>*>(this); \
94  } \
95  \
96  inline const Sbx_##libId##_##T<T_Sbx>& get_sandbox_value_ref() \
97  const noexcept \
98  { \
99  return *reinterpret_cast<const Sbx_##libId##_##T<T_Sbx>*>(this); \
100  } \
101  \
102  inline T get_raw_value() const noexcept \
103  { \
104  T lhs; \
105  const auto& rhs = get_sandbox_value_ref(); \
106  constexpr auto Direction = \
107  detail::adjust_type_direction::TO_APPLICATION; \
108  constexpr auto Context = detail::adjust_type_context::EXAMPLE; \
109  /* This is a tainted_volatile, so its address is a valid example for use \
110  * as example_unsandboxed_ptr */ \
111  const void* example_unsandboxed_ptr = &rhs; \
112  rlbox_sandbox<T_Sbx>* sandbox_ptr = nullptr; \
113  sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
114  helper_no_op) \
115  \
116  return lhs; \
117  } \
118  \
119  /* get_raw_sandbox_value has to return a custom struct to deal with the \
120  * adjusted machine model, to ensure */ \
121  inline Sbx_##libId##_##T<T_Sbx> get_raw_sandbox_value() const noexcept \
122  { \
123  auto ret_ptr = reinterpret_cast<const Sbx_##libId##_##T<T_Sbx>*>(this); \
124  return *ret_ptr; \
125  } \
126  \
127  inline std::remove_cv_t<T> get_raw_value() noexcept \
128  { \
129  rlbox_detail_forward_to_const(get_raw_value, std::remove_cv_t<T>); \
130  } \
131  \
132  inline std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>> \
133  get_raw_sandbox_value() noexcept \
134  { \
135  rlbox_detail_forward_to_const( \
136  get_raw_sandbox_value, std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>>); \
137  } \
138  \
139  tainted_volatile() = default; \
140  tainted_volatile(const tainted_volatile<MaybeConst T, T_Sbx>& p) = \
141  default; \
142  \
143  public: \
144  sandbox_fields_reflection_##libId##_class_##T( \
145  helper_create_tainted_vol_field, \
146  helper_no_op, \
147  MaybeConst) \
148  \
149  inline tainted<MaybeConst T*, T_Sbx> \
150  operator&() noexcept \
151  { \
152  auto ref_cast = \
153  reinterpret_cast<MaybeConst T*>(&get_sandbox_value_ref()); \
154  auto ret = tainted<MaybeConst T*, T_Sbx>::internal_factory(ref_cast); \
155  return ret; \
156  } \
157  \
158  inline auto UNSAFE_unverified() { return get_raw_value(); } \
159  inline auto UNSAFE_unverified() const { return get_raw_value(); } \
160  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) \
161  { \
162  return get_raw_sandbox_value(sandbox); \
163  } \
164  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const \
165  { \
166  return get_raw_sandbox_value(sandbox); \
167  } \
168  \
169  template<size_t N> \
170  inline auto unverified_safe_because(const char (&reason)[N]) \
171  { \
172  RLBOX_UNUSED(reason); \
173  return UNSAFE_unverified(); \
174  } \
175  template<size_t N> \
176  inline auto unverified_safe_because(const char (&reason)[N]) const \
177  { \
178  RLBOX_UNUSED(reason); \
179  return UNSAFE_unverified(); \
180  } \
181  \
182  T copy_and_verify(std::function<T(tainted<T, T_Sbx>)> verifier) \
183  { \
184  tainted<T, T_Sbx> val(*this); \
185  return verifier(val); \
186  } \
187  \
188  /* Can't define this yet due, to mutually dependent definition between \
189  tainted and tainted_volatile for structs */ \
190  inline tainted_volatile<MaybeConst T, T_Sbx>& operator=( \
191  const tainted<T, T_Sbx>& rhs); \
192  }; \
193  \
194  template<typename T_Sbx> \
195  class tainted<MaybeConst T, T_Sbx> \
196  { \
197  KEEP_CLASSES_FRIENDLY \
198  KEEP_CAST_FRIENDLY \
199  \
200  private: \
201  inline MaybeConst T& get_raw_value_ref() noexcept \
202  { \
203  return *reinterpret_cast<MaybeConst T*>(this); \
204  } \
205  \
206  inline const T& get_raw_value_ref() const noexcept \
207  { \
208  return *reinterpret_cast<const T*>(this); \
209  } \
210  \
211  inline T get_raw_value() const noexcept \
212  { \
213  auto ret_ptr = reinterpret_cast<const T*>(this); \
214  return *ret_ptr; \
215  } \
216  \
217  /* get_raw_sandbox_value has to return a custom struct to deal with the \
218  * adjusted machine model, to ensure */ \
219  inline Sbx_##libId##_##T<T_Sbx> get_raw_sandbox_value( \
220  rlbox_sandbox<T_Sbx>& sandbox) const noexcept \
221  { \
222  Sbx_##libId##_##T<T_Sbx> lhs; \
223  const auto& rhs = get_raw_value_ref(); \
224  constexpr auto Direction = detail::adjust_type_direction::TO_SANDBOX; \
225  constexpr auto Context = detail::adjust_type_context::SANDBOX; \
226  const void* example_unsandboxed_ptr = nullptr; \
227  rlbox_sandbox<T_Sbx>* sandbox_ptr = &sandbox; \
228  sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
229  helper_no_op) \
230  \
231  return lhs; \
232  } \
233  \
234  inline std::remove_cv_t<T> get_raw_value() noexcept \
235  { \
236  rlbox_detail_forward_to_const(get_raw_value, std::remove_cv_t<T>); \
237  } \
238  \
239  inline std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>> get_raw_sandbox_value( \
240  rlbox_sandbox<T_Sbx>& sandbox) noexcept \
241  { \
242  rlbox_detail_forward_to_const_a( \
243  get_raw_sandbox_value, \
244  std::remove_cv_t<Sbx_##libId##_##T<T_Sbx>>, \
245  sandbox); \
246  } \
247  \
248  inline const void* find_example_pointer_or_null() const noexcept \
249  { \
250  sandbox_fields_reflection_##libId##_class_##T( \
251  helper_find_example_pointer_or_null, helper_no_op) \
252  \
253  return nullptr; \
254  } \
255  \
256  public: \
257  sandbox_fields_reflection_##libId##_class_##T(helper_create_tainted_field, \
258  helper_no_op, \
259  MaybeConst) \
260  \
261  tainted() = default; \
262  tainted(const tainted<MaybeConst T, T_Sbx>& p) = default; \
263  \
264  tainted(const tainted_volatile<T, T_Sbx>& p) \
265  { \
266  auto& lhs = get_raw_value_ref(); \
267  auto& rhs = p.get_sandbox_value_ref(); \
268  constexpr auto Direction = \
269  detail::adjust_type_direction::TO_APPLICATION; \
270  constexpr auto Context = detail::adjust_type_context::EXAMPLE; \
271  /* This is a tainted_volatile, so its address is a valid for use as */ \
272  /* example_unsandboxed_ptr */ \
273  const void* example_unsandboxed_ptr = &rhs; \
274  rlbox_sandbox<T_Sbx>* sandbox_ptr = nullptr; \
275  sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
276  helper_no_op) \
277  } \
278  \
279  inline tainted_opaque<MaybeConst T, T_Sbx> to_opaque() \
280  { \
281  return *reinterpret_cast<tainted_opaque<MaybeConst T, T_Sbx>*>(this); \
282  } \
283  \
284  inline auto UNSAFE_unverified() { return get_raw_value(); } \
285  inline auto UNSAFE_unverified() const { return get_raw_value(); } \
286  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) \
287  { \
288  return get_raw_sandbox_value(sandbox); \
289  } \
290  inline auto UNSAFE_sandboxed(rlbox_sandbox<T_Sbx>& sandbox) const \
291  { \
292  return get_raw_sandbox_value(sandbox); \
293  } \
294  \
295  template<size_t N> \
296  inline auto unverified_safe_because(const char (&reason)[N]) \
297  { \
298  RLBOX_UNUSED(reason); \
299  return UNSAFE_unverified(); \
300  } \
301  template<size_t N> \
302  inline auto unverified_safe_because(const char (&reason)[N]) const \
303  { \
304  RLBOX_UNUSED(reason); \
305  return UNSAFE_unverified(); \
306  } \
307  \
308  T copy_and_verify(std::function<T(tainted<T, T_Sbx>)> verifier) \
309  { \
310  return verifier(*this); \
311  } \
312  }; \
313  \
314  /* Had to delay the definition due, to mutually dependence between \
315  tainted and tainted_volatile for structs */ \
316  template<typename T_Sbx> \
317  inline tainted_volatile<MaybeConst T, T_Sbx>& \
318  tainted_volatile<MaybeConst T, T_Sbx>::operator=( \
319  const tainted<T, T_Sbx>& rhs_wrap) \
320  { \
321  auto& lhs = get_sandbox_value_ref(); \
322  auto& rhs = rhs_wrap.get_raw_value_ref(); \
323  constexpr auto Direction = detail::adjust_type_direction::TO_SANDBOX; \
324  constexpr auto Context = detail::adjust_type_context::EXAMPLE; \
325  /* This is a tainted_volatile, so its address is a valid example for */ \
326  /* use as example_unsandboxed_ptr */ \
327  const void* example_unsandboxed_ptr = &lhs; \
328  rlbox_sandbox<T_Sbx>* sandbox_ptr = nullptr; \
329  sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
330  helper_no_op) \
331  \
332  return *this; \
333  }
334 
335 #define tainted_data_specialization(T, libId) \
336  tainted_data_specialization_helper(, T, libId) \
337  tainted_data_specialization_helper(const, T, libId)
338 
339 #define convert_type_specialization(T, libId) \
340  namespace detail { \
341  template<typename T_Sbx, \
342  detail::adjust_type_direction Direction, \
343  adjust_type_context Context, \
344  typename T_From> \
345  class convert_type_class<T_Sbx, Direction, Context, T, T_From> \
346  { \
347  public: \
348  static inline void run(T& lhs, \
349  const T_From& rhs, \
350  const void* example_unsandboxed_ptr, \
351  rlbox_sandbox<T_Sbx>* sandbox_ptr) \
352  { \
353  sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
354  helper_no_op) \
355  } \
356  }; \
357  \
358  template<typename T_Sbx, \
359  detail::adjust_type_direction Direction, \
360  adjust_type_context Context, \
361  typename T_From> \
362  class convert_type_class<T_Sbx, \
363  Direction, \
364  Context, \
365  Sbx_##libId##_##T<T_Sbx>, \
366  T_From> \
367  { \
368  public: \
369  static inline void run(Sbx_##libId##_##T<T_Sbx>& lhs, \
370  const T_From& rhs, \
371  const void* example_unsandboxed_ptr, \
372  rlbox_sandbox<T_Sbx>* sandbox_ptr) \
373  { \
374  sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \
375  helper_no_op) \
376  } \
377  }; \
378  }
379 
380 // clang-format off
381 #define rlbox_load_structs_from_library(libId) \
382  namespace rlbox { \
383  namespace detail { \
384  struct markerStruct \
385  {}; \
386  } \
387  /* check that this macro is called in a global namespace */ \
388  static_assert( \
389  ::rlbox::detail::is_member_of_rlbox_detail<detail::markerStruct>, \
390  "Invoke rlbox_load_structs_from_library in the global namespace"); \
391  \
392  sandbox_fields_reflection_##libId##_allClasses( \
393  sandbox_equivalent_specialization) \
394  \
395  sandbox_fields_reflection_##libId##_allClasses( \
396  tainted_data_specialization) \
397  \
398  sandbox_fields_reflection_##libId##_allClasses( \
399  convert_type_specialization) \
400  } \
401  RLBOX_REQUIRE_SEMI_COLON
402 
403 // clang-format on
Encapsulation for sandboxes.
Definition: rlbox_sandbox.hpp:95
Definition: rlbox_struct_support.hpp:17