changeset 14069:13ecd3583387

3775 Upstreaming of ALUA use-after-free fixes from Nexenta Reviewed by: Saso Kiselkov <skiselkov.ml@gmail.com> Reviewed by: T Nguyen <truongqnguien@gmail.com> Approved by: Richard Lowe <richlowe@richlowe.net>
author Dan McDonald <danmcd@nexenta.com>
date Thu, 27 Jun 2013 13:54:16 -0400
parents 2547a41b1162
children d4c9f8eba8fa
files usr/src/uts/common/io/comstar/port/pppt/pppt.c usr/src/uts/common/io/comstar/port/pppt/pppt.h usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c
diffstat 3 files changed, 23 insertions(+), 10 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/uts/common/io/comstar/port/pppt/pppt.c	Mon Jun 24 09:23:31 2013 +0200
+++ b/usr/src/uts/common/io/comstar/port/pppt/pppt.c	Thu Jun 27 13:54:16 2013 -0400
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/cpuvar.h>
@@ -131,8 +132,6 @@
 
 static pppt_status_t pppt_task_try_abort(pppt_task_t *ptask);
 
-static pppt_status_t pppt_task_hold(pppt_task_t *ptask);
-
 static void pppt_task_rele(pppt_task_t *ptask);
 
 static void pppt_task_update_state(pppt_task_t *ptask,
@@ -801,7 +800,7 @@
 	pppt_task_t *ptask = task->task_port_private;
 	pppt_sess_t *ps = ptask->pt_sess;
 
-	pppt_task_free(ptask);
+	pppt_task_rele(ptask);
 	pppt_sess_rele(ps);
 }
 
@@ -1209,7 +1208,7 @@
 		ptask->pt_state = PTS_INIT;
 		ptask->pt_read_buf = NULL;
 		ptask->pt_read_xfer_msgid = 0;
-		cv_init(&ptask->pt_cv, NULL, CV_DRIVER, NULL);
+		ptask->pt_refcnt = 0;
 		mutex_init(&ptask->pt_mutex, NULL, MUTEX_DRIVER, NULL);
 		immed_pbuf = (pppt_buf_t *)(ptask + 1);
 		bzero(immed_pbuf, sizeof (*immed_pbuf));
@@ -1232,8 +1231,8 @@
 pppt_task_free(pppt_task_t *ptask)
 {
 	mutex_enter(&ptask->pt_mutex);
+	ASSERT(ptask->pt_refcnt == 0);
 	mutex_destroy(&ptask->pt_mutex);
-	cv_destroy(&ptask->pt_cv);
 	kmem_free(ptask, sizeof (pppt_task_t) + sizeof (pppt_buf_t) +
 	    sizeof (stmf_data_buf_t));
 }
@@ -1249,6 +1248,8 @@
 	mutex_enter(&ptask->pt_mutex);
 	if (avl_find(&ptask->pt_sess->ps_task_list, ptask, &where) == NULL) {
 		pppt_task_update_state(ptask, PTS_ACTIVE);
+		/* Manually increment refcnt, sincd we hold the mutex... */
+		ptask->pt_refcnt++;
 		avl_insert(&ptask->pt_sess->ps_task_list, ptask, where);
 		mutex_exit(&ptask->pt_mutex);
 		mutex_exit(&ptask->pt_sess->ps_mutex);
@@ -1289,6 +1290,8 @@
 		mutex_enter(&ptask->pt_sess->ps_mutex);
 		avl_remove(&ptask->pt_sess->ps_task_list, ptask);
 		mutex_exit(&ptask->pt_sess->ps_mutex);
+		/* Out of the AVL tree, so drop a reference. */
+		pppt_task_rele(ptask);
 	}
 
 	return (pppt_status);
@@ -1401,12 +1404,14 @@
 		mutex_enter(&ptask->pt_sess->ps_mutex);
 		avl_remove(&ptask->pt_sess->ps_task_list, ptask);
 		mutex_exit(&ptask->pt_sess->ps_mutex);
+		/* Out of the AVL tree, so drop a reference. */
+		pppt_task_rele(ptask);
 	}
 
 	return (pppt_status);
 }
 
-static pppt_status_t
+pppt_status_t
 pppt_task_hold(pppt_task_t *ptask)
 {
 	pppt_status_t	pppt_status = PPPT_STATUS_SUCCESS;
@@ -1425,10 +1430,14 @@
 static void
 pppt_task_rele(pppt_task_t *ptask)
 {
+	boolean_t freeit;
+
 	mutex_enter(&ptask->pt_mutex);
 	ptask->pt_refcnt--;
-	cv_signal(&ptask->pt_cv);
+	freeit = (ptask->pt_refcnt == 0);
 	mutex_exit(&ptask->pt_mutex);
+	if (freeit)
+		pppt_task_free(ptask);
 }
 
 static void
@@ -1440,5 +1449,4 @@
 
 	ASSERT(mutex_owned(&ptask->pt_mutex));
 	ptask->pt_state = new_state;
-	cv_signal(&ptask->pt_cv);
 }
--- a/usr/src/uts/common/io/comstar/port/pppt/pppt.h	Mon Jun 24 09:23:31 2013 +0200
+++ b/usr/src/uts/common/io/comstar/port/pppt/pppt.h	Thu Jun 27 13:54:16 2013 -0400
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
  */
 #ifndef _PPPT_H
 #define	_PPPT_H
@@ -168,7 +169,6 @@
 	avl_node_t		pt_sess_ln;
 	int			pt_refcnt;
 	kmutex_t		pt_mutex;
-	kcondvar_t		pt_cv;
 	stmf_ic_msgid_t		pt_task_id;
 	uint8_t			pt_lun_id[16];
 	pppt_task_state_t	pt_state;
@@ -296,6 +296,8 @@
 
 void pppt_tgt_sm_ctl(stmf_local_port_t *lport, int cmd, void *arg);
 
+pppt_status_t pppt_task_hold(pppt_task_t *);
+
 #ifdef	__cplusplus
 }
 #endif
--- a/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c	Mon Jun 24 09:23:31 2013 +0200
+++ b/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c	Thu Jun 27 13:54:16 2013 -0400
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2009, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013, Nexenta Systems, Inc. All rights reserved.
  */
 
 #include <sys/cpuvar.h>
@@ -316,8 +317,8 @@
 	    scmd->icsc_task_lun_no,
 	    scmd->icsc_task_cdb_length, 0);
 	if (ptask->pt_stmf_task == NULL) {
+		/* NOTE: pppt_task_done() will free ptask. */
 		(void) pppt_task_done(ptask);
-		pppt_task_free(ptask);
 		pppt_sess_rele(pppt_sess);
 		pppt_msg_tx_status(msg, STMF_ALLOC_FAILURE);
 		stmf_ic_msg_free(msg);
@@ -326,6 +327,8 @@
 	}
 
 	task = ptask->pt_stmf_task;
+	/* task_port_private reference is a real reference. */
+	(void) pppt_task_hold(ptask);
 	task->task_port_private = ptask;
 	task->task_flags = scmd->icsc_task_flags;
 	task->task_additional_flags = 0;