From 9987fe8ca05e5d367fc54eb94a5a583138d2e1f8 Mon Sep 17 00:00:00 2001 From: LemonBoy Date: Thu, 4 Jul 2024 13:20:49 +0200 Subject: patch 9.1.0518: initialize the random buffer can be improved Problem: initialize the random buffer can be improved Solution: refactor init_srand() function, move machine-specific parts to os_mswin and os_unix, implement a fallback for Windows 10 and later (LemonBoy) closes: #15125 Signed-off-by: LemonBoy Signed-off-by: Christian Brabandt --- src/evalfunc.c | 72 ++++++++++++++++++-------------------------------- src/os_mswin.c | 34 ++++++++++++++++++++++++ src/os_unix.c | 28 ++++++++++++++++++++ src/proto/os_mswin.pro | 1 + src/proto/os_unix.pro | 1 + src/version.c | 2 ++ 6 files changed, 91 insertions(+), 47 deletions(-) diff --git a/src/evalfunc.c b/src/evalfunc.c index 4fffa50d31..d18d50a284 100644 --- a/src/evalfunc.c +++ b/src/evalfunc.c @@ -9267,69 +9267,47 @@ f_test_srand_seed(typval_T *argvars, typval_T *rettv UNUSED) static void init_srand(UINT32_T *x) { -#ifndef MSWIN - static int dev_urandom_state = NOTDONE; // FAIL or OK once tried -#endif + struct { + union { + UINT32_T number; + char_u bytes[sizeof(UINT32_T)]; + } contents; + } buf; if (srand_seed_for_testing_is_used) { *x = srand_seed_for_testing; return; } -#ifndef MSWIN - if (dev_urandom_state != FAIL) - { - int fd = open("/dev/urandom", O_RDONLY); - struct { - union { - UINT32_T number; - char bytes[sizeof(UINT32_T)]; - } contents; - } buf; - // Attempt reading /dev/urandom. - if (fd == -1) - dev_urandom_state = FAIL; - else - { - buf.contents.number = 0; - if (read(fd, buf.contents.bytes, sizeof(UINT32_T)) - != sizeof(UINT32_T)) - dev_urandom_state = FAIL; - else - { - dev_urandom_state = OK; - *x = buf.contents.number; - } - close(fd); - } - } - if (dev_urandom_state != OK) -#endif + if (mch_get_random(buf.contents.bytes, sizeof(buf.contents.bytes)) == OK) { - // Reading /dev/urandom doesn't work, fall back to: - // - randombytes_random() - // - reltime() or time() - // - XOR with process ID + *x = buf.contents.number; + return; + } + + // The system's random number generator doesn't work, fall back to: + // - randombytes_random() + // - reltime() or time() + // - XOR with process ID #if defined(FEAT_SODIUM) - if (crypt_sodium_init() >= 0) - *x = crypt_sodium_randombytes_random(); - else + if (crypt_sodium_init() >= 0) + *x = crypt_sodium_randombytes_random(); + else #endif - { + { #if defined(FEAT_RELTIME) - proftime_T res; - profile_start(&res); + proftime_T res; + profile_start(&res); # if defined(MSWIN) - *x = (UINT32_T)res.LowPart; + *x = (UINT32_T)res.LowPart; # else - *x = (UINT32_T)res.tv_fsec; + *x = (UINT32_T)res.tv_fsec; # endif #else - *x = vim_time(); + *x = vim_time(); #endif - *x ^= mch_get_pid(); - } + *x ^= mch_get_pid(); } } diff --git a/src/os_mswin.c b/src/os_mswin.c index 9d0e1a08a4..df760fd5ec 100644 --- a/src/os_mswin.c +++ b/src/os_mswin.c @@ -830,6 +830,40 @@ mch_icon_load(HANDLE *iconp) 0, mch_icon_load_cb, iconp); } +/* + * Fill the buffer 'buf' with 'len' random bytes. + * Returns FAIL if the OS PRNG is not available or something went wrong. + */ + int +mch_get_random(char_u *buf, int len) +{ + static int initialized = NOTDONE; + static HINSTANCE hInstLib; + static BOOL (WINAPI *pProcessPrng)(PUCHAR, ULONG); + + if (initialized == NOTDONE) + { + hInstLib = vimLoadLib("bcryptprimitives.dll"); + if (hInstLib != NULL) + pProcessPrng = (void *)GetProcAddress(hInstLib, "ProcessPrng"); + if (hInstLib == NULL || pProcessPrng == NULL) + { + FreeLibrary(hInstLib); + initialized = FAIL; + } + else + initialized = OK; + } + + if (initialized == FAIL) + return FAIL; + + // According to the documentation this call cannot fail. + pProcessPrng(buf, len); + + return OK; +} + int mch_libcall( char_u *libname, diff --git a/src/os_unix.c b/src/os_unix.c index d15514268f..b7da55205d 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -7722,6 +7722,34 @@ sig_sysmouse SIGDEFARG(sigarg) } #endif // FEAT_SYSMOUSE +/* + * Fill the buffer 'buf' with 'len' random bytes. + * Returns FAIL if the OS PRNG is not available or something went wrong. + */ + int +mch_get_random(char_u *buf, int len) +{ + static int dev_urandom_state = NOTDONE; + + if (dev_urandom_state == FAIL) + return FAIL; + + int fd = open("/dev/urandom", O_RDONLY); + + // Attempt reading /dev/urandom. + if (fd == -1) + dev_urandom_state = FAIL; + else if (read(fd, buf, len) == len) + dev_urandom_state = OK; + else + { + dev_urandom_state = FAIL; + close(fd); + } + + return dev_urandom_state; +} + #if defined(FEAT_LIBCALL) || defined(PROTO) typedef char_u * (*STRPROCSTR)(char_u *); typedef char_u * (*INTPROCSTR)(int); diff --git a/src/proto/os_mswin.pro b/src/proto/os_mswin.pro index 383dcbad1e..cde9ceaeed 100644 --- a/src/proto/os_mswin.pro +++ b/src/proto/os_mswin.pro @@ -23,6 +23,7 @@ int mch_has_wildcard(char_u *p); int mch_chdir(char *path); int mch_icon_load(HANDLE *iconp); int mch_libcall(char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result); +int mch_get_random(char_u *buf, int len); void DumpPutS(const char *psz); int mch_get_winpos(int *x, int *y); void mch_set_winpos(int x, int y); diff --git a/src/proto/os_unix.pro b/src/proto/os_unix.pro index 6e13de6caa..d9dc8d9d54 100644 --- a/src/proto/os_unix.pro +++ b/src/proto/os_unix.pro @@ -76,6 +76,7 @@ int mch_rename(const char *src, const char *dest); int gpm_available(void); int gpm_enabled(void); int mch_libcall(char_u *libname, char_u *funcname, char_u *argstring, int argint, char_u **string_result, int *number_result); +int mch_get_random(char_u *buf, int len); void setup_term_clip(void); void start_xterm_trace(int button); void stop_xterm_trace(void); diff --git a/src/version.c b/src/version.c index c33303ab43..2391e5ba9e 100644 --- a/src/version.c +++ b/src/version.c @@ -704,6 +704,8 @@ static char *(features[]) = static int included_patches[] = { /* Add new patch number below this line */ +/**/ + 518, /**/ 517, /**/ -- cgit v1.2.3