Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 24c65bc7 authored by Greg Kurz's avatar Greg Kurz Committed by Herbert Xu
Browse files

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



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.

Cc: stable@vger.kernel.org
Signed-off-by: default avatarGreg Kurz <gkurz@linux.vnet.ibm.com>
Signed-off-by: default avatarHerbert Xu <herbert@gondor.apana.org.au>
parent 738459e3
Loading
Loading
Loading
Loading
+7 −4
Original line number Original line Diff line number Diff line
@@ -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)


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,