changeset 5063:c7cb857a0196

6602421 panic in dca_encrypt() while handling an in-place call
author gm89044
date Mon, 17 Sep 2007 08:01:53 -0700
parents d04e7c32c7ca
children 0fbdaabf14a1
files usr/src/uts/common/crypto/io/dca.c usr/src/uts/common/crypto/io/dca_3des.c usr/src/uts/common/crypto/io/dca_rsa.c
diffstat 3 files changed, 102 insertions(+), 70 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/crypto/io/dca.c	Mon Sep 17 06:05:15 2007 -0700
+++ b/usr/src/uts/common/crypto/io/dca.c	Mon Sep 17 08:01:53 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -834,9 +834,9 @@
 	}
 
 	crypto_prov_notify(WORKLIST(dca, MCR1)->dwl_prov,
-		CRYPTO_PROVIDER_READY);
+	    CRYPTO_PROVIDER_READY);
 	crypto_prov_notify(WORKLIST(dca, MCR2)->dwl_prov,
-		CRYPTO_PROVIDER_READY);
+	    CRYPTO_PROVIDER_READY);
 
 	/* Initialize the local random number pool for this instance */
 	if ((ret = dca_random_init(dca)) != CRYPTO_SUCCESS) {
@@ -861,10 +861,12 @@
 failed:
 	/* unregister from the crypto framework */
 	if (WORKLIST(dca, MCR1)->dwl_prov != NULL) {
-	    (void) crypto_unregister_provider(WORKLIST(dca, MCR1)->dwl_prov);
+		(void) crypto_unregister_provider(
+		    WORKLIST(dca, MCR1)->dwl_prov);
 	}
 	if (WORKLIST(dca, MCR2)->dwl_prov != NULL) {
-	    (void) crypto_unregister_provider(WORKLIST(dca, MCR2)->dwl_prov);
+		(void) crypto_unregister_provider(
+		    WORKLIST(dca, MCR2)->dwl_prov);
 	}
 	if (intr_added) {
 		CLRBIT(dca, CSR_DMACTL,
@@ -928,19 +930,19 @@
 	 * This needs to be done at the beginning of detach.
 	 */
 	if (WORKLIST(dca, MCR1)->dwl_prov != NULL) {
-	    if (crypto_unregister_provider(WORKLIST(dca, MCR1)->dwl_prov) !=
-		CRYPTO_SUCCESS) {
-		    dca_error(dca, "unable to unregister MCR1 from kcf");
-		    return (DDI_FAILURE);
-	    }
+		if (crypto_unregister_provider(
+		    WORKLIST(dca, MCR1)->dwl_prov) != CRYPTO_SUCCESS) {
+			dca_error(dca, "unable to unregister MCR1 from kcf");
+			return (DDI_FAILURE);
+		}
 	}
 
 	if (WORKLIST(dca, MCR2)->dwl_prov != NULL) {
-	    if (crypto_unregister_provider(WORKLIST(dca, MCR2)->dwl_prov) !=
-		CRYPTO_SUCCESS) {
-		    dca_error(dca, "unable to unregister MCR2 from kcf");
-		    return (DDI_FAILURE);
-	    }
+		if (crypto_unregister_provider(
+		    WORKLIST(dca, MCR2)->dwl_prov) != CRYPTO_SUCCESS) {
+			dca_error(dca, "unable to unregister MCR2 from kcf");
+			return (DDI_FAILURE);
+		}
 	}
 
 	/*
@@ -1171,7 +1173,7 @@
 	 */
 	wlp = WORKLIST(dca, MCR1);
 	(void) sprintf(wlp->dwl_name, "dca%d:mcr1",
-		ddi_get_instance(dca->dca_dip));
+	    ddi_get_instance(dca->dca_dip));
 	wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY,
 	    dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
 	    "mcr1_lowater", MCR1LOWATER);
@@ -1192,7 +1194,7 @@
 	 */
 	wlp = WORKLIST(dca, MCR2);
 	(void) sprintf(wlp->dwl_name, "dca%d:mcr2",
-		ddi_get_instance(dca->dca_dip));
+	    ddi_get_instance(dca->dca_dip));
 	wlp->dwl_lowater = ddi_getprop(DDI_DEV_T_ANY,
 	    dca->dca_dip, DDI_PROP_CANSLEEP | DDI_PROP_DONTPASS,
 	    "mcr2_lowater", MCR2LOWATER);
@@ -1353,7 +1355,7 @@
 	 * unqueue takes from the "tail" of the list, i.e. just before
 	 * the sentinel.
 	 */
-	if ((node = q->dl_prev) == q) {;
+	if ((node = q->dl_prev) == q) {
 		/* queue is empty */
 		return (NULL);
 	}
@@ -1985,6 +1987,10 @@
 		reqp->dr_chain_in_head.dc_buffer_paddr = 0;
 	}
 
+	if (reqp->dr_flags & DR_INPLACE) {
+		return (rv);
+	}
+
 	/* Clear the output chain */
 	if (reqp->dr_chain_out_head.dc_buffer_paddr != NULL) {
 		(void) ddi_dma_unbind_handle(reqp->dr_chain_out_dmah);
@@ -2175,7 +2181,7 @@
 		/* if there isn't enough to do, don't bother now */
 		if ((wlp->dwl_count < wlp->dwl_reqspermcr) &&
 		    (ddi_get_lbolt() < (wlp->dwl_lastsubmit +
-			drv_usectohz(MSEC)))) {
+		    drv_usectohz(MSEC)))) {
 			/* wait a bit longer... */
 			if (wlp->dwl_schedtid == 0) {
 				wlp->dwl_schedtid = timeout(dca_schedtimeout,
@@ -2294,7 +2300,7 @@
 		workp->dw_lbolt = ddi_get_lbolt();
 		/* Make sure MCR is synced out to device. */
 		(void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 0,
-			DDI_DMA_SYNC_FORDEV);
+		    DDI_DMA_SYNC_FORDEV);
 		if (dca_check_dma_handle(dca, workp->dw_mcr_dmah,
 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
 			dca_destroywork(workp);
@@ -2343,7 +2349,7 @@
 
 		/* only sync the MCR flags, since that's all we need */
 		(void) ddi_dma_sync(workp->dw_mcr_dmah, 0, 4,
-			DDI_DMA_SYNC_FORKERNEL);
+		    DDI_DMA_SYNC_FORKERNEL);
 		if (dca_check_dma_handle(dca, workp->dw_mcr_dmah,
 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
 			dca_rmqueue((dca_listnode_t *)workp);
@@ -2537,15 +2543,7 @@
 			for (i = 0; i < wlp->dwl_reqspermcr; i++) {
 				dca_request_t *reqp = workp->dw_reqs[i];
 				if (reqp) {
-					if (reqp->dr_flags & DR_INPLACE) {
-						dca_done(reqp, errno);
-					} else {
-						/*
-						 * cause it to get retried
-						 * elsewhere (software)
-						 */
-						dca_done(reqp, CRYPTO_FAILED);
-					}
+					dca_done(reqp, errno);
 					workp->dw_reqs[i] = NULL;
 				}
 			}
@@ -2875,7 +2873,8 @@
 		uiop = data->cd_uio;
 		for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
 		    off >= uiop->uio_iov[vec_idx].iov_len;
-		    off -= uiop->uio_iov[vec_idx++].iov_len);
+		    off -= uiop->uio_iov[vec_idx++].iov_len)
+			;
 		if (vec_idx == uiop->uio_iovcnt) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -2913,7 +2912,8 @@
 		 * Jump to the first mblk_t containing data to be processed.
 		 */
 		for (mp = data->cd_mp; mp != NULL && off >= MBLKL(mp);
-		    off -= MBLKL(mp), mp = mp->b_cont);
+		    off -= MBLKL(mp), mp = mp->b_cont)
+			;
 		if (mp == NULL) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -3117,7 +3117,8 @@
 		uiop = in->cd_uio;
 		for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
 		    off >= uiop->uio_iov[vec_idx].iov_len;
-		    off -= uiop->uio_iov[vec_idx++].iov_len);
+		    off -= uiop->uio_iov[vec_idx++].iov_len)
+			;
 		if (vec_idx == uiop->uio_iovcnt) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -3163,7 +3164,8 @@
 		 * Jump to the first mblk_t containing data to be processed.
 		 */
 		for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp);
-		    off -= MBLKL(mp), mp = mp->b_cont);
+		    off -= MBLKL(mp), mp = mp->b_cont)
+			;
 		if (mp == NULL) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -3266,7 +3268,8 @@
 		uiop = in->cd_uio;
 		for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
 		    off >= uiop->uio_iov[vec_idx].iov_len;
-		    off -= uiop->uio_iov[vec_idx++].iov_len);
+		    off -= uiop->uio_iov[vec_idx++].iov_len)
+			;
 		if (vec_idx == uiop->uio_iovcnt) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -3306,7 +3309,8 @@
 		 * Jump to the first mblk_t containing data to be processed.
 		 */
 		for (mp = in->cd_mp; mp != NULL && off >= MBLKL(mp);
-		    off -= MBLKL(mp), mp = mp->b_cont);
+		    off -= MBLKL(mp), mp = mp->b_cont)
+			;
 		if (mp == NULL) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -3383,7 +3387,8 @@
 		uiop = out->cd_uio;
 		for (vec_idx = 0; vec_idx < uiop->uio_iovcnt &&
 		    offset >= uiop->uio_iov[vec_idx].iov_len;
-		    offset -= uiop->uio_iov[vec_idx++].iov_len);
+		    offset -= uiop->uio_iov[vec_idx++].iov_len)
+			;
 		if (vec_idx == uiop->uio_iovcnt) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -3428,7 +3433,8 @@
 		 * Jump to the first mblk_t that can be written to.
 		 */
 		for (mp = out->cd_mp; mp != NULL && offset >= MBLKL(mp);
-		    offset -= MBLKL(mp), mp = mp->b_cont);
+		    offset -= MBLKL(mp), mp = mp->b_cont)
+			;
 		if (mp == NULL) {
 			/*
 			 * The caller specified an offset that is larger than
@@ -3740,6 +3746,13 @@
 	DCA_SOFTC_FROM_CTX(ctx, softc, instance);
 	DBG(softc, DENTRY, "dca_encrypt: started");
 
+	/* handle inplace ops */
+	if (!ciphertext) {
+		dca_request_t *reqp = ctx->cc_provider_private;
+		reqp->dr_flags |= DR_INPLACE;
+		ciphertext = plaintext;
+	}
+
 	/* check mechanism */
 	switch (DCA_MECH_FROM_CTX(ctx)) {
 	case DES_CBC_MECH_INFO_TYPE:
@@ -3788,6 +3801,13 @@
 	DCA_SOFTC_FROM_CTX(ctx, softc, instance);
 	DBG(softc, DENTRY, "dca_encrypt_update: started");
 
+	/* handle inplace ops */
+	if (!ciphertext) {
+		dca_request_t *reqp = ctx->cc_provider_private;
+		reqp->dr_flags |= DR_INPLACE;
+		ciphertext = plaintext;
+	}
+
 	/* check mechanism */
 	switch (DCA_MECH_FROM_CTX(ctx)) {
 	case DES_CBC_MECH_INFO_TYPE:
@@ -3862,6 +3882,11 @@
 	if (ctx_template != NULL)
 		return (CRYPTO_ARGUMENTS_BAD);
 
+	/* handle inplace ops */
+	if (!ciphertext) {
+		ciphertext = plaintext;
+	}
+
 	/* check mechanism */
 	switch (mechanism->cm_type) {
 	case DES_CBC_MECH_INFO_TYPE:
@@ -3955,6 +3980,13 @@
 	DCA_SOFTC_FROM_CTX(ctx, softc, instance);
 	DBG(softc, DENTRY, "dca_decrypt: started");
 
+	/* handle inplace ops */
+	if (!plaintext) {
+		dca_request_t *reqp = ctx->cc_provider_private;
+		reqp->dr_flags |= DR_INPLACE;
+		plaintext = ciphertext;
+	}
+
 	/* check mechanism */
 	switch (DCA_MECH_FROM_CTX(ctx)) {
 	case DES_CBC_MECH_INFO_TYPE:
@@ -4004,6 +4036,13 @@
 	DCA_SOFTC_FROM_CTX(ctx, softc, instance);
 	DBG(softc, DENTRY, "dca_decrypt_update: started");
 
+	/* handle inplace ops */
+	if (!plaintext) {
+		dca_request_t *reqp = ctx->cc_provider_private;
+		reqp->dr_flags |= DR_INPLACE;
+		plaintext = ciphertext;
+	}
+
 	/* check mechanism */
 	switch (DCA_MECH_FROM_CTX(ctx)) {
 	case DES_CBC_MECH_INFO_TYPE:
@@ -4078,6 +4117,11 @@
 	if (ctx_template != NULL)
 		return (CRYPTO_ARGUMENTS_BAD);
 
+	/* handle inplace ops */
+	if (!plaintext) {
+		plaintext = ciphertext;
+	}
+
 	/* check mechanism */
 	switch (mechanism->cm_type) {
 	case DES_CBC_MECH_INFO_TYPE:
@@ -4794,7 +4838,7 @@
 
 	/* Manufacturer ID */
 	(void) sprintf((char *)ext_info->ei_manufacturerID, "%s",
-		DCA_MANUFACTURER_ID);
+	    DCA_MANUFACTURER_ID);
 	len = strlen((char *)ext_info->ei_manufacturerID);
 	(void) memset(ext_info->ei_manufacturerID + len, ' ',
 	    CRYPTO_EXT_SIZE_MANUF - len);
@@ -4806,7 +4850,7 @@
 
 	len = strlen((char *)ext_info->ei_model);
 	(void) memset(ext_info->ei_model + len, ' ',
-		CRYPTO_EXT_SIZE_MODEL - len);
+	    CRYPTO_EXT_SIZE_MODEL - len);
 
 	/* Serial Number. Blank for Deimos */
 	(void) memset(ext_info->ei_serial_number, ' ', CRYPTO_EXT_SIZE_SERIAL);
@@ -4836,8 +4880,8 @@
 {
 	ddi_iblock_cookie_t fm_ibc;
 	int fm_capabilities = DDI_FM_EREPORT_CAPABLE |
-		DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE |
-		DDI_FM_ERRCB_CAPABLE;
+	    DDI_FM_ACCCHK_CAPABLE | DDI_FM_DMACHK_CAPABLE |
+	    DDI_FM_ERRCB_CAPABLE;
 
 	/* Read FMA capabilities from dca.conf file (if present) */
 	dca->fm_capabilities = ddi_getprop(DDI_DEV_T_ANY, dca->dca_dip,
--- a/usr/src/uts/common/crypto/io/dca_3des.c	Mon Sep 17 06:05:15 2007 -0700
+++ b/usr/src/uts/common/crypto/io/dca_3des.c	Mon Sep 17 08:01:53 2007 -0700
@@ -21,7 +21,7 @@
  */
 
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -79,13 +79,6 @@
 		des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7];
 	}
 
-	/*
-	 * In-place operations (input == out) are indicated by having a
-	 * NULL output. In this case set the output to point to the input.
-	 */
-	if (out == NULL) {
-		out = in;
-	}
 	if (len > dca_length(out)) {
 		DBG(dca, DWARN, "inadequate output space (need %d, got %d)",
 		    len, dca_length(out));
@@ -180,13 +173,6 @@
 		des_ctx->dr_ctx.iv[1] = p[4]<<24 | p[5]<<16 | p[6]<<8 | p[7];
 	}
 
-	/*
-	 * In-place operations (in == out) are indicated by having a
-	 * NULL output. In this case set the output to point to the input.
-	 */
-	if (out == NULL) {
-		out = in;
-	}
 	if (len > dca_length(out)) {
 		DBG(dca, DWARN, "not enough output space (need %d, got %d)",
 		    len, dca_length(out));
@@ -346,6 +332,12 @@
 	 */
 	((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
 
+	/* check for inplace ops */
+	if (input == output) {
+		((dca_request_t *)ctx.cc_provider_private)->dr_flags
+		    |= DR_INPLACE;
+	}
+
 	rv = dca_3des(&ctx, input, output, req, mode);
 	if ((rv != CRYPTO_QUEUED) && (rv != CRYPTO_SUCCESS)) {
 		DBG(NULL, DWARN, "dca_3desatomic: dca_3des() failed");
@@ -470,7 +462,7 @@
 		 * Use the actual length if the first entry is sufficient.
 		 */
 		(void) ddi_dma_sync(reqp->dr_ibuf_dmah, 0, len,
-			DDI_DMA_SYNC_FORDEV);
+		    DDI_DMA_SYNC_FORDEV);
 		if (dca_check_dma_handle(dca, reqp->dr_ibuf_dmah,
 		    DCA_FM_ECLASS_NONE) != DDI_SUCCESS) {
 			reqp->destroy = TRUE;
@@ -529,7 +521,7 @@
 
 		if (reqp->dr_flags & DR_SCATTER) {
 			(void) ddi_dma_sync(reqp->dr_obuf_dmah, 0,
-				reqp->dr_out_len, DDI_DMA_SYNC_FORKERNEL);
+			    reqp->dr_out_len, DDI_DMA_SYNC_FORKERNEL);
 			if (dca_check_dma_handle(reqp->dr_dca,
 			    reqp->dr_obuf_dmah, DCA_FM_ECLASS_NONE) !=
 			    DDI_SUCCESS) {
--- a/usr/src/uts/common/crypto/io/dca_rsa.c	Mon Sep 17 06:05:15 2007 -0700
+++ b/usr/src/uts/common/crypto/io/dca_rsa.c	Mon Sep 17 08:01:53 2007 -0700
@@ -20,7 +20,7 @@
  */
 
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -69,16 +69,6 @@
 	int			rv = CRYPTO_QUEUED;
 	int			len;
 
-	/*
-	 * In-place operations (in == out) are indicated by having a
-	 * NULL output. In this case set the out to point to the in.
-	 * Note that this only works for CKM_RSA_X_509 without any padding
-	 */
-	if (!out) {
-		DBG(dca, DWARN, "Using inline since output buffer is NULL.");
-		out = in;
-	}
-
 	/* We don't support non-contiguous buffers for RSA */
 	if (dca_sgcheck(dca, in, DCA_SG_CONTIG) ||
 	    dca_sgcheck(dca, out, DCA_SG_CONTIG)) {
@@ -661,6 +651,12 @@
 	 */
 	((dca_request_t *)ctx.cc_provider_private)->dr_ctx.atomic = 1;
 
+	/* check for inplace ops */
+	if (input == output) {
+		((dca_request_t *)ctx.cc_provider_private)->dr_flags
+		    |= DR_INPLACE;
+	}
+
 	rv = dca_rsastart(&ctx, input, output, req, mode);
 
 	/*