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".
This commit is contained in:
Miroslav Lichvar 2021-11-23 13:17:26 +01:00
parent 09067e06d3
commit a0a9560258
6 changed files with 48 additions and 9 deletions

2
main.c
View file

@ -141,6 +141,8 @@ MAI_CleanupAndExit(void)
HSH_Finalise();
LOG_Finalise();
UTI_ResetGetRandomFunctions();
exit(exit_status);
}

View file

@ -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();

View file

@ -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);

View file

@ -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);

35
util.c
View file

@ -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)
{

4
util.h
View file

@ -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);