Module Name:    src
Committed By:   knakahara
Date:           Fri Apr  7 12:15:51 UTC 2017

Modified Files:
        src/sys/opencrypto: cryptodev.c cryptodev.h

Log Message:
fix race among crypto_done(), cryptoret(), and {cryptodev_op(), 
cryptodev_key()}.

crypto_op() waited to be set CRYPTO_F_DONE with crp->crp_cv.
However, there is context switch chances between being set CRYPTO_F_DONE in
crypto_done() and done cv_signal(crp->crp_cv) in cryptodev_cb(), that is,
cryptodev_op() thread can run to cv_destroy(crp->crp_cv) before cryptoret()
thread is waken up. As a result, cryptodev_cb() can call invalid(destroyed)
cv_signal(crp->crp_cv).

Furthermore, below two implementations cause other races.
    - waiting CRYPTO_F_DONE with crp->crp_cv
    - context witch chances between set CRYPTO_F_DONE and cv_signal(crp->crp_cv)

So, use other flag(CRYPTO_F_DQRETQ) for cryptodev_op() and cryptodev_key(),
and then call cv_signal(crp->crp_cv) immediately after set CRYPTO_F_DQRETQ.

Tested concurrent over 20 processes with software and hardware drivers.


To generate a diff of this commit:
cvs rdiff -u -r1.86 -r1.87 src/sys/opencrypto/cryptodev.c
cvs rdiff -u -r1.29 -r1.30 src/sys/opencrypto/cryptodev.h

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/opencrypto/cryptodev.c
diff -u src/sys/opencrypto/cryptodev.c:1.86 src/sys/opencrypto/cryptodev.c:1.87
--- src/sys/opencrypto/cryptodev.c:1.86	Wed Apr  5 08:51:04 2017
+++ src/sys/opencrypto/cryptodev.c	Fri Apr  7 12:15:51 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: cryptodev.c,v 1.86 2017/04/05 08:51:04 knakahara Exp $ */
+/*	$NetBSD: cryptodev.c,v 1.87 2017/04/07 12:15:51 knakahara Exp $ */
 /*	$FreeBSD: src/sys/opencrypto/cryptodev.c,v 1.4.2.4 2003/06/03 00:09:02 sam Exp $	*/
 /*	$OpenBSD: cryptodev.c,v 1.53 2002/07/10 22:21:30 mickey Exp $	*/
 
@@ -64,7 +64,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: cryptodev.c,v 1.86 2017/04/05 08:51:04 knakahara Exp $");
+__KERNEL_RCSID(0, "$NetBSD: cryptodev.c,v 1.87 2017/04/07 12:15:51 knakahara Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -663,7 +663,7 @@ eagain:
 		goto bail;
 	}
 
-	while (!(crp->crp_flags & CRYPTO_F_DONE)) {
+	while (!(crp->crp_flags & CRYPTO_F_DQRETQ)) {
 		DPRINTF(("cryptodev_op[%d]: sleeping on cv %p for crp %p\n",
 			(uint32_t)cse->sid, &crp->crp_cv, crp));
 		cv_wait(&crp->crp_cv, &crypto_mtx);	/* XXX cv_wait_sig? */
@@ -744,6 +744,7 @@ cryptodev_cb(void *op)
 		mutex_enter(&crypto_mtx);
 	}
 	if (error != 0 || (crp->crp_flags & CRYPTO_F_DONE)) {
+		crp->crp_flags |= CRYPTO_F_DQRETQ;
 		cv_signal(&crp->crp_cv);
 	}
 	mutex_exit(&crypto_mtx);
@@ -780,6 +781,7 @@ cryptodevkey_cb(void *op)
 	struct cryptkop *krp = op;
 	
 	mutex_enter(&crypto_mtx);
+	krp->krp_flags |= CRYPTO_F_DQRETQ;
 	cv_signal(&krp->krp_cv);
 	mutex_exit(&crypto_mtx);
 	return 0;
@@ -890,7 +892,7 @@ cryptodev_key(struct crypt_kop *kop)
 	}
 
 	mutex_enter(&crypto_mtx);
-	while (!(krp->krp_flags & CRYPTO_F_DONE)) {
+	while (!(krp->krp_flags & CRYPTO_F_DQRETQ)) {
 		cv_wait(&krp->krp_cv, &crypto_mtx);	/* XXX cv_wait_sig? */
 	}
 	if (krp->krp_flags & CRYPTO_F_ONRETQ) {

Index: src/sys/opencrypto/cryptodev.h
diff -u src/sys/opencrypto/cryptodev.h:1.29 src/sys/opencrypto/cryptodev.h:1.30
--- src/sys/opencrypto/cryptodev.h:1.29	Mon Mar  6 09:59:05 2017
+++ src/sys/opencrypto/cryptodev.h	Fri Apr  7 12:15:51 2017
@@ -1,4 +1,4 @@
-/*	$NetBSD: cryptodev.h,v 1.29 2017/03/06 09:59:05 knakahara Exp $ */
+/*	$NetBSD: cryptodev.h,v 1.30 2017/04/07 12:15:51 knakahara Exp $ */
 /*	$FreeBSD: src/sys/opencrypto/cryptodev.h,v 1.2.2.6 2003/07/02 17:04:50 sam Exp $	*/
 /*	$OpenBSD: cryptodev.h,v 1.33 2002/07/17 23:52:39 art Exp $	*/
 
@@ -473,6 +473,7 @@ struct cryptop {
 #define	CRYPTO_F_ONRETQ		0x0080	/* Request is on return queue */
 #define	CRYPTO_F_USER		0x0100	/* Request is in user context */
 #define	CRYPTO_F_MORE		0x0200	/* more data to follow */
+#define	CRYPTO_F_DQRETQ		0x0400	/* Dequeued from crp_ret_{,k}q */
 
 	void *		crp_buf;	/* Data to be processed */
 	void *		crp_opaque;	/* Opaque pointer, passed along */

Reply via email to