• Nicholas Bellinger's avatar
    iscsi-target: Fix initial login PDU asynchronous socket close OOPs · 67819fe3
    Nicholas Bellinger authored
    commit 25cdda95 upstream.
    
    This patch fixes a OOPs originally introduced by:
    
       commit bb048357
       Author: Nicholas Bellinger <nab@linux-iscsi.org>
       Date:   Thu Sep 5 14:54:04 2013 -0700
    
       iscsi-target: Add sk->sk_state_change to cleanup after TCP failure
    
    which would trigger a NULL pointer dereference when a TCP connection
    was closed asynchronously via iscsi_target_sk_state_change(), but only
    when the initial PDU processing in iscsi_target_do_login() from iscsi_np
    process context was blocked waiting for backend I/O to complete.
    
    To address this issue, this patch makes the following changes.
    
    First, it introduces some common helper functions used for checking
    socket closing state, checking login_flags, and atomically checking
    socket closing state + setting login_flags.
    
    Second, it introduces a LOGIN_FLAGS_INITIAL_PDU bit to know when a TCP
    connection has dropped via iscsi_target_sk_state_change(), but the
    initial PDU processing within iscsi_target_do_login() in iscsi_np
    context is still running.  For this case, it sets LOGIN_FLAGS_CLOSED,
    but doesn't invoke schedule_delayed_work().
    
    The original NULL pointer dereference case reported by MNC is now handled
    by iscsi_target_do_login() doing a iscsi_target_sk_check_close() before
    transitioning to FFP to determine when the socket has already closed,
    or iscsi_target_start_negotiation() if the login needs to exchange
    more PDUs (eg: iscsi_target_do_login returned 0) but the socket has
    closed.  For both of these cases, the cleanup up of remaining connection
    resources will occur in iscsi_target_start_negotiation() from iscsi_np
    process context once the failure is detected.
    
    Finally, to handle to case where iscsi_target_sk_state_change() is
    called after the initial PDU procesing is complete, it now invokes
    conn->login_work -> iscsi_target_do_login_rx() to perform cleanup once
    existing iscsi_target_sk_check_close() checks detect connection failure.
    For this case, the cleanup of remaining connection resources will occur
    in iscsi_target_do_login_rx() from delayed workqueue process context
    once the failure is detected.
    Reported-by: default avatarMike Christie <mchristi@redhat.com>
    Reviewed-by: default avatarMike Christie <mchristi@redhat.com>
    Tested-by: default avatarMike Christie <mchristi@redhat.com>
    Cc: Mike Christie <mchristi@redhat.com>
    Reported-by: default avatarHannes Reinecke <hare@suse.com>
    Cc: Hannes Reinecke <hare@suse.com>
    Cc: Sagi Grimberg <sagi@grimberg.me>
    Cc: Varun Prakash <varun@chelsio.com>
    Cc: <stable@vger.kernel.org> # v3.12+
    Signed-off-by: default avatarNicholas Bellinger <nab@linux-iscsi.org>
    Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    67819fe3
iscsi_target_nego.c 36.1 KB