Skip to content

Commit

Permalink
scsi: iscsi: iscsi_tcp: Avoid holding spinlock while calling getpeern…
Browse files Browse the repository at this point in the history
…ame()

The kernel may fail to boot or devices may fail to come up when
initializing iscsi_tcp devices starting with Linux 5.8.

Commit a79af8a ("[SCSI] iscsi_tcp: use iscsi_conn_get_addr_param
libiscsi function") introduced getpeername() within the session spinlock.

Commit 1b66d25 ("bpf: Add get{peer, sock}name attach types for
sock_addr") introduced BPF_CGROUP_RUN_SA_PROG_LOCK() within getpeername(),
which acquires a mutex and when used from iscsi_tcp devices can now lead to
"BUG: scheduling while atomic:" and subsequent damage.

Ensure that the spinlock is released before calling getpeername() or
getsockname(). sock_hold() and sock_put() are used to ensure that the
socket reference is preserved until after the getpeername() or
getsockname() complete.

Link: https://bugzilla.redhat.com/show_bug.cgi?id=1877345
Link: https://lkml.org/lkml/2020/7/28/1085
Link: https://lkml.org/lkml/2020/8/31/459
Link: https://lore.kernel.org/r/20200928043329.606781-1-mark.mielke@gmail.com
Fixes: a79af8a ("[SCSI] iscsi_tcp: use iscsi_conn_get_addr_param libiscsi function")
Fixes: 1b66d25 ("bpf: Add get{peer, sock}name attach types for sock_addr")
Cc: stable@vger.kernel.org
Reported-by: Marc Dionne <marc.c.dionne@gmail.com>
Tested-by: Marc Dionne <marc.c.dionne@gmail.com>
Reviewed-by: Mike Christie <michael.christie@oracle.com>
Signed-off-by: Mark Mielke <mark.mielke@gmail.com>
Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
  • Loading branch information
Mark Mielke authored and Martin K. Petersen committed Sep 30, 2020
1 parent 1494155 commit bcf3a29
Showing 1 changed file with 15 additions and 7 deletions.
22 changes: 15 additions & 7 deletions drivers/scsi/iscsi_tcp.c
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,7 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
struct iscsi_sw_tcp_conn *tcp_sw_conn = tcp_conn->dd_data;
struct sockaddr_in6 addr;
struct socket *sock;
int rc;

switch(param) {
Expand All @@ -747,13 +748,17 @@ static int iscsi_sw_tcp_conn_get_param(struct iscsi_cls_conn *cls_conn,
spin_unlock_bh(&conn->session->frwd_lock);
return -ENOTCONN;
}
sock = tcp_sw_conn->sock;
sock_hold(sock->sk);
spin_unlock_bh(&conn->session->frwd_lock);

if (param == ISCSI_PARAM_LOCAL_PORT)
rc = kernel_getsockname(tcp_sw_conn->sock,
rc = kernel_getsockname(sock,
(struct sockaddr *)&addr);
else
rc = kernel_getpeername(tcp_sw_conn->sock,
rc = kernel_getpeername(sock,
(struct sockaddr *)&addr);
spin_unlock_bh(&conn->session->frwd_lock);
sock_put(sock->sk);
if (rc < 0)
return rc;

Expand All @@ -775,6 +780,7 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
struct iscsi_tcp_conn *tcp_conn;
struct iscsi_sw_tcp_conn *tcp_sw_conn;
struct sockaddr_in6 addr;
struct socket *sock;
int rc;

switch (param) {
Expand All @@ -789,16 +795,18 @@ static int iscsi_sw_tcp_host_get_param(struct Scsi_Host *shost,
return -ENOTCONN;
}
tcp_conn = conn->dd_data;

tcp_sw_conn = tcp_conn->dd_data;
if (!tcp_sw_conn->sock) {
sock = tcp_sw_conn->sock;
if (!sock) {
spin_unlock_bh(&session->frwd_lock);
return -ENOTCONN;
}
sock_hold(sock->sk);
spin_unlock_bh(&session->frwd_lock);

rc = kernel_getsockname(tcp_sw_conn->sock,
rc = kernel_getsockname(sock,
(struct sockaddr *)&addr);
spin_unlock_bh(&session->frwd_lock);
sock_put(sock->sk);
if (rc < 0)
return rc;

Expand Down

0 comments on commit bcf3a29

Please sign in to comment.