mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-12-23 11:33:32 +00:00
43937a4f5e
Check the length of data written by the device is consistent with the size of the buffers to avoid out-of-bounds memory accesses in case values aren't consistent. Signed-off-by: Andrew Scull <ascull@google.com> Cc: Sughosh Ganu <sughosh.ganu@linaro.org> Reviewed-by: Simon Glass <sjg@chromium.org>
92 lines
1.8 KiB
C
92 lines
1.8 KiB
C
// SPDX-License-Identifier: GPL-2.0+
|
|
/*
|
|
* Copyright (c) 2019, Linaro Limited
|
|
*/
|
|
|
|
#include <common.h>
|
|
#include <dm.h>
|
|
#include <log.h>
|
|
#include <rng.h>
|
|
#include <virtio_types.h>
|
|
#include <virtio.h>
|
|
#include <virtio_ring.h>
|
|
|
|
#define BUFFER_SIZE 16UL
|
|
|
|
struct virtio_rng_priv {
|
|
struct virtqueue *rng_vq;
|
|
};
|
|
|
|
static int virtio_rng_read(struct udevice *dev, void *data, size_t len)
|
|
{
|
|
int ret;
|
|
unsigned int rsize;
|
|
unsigned char buf[BUFFER_SIZE] __aligned(4);
|
|
unsigned char *ptr = data;
|
|
struct virtio_sg sg;
|
|
struct virtio_sg *sgs[1];
|
|
struct virtio_rng_priv *priv = dev_get_priv(dev);
|
|
|
|
while (len) {
|
|
sg.addr = buf;
|
|
sg.length = min(len, sizeof(buf));
|
|
sgs[0] = &sg;
|
|
|
|
ret = virtqueue_add(priv->rng_vq, sgs, 0, 1);
|
|
if (ret)
|
|
return ret;
|
|
|
|
virtqueue_kick(priv->rng_vq);
|
|
|
|
while (!virtqueue_get_buf(priv->rng_vq, &rsize))
|
|
;
|
|
|
|
if (rsize > sg.length)
|
|
return -EIO;
|
|
|
|
memcpy(ptr, buf, rsize);
|
|
len -= rsize;
|
|
ptr += rsize;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int virtio_rng_bind(struct udevice *dev)
|
|
{
|
|
struct virtio_dev_priv *uc_priv = dev_get_uclass_priv(dev->parent);
|
|
|
|
/* Indicate what driver features we support */
|
|
virtio_driver_features_init(uc_priv, NULL, 0, NULL, 0);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int virtio_rng_probe(struct udevice *dev)
|
|
{
|
|
struct virtio_rng_priv *priv = dev_get_priv(dev);
|
|
int ret;
|
|
|
|
ret = virtio_find_vqs(dev, 1, &priv->rng_vq);
|
|
if (ret < 0) {
|
|
debug("%s: virtio_find_vqs failed\n", __func__);
|
|
return ret;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static const struct dm_rng_ops virtio_rng_ops = {
|
|
.read = virtio_rng_read,
|
|
};
|
|
|
|
U_BOOT_DRIVER(virtio_rng) = {
|
|
.name = VIRTIO_RNG_DRV_NAME,
|
|
.id = UCLASS_RNG,
|
|
.bind = virtio_rng_bind,
|
|
.probe = virtio_rng_probe,
|
|
.remove = virtio_reset,
|
|
.ops = &virtio_rng_ops,
|
|
.priv_auto = sizeof(struct virtio_rng_priv),
|
|
.flags = DM_FLAG_ACTIVE_DMA,
|
|
};
|