diff --git a/include/rlbox.hpp b/include/rlbox.hpp --- a/include/rlbox.hpp +++ b/include/rlbox.hpp @@ -90,7 +90,7 @@ public: auto ret = UNSAFE_unverified(); if (ret != nullptr) { - size_t bytes = sizeof(T) * count; + size_t bytes = sizeof(T_Pointed) * count; detail::check_range_doesnt_cross_app_sbx_boundary(ret, bytes); } return ret; diff --git a/include/rlbox_sandbox.hpp b/include/rlbox_sandbox.hpp --- a/include/rlbox_sandbox.hpp +++ b/include/rlbox_sandbox.hpp @@ -344,6 +344,29 @@ private: return this_ptr->impl_create_sandbox(std::forward(args)...); } + +template +T checked_add(T aLhs, T aRhs, const char* aErrorMsg) { + static_assert(std::is_unsigned_v, "Expected unsigned type"); + + T ret = aLhs + aRhs; + bool has_overflow = ret < aLhs; + detail::dynamic_check(!has_overflow, aErrorMsg); + + return ret; +} + +template +T checked_multiply(T aLhs, T aRhs, const char* aErrorMsg) { + static_assert(std::is_unsigned_v, "Expected unsigned type"); + + T ret = aLhs * aRhs; + bool has_overflow = (aLhs != 0) && ((ret / aLhs) != aRhs); + detail::dynamic_check(!has_overflow, aErrorMsg); + + return ret; +} + public: /** * @brief Unused member that allows the calling code to save data in a @@ -556,9 +579,10 @@ public: } detail::dynamic_check(is_pointer_in_sandbox_memory(ptr), "Malloc returned pointer outside the sandbox memory"); - auto ptr_end = reinterpret_cast(ptr + (count - 1)); - detail::dynamic_check( - is_in_same_sandbox(ptr, reinterpret_cast(ptr_end)), + + const size_t obj_size = checked_multiply(static_cast(count), sizeof(T), "Malloc object size too large"); + auto ptr_end = checked_add(reinterpret_cast(ptr), reinterpret_cast(obj_size - 1), "Malloc object end too large"); + detail::dynamic_check(is_pointer_in_sandbox_memory(reinterpret_cast(ptr_end)), "Malloc returned a pointer whose range goes beyond sandbox memory"); auto cast_ptr = reinterpret_cast(ptr); return tainted::internal_factory(cast_ptr);