Commit 3ad0fb1a authored by Ye Bin's avatar Ye Bin Committed by Yang Yingliang
Browse files

iscsi: Fix KABI change for 'Fix conn use after free during resets'



hulk inclusion
category: bugfix
bugzilla: NA
CVE: NA

-----------------------------------------------

Use struct iscsi_cls_session_wrapper to avoid kabi broken.

Signed-off-by: default avatarYe Bin <yebin10@huawei.com>
Reviewed-by: default avatarJason Yan <yanaijie@huawei.com>
Signed-off-by: default avatarYang Yingliang <yangyingliang@huawei.com>
parent 25cdd823
Loading
Loading
Loading
Loading
+68 −41
Original line number Diff line number Diff line
@@ -266,10 +266,12 @@ static int iscsi_prep_bidi_ahs(struct iscsi_task *task)
static int iscsi_check_tmf_restrictions(struct iscsi_task *task, int opcode)
{
	struct iscsi_session *session = task->conn->session;
	struct iscsi_tm *tmf = &session->tmhdr;
	struct iscsi_cls_session_wrapper *cls_session =
		iscsi_cls_session_to_wrapper(session->cls_session);
	struct iscsi_tm *tmf = &cls_session->tmhdr;
	u64 hdr_lun;

	if (session->tmf_state == TMF_INITIAL)
	if (cls_session->tmf_state == TMF_INITIAL)
		return 0;

	if ((tmf->opcode & ISCSI_OPCODE_MASK) != ISCSI_OP_SCSI_TMFUNC)
@@ -988,7 +990,8 @@ iscsi_data_in_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr,
static void iscsi_tmf_rsp(struct iscsi_conn *conn, struct iscsi_hdr *hdr)
{
	struct iscsi_tm_rsp *tmf = (struct iscsi_tm_rsp *)hdr;
	struct iscsi_session *session = conn->session;
	struct iscsi_cls_session_wrapper *session =
		iscsi_cls_session_to_wrapper(conn->session->cls_session);

	conn->exp_statsn = be32_to_cpu(hdr->statsn) + 1;
	conn->tmfrsp_pdus_cnt++;
@@ -1875,14 +1878,16 @@ EXPORT_SYMBOL_GPL(iscsi_target_alloc);

static void iscsi_tmf_timedout(struct timer_list *t)
{
	struct iscsi_session *session = from_timer(session, t, tmf_timer);
	struct iscsi_cls_session_wrapper *cls_session =
		from_timer(cls_session, t, tmf_timer);
	struct iscsi_session *session = cls_session->cls_sess.dd_data;

	spin_lock(&session->frwd_lock);
	if (session->tmf_state == TMF_QUEUED) {
		session->tmf_state = TMF_TIMEDOUT;
	if (cls_session->tmf_state == TMF_QUEUED) {
		cls_session->tmf_state = TMF_TIMEDOUT;
		ISCSI_DBG_EH(session, "tmf timedout\n");
		/* unblock eh_abort() */
		wake_up(&session->ehwait);
		wake_up(&cls_session->ehwait);
	}
	spin_unlock(&session->frwd_lock);
}
@@ -1893,6 +1898,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
	__must_hold(&session->frwd_lock)
{
	struct iscsi_session *session = conn->session;
	struct iscsi_cls_session_wrapper *cls_session =
		iscsi_cls_session_to_wrapper(session->cls_session);
	struct iscsi_task *task;

	task = __iscsi_conn_send_pdu(conn, (struct iscsi_hdr *)hdr,
@@ -1905,8 +1912,8 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
		return -EPERM;
	}
	conn->tmfcmd_pdus_cnt++;
	session->tmf_timer.expires = timeout * HZ + jiffies;
	add_timer(&session->tmf_timer);
	cls_session->tmf_timer.expires = timeout * HZ + jiffies;
	add_timer(&cls_session->tmf_timer);
	ISCSI_DBG_EH(session, "tmf set timeout\n");

	spin_unlock_bh(&session->frwd_lock);
@@ -1920,12 +1927,12 @@ static int iscsi_exec_task_mgmt_fn(struct iscsi_conn *conn,
	 * 3) session is terminated or restarted or userspace has
	 * given up on recovery
	 */
	wait_event_interruptible(session->ehwait, age != session->age ||
	wait_event_interruptible(cls_session->ehwait, age != session->age ||
				 session->state != ISCSI_STATE_LOGGED_IN ||
				 session->tmf_state != TMF_QUEUED);
				 cls_session->tmf_state != TMF_QUEUED);
	if (signal_pending(current))
		flush_signals(current);
	del_timer_sync(&session->tmf_timer);
	del_timer_sync(&cls_session->tmf_timer);

	mutex_lock(&session->eh_mutex);
	spin_lock_bh(&session->frwd_lock);
@@ -2252,6 +2259,7 @@ static void iscsi_prep_abort_task_pdu(struct iscsi_task *task,
int iscsi_eh_abort(struct scsi_cmnd *sc)
{
	struct iscsi_cls_session *cls_session;
	struct iscsi_cls_session_wrapper *session_wrapper;
	struct iscsi_session *session;
	struct iscsi_conn *conn;
	struct iscsi_task *task;
@@ -2259,6 +2267,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
	int age;

	cls_session = starget_to_session(scsi_target(sc->device));
	session_wrapper = iscsi_cls_session_to_wrapper(cls_session);
	session = cls_session->dd_data;

	ISCSI_DBG_EH(session, "aborting sc %p\n", sc);
@@ -2315,17 +2324,17 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
	}

	/* only have one tmf outstanding at a time */
	if (session->tmf_state != TMF_INITIAL)
	if (session_wrapper->tmf_state != TMF_INITIAL)
		goto failed;
	session->tmf_state = TMF_QUEUED;
	session_wrapper->tmf_state = TMF_QUEUED;

	hdr = &session->tmhdr;
	hdr = &session_wrapper->tmhdr;
	iscsi_prep_abort_task_pdu(task, hdr);

	if (iscsi_exec_task_mgmt_fn(conn, hdr, age, session->abort_timeout))
		goto failed;

	switch (session->tmf_state) {
	switch (session_wrapper->tmf_state) {
	case TMF_SUCCESS:
		spin_unlock_bh(&session->frwd_lock);
		/*
@@ -2340,7 +2349,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
		 */
		spin_lock_bh(&session->frwd_lock);
		fail_scsi_task(task, DID_ABORT);
		session->tmf_state = TMF_INITIAL;
		session_wrapper->tmf_state = TMF_INITIAL;
		memset(hdr, 0, sizeof(*hdr));
		spin_unlock_bh(&session->frwd_lock);
		iscsi_start_tx(conn);
@@ -2351,7 +2360,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
		goto failed_unlocked;
	case TMF_NOT_FOUND:
		if (!sc->SCp.ptr) {
			session->tmf_state = TMF_INITIAL;
			session_wrapper->tmf_state = TMF_INITIAL;
			memset(hdr, 0, sizeof(*hdr));
			/* task completed before tmf abort response */
			ISCSI_DBG_EH(session, "sc completed while abort	in "
@@ -2360,7 +2369,7 @@ int iscsi_eh_abort(struct scsi_cmnd *sc)
		}
		/* fall through */
	default:
		session->tmf_state = TMF_INITIAL;
		session_wrapper->tmf_state = TMF_INITIAL;
		goto failed;
	}

@@ -2397,12 +2406,14 @@ static void iscsi_prep_lun_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
int iscsi_eh_device_reset(struct scsi_cmnd *sc)
{
	struct iscsi_cls_session *cls_session;
	struct iscsi_cls_session_wrapper *session_wrapper;
	struct iscsi_session *session;
	struct iscsi_conn *conn;
	struct iscsi_tm *hdr;
	int rc = FAILED;

	cls_session = starget_to_session(scsi_target(sc->device));
	session_wrapper = iscsi_cls_session_to_wrapper(cls_session);
	session = cls_session->dd_data;

	ISCSI_DBG_EH(session, "LU Reset [sc %p lun %llu]\n", sc,
@@ -2419,11 +2430,11 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
	conn = session->leadconn;

	/* only have one tmf outstanding at a time */
	if (session->tmf_state != TMF_INITIAL)
	if (session_wrapper->tmf_state != TMF_INITIAL)
		goto unlock;
	session->tmf_state = TMF_QUEUED;
	session_wrapper->tmf_state = TMF_QUEUED;

	hdr = &session->tmhdr;
	hdr = &session_wrapper->tmhdr;
	iscsi_prep_lun_reset_pdu(sc, hdr);

	if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
@@ -2432,7 +2443,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
		goto unlock;
	}

	switch (session->tmf_state) {
	switch (session_wrapper->tmf_state) {
	case TMF_SUCCESS:
		break;
	case TMF_TIMEDOUT:
@@ -2440,7 +2451,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
		iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
		goto done;
	default:
		session->tmf_state = TMF_INITIAL;
		session_wrapper->tmf_state = TMF_INITIAL;
		goto unlock;
	}

@@ -2452,7 +2463,7 @@ int iscsi_eh_device_reset(struct scsi_cmnd *sc)
	spin_lock_bh(&session->frwd_lock);
	memset(hdr, 0, sizeof(*hdr));
	fail_scsi_tasks(conn, sc->device->lun, DID_ERROR);
	session->tmf_state = TMF_INITIAL;
	session_wrapper->tmf_state = TMF_INITIAL;
	spin_unlock_bh(&session->frwd_lock);

	iscsi_start_tx(conn);
@@ -2471,11 +2482,13 @@ EXPORT_SYMBOL_GPL(iscsi_eh_device_reset);
void iscsi_session_recovery_timedout(struct iscsi_cls_session *cls_session)
{
	struct iscsi_session *session = cls_session->dd_data;
	struct iscsi_cls_session_wrapper *session_wrapper =
		iscsi_cls_session_to_wrapper(cls_session);

	spin_lock_bh(&session->frwd_lock);
	if (session->state != ISCSI_STATE_LOGGED_IN) {
		session->state = ISCSI_STATE_RECOVERY_FAILED;
		wake_up(&session->ehwait);
		wake_up(&session_wrapper->ehwait);
	}
	spin_unlock_bh(&session->frwd_lock);
}
@@ -2491,10 +2504,12 @@ EXPORT_SYMBOL_GPL(iscsi_session_recovery_timedout);
int iscsi_eh_session_reset(struct scsi_cmnd *sc)
{
	struct iscsi_cls_session *cls_session;
	struct iscsi_cls_session_wrapper *session_wrapper;
	struct iscsi_session *session;
	struct iscsi_conn *conn;

	cls_session = starget_to_session(scsi_target(sc->device));
	session_wrapper = iscsi_cls_session_to_wrapper(cls_session);
	session = cls_session->dd_data;
	conn = session->leadconn;

@@ -2530,7 +2545,7 @@ int iscsi_eh_session_reset(struct scsi_cmnd *sc)
	iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);

	ISCSI_DBG_EH(session, "wait for relogin\n");
	wait_event_interruptible_timeout(session->ehwait,
	wait_event_interruptible_timeout(session_wrapper->ehwait,
				 session->state == ISCSI_STATE_TERMINATE ||
				 session->state == ISCSI_STATE_LOGGED_IN ||
				 session->state == ISCSI_STATE_RECOVERY_FAILED,
@@ -2570,12 +2585,14 @@ static void iscsi_prep_tgt_reset_pdu(struct scsi_cmnd *sc, struct iscsi_tm *hdr)
static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
{
	struct iscsi_cls_session *cls_session;
	struct iscsi_cls_session_wrapper *session_wrapper;
	struct iscsi_session *session;
	struct iscsi_conn *conn;
	struct iscsi_tm *hdr;
	int rc = FAILED;

	cls_session = starget_to_session(scsi_target(sc->device));
	session_wrapper = iscsi_cls_session_to_wrapper(cls_session);
	session = cls_session->dd_data;

	ISCSI_DBG_EH(session, "tgt Reset [sc %p tgt %s]\n", sc,
@@ -2592,11 +2609,11 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
	conn = session->leadconn;

	/* only have one tmf outstanding at a time */
	if (session->tmf_state != TMF_INITIAL)
	if (session_wrapper->tmf_state != TMF_INITIAL)
		goto unlock;
	session->tmf_state = TMF_QUEUED;
	session_wrapper->tmf_state = TMF_QUEUED;

	hdr = &session->tmhdr;
	hdr = &session_wrapper->tmhdr;
	iscsi_prep_tgt_reset_pdu(sc, hdr);

	if (iscsi_exec_task_mgmt_fn(conn, hdr, session->age,
@@ -2605,7 +2622,7 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
		goto unlock;
	}

	switch (session->tmf_state) {
	switch (session_wrapper->tmf_state) {
	case TMF_SUCCESS:
		break;
	case TMF_TIMEDOUT:
@@ -2613,7 +2630,7 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
		iscsi_conn_failure(conn, ISCSI_ERR_SCSI_EH_SESSION_RST);
		goto done;
	default:
		session->tmf_state = TMF_INITIAL;
		session_wrapper->tmf_state = TMF_INITIAL;
		goto unlock;
	}

@@ -2625,7 +2642,7 @@ static int iscsi_eh_target_reset(struct scsi_cmnd *sc)
	spin_lock_bh(&session->frwd_lock);
	memset(hdr, 0, sizeof(*hdr));
	fail_scsi_tasks(conn, -1, DID_ERROR);
	session->tmf_state = TMF_INITIAL;
	session_wrapper->tmf_state = TMF_INITIAL;
	spin_unlock_bh(&session->frwd_lock);

	iscsi_start_tx(conn);
@@ -2918,6 +2935,7 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
	struct iscsi_host *ihost = shost_priv(shost);
	struct iscsi_session *session;
	struct iscsi_cls_session *cls_session;
	struct iscsi_cls_session_wrapper *cls_sess_wrapper;
	int cmd_i, scsi_cmds;
	unsigned long flags;

@@ -2955,8 +2973,9 @@ iscsi_session_setup(struct iscsi_transport *iscsit, struct Scsi_Host *shost,
	session->tt = iscsit;
	session->dd_data = cls_session->dd_data + sizeof(*session);

	session->tmf_state = TMF_INITIAL;
	timer_setup(&session->tmf_timer, iscsi_tmf_timedout, 0);
	cls_sess_wrapper = iscsi_cls_session_to_wrapper(cls_session);
	cls_sess_wrapper->tmf_state = TMF_INITIAL;
	timer_setup(&cls_sess_wrapper->tmf_timer, iscsi_tmf_timedout, 0);
	mutex_init(&session->eh_mutex);

	spin_lock_init(&session->frwd_lock);
@@ -3045,6 +3064,8 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
		 uint32_t conn_idx)
{
	struct iscsi_session *session = cls_session->dd_data;
	struct iscsi_cls_session_wrapper *session_wrapper =
		iscsi_cls_session_to_wrapper(cls_session);
	struct iscsi_conn *conn;
	struct iscsi_cls_conn *cls_conn;
	char *data;
@@ -3062,7 +3083,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
	conn->c_stage = ISCSI_CONN_INITIAL_STAGE;
	conn->id = conn_idx;
	conn->exp_statsn = 0;
	session->tmf_state = TMF_INITIAL;
	session_wrapper->tmf_state = TMF_INITIAL;
	conn->intimate_cpu = -1;

	timer_setup(&conn->transport_timer, iscsi_check_transport_timeouts, 0);
@@ -3088,7 +3109,7 @@ iscsi_conn_setup(struct iscsi_cls_session *cls_session, int dd_size,
		goto login_task_data_alloc_fail;
	conn->login_task->data = conn->data = data;

	init_waitqueue_head(&session->ehwait);
	init_waitqueue_head(&session_wrapper->ehwait);

	return cls_conn;

@@ -3119,11 +3140,13 @@ void iscsi_conn_teardown(struct iscsi_cls_conn *cls_conn)
	spin_lock_bh(&session->frwd_lock);
	conn->c_stage = ISCSI_CONN_CLEANUP_WAIT;
	if (session->leadconn == conn) {
		struct iscsi_cls_session_wrapper *cls_session =
		iscsi_cls_session_to_wrapper(session->cls_session);
		/*
		 * leading connection? then give up on recovery.
		 */
		session->state = ISCSI_STATE_TERMINATE;
		wake_up(&session->ehwait);
		wake_up(&cls_session->ehwait);
	}
	spin_unlock_bh(&session->frwd_lock);

@@ -3153,6 +3176,8 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
{
	struct iscsi_conn *conn = cls_conn->dd_data;
	struct iscsi_session *session = conn->session;
	struct iscsi_cls_session_wrapper *cls_session =
		iscsi_cls_session_to_wrapper(session->cls_session);

	if (!session) {
		iscsi_conn_printk(KERN_ERR, conn,
@@ -3198,7 +3223,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
		 * commands after successful recovery
		 */
		conn->stop_stage = 0;
		session->tmf_state = TMF_INITIAL;
		cls_session->tmf_state = TMF_INITIAL;
		session->age++;
		if (session->age == 16)
			session->age = 0;
@@ -3212,7 +3237,7 @@ int iscsi_conn_start(struct iscsi_cls_conn *cls_conn)
	spin_unlock_bh(&session->frwd_lock);

	iscsi_unblock_session(session->cls_session);
	wake_up(&session->ehwait);
	wake_up(&cls_session->ehwait);
	return 0;
}
EXPORT_SYMBOL_GPL(iscsi_conn_start);
@@ -3253,6 +3278,8 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
					 struct iscsi_conn *conn, int flag)
{
	int old_stop_stage;
	struct iscsi_cls_session_wrapper *cls_session =
		iscsi_cls_session_to_wrapper(session->cls_session);

	mutex_lock(&session->eh_mutex);
	spin_lock_bh(&session->frwd_lock);
@@ -3305,7 +3332,7 @@ static void iscsi_start_session_recovery(struct iscsi_session *session,
	spin_lock_bh(&session->frwd_lock);
	fail_scsi_tasks(conn, -1, DID_TRANSPORT_DISRUPTED);
	fail_mgmt_tasks(session, conn);
	memset(&session->tmhdr, 0, sizeof(session->tmhdr));
	memset(&cls_session->tmhdr, 0, sizeof(cls_session->tmhdr));
	spin_unlock_bh(&session->frwd_lock);
	mutex_unlock(&session->eh_mutex);
}
+14 −6
Original line number Diff line number Diff line
@@ -208,6 +208,20 @@ struct iscsi_conn {
	unsigned long		suspend_tx;	/* suspend Tx */
	unsigned long		suspend_rx;	/* suspend Rx */

	/* follow four member move to iscsi_cls_session_wrapper, discard it */
#ifndef __GENKSYMS__
	/* abort */
	wait_queue_head_t	ehwait_discard;		/* used in eh_abort() */
	struct iscsi_tm		tmhdr_discard;
	struct timer_list	tmf_timer_discard;
	int			tmf_state_discard;	/* see TMF_INITIAL, etc.*/
#else
	/* abort */
	wait_queue_head_t	ehwait;		/* used in eh_abort() */
	struct iscsi_tm		tmhdr;
	struct timer_list	tmf_timer;
	int			tmf_state;	/* see TMF_INITIAL, etc.*/
#endif
	/* negotiated params */
	unsigned		max_recv_dlength; /* initiator_max_recv_dsl*/
	unsigned		max_xmit_dlength; /* target_max_recv_dsl */
@@ -278,12 +292,6 @@ struct iscsi_session {
	 * and recv lock.
	 */
	struct mutex		eh_mutex;
	/* abort */
	wait_queue_head_t	ehwait;		/* used in eh_abort() */
	struct iscsi_tm		tmhdr;
	struct timer_list	tmf_timer;
	int			tmf_state;	/* see TMF_INITIAL, etc.*/

	/* iSCSI session-wide sequencing */
	uint32_t		cmdsn;
	uint32_t		exp_cmdsn;