Skip to contentSkip to conversation

hwrng: cctrng - fix destination offset in cctrng_read()

PATCH In review Thorsten Blum 2 participants 3 messages Oct 15 – Nov 6

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

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.

Fixes a583ed310bb6 ("hwrng: cctrng - introduce Arm CryptoCell driver")
---
 drivers/char/hw_random/cctrng.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/char/hw_random/cctrng.c +1 -1
index a6925211c3b5..e070581237e5 100644
@@ -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);
 	}
maintainer
#1 lore raw

PATCH 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")
---
 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.

Fixes a583ed310bb6 ("hwrng: cctrng - introduce Arm CryptoCell driver")
drivers/char/hw_random/cctrng.c +20 -18
index 03401ee59a8e..ef49e0195ee9 100644
@@ -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
maintainer
#2 lore raw
In reply to Thorsten Blum
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")
---
 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