diff --git a/src/common.cpp b/src/common.cpp index 52642c3..670f1c0 100644 --- a/src/common.cpp +++ b/src/common.cpp @@ -76,6 +76,18 @@ #include #include +#ifdef __linux__ +// glibc introduced arc4random_buf in 2.36 +#if defined(__GLIBC__) && !(__GLIBC__ < 2 || __GLIBC__ == 2 && __GLIBC_MINOR__ < 36) +#define HAS_ARC4RANDOM_BUF 1 +#else +#include +#endif +#else +// OSX has arc4random_buf +#define HAS_ARC4RANDOM_BUF 1 +#endif + using namespace shim; void shim::handle_runtime_error(const char *fmt, ...) { @@ -275,10 +287,6 @@ int shim::prctl(bionic::prctl_num opt, unsigned long a2, unsigned long a3, unsig #endif } -uint32_t shim::arc4random() { - return 0; // TODO: -} - void* shim::__memcpy_chk(void *dst, const void *src, size_t size, size_t max_len) { if (size > max_len) { fprintf(stderr, "detected copy past buffer size"); @@ -410,7 +418,7 @@ ssize_t shim::getrandom(void *buf, size_t len, unsigned int flags) { #else // TODO do we need look at flags? // Should work for bsd and macOS - arc4random_buf(buf, len); + ::arc4random_buf(buf, len); return (ssize_t)len; #endif } @@ -441,6 +449,32 @@ int shim::isnan(double d) { return std::isnan(d); } +void shim::arc4random_buf(void* buf, size_t len) { +#ifdef HAS_ARC4RANDOM_BUF + ::arc4random_buf(buf, len); +#else + // Using SYS_getrandom is a bit complex since it can be interrupted + // or not supported. Even if we used SYS_getrandom, we would have to + // fall back to an alternative strategy or error out if it failed. + // Instead rely on std::random_device to fill buf, allowing + // std::random_device to handle the complex stuff. + std::random_device get_rand; + while(len > 0) { + unsigned int u = get_rand(); + size_t n = std::min(len, sizeof(unsigned int)); + ::memcpy(buf, &u, n); + buf = (uint8_t*)buf + n; + len -= n; + } +#endif +} + +uint32_t shim::arc4random() { + uint32_t u; + shim::arc4random_buf(&u, sizeof(u)); + return u; +} + void shim::add_common_shimmed_symbols(std::vector &list) { list.insert(list.end(), { {"__errno", bionic::get_errno}, @@ -631,6 +665,11 @@ void shim::add_time_shimmed_symbols(std::vector &list) { {"ctime_r", ::ctime_r}, {"tzname", ::tzname}, {"tzset", ::tzset}, +#ifndef HAS_ARC4RANDOM_BUF + {"arc4random_buf", shim::arc4random_buf}, +#else + {"arc4random_buf", ::arc4random_buf}, +#endif #ifndef __FreeBSD__ {"daylight", &::daylight}, #endif @@ -980,8 +1019,11 @@ void shim::add_misc_shimmed_symbols(std::vector &list) { {"openlog", openlog}, {"closelog", closelog}, {"syslog", syslog}, - - {"arc4random", arc4random}, +#ifndef HAS_ARC4RANDOM_BUF + {"arc4random", shim::arc4random}, +#else + {"arc4random", ::arc4random}, +#endif }); } diff --git a/src/common.h b/src/common.h index 78d6fb7..05d7f55 100644 --- a/src/common.h +++ b/src/common.h @@ -101,8 +101,6 @@ namespace shim { int sendfile(int src, int dst, bionic::off_t *offset, size_t count); - uint32_t arc4random(); - void *__memcpy_chk(void *dst, const void *src, size_t size, size_t max_len); void *__memmove_chk(void *dst, const void *src, size_t size, size_t max_len); @@ -151,6 +149,10 @@ namespace shim { int isnan(double d); + void arc4random_buf(void* buf, size_t len); + + uint32_t arc4random(); + int utimensat(int dirfd, const char *pathname, const struct timespec times[2], int flags); void add_common_shimmed_symbols(std::vector &list);