scsi: target: iscsi: Prevent login threads from racing between each other
authorMaurizio Lombardi <mlombard@redhat.com>
Mon, 8 May 2023 16:22:19 +0000 (18:22 +0200)
committerMartin K. Petersen <martin.petersen@oracle.com>
Mon, 22 May 2023 20:29:39 +0000 (16:29 -0400)
The tpg->np_login_sem is a semaphore that is used to serialize the login
process when multiple login threads run concurrently against the same
target portal group.

The iscsi_target_locate_portal() function finds the tpg, calls
iscsit_access_np() against the np_login_sem semaphore and saves the tpg
pointer in conn->tpg;

If iscsi_target_locate_portal() fails, the caller will check for the
conn->tpg pointer and, if it's not NULL, then it will assume that
iscsi_target_locate_portal() called iscsit_access_np() on the semaphore.

Make sure that conn->tpg gets initialized only if iscsit_access_np() was
successful, otherwise iscsit_deaccess_np() may end up being called against
a semaphore we never took, allowing more than one thread to access the same
tpg.

Signed-off-by: Maurizio Lombardi <mlombard@redhat.com>
Link: https://lore.kernel.org/r/20230508162219.1731964-4-mlombard@redhat.com
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
drivers/target/iscsi/iscsi_target_nego.c

index e3a5644a70b369693f6cc7ab2249a06af7e49430..fa3fb5f4e6bc44db94eb42740dec672c099dd889 100644 (file)
@@ -1122,6 +1122,7 @@ int iscsi_target_locate_portal(
        iscsi_target_set_sock_callbacks(conn);
 
        login->np = np;
+       conn->tpg = NULL;
 
        login_req = (struct iscsi_login_req *) login->req;
        payload_length = ntoh24(login_req->dlength);
@@ -1189,7 +1190,6 @@ int iscsi_target_locate_portal(
         */
        sessiontype = strncmp(s_buf, DISCOVERY, 9);
        if (!sessiontype) {
-               conn->tpg = iscsit_global->discovery_tpg;
                if (!login->leading_connection)
                        goto get_target;
 
@@ -1206,9 +1206,11 @@ int iscsi_target_locate_portal(
                 * Serialize access across the discovery struct iscsi_portal_group to
                 * process login attempt.
                 */
+               conn->tpg = iscsit_global->discovery_tpg;
                if (iscsit_access_np(np, conn->tpg) < 0) {
                        iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_TARGET_ERR,
                                ISCSI_LOGIN_STATUS_SVC_UNAVAILABLE);
+                       conn->tpg = NULL;
                        ret = -1;
                        goto out;
                }