Bug 1584011 - Bump RLBox library to the latest version r=froydnj

Differential Revision: https://phabricator.services.mozilla.com/D47389

--HG--
extra : moz-landing-system : lando
This commit is contained in:
shravanrn@gmail.com 2019-09-27 19:24:47 +00:00
parent c244a4d41d
commit 18f49450b7
8 changed files with 213 additions and 45 deletions

View File

@ -1,7 +1,7 @@
This directory contains the rlbox source from the upstream repo:
https://github.com/PLSysSec/rlbox_sandboxing_api/
Current version: [commit d4eb25c469c45a2d18c34e96ef49581f9a5802c3]
Current version: [commit 521dcd664b60d03e7b7082199407fa20c3f812b7]
UPDATING:

View File

@ -65,18 +65,45 @@ public:
*
* @param reason An explanation why the unverified unwrapping is safe.
*/
template<size_t N>
inline auto unverified_safe_because(const char (&reason)[N])
{
RLBOX_UNUSED(reason);
return UNSAFE_unverified();
}
template<size_t N>
inline auto unverified_safe_because(const char (&reason)[N]) const
{
RLBOX_UNUSED(reason);
return UNSAFE_unverified();
}
rlbox_detail_member_and_const(
template<size_t N>
inline auto unverified_safe_because(const char (&reason)[N]),
{
RLBOX_UNUSED(reason);
static_assert(!std::is_pointer_v<T>,
"unverified_safe_because does not support pointers. Use "
"unverified_safe_pointer_because.");
return UNSAFE_unverified();
});
rlbox_detail_member_and_const(
template<size_t N>
inline auto unverified_safe_pointer_because(size_t count,
const char (&reason)[N]),
{
RLBOX_UNUSED(reason);
static_assert(std::is_pointer_v<T>, "Expected pointer type");
using T_Pointed = std::remove_pointer_t<T>;
if_constexpr_named(cond1, std::is_pointer_v<T_Pointed>)
{
rlbox_detail_static_fail_because(
cond1,
"There is no way to use unverified_safe_pointer_because for "
"'pointers to pointers' safely. Use copy_and_verify instead.");
return nullptr;
}
auto ret = UNSAFE_unverified();
if (ret != nullptr) {
size_t bytes = sizeof(T) * count;
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(ret, bytes);
}
return ret;
});
inline auto INTERNAL_unverified_safe() { return UNSAFE_unverified(); }
inline auto INTERNAL_unverified_safe() const { return UNSAFE_unverified(); }
#define BinaryOpValAndPtr(opSymbol) \
template<typename T_Rhs> \

View File

@ -68,17 +68,17 @@ namespace detail {
// Create an extension point so applications can provide their own shared lock
// implementation
#ifndef rlbox_use_custom_shared_lock
# define rlbox_shared_lock(name) std::shared_timed_mutex name
# define rlbox_acquire_shared_guard(name, ...) \
#ifndef RLBOX_USE_CUSTOM_SHARED_LOCK
# define RLBOX_SHARED_LOCK(name) std::shared_timed_mutex name
# define RLBOX_ACQUIRE_SHARED_GUARD(name, ...) \
std::shared_lock<std::shared_timed_mutex> name(__VA_ARGS__)
# define rlbox_acquire_unique_guard(name, ...) \
# define RLBOX_ACQUIRE_UNIQUE_GUARD(name, ...) \
std::unique_lock<std::shared_timed_mutex> name(__VA_ARGS__)
#else
# if !defined(rlbox_shared_lock) || !defined(rlbox_acquire_shared_guard) || \
!defined(rlbox_acquire_unique_guard)
# if !defined(RLBOX_SHARED_LOCK) || !defined(RLBOX_ACQUIRE_SHARED_GUARD) || \
!defined(RLBOX_ACQUIRE_UNIQUE_GUARD)
# error \
"rlbox_use_custom_shared_lock defined but missing definitions for rlbox_shared_lock, rlbox_acquire_shared_guard, rlbox_acquire_unique_guard"
"RLBOX_USE_CUSTOM_SHARED_LOCK defined but missing definitions for RLBOX_SHARED_LOCK, RLBOX_ACQUIRE_SHARED_GUARD, RLBOX_ACQUIRE_UNIQUE_GUARD"
# endif
#endif
@ -124,6 +124,13 @@ namespace detail {
const_cast<T_ConstClassPtr>(this)->func_name(__VA_ARGS__)); \
}
#define rlbox_detail_member_and_const(sig, ...) \
sig __VA_ARGS__ \
\
sig const __VA_ARGS__ \
\
static_assert(true)
template<typename T>
inline auto remove_volatile_from_ptr_cast(T* ptr)
{
@ -168,6 +175,48 @@ namespace detail {
}
}
// Scope Exit guards
template<typename T_ExitFunc>
class scope_exit
{
T_ExitFunc exit_func;
bool released;
public:
explicit scope_exit(T_ExitFunc&& cleanup)
: exit_func(cleanup)
, released(true)
{}
scope_exit(scope_exit&& rhs)
: exit_func(std::move(rhs.exit_func))
, released(rhs.released)
{
rhs.release();
}
~scope_exit()
{
if (released) {
exit_func();
}
}
void release() { released = false; }
private:
explicit scope_exit(const scope_exit&) = delete;
scope_exit& operator=(const scope_exit&) = delete;
scope_exit& operator=(scope_exit&&) = delete;
};
template<typename T_ExitFunc>
[[nodiscard]] scope_exit<T_ExitFunc> make_scope_exit(
T_ExitFunc&& exitFunction)
{
return scope_exit<T_ExitFunc>(std::move(exitFunction));
}
/*
Make sure classes can access the private memmbers of tainted<T1> and
tainted_volatile. Ideally, this should be

View File

@ -3,7 +3,7 @@
#include <cstdint>
#include <cstdlib>
#include <mutex>
#ifndef rlbox_use_custom_shared_lock
#ifndef RLBOX_USE_CUSTOM_SHARED_LOCK
# include <shared_mutex>
#endif
#include <utility>
@ -28,7 +28,7 @@ public:
using T_ShortType = short;
private:
rlbox_shared_lock(callback_mutex);
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 };
@ -49,7 +49,7 @@ private:
using T_Func = T_Ret (*)(T_Args...);
T_Func func;
{
rlbox_acquire_shared_guard(lock, thread_data.sandbox->callback_mutex);
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
@ -158,7 +158,7 @@ protected:
template<typename T_Ret, typename... T_Args>
inline T_PointerType impl_register_callback(void* key, void* callback)
{
rlbox_acquire_unique_guard(lock, callback_mutex);
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, callback_mutex);
void* chosen_trampoline = nullptr;
@ -188,7 +188,7 @@ protected:
template<typename T_Ret, typename... T_Args>
inline void impl_unregister_callback(void* key)
{
rlbox_acquire_unique_guard(lock, callback_mutex);
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;

View File

@ -4,12 +4,19 @@
#include <algorithm>
#include <atomic>
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
# include <chrono>
#endif
#include <cstdlib>
#include <map>
#include <mutex>
#ifndef rlbox_use_custom_shared_lock
#ifndef RLBOX_USE_CUSTOM_SHARED_LOCK
# include <shared_mutex>
#endif
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
# include <sstream>
# include <string>
#endif
#include <type_traits>
#include <utility>
#include <vector>
@ -21,6 +28,10 @@
#include "rlbox_type_traits.hpp"
#include "rlbox_wrapper_traits.hpp"
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
using namespace std::chrono;
#endif
namespace rlbox {
namespace convert_fn_ptr_to_sandbox_equivalent_detail {
@ -35,6 +46,39 @@ namespace convert_fn_ptr_to_sandbox_equivalent_detail {
T_Ret (*)(T_Args...));
}
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
enum class rlbox_transition
{
INVOKE,
CALLBACK
};
struct rlbox_transition_timing
{
rlbox_transition invoke;
const char* name;
void* ptr;
int64_t time;
std::string to_string()
{
std::ostringstream ret;
if (invoke == rlbox_transition::INVOKE) {
ret << name;
} else {
ret << "Callback " << ptr;
}
ret << " : " << time << "\n";
return ret.str();
}
};
#endif
#ifndef RLBOX_SINGLE_THREADED_INVOCATIONS
# error \
"RLBox does not yet support threading. Please define RLBOX_SINGLE_THREADED_INVOCATIONS prior to including RLBox and ensure you are only using it from a single thread. If threading is required, please file a bug."
#endif
/**
* @brief Encapsulation for sandboxes.
*
@ -47,13 +91,17 @@ class rlbox_sandbox : protected T_Sbx
KEEP_CLASSES_FRIENDLY
private:
static inline rlbox_shared_lock(sandbox_list_lock);
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
std::vector<rlbox_transition_timing> transition_times;
#endif
static inline RLBOX_SHARED_LOCK(sandbox_list_lock);
// The actual type of the vector is std::vector<rlbox_sandbox<T_Sbx>*>
// However clang 5, 6 have bugs where compilation seg-faults on this type
// So we just use this std::vector<void*>
static inline std::vector<void*> sandbox_list;
rlbox_shared_lock(func_ptr_cache_lock);
RLBOX_SHARED_LOCK(func_ptr_cache_lock);
std::map<std::string, void*> func_ptr_map;
// This variable tracks of the sandbox has already been created/destroyed.
@ -180,6 +228,19 @@ private:
T_Func_Ret (*)(rlbox_sandbox<T_Sbx>&, tainted<T_Args, T_Sbx>...);
auto target_fn_ptr = reinterpret_cast<T_Func>(key);
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
high_resolution_clock::time_point enter_time = high_resolution_clock::now();
auto on_exit = rlbox::detail::make_scope_exit([&] {
auto exit_time = high_resolution_clock::now();
int64_t ns = duration_cast<nanoseconds>(exit_time - enter_time).count();
sandbox.transition_times.push_back(
rlbox_transition_timing{ rlbox_transition::CALLBACK,
nullptr /* func_name */,
key /* func_ptr */,
ns });
});
#endif
if constexpr (std::is_void_v<T_Func_Ret>) {
(*target_fn_ptr)(
sandbox,
@ -236,7 +297,7 @@ private:
example_sandbox_ptr != nullptr,
"Internal error: received a null example pointer. Please file a bug.");
rlbox_acquire_shared_guard(lock, sandbox_list_lock);
RLBOX_ACQUIRE_SHARED_GUARD(lock, sandbox_list_lock);
for (auto sandbox_v : sandbox_list) {
auto sandbox = reinterpret_cast<rlbox_sandbox<T_Sbx>*>(sandbox_v);
if (sandbox->is_pointer_in_sandbox_memory(example_sandbox_ptr)) {
@ -274,6 +335,14 @@ public:
template<typename... T_Args>
inline auto 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
// platform)
for (int i = 0; i < 10; i++) {
auto val = high_resolution_clock::now();
RLBOX_UNUSED(val);
}
#endif
auto expected = Sandbox_Status::NOT_CREATED;
bool success = sandbox_created.compare_exchange_strong(
expected, Sandbox_Status::INITIALIZING /* desired */);
@ -288,7 +357,7 @@ public:
},
[&]() {
sandbox_created.store(Sandbox_Status::CREATED);
rlbox_acquire_unique_guard(lock, sandbox_list_lock);
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, sandbox_list_lock);
sandbox_list.push_back(this);
});
}
@ -308,7 +377,7 @@ public:
"destroyed concurrently");
{
rlbox_acquire_unique_guard(lock, sandbox_list_lock);
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, sandbox_list_lock);
auto el_ref = std::find(sandbox_list.begin(), sandbox_list.end(), this);
detail::dynamic_check(
el_ref != sandbox_list.end(),
@ -478,7 +547,7 @@ public:
void* lookup_symbol(const char* func_name)
{
{
rlbox_acquire_shared_guard(lock, func_ptr_cache_lock);
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()) {
@ -487,7 +556,7 @@ public:
}
void* func_ptr = this->impl_lookup_symbol(func_name);
rlbox_acquire_unique_guard(lock, func_ptr_cache_lock);
RLBOX_ACQUIRE_UNIQUE_GUARD(lock, func_ptr_cache_lock);
func_ptr_map[func_name] = func_ptr;
return func_ptr;
}
@ -498,7 +567,7 @@ public:
T_Args&&... params)
{
return INTERNAL_invoke_with_func_ptr<T, T_Args...>(
lookup_symbol(func_name), std::forward<T_Args>(params)...);
func_name, lookup_symbol(func_name), std::forward<T_Args>(params)...);
}
// this is an internal function invoked from macros, so it has be public
@ -507,8 +576,21 @@ public:
// calls with the same signature can share the same code segments for
// sandboxed function execution in the binary
template<typename T, typename... T_Args>
auto INTERNAL_invoke_with_func_ptr(void* func_ptr, T_Args&&... params)
auto INTERNAL_invoke_with_func_ptr(const char* func_name,
void* func_ptr,
T_Args&&... params)
{
// unused in some paths
RLBOX_UNUSED(func_name);
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
auto enter_time = high_resolution_clock::now();
auto on_exit = rlbox::detail::make_scope_exit([&] {
auto exit_time = high_resolution_clock::now();
int64_t ns = duration_cast<nanoseconds>(exit_time - enter_time).count();
transition_times.push_back(rlbox_transition_timing{
rlbox_transition::INVOKE, func_name, func_ptr, ns });
});
#endif
(check_invoke_param_type_is_ok<T_Args>(), ...);
static_assert(
@ -710,6 +792,14 @@ public:
{
return tainted<T*, T_Sbx>::internal_factory(reinterpret_cast<T*>(func_ptr));
}
#ifdef RLBOX_MEASURE_TRANSITION_TIMES
inline std::vector<rlbox_transition_timing>&
process_and_get_transition_times()
{
return transition_times;
}
#endif
};
#if defined(__clang__)
@ -739,6 +829,7 @@ public:
# define invoke_sandbox_function(func_name, ...) \
template INTERNAL_invoke_with_func_ptr<decltype(func_name)>( \
#func_name, \
sandbox_lookup_symbol_helper(RLBOX_USE_STATIC_CALLS(), func_name), \
##__VA_ARGS__)

View File

@ -52,8 +52,7 @@ inline tainted<T_Lhs, T_Sbx> sandbox_reinterpret_cast(
"sandbox_reinterpret_cast on incompatible types");
tainted<T_Rhs, T_Sbx> taintedVal = rhs;
auto raw =
reinterpret_cast<T_Lhs>(taintedVal.unverified_safe_because("internal use"));
auto raw = reinterpret_cast<T_Lhs>(taintedVal.INTERNAL_unverified_safe());
auto ret = tainted<T_Lhs, T_Sbx>::internal_factory(raw);
return ret;
}
@ -73,8 +72,7 @@ inline tainted<T_Lhs, T_Sbx> sandbox_const_cast(
"sandbox_const_cast on incompatible types");
tainted<T_Rhs, T_Sbx> taintedVal = rhs;
auto raw =
const_cast<T_Lhs>(taintedVal.unverified_safe_because("internal use"));
auto raw = const_cast<T_Lhs>(taintedVal.INTERNAL_unverified_safe());
auto ret = tainted<T_Lhs, T_Sbx>::internal_factory(raw);
return ret;
}
@ -94,8 +92,7 @@ inline tainted<T_Lhs, T_Sbx> sandbox_static_cast(
"sandbox_static_cast on incompatible types");
tainted<T_Rhs, T_Sbx> taintedVal = rhs;
auto raw =
static_cast<T_Lhs>(taintedVal.unverified_safe_because("internal use"));
auto raw = static_cast<T_Lhs>(taintedVal.INTERNAL_unverified_safe());
auto ret = tainted<T_Lhs, T_Sbx>::internal_factory(raw);
return ret;
}
@ -125,7 +122,7 @@ inline T_Wrap<T_Rhs*, T_Sbx> memset(rlbox_sandbox<T_Sbx>& sandbox,
"Called memset for memory larger than the sandbox");
tainted<T_Rhs*, T_Sbx> ptr_tainted = ptr;
void* dest_start = ptr_tainted.unverified_safe_because("internal use");
void* dest_start = ptr_tainted.INTERNAL_unverified_safe();
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(dest_start, num_val);
std::memset(dest_start, detail::unwrap_value(value), num_val);
@ -157,7 +154,7 @@ inline T_Wrap<T_Rhs*, T_Sbx> memcpy(rlbox_sandbox<T_Sbx>& sandbox,
"Called memcpy for memory larger than the sandbox");
tainted<T_Rhs*, T_Sbx> dest_tainted = dest;
void* dest_start = dest_tainted.unverified_safe_because("internal use");
void* dest_start = dest_tainted.INTERNAL_unverified_safe();
detail::check_range_doesnt_cross_app_sbx_boundary<T_Sbx>(dest_start, num_val);
// src also needs to be checked, as we don't want to allow a src rand to start

View File

@ -45,6 +45,10 @@ public:
(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(); }
};
template<typename T_Sbx>

View File

@ -14,9 +14,9 @@ inline auto unwrap_value(T_Rhs&& rhs) noexcept
{
using T_RhsNoQ = detail::remove_cv_ref_t<T_Rhs>;
if constexpr (detail::rlbox_is_wrapper_v<T_RhsNoQ>) {
return rhs.unverified_safe_because("internal use");
return rhs.INTERNAL_unverified_safe();
} else if constexpr (detail::rlbox_is_tainted_boolean_hint_v<T_RhsNoQ>) {
return rhs.unverified_safe_because("internal use");
return rhs.INTERNAL_unverified_safe();
} else {
return rhs;
}