newfs silently fails if random is not ready (?)
Conrad Meyer
cem at freebsd.org
Wed Sep 5 03:13:45 UTC 2018
Hi Lev,
I took a first attempt at reproducing this problem on a fast
desktop-class system. First steps, give us a way to revert back to
unseeded status:
--- a/sys/dev/random/fortuna.c
+++ b/sys/dev/random/fortuna.c
@@ -39,6 +39,7 @@ __FBSDID("$FreeBSD$");
#ifdef _KERNEL
#include <sys/param.h>
+#include <sys/fail.h>
#include <sys/kernel.h>
#include <sys/lock.h>
#include <sys/malloc.h>
@@ -384,6 +385,17 @@ random_fortuna_pre_read(void)
return;
}
+ /*
+ * When set, pretend we do not have enough entropy to reseed yet.
+ */
+ KFAIL_POINT_CODE(DEBUG_FP, random_fortuna_pre_read, {
+ if (RETURN_VALUE != 0) {
+ RANDOM_RESEED_UNLOCK();
+ return;
+ }
+ });
+
+
#ifdef _KERNEL
fortuna_state.fs_lasttime = now;
#endif
@@ -442,5 +454,11 @@ bool
random_fortuna_seeded(void)
{
+ /* When set, act as if we are not seeded. */
+ KFAIL_POINT_CODE(DEBUG_FP, random_fortuna_seeded, {
+ if (RETURN_VALUE != 0)
+ fortuna_state.fs_counter = UINT128_ZERO;
+ });
+
return (!uint128_is_zero(fortuna_state.fs_counter));
}
Second step, enable the failpoints and launch repro program:
$ sudo sysctl debug.fail_point.random_fortuna_pre_read='return(1)'
debug.fail_point.random_fortuna_pre_read: off -> return(1)
$ sudo sysctl debug.fail_point.random_fortuna_seeded='return(1)'
debug.fail_point.random_fortuna_seeded: off -> return(1)
$ cat ./blocked_random_poc.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char **argv)
{
printf("%x\n", arc4random());
return (0);
}
$ ./blocked_random_poc
...
Third step, I looked at what that process was doing:
Curiously, it is not in getrandom() at all, but instead the ARND
sysctl fallback. I probably need to rebuild world (libc) to test this
(new libc arc4random based on Chacha).
$ procstat -kk 1196
PID TID COMM TDNAME KSTACK
1196 100435 blocked_random_poc - read_random+0x3d
sysctl_kern_arnd+0x3a sysctl_root_handler_locked+0x89
sysctl_root.isra.8+0x167 userland_sysctl+0x126 sys___sysctl+0x7b
amd64_syscall+0x940 fast_syscall_common+0x101
When I unblocked the failpoints, it completed successfully:
$ sudo sysctl debug.fail_point.random_fortuna_pre_read='off'
debug.fail_point.random_fortuna_pre_read: return(1) -> off
$ sudo sysctl debug.fail_point.random_fortuna_seeded=off
debug.fail_point.random_fortuna_seeded: return(1) -> off
...
9e5eb30f
Best,
Conrad
More information about the freebsd-current
mailing list