## Sysctls and the blocking pool.

You can increase the value of the `kernel.random.read_wakeup_threshold` sysctl. This sysctl changes the behavior of the [blocking pool](https://man7.org/linux/man-pages/man7/random.7.html), forcing users of the blocking pool to wait until the entropy estimate exceeds this value. From the manpage at [`random(4)`](https://man7.org/linux/man-pages/man4/random.4.html):

 read_wakeup_threshold
 This file contains the number of bits of entropy required for
 waking up processes that sleep waiting for entropy from
 /dev/random. The default is 64.

Note however that the blocking behavior you describe only applies to the system at very early boot. Once it has enough entropy, it will change to non-blocking behavior regardless of how low the current estimate gets. This is because you only need a certain number of bits of entropy _once_, and can create a virtually unlimited amount of cryptographically secure pseudorandom data once you have it. The entropy estimate going down does not change this fact.

## Answering your exact question

Now, is it possible to change this initial threshold for the non-blocking pool (if you don't want to learn all the nitty-gritty, skip to the end of this answer)? I suspected it was not, but I wasn't sure, so I went to consult to the most authoritative documentation available: the source. The syscall [`getrandom(2)`](https://man7.org/linux/man-pages/man2/getrandom.2.html) is [defined](https://elixir.bootlin.com/linux/v4.14/source/drivers/char/random.c#L1908) in the kernel randomness driver. _Note that this is specific to Linux kernel 4.14 (major changes to the randomness driver were made in 4.8)._

Comments added by me for clarification to the `getrandom()` syscall code:

 SYSCALL_DEFINE3(getrandom, char __user *, buf, size_t, count,
 unsigned int, flags)
 {
 int ret;
 
 // If the flags bitmask is invalid, return an error.
 if (flags & ~(GRND_NONBLOCK|GRND_RANDOM))
 return -EINVAL;
 
 // Cap the requested size at the maximum value.
 if (count > INT_MAX)
 count = INT_MAX;
 
 // If the blocking pool is selected, read from it and return.
 // The _random_read() function will deal with blocking.
 if (flags & GRND_RANDOM)
 return _random_read(flags & GRND_NONBLOCK, buf, count);
 
 // If we get to here, we know the non-blocking pool was selected.
 
 // Is the CRNG ready? Evaluates true if it is not.
 if (!crng_ready()) {
 // If we want to bail out and not block, return -EAGAIN.
 if (flags & GRND_NONBLOCK)
 return -EAGAIN;
 
 // Otherwise, block until random bytes become available.
 ret = wait_for_random_bytes();
 if (unlikely(ret))
 return ret;
 }
 
 // Finally, read from the non-blocking pool and return.
 return urandom_read(NULL, buf, count, NULL);
 }

OK, so most of this is pretty self-evident, but what are the functions `crng_ready()` and `wait_for_random_bytes()` for? The latter is [defined](https://elixir.bootlin.com/linux/v4.14/source/drivers/char/random.c#L1539) in the same file:

 int wait_for_random_bytes(void)
 {
 // If crng_ready() returns true (which is likely), return 0.
 if (likely(crng_ready()))
 return 0;
 
 // Otherwise, wait until it does return true before returning.
 return wait_event_interruptible(crng_init_wait, crng_ready());
 }
 EXPORT_SYMBOL(wait_for_random_bytes);

So now we know in the definition of `getrandom()` that, if the non-blocking pool is selected, it will check if `crng_ready()` returns true. If it does not return true, then we will wait, sleeping until it does. What does `crng_ready()` do? It turns out it's [defined](https://elixir.bootlin.com/linux/v4.14/source/drivers/char/random.c#L422) as a simple macro:

 #define crng_ready() (likely(crng_init > 0))

The variable starts out as zero, but what matters is where exactly it is set to 1. It appears that this is done in the `crng_fast_load()` function, [defined here](https://elixir.bootlin.com/linux/v4.14/source/drivers/char/random.c#L790):

 static int crng_fast_load(const char *cp, size_t len)
 {
 unsigned long flags;
 char *p;
 
 // Enter the critical section (acquire the spinlock).
 if (!spin_trylock_irqsave(&primary_crng.lock, flags))
 return 0;
 
 // If crng_ready() is already true, leave the critical section and return.
 if (crng_ready()) {
 spin_unlock_irqrestore(&primary_crng.lock, flags);
 return 0;
 }
 
 // Mix in the values at cp with the CRNG state. Increment crng_init_cnt
 // for each byte from cp that gets mixed in (up to len times).
 p = (unsigned char *) &primary_crng.state[4];
 while (len > 0 && crng_init_cnt < CRNG_INIT_CNT_THRESH) {
 p[crng_init_cnt % CHACHA20_KEY_SIZE] ^= *cp;
 cp++; crng_init_cnt++; len--;
 }
 
 // Leave the critical section (release the spinlock).
 spin_unlock_irqrestore(&primary_crng.lock, flags);
 
 // If crng_init_cnt is >= CRNG_INIT_CNT_THRESH, set crng_init to 1.
 if (crng_init_cnt >= CRNG_INIT_CNT_THRESH) {
 invalidate_batched_entropy();
 crng_init = 1;
 wake_up_interruptible(&crng_init_wait);
 pr_notice("random: fast init done\n");
 }
 return 1;
 }

From this, we see that `crng_init_cnt` is incremented for each byte which `crng_fast_load()` takes in. The function is called early at boot in various entropy-gathering functions to add as much possible data to the pool early on. We're almost there! Last thing to do is find out the value of `CRNG_INIT_CNT_THRESH`, [defined here](https://elixir.bootlin.com/linux/v4.14/source/drivers/char/random.c#L433):

 #define CRNG_INIT_CNT_THRESH (2*CHACHA20_KEY_SIZE)

So it's double `CHACHA20_KEY_SIZE`. This one is [defined](https://elixir.bootlin.com/linux/v4.14/source/include/crypto/chacha20.h#L14) in a header file, `crypto/chacha20.h`:

 #define CHACHA20_KEY_SIZE 32

So `CRNG_INIT_CNT_THRESH` is 64. And there's your answer!

## Recap

* `CHACHA20_KEY_SIZE` is hardcoded as 32.
* `CRNG_INIT_CNT_THRESH` is double `CHACHA20_KEY_SIZE`, making it 64.
* `crng_init_cnt` is incremented for every byte of early randomness gathered.
* When at least 64 bytes of randomness are gathered, `crng_init` is set to 1.
* When `crng_init` is 1, `crng_ready()` evaluates true.
* When `crng_ready()` evaluates true, `getrandom()` resumes and returns.

**The amount of early entropy required before `getrandom()` resumes and returns is not in fact 128 bits. It is already hardcoded as 64 bytes (512 bits), twice the amount you wanted.**