aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndre Przywara <andre.przywara@arm.com>2023-05-24 12:22:07 +0100
committerWill Deacon <will@kernel.org>2023-06-05 13:18:03 +0100
commitbc23b9d9b152eaf56bacb1e2bae9a2b2252ade46 (patch)
tree61805ad421df722591c5023f2946f308752c07b8
parent62ba372b0e67b92efe20f63330fa0d40004d9fdd (diff)
downloadkvmtool-bc23b9d9b152eaf56bacb1e2bae9a2b2252ade46.tar.gz
virtio/rng: return at least one byte of entropy
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. /dev/urandom should always return at least 256 bytes of entropy, unless interrupted by a signal. Repeat the read if that happens, and give up if that fails as well. This makes sure we return some entropy and become spec compliant. Signed-off-by: Andre Przywara <andre.przywara@arm.com> Reported-by: Sami Mujawar <sami.mujawar@arm.com> Link: https://lore.kernel.org/r/20230524112207.586101-3-andre.przywara@arm.com Signed-off-by: Will Deacon <will@kernel.org>
-rw-r--r--virtio/rng.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/virtio/rng.c b/virtio/rng.c
index e6e70ced..77a3a113 100644
--- a/virtio/rng.c
+++ b/virtio/rng.c
@@ -61,13 +61,25 @@ static u64 get_host_features(struct kvm *kvm, void *dev)
static bool virtio_rng_do_io_request(struct kvm *kvm, struct rng_dev *rdev, struct virt_queue *queue)
{
struct iovec iov[VIRTIO_RNG_QUEUE_SIZE];
- ssize_t len = 0;
+ ssize_t len;
u16 out, in, head;
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 || errno == EINTR)) {
+ /*
+ * The virtio 1.0 spec demands at least one byte of entropy,
+ * so we cannot just return with 0 if something goes wrong.
+ * The urandom(4) manpage mentions that a read from /dev/urandom
+ * should always return at least 256 bytes of randomness, so
+ * just retry here, with the requested size clamped to that
+ * maximum, in case we were interrupted by a signal.
+ */
+ iov[0].iov_len = min(iov[0].iov_len, 256UL);
+ len = readv(rdev->fd, iov, 1);
+ if (len < 1)
+ return false;
+ }
virt_queue__set_used_elem(queue, head, len);