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