add SYS_getrandom fallback for posix PAL (#431)
* add SYS_getrandom fallback for posix PAL Signed-off-by: SchrodingerZhu <i@zhuyi.fan> * address CR Signed-off-by: SchrodingerZhu <i@zhuyi.fan> * guard and comments Signed-off-by: SchrodingerZhu <i@zhuyi.fan> * more fallback behavior Signed-off-by: SchrodingerZhu <i@zhuyi.fan> * fix random device fd Signed-off-by: SchrodingerZhu <i@zhuyi.fan> * special handling for EAGAIN Signed-off-by: SchrodingerZhu <i@zhuyi.fan>
This commit is contained in:
committed by
GitHub
parent
9329db102f
commit
71d5bb8756
@@ -89,7 +89,7 @@ CHECK_CXX_SOURCE_COMPILES("
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#if __has_include(<sys/random.h>)
|
||||
#include <sys/random.h>
|
||||
# include <sys/random.h>
|
||||
#endif
|
||||
int main() {
|
||||
int entropy = 0;
|
||||
@@ -97,7 +97,6 @@ int main() {
|
||||
return res;
|
||||
}
|
||||
" SNMALLOC_PLATFORM_HAS_GETENTROPY)
|
||||
|
||||
# Provide as function so other projects can reuse
|
||||
# FIXME: This modifies some variables that may or may not be the ones that
|
||||
# provide flags and so is broken by design. It should be removed once Verona
|
||||
@@ -123,7 +122,7 @@ endfunction()
|
||||
function(clangformat_targets)
|
||||
# The clang-format tool is installed under a variety of different names. Try
|
||||
# to find a sensible one. Only look for versions 9 explicitly - we don't
|
||||
# know whether our clang-format file will work with newer versions of the
|
||||
# know whether our clang-format file will work with newer versions of the
|
||||
# tool. It does not work with older versions as AfterCaseLabel is not supported
|
||||
# in earlier versions.
|
||||
find_program(CLANG_FORMAT NAMES
|
||||
@@ -196,6 +195,7 @@ add_as_define(USE_SNMALLOC_STATS)
|
||||
add_as_define(SNMALLOC_QEMU_WORKAROUND)
|
||||
add_as_define(SNMALLOC_CI_BUILD)
|
||||
add_as_define(SNMALLOC_PLATFORM_HAS_GETENTROPY)
|
||||
|
||||
target_compile_definitions(snmalloc INTERFACE $<$<BOOL:CONST_QUALIFIED_MALLOC_USABLE_SIZE>:MALLOC_USABLE_SIZE_QUALIFIER=const>)
|
||||
|
||||
# In debug and CI builds, link the backtrace library so that we can get stack
|
||||
|
||||
@@ -4,8 +4,10 @@
|
||||
# include "../ds/bits.h"
|
||||
# include "pal_posix.h"
|
||||
|
||||
# include <fcntl.h>
|
||||
# include <string.h>
|
||||
# include <sys/mman.h>
|
||||
# include <syscall.h>
|
||||
|
||||
extern "C" int puts(const char* str);
|
||||
|
||||
@@ -18,12 +20,9 @@ namespace snmalloc
|
||||
* Bitmap of PalFeatures flags indicating the optional features that this
|
||||
* PAL supports.
|
||||
*
|
||||
* Linux does not support any features other than those in a generic POSIX
|
||||
* platform. This field is declared explicitly to remind anyone who
|
||||
* extends this PAL that they may need to extend the set of advertised
|
||||
* features.
|
||||
* We always make sure that linux has entropy support.
|
||||
*/
|
||||
static constexpr uint64_t pal_features = PALPOSIX::pal_features;
|
||||
static constexpr uint64_t pal_features = PALPOSIX::pal_features | Entropy;
|
||||
|
||||
static constexpr size_t page_size =
|
||||
Aal::aal_name == PowerPC ? 0x10000 : PALPOSIX::page_size;
|
||||
@@ -85,6 +84,122 @@ namespace snmalloc
|
||||
madvise(p, size, MADV_FREE);
|
||||
}
|
||||
}
|
||||
|
||||
static uint64_t get_entropy64()
|
||||
{
|
||||
// TODO: If the system call fails then the POSIX PAL calls libc
|
||||
// functions that can require malloc, which may result in deadlock.
|
||||
|
||||
// SYS_getrandom API stablized since 3.17.
|
||||
// This fallback implementation is to aid some environments
|
||||
// where SYS_getrandom is provided in kernel but the libc
|
||||
// is not providing getentropy interface.
|
||||
|
||||
union
|
||||
{
|
||||
uint64_t result;
|
||||
char buffer[sizeof(uint64_t)];
|
||||
};
|
||||
ssize_t ret;
|
||||
|
||||
// give a try to SYS_getrandom
|
||||
# ifdef SYS_getrandom
|
||||
static std::atomic_bool syscall_not_working = false;
|
||||
// Relaxed ordering should be fine here. This function will be called
|
||||
// during early initialisation, which will examine the availability in a
|
||||
// protected routine.
|
||||
if (false == syscall_not_working.load(std::memory_order_relaxed))
|
||||
{
|
||||
auto current = std::begin(buffer);
|
||||
auto target = std::end(buffer);
|
||||
while (auto length = target - current)
|
||||
{
|
||||
// Reading data via syscall from system entropy pool.
|
||||
// According to both MUSL and GLIBC implementation, getentropy uses
|
||||
// /dev/urandom (blocking API).
|
||||
//
|
||||
// The third argument here indicates:
|
||||
// 1. `GRND_RANDOM` bit is not set, so the source of entropy will be
|
||||
// `urandom`.
|
||||
// 2. `GRND_NONBLOCK` bit is set. Since we are reading from
|
||||
// `urandom`, this means if the entropy pool is
|
||||
// not initialised, we will get a EAGAIN.
|
||||
ret = syscall(SYS_getrandom, current, length, GRND_NONBLOCK);
|
||||
// check whether are interrupt by a signal
|
||||
if (SNMALLOC_UNLIKELY(ret < 0))
|
||||
{
|
||||
if (SNMALLOC_UNLIKELY(errno == EAGAIN))
|
||||
{
|
||||
// the system is going through early initialisation: at this stage
|
||||
// it is very likely that snmalloc is being used in some system
|
||||
// programs and we do not want to block it.
|
||||
return reinterpret_cast<uint64_t>(&result) ^
|
||||
reinterpret_cast<uint64_t>(&error);
|
||||
}
|
||||
if (errno != EINTR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
current += ret;
|
||||
}
|
||||
}
|
||||
if (SNMALLOC_UNLIKELY(target != current))
|
||||
{
|
||||
// in this routine, the only possible situations should be ENOSYS
|
||||
// or EPERM (forbidden by seccomp, for example).
|
||||
SNMALLOC_ASSERT(errno == ENOSYS || errno == EPERM);
|
||||
syscall_not_working.store(true, std::memory_order_relaxed);
|
||||
}
|
||||
else
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
# endif
|
||||
|
||||
// Syscall is not working.
|
||||
// In this case, it is not a good idea to fallback to std::random_device:
|
||||
// 1. it may want to use malloc to create a buffer, which causes
|
||||
// reentrancy problem during initialisation routine.
|
||||
// 2. some implementations also require libstdc++ to be linked since
|
||||
// its APIs are not exception-free.
|
||||
int flags = O_RDONLY;
|
||||
# if defined(O_CLOEXEC)
|
||||
flags |= O_CLOEXEC;
|
||||
# endif
|
||||
auto fd = open("/dev/urandom", flags, 0);
|
||||
if (fd > 0)
|
||||
{
|
||||
auto current = std::begin(buffer);
|
||||
auto target = std::end(buffer);
|
||||
while (auto length = static_cast<size_t>(target - current))
|
||||
{
|
||||
ret = read(fd, current, length);
|
||||
if (ret <= 0)
|
||||
{
|
||||
if (errno != EAGAIN && errno != EINTR)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
current += ret;
|
||||
}
|
||||
}
|
||||
ret = close(fd);
|
||||
SNMALLOC_ASSERT(0 == ret);
|
||||
if (SNMALLOC_LIKELY(target == current))
|
||||
{
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
error("Failed to get system randomness");
|
||||
}
|
||||
};
|
||||
} // namespace snmalloc
|
||||
#endif
|
||||
|
||||
@@ -19,9 +19,6 @@
|
||||
#if __has_include(<sys/random.h>)
|
||||
# include <sys/random.h>
|
||||
#endif
|
||||
#if __has_include(<unistd.h>)
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
|
||||
extern "C" int puts(const char* str);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user