From b6a63f98efa6974d4c60558e3945606702b8d08e Mon Sep 17 00:00:00 2001 From: David CARLIER Date: Sun, 2 Jan 2022 09:51:22 +0000 Subject: [PATCH] rand macOs handling update. from Yosemite, there is the new CCRandomGenerateBytes which returns a success status while arc4random might not be 100% reliable 100% of the time. In the case of failure, we fallback to the classic rand() calls. --- src/CMakeLists.txt | 5 +++++ src/config.h.cmake | 5 +++++ src/meson.build | 9 +++++++++ src/rand.c | 31 +++++++++++++++++++++++++++---- 4 files changed, 46 insertions(+), 4 deletions(-) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6f540ed5..8e008302 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -152,6 +152,11 @@ set(CMAKE_EXTRA_INCLUDE_FILES linux/random.h) check_function_exists(getrandom HAVE_GETRANDOM) set(CMAKE_EXTRA_INCLUDE_FILES) +check_include_files(CommonCrypto/CommonRandom.h HAVE_COMMONCRYPTO_COMMONRANDOM_H) +set(CMAKE_EXTRA_INCLUDE_FILES CommonCrypto/CommonRandom.h) +check_function_exists(CCRandomGenerateBytes HAVE_CCRANDOMGENERATEBYTES) +set(CMAKE_EXTRA_INCLUDE_FILES) + set(CMAKE_EXTRA_INCLUDE_FILES time.h) check_function_exists(timegm HAVE_TIMEGM) set(CMAKE_EXTRA_INCLUDE_FILES) diff --git a/src/config.h.cmake b/src/config.h.cmake index f8df2117..d113c136 100644 --- a/src/config.h.cmake +++ b/src/config.h.cmake @@ -13,7 +13,9 @@ #endif /* System */ +#cmakedefine HAVE_COMMONCRYPTO_COMMONRANDOM_H #cmakedefine HAVE_DLFCN_H +#cmakedefine HAVE_LINUX_RANDOM_H #cmakedefine HAVE_PORT_H #cmakedefine HAVE_SYS_DEVPOLL_H #cmakedefine HAVE_SYS_EPOLL_H @@ -120,9 +122,12 @@ #cmakedefine SIZEOF_OFF_T ${SIZEOF_OFF_T} /* Functions */ +#cmakedefine HAVE_ARC4RANDOM_BUF +#cmakedefine HAVE_CCRANDOMGENERATEBYTES #cmakedefine HAVE_CHROOT #cmakedefine HAVE_EPOLL_CTL #cmakedefine HAVE_FORK +#cmakedefine HAVE_GETRANDOM #cmakedefine HAVE_GETRLIMIT #cmakedefine HAVE_GETUID #cmakedefine HAVE_GMTIME_R diff --git a/src/meson.build b/src/meson.build index da99d459..4a424d09 100644 --- a/src/meson.build +++ b/src/meson.build @@ -108,6 +108,15 @@ if conf_data.get('HAVE_LINUX_RANDOM_H') )) endif +conf_data.set('HAVE_COMMONCRYPTO_COMMONRANDOM_H', compiler.has_header('CommonCrypto/CommonRandom.h')) +if conf_data.get('HAVE_COMMONCRYPTO_COMMONRANDOM_H') + conf_data.set('HAVE_CCRANDOMGENERATEBYTES', compiler.has_function( + 'CCRandomGenerateBytes', + args: defs, + prefix: '#include ' + )) +endif + conf_data.set('SIZEOF_LONG', compiler.sizeof('long', args: defs)) conf_data.set('SIZEOF_OFF_T', compiler.sizeof('off_t', args: defs)) diff --git a/src/rand.c b/src/rand.c index 7b420ddf..8034e090 100644 --- a/src/rand.c +++ b/src/rand.c @@ -78,6 +78,9 @@ #include #include #endif +#ifdef HAVE_COMMONCRYPTO_COMMONRANDOM_H +#include +#endif #ifdef RNDGETENTCNT #include #endif @@ -240,21 +243,36 @@ static void li_rand_init (void) u = ((unsigned int)xsubi[0] << 16) | xsubi[1]; } else { - #ifdef HAVE_ARC4RANDOM_BUF + #if defined(HAVE_CCRANDOMGENERATEBYTES) + /* purposely intended to be considered in priority above the arc4random api + * on macOs releases supporting this call (from Yosemite) + * indeed arc4random while reliable on BSD has two little flaws in macOs case: + * - one of them can't occur here (when size is 0 from macOs 10.15) + * - internally arc4random_buf uses ccrng_generate which returns a success status + * but is silently ignored to respect the "no fail" arc4random interface contract. + * While it occurs rarely concretally, we re taking precautions here to cathc possible + * failures and falling back to the classic rand() api. + */ + if (CCRandomGenerateBytes(&u, sizeof(u)) != kCCSuccess) + goto li_rand_fallback; + if (CCRandomGenerateBytes(xsubi, sizeof(xsubi)) != kCCSuccess) + goto li_rand_fallback; + #elif defined(HAVE_ARC4RANDOM_BUF) u = arc4random(); arc4random_buf(xsubi, sizeof(xsubi)); + return; #elif defined(__COVERITY__) /* Coverity Scan ignores(?) annotation below, * so hide fallback path from Coverity Scan */ u = (unsigned int)(time(NULL) ^ getpid()); - #else + #endif +li_rand_fallback: /* NOTE: not cryptographically random !!! */ srand((unsigned int)(time(NULL) ^ getpid())); for (u = 0; u < sizeof(unsigned short); ++u) /* coverity[dont_call : FALSE] */ xsubi[u] = (unsigned short)(rand() & 0xFFFF); u = ((unsigned int)xsubi[0] << 16) | xsubi[1]; - #endif } srand(u); /*(initialize just in case rand() used elsewhere)*/ #ifdef HAVE_SRANDOM @@ -373,7 +391,12 @@ int li_rand_pseudo (void) if (SECSuccess == PK11_GenerateRandom((unsigned char *)&i, sizeof(i))) return i; #endif - #ifdef HAVE_ARC4RANDOM_BUF + #if defined(HAVE_CCRANDOMGENERATEBYTES) + int i; + if (CCRandomGenerateBytes(&i, sizeof(i)) != kCCSuccess) + return (int)random(); + return i; + #elif defined(HAVE_ARC4RANDOM_BUF) return (int)arc4random(); #elif defined(__COVERITY__) /* li_rand_pseudo() is not intended for cryptographic use */ -- 2.32.0 (Apple Git-132)