hwrng: cctrng - fix destination offset in cctrng_read()
Subsystems (3)
PATCH 1/1 hwrng: cctrng - fix destination offset in cctrng_read()
cctrng_read() copies random data in two steps when a read wraps around the end of the circular buffer.
Use the correct destination offset for the second copy instead of overwriting the start of the destination buffer.
--- drivers/char/hw_random/cctrng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/char/hw_random/cctrng.c +1 -1
@@ -237,7 +237,7 @@ static int cctrng_read(struct hwrng *rng, void *data, size_t max, bool wait) cnt_w =CIRC_CNT (drvdata->circ.head, drvdata->circ.tail,CCTRNG_DATA_BUF_WORDS ); size =min ((cnt_w<<2 ), left); -memcpy (data, &(buf[drvdata->circ.tail]), size); +memcpy (data + copied, &buf[drvdata->circ.tail], size); copied += size;circ_idx_inc (&drvdata->circ.tail, size); }
Herbert Xu
maintainerPATCH 1/1 hwrng: cctrng - Lock read and writer of circular buffer
Quoted 6 lines · Thorsten Blum
cctrng_read()copies random data in two steps when a read wraps around the end of the circular buffer.Use the correct destination offset for the second copy instead of overwriting the start of the destination buffer.
Quoted 6 lines
Fixes a583ed310bb6 ("hwrng: cctrng - introduce Arm CryptoCell driver")Signed-off-by Thorsten Blum <[email protected]>--- drivers/char/hw_random/cctrng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Sashiko complained about the lack of memory barries in the circular buffer code. This is taking a spinlock on the read-path, so it might as well do it for both reading and writing.
I've also changed it to a mutex and added support for the wait flag.
---8<---
The circular buffer handling in cctrng is buggy as it doesn't use any synchronisation mechanism between the reader and the writer.
As this isn't performance-critical, simply change it to use a mutex that covers both reading and writing.
While adding an inclusion for linux/err.h and linux/mutex.h, also sort the headers alphabetically to avoid potential duplicates.
drivers/char/hw_random/cctrng.c +20 -18
@@ -1,21 +1,23 @@// SPDX-License-Identifier: GPL-2.0 /* Copyright (C) 2019-2020 ARM Limited or its affiliates. */ -#include <linux/kernel.h> -#include <linux/module.h> +#include <linux/bitfield.h> +#include <linux/circ_buf.h> #include <linux/clk.h> +#include <linux/completion.h> +#include <linux/err.h> +#include <linux/fips.h> +#include <linux/kernel.h> #include <linux/hw_random.h> +#include <linux/interrupt.h> #include <linux/io.h> +#include <linux/irqreturn.h> +#include <linux/module.h> +#include <linux/mutex.h> +#include <linux/of.h> #include <linux/platform_device.h> #include <linux/pm_runtime.h> -#include <linux/interrupt.h> -#include <linux/irqreturn.h> #include <linux/workqueue.h> -#include <linux/circ_buf.h> -#include <linux/completion.h> -#include <linux/of.h> -#include <linux/bitfield.h> -#include <linux/fips.h> #include "cctrng.h"
@@ -68,8 +70,8 @@ struct cctrng_drvdata {/* pending_hw - 1 when HW is pending, 0 when it is idle */ atomic_t pending_hw; -/* protects against multiple concurrent consumers of data_buf */ -spinlock_t read_lock; +/* protects data_buf */ +struct mutex lock; };
@@ -213,11 +215,8 @@ static int cctrng_read(struct hwrng *rng, void *data, size_t max, bool wait)size_t size;size_t left; -if (!spin_trylock (&drvdata->read_lock)) { -/* concurrent consumers from data_buf cannot be served */ -dev_dbg_ratelimited (dev,"unable to hold lock\n" ); -return 0 ; - } +if (mutex_lock_interruptible (&drvdata->lock)) +return -ERESTARTSYS ;/* copy till end of data buffer (without wrap back) */ cnt_w = CIRC_CNT_TO_END(drvdata->circ.head,
@@ -237,7 +236,7 @@ static int cctrng_read(struct hwrng *rng, void *data, size_t max, bool wait)circ_idx_inc (&drvdata->circ.tail, size); } -spin_unlock (&drvdata->read_lock); +mutex_unlock (&drvdata->lock);if (circ_buf_space (drvdata) >=CC_TRNG_EHR_IN_WORDS ) {if (atomic_cmpxchg (&drvdata->pending_hw,0 ,1 ) ==0 ) {
@@ -347,6 +346,7 @@ static void cc_trng_compwork_handler(struct work_struct *w) }/* read EHR data from registers */ +mutex_lock (&drvdata->lock);for (i =0 ; i <CC_TRNG_EHR_IN_WORDS ; i++) {/* calc word ptr in data_buf */ u32 *buf = (u32 *)drvdata->circ.buf;
@@ -358,6 +358,7 @@ static void cc_trng_compwork_handler(struct work_struct *w)* returned, restart the entropy collection. */ if (buf[drvdata->circ.head] ==0 ) { +mutex_unlock (&drvdata->lock);dev_dbg (dev,"Got 0 value in EHR. active_rosc %u\n" , drvdata->active_rosc); goto next_rosc;
@@ -365,6 +366,7 @@ static void cc_trng_compwork_handler(struct work_struct *w)circ_idx_inc (&drvdata->circ.head,1 <<2 ); } +mutex_unlock (&drvdata->lock);atomic_set (&drvdata->pending_hw,0 );
@@ -499,7 +501,7 @@ static int cctrng_probe(struct platform_device *pdev)INIT_WORK (&drvdata->compwork, cc_trng_compwork_handler);INIT_WORK (&drvdata->startwork, cc_trng_startwork_handler); -spin_lock_init (&drvdata->read_lock); +mutex_init (&drvdata->lock);/* register the driver isr function */ rc =devm_request_irq (dev, irq, cc_isr,IRQF_SHARED ,"cctrng" , drvdata);
Signature · 3 lines
Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
Herbert Xu
maintainerQuoted 6 lines · Thorsten Blum
cctrng_read()copies random data in two steps when a read wraps around the end of the circular buffer.Use the correct destination offset for the second copy instead of overwriting the start of the destination buffer.
Quoted 6 lines
Fixes a583ed310bb6 ("hwrng: cctrng - introduce Arm CryptoCell driver")Signed-off-by Thorsten Blum <[email protected]>--- drivers/char/hw_random/cctrng.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
Patch applied. Thanks.
Signature · 3 lines
Email: Herbert Xu <[email protected]> Home Page: http://gondor.apana.org.au/~herbert/ PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt