mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-21 17:25:36 +00:00
Bug 1737701 - Update rlbox for fallible sandbox, static linking support r=glandium
Differential Revision: https://phabricator.services.mozilla.com/D129455
This commit is contained in:
parent
e58ea79f59
commit
321dd6bde0
2
third_party/rlbox/README-mozilla
vendored
2
third_party/rlbox/README-mozilla
vendored
@ -1,7 +1,7 @@
|
||||
This directory contains the rlbox source from the upstream repo:
|
||||
https://github.com/PLSysSec/rlbox_sandboxing_api/
|
||||
|
||||
Current version: [commit fc796e549b3a48e89b9a8db28011dcad06494ba3]
|
||||
Current version: [commit 71222a234ceae75ff70e09d0855ebeb3b4c961a7]
|
||||
|
||||
UPDATING:
|
||||
|
||||
|
74
third_party/rlbox/include/rlbox.hpp
vendored
74
third_party/rlbox/include/rlbox.hpp
vendored
@ -655,7 +655,7 @@ public:
|
||||
* @brief Copy a tainted string from sandbox and verify it.
|
||||
*
|
||||
* @param verifer Function used to verify the copied value.
|
||||
* @tparam T_Func the type of the verifier ``T_Ret(*)(unique_ptr<char[]>)``
|
||||
* @tparam T_Func the type of the verifier either ``T_Ret(*)(unique_ptr<char[]>)`` or ``T_Ret(*)(std::string)``
|
||||
* @return Whatever the verifier function returns.
|
||||
*/
|
||||
template<typename T_Func>
|
||||
@ -667,23 +667,53 @@ public:
|
||||
static_assert(std::is_same_v<char, T_CopyAndVerifyRangeEl>,
|
||||
"copy_and_verify_string only allows char*");
|
||||
|
||||
using T_VerifParam = detail::func_first_arg_t<T_Func>;
|
||||
|
||||
auto start = impl().get_raw_value();
|
||||
if (start == nullptr) {
|
||||
return verifier(nullptr);
|
||||
if_constexpr_named(cond1, std::is_same_v<T_VerifParam, std::unique_ptr<char[]>> || std::is_same_v<T_VerifParam, std::unique_ptr<const char[]>>) {
|
||||
if (start == nullptr) {
|
||||
return verifier(nullptr);
|
||||
}
|
||||
|
||||
// it is safe to run strlen on a tainted<string> as worst case, the string
|
||||
// does not have a null and we try to copy all the memory out of the sandbox
|
||||
// however, copy_and_verify_range ensures that we never copy memory outsider
|
||||
// the range
|
||||
auto str_len = std::strlen(start) + 1;
|
||||
std::unique_ptr<T_CopyAndVerifyRangeEl[]> target =
|
||||
copy_and_verify_range_helper(str_len);
|
||||
|
||||
// ensure the string has a trailing null
|
||||
target[str_len - 1] = '\0';
|
||||
|
||||
return verifier(std::move(target));
|
||||
} else if_constexpr_named (cond2, std::is_same_v<T_VerifParam, std::string>) {
|
||||
if (start == nullptr) {
|
||||
std::string param = "";
|
||||
return verifier(param);
|
||||
}
|
||||
|
||||
// it is safe to run strlen on a tainted<string> as worst case, the string
|
||||
// does not have a null and we try to copy all the memory out of the sandbox
|
||||
// however, copy_and_verify_range ensures that we never copy memory outsider
|
||||
// the range
|
||||
auto str_len = std::strlen(start) + 1;
|
||||
|
||||
const char* checked_start = (const char*) verify_range_helper(str_len);
|
||||
if (checked_start == nullptr) {
|
||||
std::string param = "";
|
||||
return verifier(param);
|
||||
}
|
||||
|
||||
std::string copy(checked_start, str_len - 1);
|
||||
return verifier(std::move(copy));
|
||||
} else {
|
||||
constexpr bool unknownCase = !(cond1 || cond2);
|
||||
rlbox_detail_static_fail_because(
|
||||
unknownCase,
|
||||
"copy_and_verify_string verifier parameter should either be unique_ptr<char[]>, unique_ptr<const char[]> or std::string"
|
||||
);
|
||||
}
|
||||
|
||||
// it is safe to run strlen on a tainted<string> as worst case, the string
|
||||
// does not have a null and we try to copy all the memory out of the sandbox
|
||||
// however, copy_and_verify_range ensures that we never copy memory outsider
|
||||
// the range
|
||||
auto str_len = std::strlen(start) + 1;
|
||||
std::unique_ptr<T_CopyAndVerifyRangeEl[]> target =
|
||||
copy_and_verify_range_helper(str_len);
|
||||
|
||||
// ensure the string has a trailing null
|
||||
target[str_len - 1] = '\0';
|
||||
|
||||
return verifier(std::move(target));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -851,10 +881,10 @@ class tainted : public tainted_base_impl<tainted, T, T_Sbx>
|
||||
// Classes recieve their own specialization
|
||||
static_assert(
|
||||
!std::is_class_v<T>,
|
||||
"Missing specialization for class T. This error occurs for one "
|
||||
"Missing definition for class T. This error occurs for one "
|
||||
"of 2 reasons.\n"
|
||||
" 1) Make sure you have include a call rlbox_load_structs_from_library "
|
||||
"for this library.\n"
|
||||
"for this library with this class included.\n"
|
||||
" 2) Make sure you run (re-run) the struct-dump tool to list "
|
||||
"all structs in use by your program.\n");
|
||||
|
||||
@ -1105,10 +1135,10 @@ class tainted_volatile : public tainted_base_impl<tainted_volatile, T, T_Sbx>
|
||||
// Classes recieve their own specialization
|
||||
static_assert(
|
||||
!std::is_class_v<T>,
|
||||
"Missing specialization for class T. This error occurs for one "
|
||||
"Missing definition for class T. This error occurs for one "
|
||||
"of 2 reasons.\n"
|
||||
" 1) Make sure you have include a call rlbox_load_structs_from_library "
|
||||
"for this library.\n"
|
||||
"for this library with this class included.\n"
|
||||
" 2) Make sure you run (re-run) the struct-dump tool to list "
|
||||
"all structs in use by your program.\n");
|
||||
|
||||
@ -1152,6 +1182,7 @@ private:
|
||||
inline std::remove_cv_t<T_SandboxedType> get_raw_sandbox_value(
|
||||
rlbox_sandbox<T_Sbx>& sandbox) const noexcept
|
||||
{
|
||||
RLBOX_UNUSED(sandbox);
|
||||
return data;
|
||||
};
|
||||
|
||||
@ -1169,6 +1200,7 @@ private:
|
||||
inline std::remove_cv_t<T_SandboxedType> get_raw_sandbox_value(
|
||||
rlbox_sandbox<T_Sbx>& sandbox) noexcept
|
||||
{
|
||||
RLBOX_UNUSED(sandbox);
|
||||
rlbox_detail_forward_to_const(get_raw_sandbox_value,
|
||||
std::remove_cv_t<T_SandboxedType>);
|
||||
};
|
||||
@ -1261,7 +1293,7 @@ public:
|
||||
// is safe.
|
||||
auto func = val.get_raw_sandbox_value();
|
||||
using T_Cast = std::remove_volatile_t<T_SandboxedType>;
|
||||
get_sandbox_value_ref() = reinterpret_cast<T_Cast>(func);
|
||||
get_sandbox_value_ref() = (T_Cast)func;
|
||||
}
|
||||
}
|
||||
else if_constexpr_named(
|
||||
|
13
third_party/rlbox/include/rlbox_app_pointer.hpp
vendored
13
third_party/rlbox/include/rlbox_app_pointer.hpp
vendored
@ -32,13 +32,13 @@ private:
|
||||
for (T_PointerTypeUnsigned i = counter; i < max_val; i++) {
|
||||
if (pointer_map.find(i) == pointer_map.end()) {
|
||||
counter = i + 1;
|
||||
return reinterpret_cast<T_PointerType>(i);
|
||||
return (T_PointerType)i;
|
||||
}
|
||||
}
|
||||
for (T_PointerTypeUnsigned i = min_val; i < counter; i++) {
|
||||
if (pointer_map.find(i) == pointer_map.end()) {
|
||||
counter = i + 1;
|
||||
return reinterpret_cast<T_PointerType>(i);
|
||||
return (T_PointerType)i;
|
||||
}
|
||||
}
|
||||
detail::dynamic_check(false, "Could not find free app pointer slot");
|
||||
@ -57,8 +57,7 @@ public:
|
||||
{
|
||||
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, map_mutex);
|
||||
T_PointerType idx = get_unused_index();
|
||||
T_PointerTypeUnsigned idx_int =
|
||||
reinterpret_cast<T_PointerTypeUnsigned>(idx);
|
||||
T_PointerTypeUnsigned idx_int = (T_PointerTypeUnsigned)idx;
|
||||
pointer_map[idx_int] = ptr;
|
||||
return idx;
|
||||
}
|
||||
@ -66,8 +65,7 @@ public:
|
||||
void remove_app_ptr(T_PointerType idx)
|
||||
{
|
||||
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, map_mutex);
|
||||
T_PointerTypeUnsigned idx_int =
|
||||
reinterpret_cast<T_PointerTypeUnsigned>(idx);
|
||||
T_PointerTypeUnsigned idx_int = (T_PointerTypeUnsigned)idx;
|
||||
auto it = pointer_map.find(idx_int);
|
||||
detail::dynamic_check(it != pointer_map.end(),
|
||||
"Error: removing a non-existing app pointer");
|
||||
@ -77,8 +75,7 @@ public:
|
||||
void* lookup_index(T_PointerType idx)
|
||||
{
|
||||
RLBOX_ACQUIRE_SHARED_GUARD(lock, map_mutex);
|
||||
T_PointerTypeUnsigned idx_int =
|
||||
reinterpret_cast<T_PointerTypeUnsigned>(idx);
|
||||
T_PointerTypeUnsigned idx_int = (T_PointerTypeUnsigned)idx;
|
||||
auto it = pointer_map.find(idx_int);
|
||||
detail::dynamic_check(it != pointer_map.end(),
|
||||
"Error: looking up a non-existing app pointer");
|
||||
|
@ -131,7 +131,7 @@ inline constexpr void convert_type_fundamental_or_array(T_To& to,
|
||||
is_signed_v<T_To_El> == is_signed_v<T_From_El>) {
|
||||
// Sanity check - this should definitely be true
|
||||
static_assert(sizeof(T_From_C) == sizeof(T_To_C));
|
||||
memcpy(&to, &from, sizeof(T_To_C));
|
||||
std::memcpy(&to, &from, sizeof(T_To_C));
|
||||
} else {
|
||||
for (size_t i = 0; i < std::extent_v<T_To_C>; i++) {
|
||||
convert_type_fundamental_or_array(to[i], from[i]);
|
||||
|
309
third_party/rlbox/include/rlbox_dylib_sandbox.hpp
vendored
Normal file
309
third_party/rlbox/include/rlbox_dylib_sandbox.hpp
vendored
Normal file
@ -0,0 +1,309 @@
|
||||
#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;
|
||||
{
|
||||
RLBOX_ACQUIRE_SHARED_GUARD(lock, thread_data.sandbox->callback_mutex);
|
||||
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
|
||||
thread_data.sandbox = this;
|
||||
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;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
11
third_party/rlbox/include/rlbox_helpers.hpp
vendored
11
third_party/rlbox/include/rlbox_helpers.hpp
vendored
@ -7,6 +7,9 @@
|
||||
#include <stdexcept>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#ifndef RLBOX_USE_CUSTOM_SHARED_LOCK
|
||||
#include <mutex>
|
||||
#endif
|
||||
|
||||
#include "rlbox_stdlib_polyfill.hpp"
|
||||
|
||||
@ -21,8 +24,12 @@ namespace detail {
|
||||
#if __cpp_exceptions && defined(RLBOX_USE_EXCEPTIONS)
|
||||
throw std::runtime_error(msg);
|
||||
#else
|
||||
std::cerr << msg << std::endl;
|
||||
std::abort();
|
||||
#ifdef RLBOX_CUSTOM_ABORT
|
||||
RLBOX_CUSTOM_ABORT(msg);
|
||||
#else
|
||||
std::cerr << msg << std::endl;
|
||||
std::abort();
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
// clang-format on
|
||||
|
14
third_party/rlbox/include/rlbox_noop_sandbox.hpp
vendored
14
third_party/rlbox/include/rlbox_noop_sandbox.hpp
vendored
@ -104,10 +104,9 @@ protected:
|
||||
static inline void* impl_get_unsandboxed_pointer_no_ctx(
|
||||
T_PointerType p,
|
||||
const void* /* example_unsandboxed_ptr */,
|
||||
rlbox_noop_sandbox* (
|
||||
* // Func ptr
|
||||
/* param: expensive_sandbox_finder */)(const void*
|
||||
example_unsandboxed_ptr))
|
||||
rlbox_noop_sandbox* (* // Func ptr
|
||||
/* param: expensive_sandbox_finder */)(
|
||||
const void* example_unsandboxed_ptr))
|
||||
{
|
||||
return p;
|
||||
}
|
||||
@ -116,10 +115,9 @@ protected:
|
||||
static inline T_PointerType impl_get_sandboxed_pointer_no_ctx(
|
||||
const void* p,
|
||||
const void* /* example_unsandboxed_ptr */,
|
||||
rlbox_noop_sandbox* (
|
||||
* // Func ptr
|
||||
/* param: expensive_sandbox_finder */)(const void*
|
||||
example_unsandboxed_ptr))
|
||||
rlbox_noop_sandbox* (* // Func ptr
|
||||
/* param: expensive_sandbox_finder */)(
|
||||
const void* example_unsandboxed_ptr))
|
||||
{
|
||||
return const_cast<T_PointerType>(p);
|
||||
}
|
||||
|
116
third_party/rlbox/include/rlbox_policy_types.hpp
vendored
116
third_party/rlbox/include/rlbox_policy_types.hpp
vendored
@ -281,4 +281,120 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tainted boolean value that serves as a "hint" and not a definite
|
||||
* answer. Comparisons with a tainted_volatile return such hints. They are
|
||||
* not `tainted<bool>` values because a compromised sandbox can modify
|
||||
* tainted_volatile data at any time.
|
||||
*/
|
||||
class tainted_boolean_hint
|
||||
{
|
||||
private:
|
||||
bool val;
|
||||
|
||||
public:
|
||||
tainted_boolean_hint(bool init)
|
||||
: val(init)
|
||||
{}
|
||||
tainted_boolean_hint(const tainted_boolean_hint&) = default;
|
||||
inline tainted_boolean_hint& operator=(bool rhs)
|
||||
{
|
||||
val = rhs;
|
||||
return *this;
|
||||
}
|
||||
inline tainted_boolean_hint operator!() { return tainted_boolean_hint(!val); }
|
||||
template<size_t N>
|
||||
inline bool unverified_safe_because(const char (&reason)[N]) const
|
||||
{
|
||||
(void)reason; /* unused */
|
||||
return val;
|
||||
}
|
||||
inline bool UNSAFE_unverified() const { return val; }
|
||||
inline bool UNSAFE_unverified() { return val; }
|
||||
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
|
||||
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
|
||||
|
||||
// Add a template parameter to make sure the assert only fires when called
|
||||
template<typename T=void>
|
||||
inline bool copy_and_verify(...) const
|
||||
{
|
||||
rlbox_detail_static_fail_because(
|
||||
detail::true_v<T>,
|
||||
"You can't call copy_and_verify on this value, as this is a result of a "
|
||||
"comparison with memory accessible by the sandbox. \n"
|
||||
"The sandbox could unexpectedly change the value leading to "
|
||||
"time-of-check-time-of-use attacks. \n"
|
||||
"You can avoid this by making a local copy of the data."
|
||||
"For example, if your original code, looked like \n"
|
||||
"if ((tainted_ptr->member == 5).copy_and_verify(...)) { ... } \n\n"
|
||||
"Change this to \n\n"
|
||||
"tainted<int> val = tainted_ptr->member\n"
|
||||
"if ((val == 5).copy_and_verify(...)) { ... } \n\n"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox) {...} \n\n"
|
||||
"Alternately, if you are sure your code is safe you can use the "
|
||||
"unverified_safe_because API to remove tainting\n");
|
||||
|
||||
// this is never executed, but we need it for the function to type-check
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tainted integer value that serves as a "hint" and not a definite
|
||||
* answer. Comparisons with a tainted_volatile return such hints. They are
|
||||
* not `tainted<int>` values because a compromised sandbox can modify
|
||||
* tainted_volatile data at any time.
|
||||
*/
|
||||
class tainted_int_hint
|
||||
{
|
||||
private:
|
||||
int val;
|
||||
|
||||
public:
|
||||
tainted_int_hint(int init)
|
||||
: val(init)
|
||||
{}
|
||||
tainted_int_hint(const tainted_int_hint&) = default;
|
||||
inline tainted_int_hint& operator=(int rhs)
|
||||
{
|
||||
val = rhs;
|
||||
return *this;
|
||||
}
|
||||
inline tainted_boolean_hint operator!() { return tainted_boolean_hint(!val); }
|
||||
template<size_t N>
|
||||
inline int unverified_safe_because(const char (&reason)[N]) const
|
||||
{
|
||||
(void)reason; /* unused */
|
||||
return val;
|
||||
}
|
||||
inline int UNSAFE_unverified() const { return val; }
|
||||
inline int UNSAFE_unverified() { return val; }
|
||||
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
|
||||
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
|
||||
|
||||
// Add a template parameter to make sure the assert only fires when called
|
||||
template<typename T=void>
|
||||
inline int copy_and_verify(...) const
|
||||
{
|
||||
rlbox_detail_static_fail_because(
|
||||
detail::true_v<T>,
|
||||
"You can't call copy_and_verify on this value, as this is a result of a "
|
||||
"comparison with memory accessible by the sandbox. \n"
|
||||
"The sandbox could unexpectedly change the value leading to "
|
||||
"time-of-check-time-of-use attacks. \n"
|
||||
"You can avoid this by making a local copy of the data."
|
||||
"For example, if your original code, looked like \n"
|
||||
"if ((tainted_ptr->member == 5).copy_and_verify(...)) { ... } \n\n"
|
||||
"Change this to \n\n"
|
||||
"tainted<int> val = tainted_ptr->member\n"
|
||||
"if ((val == 5).copy_and_verify(...)) { ... } \n\n"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox) {...} \n\n"
|
||||
"Alternately, if you are sure your code is safe you can use the "
|
||||
"unverified_safe_because API to remove tainting\n");
|
||||
|
||||
// this is never executed, but we need it for the function to type-check
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
|
98
third_party/rlbox/include/rlbox_sandbox.hpp
vendored
98
third_party/rlbox/include/rlbox_sandbox.hpp
vendored
@ -174,7 +174,7 @@ private:
|
||||
constexpr auto unknownCase = !(cond1 || cond2);
|
||||
rlbox_detail_static_fail_because(
|
||||
unknownCase,
|
||||
"Arguments to a sandbox function call should be primitives or wrapped "
|
||||
"Arguments to a sandbox function call should be primitives or wrapped "
|
||||
"types like tainted, callbacks etc.");
|
||||
}
|
||||
}
|
||||
@ -200,7 +200,10 @@ private:
|
||||
tainted<T_NoRef, T_Sbx> ret = param;
|
||||
return ret.UNSAFE_sandboxed(*this);
|
||||
} else {
|
||||
rlbox_detail_static_fail_because(detail::true_v<T_NoRef>, "Unknown case");
|
||||
rlbox_detail_static_fail_because(detail::true_v<T_NoRef>,
|
||||
"Only tainted types, callbacks or primitive values such as ints can be passed as parameters.\n"
|
||||
"To make a parameter tainted, try moving the allocation into the sandbox.\n"
|
||||
"If the parameter is a callback, try registering the callback via the register_callback API.");
|
||||
}
|
||||
}
|
||||
|
||||
@ -327,13 +330,14 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
detail::dynamic_check(
|
||||
false,
|
||||
"Internal error: Could not find the sandbox associated with example "
|
||||
"pointer. Please file a bug.");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename... T_Args>
|
||||
static auto impl_create_sandbox_helper(rlbox_sandbox<T_Sbx>* this_ptr, T_Args... args) {
|
||||
return this_ptr->impl_create_sandbox(std::forward<T_Args>(args)...);
|
||||
}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Unused member that allows the calling code to save data in a
|
||||
@ -362,7 +366,7 @@ public:
|
||||
* implementation. For the null sandbox, no arguments are necessary.
|
||||
*/
|
||||
template<typename... T_Args>
|
||||
inline auto create_sandbox(T_Args... args)
|
||||
inline bool create_sandbox(T_Args... args)
|
||||
{
|
||||
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
|
||||
// Warm up the timer. The first call is always slow (at least on the test
|
||||
@ -380,15 +384,27 @@ public:
|
||||
"create_sandbox called when sandbox already created/is being "
|
||||
"created concurrently");
|
||||
|
||||
return detail::return_first_result(
|
||||
[&]() {
|
||||
return this->impl_create_sandbox(std::forward<T_Args>(args)...);
|
||||
},
|
||||
[&]() {
|
||||
sandbox_created.store(Sandbox_Status::CREATED);
|
||||
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, sandbox_list_lock);
|
||||
sandbox_list.push_back(this);
|
||||
});
|
||||
using T_Result = rlbox::detail::polyfill::invoke_result_t<decltype(impl_create_sandbox_helper<T_Args...>), decltype(this), T_Args...>;
|
||||
|
||||
bool created = true;
|
||||
if constexpr (std::is_same_v<T_Result, void>) {
|
||||
this->impl_create_sandbox(std::forward<T_Args>(args)...);
|
||||
} else if constexpr (std::is_same_v<T_Result, bool>) {
|
||||
created = this->impl_create_sandbox(std::forward<T_Args>(args)...);
|
||||
} else {
|
||||
rlbox_detail_static_fail_because(
|
||||
(!std::is_same_v<T_Result, void> && !std::is_same_v<T_Result, bool>),
|
||||
"Expected impl_create_sandbox to return void or a boolean"
|
||||
);
|
||||
}
|
||||
|
||||
if (created) {
|
||||
sandbox_created.store(Sandbox_Status::CREATED);
|
||||
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, sandbox_list_lock);
|
||||
sandbox_list.push_back(this);
|
||||
}
|
||||
|
||||
return created;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -587,7 +603,13 @@ public:
|
||||
*/
|
||||
static inline bool is_in_same_sandbox(const void* p1, const void* p2)
|
||||
{
|
||||
return T_Sbx::impl_is_in_same_sandbox(p1, p2);
|
||||
const size_t num_args =
|
||||
detail::func_arg_nums_v<decltype(T_Sbx::impl_is_in_same_sandbox)>;
|
||||
if constexpr (num_args == 2) {
|
||||
return T_Sbx::impl_is_in_same_sandbox(p1, p2);
|
||||
} else {
|
||||
return T_Sbx::impl_is_in_same_sandbox(p1, p2, find_sandbox_from_example);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -673,6 +695,28 @@ public:
|
||||
return func_ptr;
|
||||
}
|
||||
|
||||
void* internal_lookup_symbol(const char* func_name)
|
||||
{
|
||||
{
|
||||
RLBOX_ACQUIRE_SHARED_GUARD(lock, func_ptr_cache_lock);
|
||||
|
||||
auto func_ptr_ref = func_ptr_map.find(func_name);
|
||||
if (func_ptr_ref != func_ptr_map.end()) {
|
||||
return func_ptr_ref->second;
|
||||
}
|
||||
}
|
||||
|
||||
void* func_ptr = 0;
|
||||
if constexpr(rlbox::detail::has_member_using_needs_internal_lookup_symbol_v<T_Sbx>) {
|
||||
func_ptr = this->impl_internal_lookup_symbol(func_name);
|
||||
} else {
|
||||
func_ptr = this->impl_lookup_symbol(func_name);
|
||||
}
|
||||
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, func_ptr_cache_lock);
|
||||
func_ptr_map[func_name] = func_ptr;
|
||||
return func_ptr;
|
||||
}
|
||||
|
||||
// this is an internal function invoked from macros, so it has be public
|
||||
template<typename T, typename... T_Args>
|
||||
inline auto INTERNAL_invoke_with_func_name(const char* func_name,
|
||||
@ -772,7 +816,7 @@ public:
|
||||
{
|
||||
rlbox_detail_static_fail_because(
|
||||
detail::true_v<T_Ret>,
|
||||
"Modify the callback to change the first parameter to a sandbox."
|
||||
"Modify the callback to change the first parameter to a sandbox. "
|
||||
"For instance if a callback has type\n\n"
|
||||
"int foo() {...}\n\n"
|
||||
"Change this to \n\n"
|
||||
@ -805,11 +849,11 @@ public:
|
||||
{
|
||||
rlbox_detail_static_fail_because(
|
||||
cond1,
|
||||
"Modify the callback to change the first parameter to a sandbox."
|
||||
"Modify the callback to change the first parameter to a sandbox. "
|
||||
"For instance if a callback has type\n\n"
|
||||
"int foo(int a, int b) {...}\n\n"
|
||||
"Change this to \n\n"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox,"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox, "
|
||||
"tainted<int, T_Sbx> a, tainted<int, T_Sbx> b) {...}\n");
|
||||
}
|
||||
else if_constexpr_named(
|
||||
@ -818,11 +862,11 @@ public:
|
||||
rlbox_detail_static_fail_because(
|
||||
cond2,
|
||||
"Change all arguments to the callback have to be tainted or "
|
||||
"tainted_opaque."
|
||||
"tainted_opaque. "
|
||||
"For instance if a callback has type\n\n"
|
||||
"int foo(int a, int b) {...}\n\n"
|
||||
"Change this to \n\n"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox,"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox, "
|
||||
"tainted<int, T_Sbx> a, tainted<int, T_Sbx> b) {...}\n");
|
||||
}
|
||||
else if_constexpr_named(
|
||||
@ -830,11 +874,11 @@ public:
|
||||
{
|
||||
rlbox_detail_static_fail_because(
|
||||
cond3,
|
||||
"Change all static array arguments to the callback to be pointers."
|
||||
"Change all static array arguments to the callback to be pointers. "
|
||||
"For instance if a callback has type\n\n"
|
||||
"int foo(int a[4]) {...}\n\n"
|
||||
"Change this to \n\n"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox,"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox, "
|
||||
"tainted<int*, T_Sbx> a) {...}\n");
|
||||
}
|
||||
else if_constexpr_named(
|
||||
@ -844,11 +888,11 @@ public:
|
||||
rlbox_detail_static_fail_because(
|
||||
cond4,
|
||||
"Change the callback return type to be tainted or tainted_opaque if it "
|
||||
"is not void."
|
||||
"is not void. "
|
||||
"For instance if a callback has type\n\n"
|
||||
"int foo(int a, int b) {...}\n\n"
|
||||
"Change this to \n\n"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox,"
|
||||
"tainted<int, T_Sbx> foo(rlbox_sandbox<T_Sbx>& sandbox, "
|
||||
"tainted<int, T_Sbx> a, tainted<int, T_Sbx> b) {...}\n");
|
||||
}
|
||||
else
|
||||
@ -905,7 +949,7 @@ public:
|
||||
inline tainted<T*, T_Sbx> INTERNAL_get_sandbox_function_name(
|
||||
const char* func_name)
|
||||
{
|
||||
return INTERNAL_get_sandbox_function_ptr<T>(lookup_symbol(func_name));
|
||||
return INTERNAL_get_sandbox_function_ptr<T>(internal_lookup_symbol(func_name));
|
||||
}
|
||||
|
||||
// this is an internal function invoked from macros, so it has be public
|
||||
|
20
third_party/rlbox/include/rlbox_stdlib.hpp
vendored
20
third_party/rlbox/include/rlbox_stdlib.hpp
vendored
@ -130,7 +130,12 @@ inline T_Wrap<T_Rhs*, T_Sbx> memset(rlbox_sandbox<T_Sbx>& sandbox,
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy to sandbox memory area.
|
||||
* @brief Copy to sandbox memory area. Note that memcpy is meant to be called on
|
||||
* byte arrays does not adjust data according to ABI differences. If the
|
||||
* programmer does accidentally call memcpy on buffers that needs ABI
|
||||
* adjustment, this may cause compatibility issues, but will not cause a
|
||||
* security issue as the destination is always a tainted or tainted_volatile
|
||||
* pointer
|
||||
*/
|
||||
template<typename T_Sbx,
|
||||
typename T_Rhs,
|
||||
@ -220,13 +225,18 @@ tainted<T*, T_Sbx> copy_memory_or_grant_access(rlbox_sandbox<T_Sbx>& sandbox,
|
||||
bool free_source_on_copy,
|
||||
bool& copied)
|
||||
{
|
||||
// Malloc in sandbox takes a uint32_t as the parameter, need a bounds check
|
||||
detail::dynamic_check(num <= std::numeric_limits<uint32_t>::max(),
|
||||
"Granting access too large a region");
|
||||
uint32_t num_trunc = num;
|
||||
|
||||
// sandbox can grant access if it includes the following line
|
||||
// using can_grant_deny_access = void;
|
||||
if constexpr (detail::has_member_using_can_grant_deny_access_v<T_Sbx>) {
|
||||
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(src, num);
|
||||
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(src, num_trunc);
|
||||
|
||||
bool success;
|
||||
auto ret = sandbox.INTERNAL_grant_access(src, num, success);
|
||||
auto ret = sandbox.INTERNAL_grant_access(src, num_trunc, success);
|
||||
if (success) {
|
||||
copied = false;
|
||||
return ret;
|
||||
@ -235,8 +245,8 @@ tainted<T*, T_Sbx> copy_memory_or_grant_access(rlbox_sandbox<T_Sbx>& sandbox,
|
||||
|
||||
using T_nocv = std::remove_cv_t<T>;
|
||||
tainted<T_nocv*, T_Sbx> copy =
|
||||
sandbox.template malloc_in_sandbox<T_nocv>(num);
|
||||
rlbox::memcpy(sandbox, copy, src, num);
|
||||
sandbox.template malloc_in_sandbox<T_nocv>(num_trunc);
|
||||
rlbox::memcpy(sandbox, copy, src, num_trunc);
|
||||
if (free_source_on_copy) {
|
||||
free(const_cast<void*>(reinterpret_cast<const void*>(src)));
|
||||
}
|
||||
|
34
third_party/rlbox/include/rlbox_type_traits.hpp
vendored
34
third_party/rlbox/include/rlbox_type_traits.hpp
vendored
@ -27,6 +27,40 @@ using valid_return_t =
|
||||
template<typename T>
|
||||
using valid_param_t = std::conditional_t<std::is_void_v<T>, void*, T>;
|
||||
|
||||
namespace func_first_arg_detail {
|
||||
template<typename Ret, typename Arg, typename... Rest>
|
||||
Arg func_first_arg_t_helper(Ret(*) (Arg, Rest...));
|
||||
|
||||
template<typename Ret, typename F, typename Arg, typename... Rest>
|
||||
Arg func_first_arg_t_helper(Ret(F::*) (Arg, Rest...));
|
||||
|
||||
template<typename Ret, typename F, typename Arg, typename... Rest>
|
||||
Arg func_first_arg_t_helper(Ret(F::*) (Arg, Rest...) const);
|
||||
|
||||
template <typename F>
|
||||
decltype(func_first_arg_t_helper(&F::operator())) first_argument_helper(F);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
using func_first_arg_t = decltype(func_first_arg_detail::first_argument_helper(std::declval<T>()));
|
||||
|
||||
namespace func_arg_nums_v_detail {
|
||||
template<typename T_Ret, typename... T_Args>
|
||||
constexpr size_t helper_two(T_Ret (*)(T_Args...))
|
||||
{
|
||||
return sizeof...(T_Args);
|
||||
}
|
||||
template<typename T_Func>
|
||||
constexpr size_t helper()
|
||||
{
|
||||
constexpr T_Func* ptr = nullptr;
|
||||
return helper_two(ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T_Func>
|
||||
constexpr size_t func_arg_nums_v = func_arg_nums_v_detail::helper<T_Func>();
|
||||
|
||||
template<typename T>
|
||||
using valid_array_el_t =
|
||||
std::conditional_t<std::is_void_v<T> || std::is_function_v<T>, int, T>;
|
||||
|
70
third_party/rlbox/include/rlbox_types.hpp
vendored
70
third_party/rlbox/include/rlbox_types.hpp
vendored
@ -24,73 +24,9 @@ class tainted;
|
||||
template<typename T, typename T_Sbx>
|
||||
class tainted_volatile;
|
||||
|
||||
/**
|
||||
* @brief Tainted boolean value that serves as a "hint" and not a definite
|
||||
* answer. Comparisons with a tainted_volatile return such hints. They are
|
||||
* not `tainted<bool>` values because a compromised sandbox can modify
|
||||
* tainted_volatile data at any time.
|
||||
*/
|
||||
class tainted_boolean_hint
|
||||
{
|
||||
private:
|
||||
bool val;
|
||||
class tainted_boolean_hint;
|
||||
|
||||
public:
|
||||
tainted_boolean_hint(bool init)
|
||||
: val(init)
|
||||
{}
|
||||
tainted_boolean_hint(const tainted_boolean_hint&) = default;
|
||||
inline tainted_boolean_hint& operator=(bool rhs)
|
||||
{
|
||||
val = rhs;
|
||||
return *this;
|
||||
}
|
||||
inline tainted_boolean_hint operator!() { return tainted_boolean_hint(!val); }
|
||||
template<size_t N>
|
||||
inline bool unverified_safe_because(const char (&reason)[N]) const
|
||||
{
|
||||
(void)reason; /* unused */
|
||||
return val;
|
||||
}
|
||||
inline bool UNSAFE_unverified() const { return val; }
|
||||
inline bool UNSAFE_unverified() { return val; }
|
||||
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
|
||||
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Tainted integer value that serves as a "hint" and not a definite
|
||||
* answer. Comparisons with a tainted_volatile return such hints. They are
|
||||
* not `tainted<int>` values because a compromised sandbox can modify
|
||||
* tainted_volatile data at any time.
|
||||
*/
|
||||
class tainted_int_hint
|
||||
{
|
||||
private:
|
||||
int val;
|
||||
|
||||
public:
|
||||
tainted_int_hint(int init)
|
||||
: val(init)
|
||||
{}
|
||||
tainted_int_hint(const tainted_int_hint&) = default;
|
||||
inline tainted_int_hint& operator=(int rhs)
|
||||
{
|
||||
val = rhs;
|
||||
return *this;
|
||||
}
|
||||
inline tainted_boolean_hint operator!() { return tainted_boolean_hint(!val); }
|
||||
template<size_t N>
|
||||
inline int unverified_safe_because(const char (&reason)[N]) const
|
||||
{
|
||||
(void)reason; /* unused */
|
||||
return val;
|
||||
}
|
||||
inline int UNSAFE_unverified() const { return val; }
|
||||
inline int UNSAFE_unverified() { return val; }
|
||||
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
|
||||
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
|
||||
};
|
||||
class tainted_int_hint;
|
||||
|
||||
template<typename T_Sbx>
|
||||
class rlbox_sandbox;
|
||||
@ -102,4 +38,6 @@ template<typename T, typename T_Sbx>
|
||||
class app_pointer;
|
||||
|
||||
class rlbox_noop_sandbox;
|
||||
|
||||
class rlbox_dylib_sandbox;
|
||||
}
|
||||
|
@ -151,4 +151,21 @@ constexpr bool has_member_using_can_grant_deny_access_v =
|
||||
detail_has_member_using_can_grant_deny_access::
|
||||
has_member_using_can_grant_deny_access<T>::value;
|
||||
|
||||
namespace detail_has_member_using_needs_internal_lookup_symbol {
|
||||
template<class T, class Enable = void>
|
||||
struct has_member_using_needs_internal_lookup_symbol : std::false_type
|
||||
{};
|
||||
|
||||
template<class T>
|
||||
struct has_member_using_needs_internal_lookup_symbol<
|
||||
T,
|
||||
std::void_t<typename T::needs_internal_lookup_symbol>> : std::true_type
|
||||
{};
|
||||
}
|
||||
|
||||
template<class T>
|
||||
constexpr bool has_member_using_needs_internal_lookup_symbol_v =
|
||||
detail_has_member_using_needs_internal_lookup_symbol::
|
||||
has_member_using_needs_internal_lookup_symbol<T>::value;
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user