NetBSD-Bugs archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

kern/58322: rndctl -L ignores nonzero entropy count on second run after initial zero entropy count



>Number:         58322
>Category:       kern
>Synopsis:       rndctl -L ignores nonzero entropy count on second run after initial zero entropy count
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    kern-bug-people
>State:          open
>Class:          sw-bug
>Submitter-Id:   net
>Arrival-Date:   Sat Jun 08 15:35:00 +0000 2024
>Originator:     Taylor R Campbell
>Release:        current, 10
>Organization:
The NetRNDCTL Foundation
>Environment:
>Description:
The rndctl -L operation (ioctl RNDADDDATA) is used to load a random seed from disk into the kernel.

The random seed format used by rndctl -L/-S stores a number of bits of entropy, up to 256, in the process that led into the seed file.

The random seed may be loaded in either by the bootloader, or by /etc/rc.d/random_seed.  Since these may not be coordinated (and the bootloader may change, e.g. from BIOS to UEFI boot), and the bootloader has no chance to update the seed file to block /etc/rc.d/random_seed from loading the same one, the kernel enforces a rule that if nonzero entropy has been counted from a seed file _once_, then it will ignore the count on subsequent seed file loads.  The content of the seed file will still be entered into the pool, but the count will be ignored.  That way, if you try to load the _same_ seed file twice, it won't double-count the entropy.

This way, we avoid double-counting the entropy from the same seed file.

However, if the system has had no entropy, it should be able to, e.g., load a seed file you generated on another machine and transferred over a non-eavesdropped channel like a direct ethernet connection.

In order to facilitate this, the _bootloader_ path records the system as seeded -- so it will ignore the entropy count in subsequent seed loads -- only if the entropy count in the seed is nonzero:

    618 	/* Test and set E->seeded.  */
    619 	seeded = E->seeded;
    620 	E->seeded = (seed->entropy > 0);

https://nxr.netbsd.org/xref/src/sys/kern/kern_entropy.c?r=1.66#618

But the _ioctl_ path (rndctl -L, ioctl RNDADDDATA) always records the system as seeded (if the caller is privileged enough for the count to matter), even if the entropy count it got is zero:

   2769 			if (!E->seeded) {
   2770 				entropybits = MIN(rdata->entropy,
   2771 				    MIN(rdata->len, ENTROPY_CAPACITY)*NBBY);
   2772 				E->seeded = true;
   2773 			}

https://nxr.netbsd.org/xref/src/sys/kern/kern_entropy.c?r=1.66#2769

As a result, if you boot the system with a seed file that has zero entropy count, then after multi-user boot has run /etc/rc.d/random_seed start, you have no opportunity to load a seed file with positive entropy count from another machine.  Instead, you should have that opportunity.
>How-To-Repeat:
On a machine with no HWRNG:

1. write a seed file with `rndctl -S'

2. make two copies of the seed file (just for the purpose of reproducing the issue), one with the first four bytes set to zero and the other with the first four bytes set to little-endian encoding of the number 256

3. move /var/db/entropy-file (or wherever your seed lives according to boot.cfg or /etc/rc.conf) out of the way

4. reboot into single-user mode

5. load the zero-entropy file with rndctl -L and verify zero bits of entropy were counted in rndctl -l or sysctl kern.entropy.needed

6. load the 256-bit-entropy file with rndctl -L and check rndctl -l and sysctl kern.entropy.needed
>Fix:
In the rndctl -L, ioctl RNDADDDATA, path, change

E->seeded = true;

to

E->seeded = (entropybits > 0);



Home | Main Index | Thread Index | Old Index