#pragma once // IWYU pragma: private, include "rlbox.hpp" // IWYU pragma: friend "rlbox_.*\.hpp" #include #include #include #include "rlbox_conversion.hpp" #include "rlbox_helpers.hpp" #include "rlbox_types.hpp" #include "rlbox_wrapper_traits.hpp" namespace rlbox::detail { template struct convert_to_sandbox_equivalent_helper; template struct convert_to_sandbox_equivalent_helper< T, T_Sbx, std::enable_if_t>> { using type = typename rlbox_sandbox< T_Sbx>::template convert_to_sandbox_equivalent_nonclass_t; }; template using convert_to_sandbox_equivalent_t = typename convert_to_sandbox_equivalent_helper::type; // This is used by rlbox_load_structs_from_library to test the current namespace struct markerStruct {}; } #define helper_create_converted_field(fieldType, fieldName, isFrozen) \ typename detail::convert_to_sandbox_equivalent_t fieldName; #define helper_no_op() #define sandbox_equivalent_specialization(T, libId) \ template \ struct Sbx_##libId##_##T \ { \ sandbox_fields_reflection_##libId##_class_##T( \ helper_create_converted_field, \ helper_no_op) \ }; \ \ /* add convert_to_sandbox_equivalent_t specialization for new struct */ \ namespace detail { \ template \ struct convert_to_sandbox_equivalent_helper< \ T_Template, \ T_Sbx, \ std::enable_if_t>> \ { \ using type = Sbx_##libId##_##T; \ }; \ } #define helper_create_tainted_field( \ fieldType, fieldName, isFrozen, MaybeConst) \ MaybeConst tainted fieldName; #define helper_create_tainted_vol_field( \ fieldType, fieldName, isFrozen, MaybeConst) \ MaybeConst tainted_volatile fieldName; #define helper_convert_type(fieldType, fieldName, isFrozen) \ ::rlbox::detail::convert_type( \ lhs.fieldName, rhs.fieldName, example_unsandboxed_ptr, sandbox_ptr); #define helper_find_example_pointer_or_null(fieldType, fieldName, isFrozen) \ { \ const void* ret = fieldName.find_example_pointer_or_null(); \ if (ret != nullptr) { \ return ret; \ } \ } #define tainted_data_specialization_helper(MaybeConst, T, libId) \ \ template \ class tainted_volatile \ { \ KEEP_CLASSES_FRIENDLY \ KEEP_CAST_FRIENDLY \ \ private: \ inline MaybeConst Sbx_##libId##_##T& \ get_sandbox_value_ref() noexcept \ { \ return *reinterpret_cast*>(this); \ } \ \ inline const Sbx_##libId##_##T& get_sandbox_value_ref() \ const noexcept \ { \ return *reinterpret_cast*>(this); \ } \ \ inline T get_raw_value() const noexcept \ { \ T lhs; \ const auto& rhs = get_sandbox_value_ref(); \ constexpr auto Direction = \ detail::adjust_type_direction::TO_APPLICATION; \ constexpr auto Context = detail::adjust_type_context::EXAMPLE; \ /* This is a tainted_volatile, so its address is a valid example for use \ * as example_unsandboxed_ptr */ \ const void* example_unsandboxed_ptr = &rhs; \ rlbox_sandbox* sandbox_ptr = nullptr; \ sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \ helper_no_op) \ \ return lhs; \ } \ \ /* get_raw_sandbox_value has to return a custom struct to deal with the \ * adjusted machine model, to ensure */ \ inline Sbx_##libId##_##T get_raw_sandbox_value() const noexcept \ { \ auto ret_ptr = reinterpret_cast*>(this); \ return *ret_ptr; \ } \ \ tainted_volatile() = default; \ tainted_volatile(const tainted_volatile& p) = \ default; \ \ public: \ sandbox_fields_reflection_##libId##_class_##T( \ helper_create_tainted_vol_field, \ helper_no_op, \ MaybeConst) \ \ inline tainted operator&() const noexcept \ { \ auto ref_cast = \ reinterpret_cast(&get_sandbox_value_ref()); \ auto ret = tainted::internal_factory(ref_cast); \ return ret; \ } \ \ inline auto UNSAFE_unverified() const { return get_raw_value(); } \ inline auto UNSAFE_sandboxed(rlbox_sandbox& sandbox) const \ { \ return get_raw_sandbox_value(sandbox); \ } \ \ template \ inline auto unverified_safe_because(const char (&reason)[N]) const \ { \ RLBOX_UNUSED(reason); \ return UNSAFE_unverified(); \ } \ \ T copy_and_verify(std::function)> verifier) \ { \ tainted val(*this); \ return verifier(val); \ } \ \ /* Can't define this yet due, to mutually dependent definition between \ tainted and tainted_volatile for structs */ \ inline tainted_volatile& operator=( \ const tainted& rhs); \ }; \ \ template \ class tainted \ { \ KEEP_CLASSES_FRIENDLY \ KEEP_CAST_FRIENDLY \ \ private: \ inline MaybeConst T& get_raw_value_ref() noexcept \ { \ return *reinterpret_cast(this); \ } \ \ inline const T& get_raw_value_ref() const noexcept \ { \ return *reinterpret_cast(this); \ } \ \ inline T get_raw_value() const noexcept \ { \ auto ret_ptr = reinterpret_cast(this); \ return *ret_ptr; \ } \ \ /* get_raw_sandbox_value has to return a custom struct to deal with the \ * adjusted machine model, to ensure */ \ inline Sbx_##libId##_##T get_raw_sandbox_value( \ rlbox_sandbox& sandbox) const noexcept \ { \ Sbx_##libId##_##T lhs; \ const auto& rhs = get_raw_value_ref(); \ constexpr auto Direction = detail::adjust_type_direction::TO_SANDBOX; \ constexpr auto Context = detail::adjust_type_context::SANDBOX; \ const void* example_unsandboxed_ptr = nullptr; \ rlbox_sandbox* sandbox_ptr = &sandbox; \ sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \ helper_no_op) \ \ return lhs; \ } \ \ inline const void* find_example_pointer_or_null() const noexcept \ { \ sandbox_fields_reflection_##libId##_class_##T( \ helper_find_example_pointer_or_null, helper_no_op) \ \ return nullptr; \ } \ \ public: \ sandbox_fields_reflection_##libId##_class_##T(helper_create_tainted_field, \ helper_no_op, \ MaybeConst) \ \ tainted() = default; \ tainted(const tainted& p) = default; \ \ tainted(const tainted_volatile& p) \ { \ auto& lhs = get_raw_value_ref(); \ auto& rhs = p.get_sandbox_value_ref(); \ constexpr auto Direction = \ detail::adjust_type_direction::TO_APPLICATION; \ constexpr auto Context = detail::adjust_type_context::EXAMPLE; \ /* This is a tainted_volatile, so its address is a valid for use as */ \ /* example_unsandboxed_ptr */ \ const void* example_unsandboxed_ptr = &rhs; \ rlbox_sandbox* sandbox_ptr = nullptr; \ sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \ helper_no_op) \ } \ \ inline tainted_opaque to_opaque() \ { \ return *reinterpret_cast*>(this); \ } \ \ inline auto UNSAFE_unverified() const { return get_raw_value(); } \ inline auto UNSAFE_sandboxed(rlbox_sandbox& sandbox) const \ { \ return get_raw_sandbox_value(sandbox); \ } \ \ template \ inline auto unverified_safe_because(const char (&reason)[N]) const \ { \ RLBOX_UNUSED(reason); \ return UNSAFE_unverified(); \ } \ \ T copy_and_verify(std::function)> verifier) \ { \ return verifier(*this); \ } \ }; \ \ /* Had to delay the definition due, to mutually dependence between \ tainted and tainted_volatile for structs */ \ template \ inline tainted_volatile& \ tainted_volatile::operator=( \ const tainted& rhs_wrap) \ { \ auto& lhs = get_sandbox_value_ref(); \ auto& rhs = rhs_wrap.get_raw_value_ref(); \ constexpr auto Direction = detail::adjust_type_direction::TO_SANDBOX; \ constexpr auto Context = detail::adjust_type_context::EXAMPLE; \ /* This is a tainted_volatile, so its address is a valid example for */ \ /* use as example_unsandboxed_ptr */ \ const void* example_unsandboxed_ptr = &lhs; \ rlbox_sandbox* sandbox_ptr = nullptr; \ sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \ helper_no_op) \ \ return *this; \ } #define tainted_data_specialization(T, libId) \ tainted_data_specialization_helper( , T, libId) \ tainted_data_specialization_helper(const, T, libId) #define convert_type_specialization(T, libId) \ namespace detail { \ template \ class convert_type_class \ { \ public: \ static inline void run(T& lhs, \ const T_From& rhs, \ const void* example_unsandboxed_ptr, \ rlbox_sandbox* sandbox_ptr) \ { \ sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \ helper_no_op) \ } \ }; \ \ template \ class convert_type_class, \ T_From> \ { \ public: \ static inline void run(Sbx_##libId##_##T& lhs, \ const T_From& rhs, \ const void* example_unsandboxed_ptr, \ rlbox_sandbox* sandbox_ptr) \ { \ sandbox_fields_reflection_##libId##_class_##T(helper_convert_type, \ helper_no_op) \ } \ }; \ } // clang-format off #define rlbox_load_structs_from_library(libId) \ namespace rlbox { \ /* check that this macro is called in a global namespace */ \ static_assert( \ ::rlbox::detail::is_member_of_rlbox_detail, \ "Invoke rlbox_load_structs_from_library in the global namespace"); \ \ sandbox_fields_reflection_##libId##_allClasses( \ sandbox_equivalent_specialization) \ \ sandbox_fields_reflection_##libId##_allClasses( \ tainted_data_specialization) \ \ sandbox_fields_reflection_##libId##_allClasses( \ convert_type_specialization) \ } \ RLBOX_REQUIRE_SEMI_COLON // clang-format on