From patchwork Thu Apr 13 16:57:56 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 13210469 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 2FDD0C77B71 for ; Thu, 13 Apr 2023 16:58:07 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229498AbjDMQ6G (ORCPT ); Thu, 13 Apr 2023 12:58:06 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58098 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229583AbjDMQ6E (ORCPT ); Thu, 13 Apr 2023 12:58:04 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 0D9D510EC for ; Thu, 13 Apr 2023 09:58:04 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4CFD81424; Thu, 13 Apr 2023 09:58:48 -0700 (PDT) Received: from donnerap.arm.com (donnerap.cambridge.arm.com [10.1.197.42]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0F8783F6C4; Thu, 13 Apr 2023 09:58:02 -0700 (PDT) From: Andre Przywara To: Will Deacon , Julien Thierry Cc: kvm@vger.kernel.org, Alexandru Elisei , Sami Mujawar Subject: [PATCH kvmtool 1/2] virtio/rng: switch to using /dev/urandom Date: Thu, 13 Apr 2023 17:57:56 +0100 Message-Id: <20230413165757.1728800-2-andre.przywara@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230413165757.1728800-1-andre.przywara@arm.com> References: <20230413165757.1728800-1-andre.przywara@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org At the moment we use /dev/random as the backing device to provide random numbers to our virtio-rng implementation. The downside of doing so is that it may block indefinitely - or return EAGAIN repeatedly in our case. On one headless systbem without ample noise sources (no keyboard, mouse, or network traffic) I measured 30 seconds to gain one byte of randomness. At the moment EDK II insists in waiting for all of the requsted random bytes (for its EFI_RNG_PROTOCOL runtime service) to arrive, that held up a Linux kernel boot for more than 10 minutes(!). According to the Internet(TM), on Linux /dev/urandom provides the same quality random numbers as /dev/random, it just does not block when the entropy estimation algorithm suggests so. For all practical purposes the recommendation is to just use /dev/urandom, QEMU did the switch as well in 2019 [1]. Use /dev/urandom instead of /dev/random when opening the file descriptor providing the randomness source for the virtio/rng implementation. [1] https://gitlab.com/qemu-project/qemu/-/commit/a2230bd778d8 Signed-off-by: Andre Przywara Reviewed-by: Jean-Philippe Brucker --- virtio/rng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/virtio/rng.c b/virtio/rng.c index 8f85d5ec1..eab8f3ac0 100644 --- a/virtio/rng.c +++ b/virtio/rng.c @@ -166,7 +166,7 @@ int virtio_rng__init(struct kvm *kvm) if (rdev == NULL) return -ENOMEM; - rdev->fd = open("/dev/random", O_RDONLY | O_NONBLOCK); + rdev->fd = open("/dev/urandom", O_RDONLY | O_NONBLOCK); if (rdev->fd < 0) { r = rdev->fd; goto cleanup; From patchwork Thu Apr 13 16:57:57 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Andre Przywara X-Patchwork-Id: 13210470 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 57E21C77B6E for ; Thu, 13 Apr 2023 16:58:08 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S229821AbjDMQ6H (ORCPT ); Thu, 13 Apr 2023 12:58:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58112 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229642AbjDMQ6F (ORCPT ); Thu, 13 Apr 2023 12:58:05 -0400 Received: from foss.arm.com (foss.arm.com [217.140.110.172]) by lindbergh.monkeyblade.net (Postfix) with ESMTP id 09D14E6F for ; Thu, 13 Apr 2023 09:58:05 -0700 (PDT) Received: from usa-sjc-imap-foss1.foss.arm.com (unknown [10.121.207.14]) by usa-sjc-mx-foss1.foss.arm.com (Postfix) with ESMTP id 4919C1477; Thu, 13 Apr 2023 09:58:49 -0700 (PDT) Received: from donnerap.arm.com (donnerap.cambridge.arm.com [10.1.197.42]) by usa-sjc-imap-foss1.foss.arm.com (Postfix) with ESMTPSA id 0C20F3F6C4; Thu, 13 Apr 2023 09:58:03 -0700 (PDT) From: Andre Przywara To: Will Deacon , Julien Thierry Cc: kvm@vger.kernel.org, Alexandru Elisei , Sami Mujawar Subject: [RFC PATCH kvmtool 2/2] virtio/rng: return at least one byte of entropy Date: Thu, 13 Apr 2023 17:57:57 +0100 Message-Id: <20230413165757.1728800-3-andre.przywara@arm.com> X-Mailer: git-send-email 2.25.1 In-Reply-To: <20230413165757.1728800-1-andre.przywara@arm.com> References: <20230413165757.1728800-1-andre.przywara@arm.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org In contrast to the original v0.9 virtio spec (which was rather vague), the virtio 1.0+ spec demands that a RNG request returns at least one byte: "The device MUST place one or more random bytes into the buffer, but it MAY use less than the entire buffer length." Our current implementation does not prevent returning zero bytes, which upsets an assert in EDK II. Since we open the fd with O_NONBLOCK, a return with not the whole buffer filled seems possible. Take care of that special case, by switching the /dev/urandom file descriptor into blocking mode when a 0-return happens, than wait for one byte to arrive. We then switch back to non-blocking mode, and try to read even more (in case multiple bytes became available at once). This makes sure we return at least one byte of entropy and become spec compliant. Signed-off-by: Andre Przywara Reported-by: Sami Mujawar --- virtio/rng.c | 31 +++++++++++++++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/virtio/rng.c b/virtio/rng.c index eab8f3ac0..0a0b31a16 100644 --- a/virtio/rng.c +++ b/virtio/rng.c @@ -66,8 +66,35 @@ static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, stru head = virt_queue__get_iov(queue, iov, &out, &in, kvm); len = readv(rdev->fd, iov, in); - if (len < 0 && errno == EAGAIN) - len = 0; + if (len < 0 && errno == EAGAIN) { + /* + * The virtio 1.0 spec demands at least one byte of entropy. + * Switch the /dev/urandom file descriptor to blocking mode, + * then wait for one byte to arrive. Switch it back to + * non-blocking mode, and try to read even more, if available. + */ + int flags = fcntl(rdev->fd, F_GETFL); + + if (flags < 0) + return false; + + fcntl(rdev->fd, F_SETFL, flags & ~O_NONBLOCK); + len = read(rdev->fd, iov[0].iov_base, 1); + if (len < 1) + return false; + fcntl(rdev->fd, F_SETFL, flags); + iov[0].iov_base++; + iov[0].iov_len--; + len = readv(rdev->fd, iov, in); + if (len < 0) { + if (errno == EAGAIN) /* no more bytes yet */ + len = 1; + else + return false; /* some error */ + } else { + len++; /* the one byte already read */ + } + } virt_queue__set_used_elem(queue, head, len);