Skip to content

Commit

Permalink
hwrng: pseries - port to new read API and fix stack corruption
Browse files Browse the repository at this point in the history
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 d3cc799
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.

Cc: stable@vger.kernel.org
Signed-off-by: Greg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
  • Loading branch information
gkurz authored and herbertx committed Nov 6, 2014
1 parent 738459e commit 24c65bc
Showing 1 changed file with 7 additions and 4 deletions.
11 changes: 7 additions & 4 deletions drivers/char/hw_random/pseries-rng.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,21 @@
#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;

rc = plpar_hcall(H_RANDOM, (unsigned long *)data);
rc = plpar_hcall(H_RANDOM, (unsigned long *)buffer);
if (rc != H_SUCCESS) {
pr_err_ratelimited("H_RANDOM call failed %d\n", rc);
return -EIO;
}
memcpy(data, buffer, size);

/* The hypervisor interface returns 64 bits */
return 8;
return size;
}

/**
Expand All @@ -55,7 +58,7 @@ static unsigned long pseries_rng_get_desired_dma(struct vio_dev *vdev)

static struct hwrng pseries_rng = {
.name = KBUILD_MODNAME,
.data_read = pseries_rng_data_read,
.read = pseries_rng_read,
};

static int __init pseries_rng_probe(struct vio_dev *dev,
Expand Down

0 comments on commit 24c65bc

Please sign in to comment.