NetBSD Problem Report #58322
From www@netbsd.org Sat Jun 8 15:31:12 2024
Return-Path: <www@netbsd.org>
Received: from mail.netbsd.org (mail.netbsd.org [199.233.217.200])
(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)
key-exchange X25519 server-signature RSA-PSS (2048 bits)
client-signature RSA-PSS (2048 bits))
(Client CN "mail.NetBSD.org", Issuer "mail.NetBSD.org CA" (not verified))
by mollari.NetBSD.org (Postfix) with ESMTPS id 722681A923A
for <gnats-bugs@gnats.NetBSD.org>; Sat, 8 Jun 2024 15:31:12 +0000 (UTC)
Message-Id: <20240608153111.356E71A923F@mollari.NetBSD.org>
Date: Sat, 8 Jun 2024 15:31:11 +0000 (UTC)
From: campbell+netbsd@mumble.net
Reply-To: campbell+netbsd@mumble.net
To: gnats-bugs@NetBSD.org
Subject: rndctl -L ignores nonzero entropy count on second run after initial zero entropy count
X-Send-Pr-Version: www-1.0
>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);
(Contact us)
$NetBSD: query-full-pr,v 1.47 2022/09/11 19:34:41 kim Exp $
$NetBSD: gnats_config.sh,v 1.9 2014/08/02 14:16:04 spz Exp $
Copyright © 1994-2024
The NetBSD Foundation, Inc. ALL RIGHTS RESERVED.