Commit 173843d8 authored by Greg Kurz's avatar Greg Kurz Committed by Luis Henriques

hwrng: pseries - port to new read API and fix stack corruption

commit 24c65bc7 upstream.

The add_early_randomness() function in drivers/char/hw_random/core.c passes
a 16-byte buffer to pseries_rng_data_read(). Unfortunately, plpar_hcall()
returns four 64-bit values and trashes 16 bytes on the stack.

This bug has been lying around for a long time. It got unveiled by:

commit d3cc7996
Author: Amit Shah <amit.shah@redhat.com>
Date:   Thu Jul 10 15:42:34 2014 +0530

    hwrng: fetch randomness only after device init

It may trig a oops while loading or unloading the pseries-rng module for both
PowerVM and PowerKVM guests.

This patch does two things:
- pass an intermediate well sized buffer to plpar_hcall(). This is acceptalbe
  since we're not on a hot path.
- move to the new read API so that we know the return buffer size for sure.
Signed-off-by: default avatarGreg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: default avatarLuis Henriques <luis.henriques@canonical.com>
parent 765893d7
...@@ -25,18 +25,21 @@ ...@@ -25,18 +25,21 @@
#include <asm/vio.h> #include <asm/vio.h>
static int pseries_rng_data_read(struct hwrng *rng, u32 *data) static int pseries_rng_read(struct hwrng *rng, void *data, size_t max, bool wait)
{ {
u64 buffer[PLPAR_HCALL_BUFSIZE];
size_t size = max < 8 ? max : 8;
int rc; int rc;
rc = plpar_hcall(H_RANDOM, (unsigned long *)data); rc = plpar_hcall(H_RANDOM, (unsigned long *)buffer);
if (rc != H_SUCCESS) { if (rc != H_SUCCESS) {
pr_err_ratelimited("H_RANDOM call failed %d\n", rc); pr_err_ratelimited("H_RANDOM call failed %d\n", rc);
return -EIO; return -EIO;
} }
memcpy(data, buffer, size);
/* The hypervisor interface returns 64 bits */ /* The hypervisor interface returns 64 bits */
return 8; return size;
} }
/** /**
...@@ -55,7 +58,7 @@ static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev) ...@@ -55,7 +58,7 @@ static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)
static struct hwrng pseries_rng = { static struct hwrng pseries_rng = {
.name = KBUILD_MODNAME, .name = KBUILD_MODNAME,
.data_read = pseries_rng_data_read, .read = pseries_rng_read,
}; };
static int __init pseries_rng_probe(struct vio_dev *dev, static int __init pseries_rng_probe(struct vio_dev *dev,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment