diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-07 19:33:14 +0000 |
commit | 36d22d82aa202bb199967e9512281e9a53db42c9 (patch) | |
tree | 105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rlbox/include/rlbox_dylib_sandbox.hpp | |
parent | Initial commit. (diff) | |
download | firefox-esr-upstream.tar.xz firefox-esr-upstream.zip |
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rlbox/include/rlbox_dylib_sandbox.hpp')
-rw-r--r-- | third_party/rlbox/include/rlbox_dylib_sandbox.hpp | 314 |
1 files changed, 314 insertions, 0 deletions
diff --git a/third_party/rlbox/include/rlbox_dylib_sandbox.hpp b/third_party/rlbox/include/rlbox_dylib_sandbox.hpp new file mode 100644 index 0000000000..9878674d71 --- /dev/null +++ b/third_party/rlbox/include/rlbox_dylib_sandbox.hpp @@ -0,0 +1,314 @@ +#pragma once + +#include <cstdint> +#include <cstdlib> +#include <mutex> +#ifndef RLBOX_USE_CUSTOM_SHARED_LOCK +# include <shared_mutex> +#endif +#include <utility> + +#if defined(_WIN32) +// Ensure the min/max macro in the header doesn't collide with functions in +// std:: +# ifndef NOMINMAX +# define NOMINMAX +# endif +# include <windows.h> +#else +# include <dlfcn.h> +#endif + +#include "rlbox_helpers.hpp" + +namespace rlbox { + +class rlbox_dylib_sandbox; + +struct rlbox_dylib_sandbox_thread_data +{ + rlbox_dylib_sandbox* sandbox; + uint32_t last_callback_invoked; +}; + +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + +rlbox_dylib_sandbox_thread_data* get_rlbox_dylib_sandbox_thread_data(); +# define RLBOX_DYLIB_SANDBOX_STATIC_VARIABLES() \ + thread_local rlbox::rlbox_dylib_sandbox_thread_data \ + rlbox_dylib_sandbox_thread_info{ 0, 0 }; \ + namespace rlbox { \ + rlbox_dylib_sandbox_thread_data* get_rlbox_dylib_sandbox_thread_data() \ + { \ + return &rlbox_dylib_sandbox_thread_info; \ + } \ + } \ + static_assert(true, "Enforce semi-colon") + +#endif + +/** + * @brief Class that implements the null sandbox. This sandbox doesn't actually + * provide any isolation and only serves as a stepping stone towards migrating + * an application to use the RLBox API. + */ +class rlbox_dylib_sandbox +{ +public: + // Stick with the system defaults + using T_LongLongType = long long; + using T_LongType = long; + using T_IntType = int; + using T_PointerType = void*; + using T_ShortType = short; + // no-op sandbox can transfer buffers as there is no sandboxings + // Thus transfer is a noop + using can_grant_deny_access = void; + // if this plugin uses a separate function to lookup internal callbacks + using needs_internal_lookup_symbol = void; + +private: + void* sandbox = nullptr; + + RLBOX_SHARED_LOCK(callback_mutex); + static inline const uint32_t MAX_CALLBACKS = 64; + void* callback_unique_keys[MAX_CALLBACKS]{ 0 }; + void* callbacks[MAX_CALLBACKS]{ 0 }; + +#ifndef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + thread_local static inline rlbox_dylib_sandbox_thread_data thread_data{ 0, + 0 }; +#endif + + template<uint32_t N, typename T_Ret, typename... T_Args> + static T_Ret callback_trampoline(T_Args... params) + { +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + auto& thread_data = *get_rlbox_dylib_sandbox_thread_data(); +#endif + thread_data.last_callback_invoked = N; + using T_Func = T_Ret (*)(T_Args...); + T_Func func; + { +#ifndef RLBOX_SINGLE_THREADED_INVOCATIONS + RLBOX_ACQUIRE_SHARED_GUARD(lock, thread_data.sandbox->callback_mutex); +#endif + func = reinterpret_cast<T_Func>(thread_data.sandbox->callbacks[N]); + } + // Callbacks are invoked through function pointers, cannot use std::forward + // as we don't have caller context for T_Args, which means they are all + // effectively passed by value + return func(params...); + } + +protected: +#if defined(_WIN32) + using path_buf = const LPCWSTR; +#else + using path_buf = const char*; +#endif + + inline void impl_create_sandbox(path_buf path) + { +#if defined(_WIN32) + sandbox = (void*)LoadLibraryW(path); +#else + sandbox = dlopen(path, RTLD_LAZY | RTLD_LOCAL); +#endif + + if (!sandbox) { + std::string error_msg = "Could not load dynamic library: "; +#if defined(_WIN32) + DWORD errorMessageID = GetLastError(); + if (errorMessageID != 0) { + LPSTR messageBuffer = nullptr; + // The api creates the buffer that holds the message + size_t size = FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + errorMessageID, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&messageBuffer, + 0, + NULL); + // Copy the error message into a std::string. + std::string message(messageBuffer, size); + error_msg += message; + LocalFree(messageBuffer); + } +#else + error_msg += dlerror(); +#endif + detail::dynamic_check(false, error_msg.c_str()); + } + } + + inline void impl_destroy_sandbox() + { +#if defined(_WIN32) + FreeLibrary((HMODULE)sandbox); +#else + dlclose(sandbox); +#endif + sandbox = nullptr; + } + + template<typename T> + inline void* impl_get_unsandboxed_pointer(T_PointerType p) const + { + return p; + } + + template<typename T> + inline T_PointerType impl_get_sandboxed_pointer(const void* p) const + { + return const_cast<T_PointerType>(p); + } + + template<typename T> + static inline void* impl_get_unsandboxed_pointer_no_ctx( + T_PointerType p, + const void* /* example_unsandboxed_ptr */, + rlbox_dylib_sandbox* (* // Func ptr + /* param: expensive_sandbox_finder */)( + const void* example_unsandboxed_ptr)) + { + return p; + } + + template<typename T> + static inline T_PointerType impl_get_sandboxed_pointer_no_ctx( + const void* p, + const void* /* example_unsandboxed_ptr */, + rlbox_dylib_sandbox* (* // Func ptr + /* param: expensive_sandbox_finder */)( + const void* example_unsandboxed_ptr)) + { + return const_cast<T_PointerType>(p); + } + + inline T_PointerType impl_malloc_in_sandbox(size_t size) + { + void* p = malloc(size); + return p; + } + + inline void impl_free_in_sandbox(T_PointerType p) { free(p); } + + static inline bool impl_is_in_same_sandbox(const void*, const void*) + { + return true; + } + + inline bool impl_is_pointer_in_sandbox_memory(const void*) { return true; } + inline bool impl_is_pointer_in_app_memory(const void*) { return true; } + + inline size_t impl_get_total_memory() + { + return std::numeric_limits<size_t>::max(); + } + + inline void* impl_get_memory_location() + { + // There isn't any sandbox memory for the dylib_sandbox as we just redirect + // to the app. Also, this is mostly used for pointer swizzling or sandbox + // bounds checks which is also not present/not required. So we can just + // return null + return nullptr; + } + + void* impl_lookup_symbol(const char* func_name) + { +#if defined(_WIN32) + void* ret = GetProcAddress((HMODULE)sandbox, func_name); +#else + void* ret = dlsym(sandbox, func_name); +#endif + detail::dynamic_check(ret != nullptr, "Symbol not found"); + return ret; + } + + void* impl_internal_lookup_symbol(const char* func_name) + { + return impl_lookup_symbol(func_name); + } + + template<typename T, typename T_Converted, typename... T_Args> + auto impl_invoke_with_func_ptr(T_Converted* func_ptr, T_Args&&... params) + { +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + auto& thread_data = *get_rlbox_dylib_sandbox_thread_data(); +#endif + auto old_sandbox = thread_data.sandbox; + thread_data.sandbox = this; + auto on_exit = detail::make_scope_exit([&] { + thread_data.sandbox = old_sandbox; + }); + return (*func_ptr)(params...); + } + + template<typename T_Ret, typename... T_Args> + inline T_PointerType impl_register_callback(void* key, void* callback) + { + RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex); + + void* chosen_trampoline = nullptr; + + // need a compile time for loop as we we need I to be a compile time value + // this is because we are returning the I'th callback trampoline + detail::compile_time_for<MAX_CALLBACKS>([&](auto I) { + if (!chosen_trampoline && callback_unique_keys[I.value] == nullptr) { + callback_unique_keys[I.value] = key; + callbacks[I.value] = callback; + chosen_trampoline = reinterpret_cast<void*>( + callback_trampoline<I.value, T_Ret, T_Args...>); + } + }); + + return reinterpret_cast<T_PointerType>(chosen_trampoline); + } + + static inline std::pair<rlbox_dylib_sandbox*, void*> + impl_get_executed_callback_sandbox_and_key() + { +#ifdef RLBOX_EMBEDDER_PROVIDES_TLS_STATIC_VARIABLES + auto& thread_data = *get_rlbox_dylib_sandbox_thread_data(); +#endif + auto sandbox = thread_data.sandbox; + auto callback_num = thread_data.last_callback_invoked; + void* key = sandbox->callback_unique_keys[callback_num]; + return std::make_pair(sandbox, key); + } + + template<typename T_Ret, typename... T_Args> + inline void impl_unregister_callback(void* key) + { + RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex); + for (uint32_t i = 0; i < MAX_CALLBACKS; i++) { + if (callback_unique_keys[i] == key) { + callback_unique_keys[i] = nullptr; + callbacks[i] = nullptr; + break; + } + } + } + + template<typename T> + inline T* impl_grant_access(T* src, size_t num, bool& success) + { + RLBOX_UNUSED(num); + success = true; + return src; + } + + template<typename T> + inline T* impl_deny_access(T* src, size_t num, bool& success) + { + RLBOX_UNUSED(num); + success = true; + return src; + } +}; + +} |