From a0a9560258cef3fa7dcd16e5f24eb087867641a0 Mon Sep 17 00:00:00 2001 From: Miroslav Lichvar Date: Tue, 23 Nov 2021 13:17:26 +0100 Subject: [PATCH] util: reset GetRandom functions in helpers after fork Close /dev/urandom and drop cached getrandom() data after forking helper processes to avoid them getting the same sequence of random numbers (e.g. two NTS-KE helpers generating cookies with identical nonces). arc4random() is assumed to be able to detect forks and reseed automatically. This is not strictly necessary with the current code, which does not use the GetRandom functions before the NTS-KE helper processes are forked, but that could change in future. Also, call the reset function before exit to close /dev/urandom in order to avoid valgrind reporting the file object as "still reachable". --- main.c | 2 ++ nts_ke_server.c | 4 ++++ privops.c | 2 ++ test/unit/util.c | 10 ++++++++++ util.c | 35 ++++++++++++++++++++++++++--------- util.h | 4 ++++ 6 files changed, 48 insertions(+), 9 deletions(-) diff --git a/main.c b/main.c index 74e2706..355cdc3 100644 --- a/main.c +++ b/main.c @@ -141,6 +141,8 @@ MAI_CleanupAndExit(void) HSH_Finalise(); LOG_Finalise(); + UTI_ResetGetRandomFunctions(); + exit(exit_status); } diff --git a/nts_ke_server.c b/nts_ke_server.c index 1239678..ece1b4c 100644 --- a/nts_ke_server.c +++ b/nts_ke_server.c @@ -669,6 +669,8 @@ run_helper(uid_t uid, gid_t gid, int scfilter_level) CNF_Finalise(); LOG_Finalise(); + UTI_ResetGetRandomFunctions(); + exit(0); } @@ -710,6 +712,8 @@ NKS_PreInitialise(uid_t uid, gid_t gid, int scfilter_level) is_helper = 1; + UTI_ResetGetRandomFunctions(); + snprintf(prefix, sizeof (prefix), "nks#%d:", i + 1); LOG_SetDebugPrefix(prefix); LOG_CloseParentFd(); diff --git a/privops.c b/privops.c index 99de867..3fb5cbd 100644 --- a/privops.c +++ b/privops.c @@ -662,6 +662,8 @@ PRV_StartHelper(void) close(fd); } + UTI_ResetGetRandomFunctions(); + /* ignore signals, the process will exit on OP_QUIT request */ UTI_SetQuitSignalsHandler(SIG_IGN, 1); diff --git a/test/unit/util.c b/test/unit/util.c index 4d7a4e8..efd9c5a 100644 --- a/test/unit/util.c +++ b/test/unit/util.c @@ -670,6 +670,10 @@ test_unit(void) UTI_GetRandomBytesUrandom(buf, j); if (j && buf[j - 1] % 2) c++; + if (random() % 10000 == 0) { + UTI_ResetGetRandomFunctions(); + TEST_CHECK(!urandom_file); + } } TEST_CHECK(c > 46000 && c < 48000); @@ -678,6 +682,12 @@ test_unit(void) UTI_GetRandomBytes(buf, j); if (j && buf[j - 1] % 2) c++; + if (random() % 10000 == 0) { + UTI_ResetGetRandomFunctions(); +#if HAVE_GETRANDOM + TEST_CHECK(getrandom_buf_available == 0); +#endif + } } TEST_CHECK(c > 46000 && c < 48000); diff --git a/util.c b/util.c index 69f523d..da99f82 100644 --- a/util.c +++ b/util.c @@ -1402,29 +1402,32 @@ UTI_DropRoot(uid_t uid, gid_t gid) #define DEV_URANDOM "/dev/urandom" +static FILE *urandom_file = NULL; + void UTI_GetRandomBytesUrandom(void *buf, unsigned int len) { - static FILE *f = NULL; - - if (!f) - f = UTI_OpenFile(NULL, DEV_URANDOM, NULL, 'R', 0); - if (fread(buf, 1, len, f) != len) + if (!urandom_file) + urandom_file = UTI_OpenFile(NULL, DEV_URANDOM, NULL, 'R', 0); + if (fread(buf, 1, len, urandom_file) != len) LOG_FATAL("Can't read from %s", DEV_URANDOM); } /* ================================================== */ #ifdef HAVE_GETRANDOM + +static unsigned int getrandom_buf_available = 0; + static void get_random_bytes_getrandom(char *buf, unsigned int len) { static char rand_buf[256]; - static unsigned int available = 0, disabled = 0; + static unsigned int disabled = 0; unsigned int i; for (i = 0; i < len; i++) { - if (!available) { + if (getrandom_buf_available == 0) { if (disabled) break; @@ -1433,10 +1436,10 @@ get_random_bytes_getrandom(char *buf, unsigned int len) break; } - available = sizeof (rand_buf); + getrandom_buf_available = sizeof (rand_buf); } - buf[i] = rand_buf[--available]; + buf[i] = rand_buf[--getrandom_buf_available]; } if (i < len) @@ -1460,6 +1463,20 @@ UTI_GetRandomBytes(void *buf, unsigned int len) /* ================================================== */ +void +UTI_ResetGetRandomFunctions(void) +{ + if (urandom_file) { + fclose(urandom_file); + urandom_file = NULL; + } +#ifdef HAVE_GETRANDOM + getrandom_buf_available = 0; +#endif +} + +/* ================================================== */ + int UTI_BytesToHex(const void *buf, unsigned int buf_len, char *hex, unsigned int hex_len) { diff --git a/util.h b/util.h index f6bf7b9..a57ef9b 100644 --- a/util.h +++ b/util.h @@ -224,6 +224,10 @@ extern void UTI_GetRandomBytesUrandom(void *buf, unsigned int len); generating long-term keys */ extern void UTI_GetRandomBytes(void *buf, unsigned int len); +/* Close /dev/urandom and drop any cached data used by the GetRandom functions + to prevent forked processes getting the same sequence of random numbers */ +extern void UTI_ResetGetRandomFunctions(void); + /* Print data in hexadecimal format */ extern int UTI_BytesToHex(const void *buf, unsigned int buf_len, char *hex, unsigned int hex_len);