From ef3b9e2fd29bbac9dc0e750d67355287620587a5 Mon Sep 17 00:00:00 2001 From: Dan McDonald Date: Thu, 27 Jun 2013 13:54:16 -0400 Subject: 3775 Upstreaming of ALUA use-after-free fixes from Nexenta Reviewed by: Saso Kiselkov Reviewed by: T Nguyen Approved by: Richard Lowe --- usr/src/uts/common/io/comstar/port/pppt/pppt.c | 24 ++++++++++++++-------- usr/src/uts/common/io/comstar/port/pppt/pppt.h | 4 +++- usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c | 5 ++++- 3 files changed, 23 insertions(+), 10 deletions(-) diff --git a/usr/src/uts/common/io/comstar/port/pppt/pppt.c b/usr/src/uts/common/io/comstar/port/pppt/pppt.c index feec2f97e4..6c59db9004 100644 --- a/usr/src/uts/common/io/comstar/port/pppt/pppt.c +++ b/usr/src/uts/common/io/comstar/port/pppt/pppt.c @@ -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 @@ -131,8 +132,6 @@ static void pppt_task_sent_status(pppt_task_t *ptask); 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_lport_task_free(scsi_task_t *task) 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 @@ pppt_task_alloc(void) 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 @@ void 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 @@ pppt_task_start(pppt_task_t *ptask) 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 @@ pppt_task_done(pppt_task_t *ptask) 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 @@ pppt_task_try_abort(pppt_task_t *ptask) 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 @@ pppt_task_hold(pppt_task_t *ptask) 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 @@ pppt_task_update_state(pppt_task_t *ptask, ASSERT(mutex_owned(&ptask->pt_mutex)); ptask->pt_state = new_state; - cv_signal(&ptask->pt_cv); } diff --git a/usr/src/uts/common/io/comstar/port/pppt/pppt.h b/usr/src/uts/common/io/comstar/port/pppt/pppt.h index 9b9bc87dd1..260eb94a8c 100644 --- a/usr/src/uts/common/io/comstar/port/pppt/pppt.h +++ b/usr/src/uts/common/io/comstar/port/pppt/pppt.h @@ -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 @@ typedef struct { 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 @@ int pppt_tgt_avl_compare(const void *void_tgt1, const void *void_tgt2); 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 diff --git a/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c b/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c index f586ea54c0..7d7f571ec0 100644 --- a/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c +++ b/usr/src/uts/common/io/comstar/port/pppt/pppt_msg.c @@ -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 @@ -316,8 +317,8 @@ pppt_msg_scsi_cmd(stmf_ic_msg_t *msg) 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 @@ pppt_msg_scsi_cmd(stmf_ic_msg_t *msg) } 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; -- cgit v1.2.3