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>
17 struct convert_to_sandbox_equivalent_helper;
18 
19 template<typename T, typename T_Sbx>
20 struct convert_to_sandbox_equivalent_helper<
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 =
31   typename convert_to_sandbox_equivalent_helper<T, T_Sbx>::type;
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