mirror of
https://github.com/SCST-project/scst.git
synced 2026-08-20 06:06:23 +00:00
isert: Fix use-after-free when killing iscsi-scstd
Our portal may be destroyed while there are connections alive. This means we are doing list_del() from list_head that no longer exists Signed-off-by: Yan Burman <yanb@mellanox.com> git-svn-id: http://svn.code.sf.net/p/scst/svn/branches/iser@5866 d57e44dd-8a1f-0410-8b47-8ef2f437770f
This commit is contained in:
@@ -9,12 +9,18 @@
|
||||
|
||||
#include "iser_hdr.h"
|
||||
|
||||
enum isert_portal_state {
|
||||
ISERT_PORTAL_ACTIVE,
|
||||
ISERT_PORTAL_INACTIVE
|
||||
};
|
||||
|
||||
struct isert_portal {
|
||||
struct rdma_cm_id *cm_id;
|
||||
struct sockaddr_storage addr;
|
||||
struct list_head list_node; /* in portals list */
|
||||
/* protected by dev_list_mutex */
|
||||
struct list_head conn_list; /* head of conns list */
|
||||
enum isert_portal_state state;
|
||||
};
|
||||
|
||||
struct isert_buf {
|
||||
@@ -164,6 +170,7 @@ struct isert_connection {
|
||||
struct isert_wr drain_wr;
|
||||
struct kref kref;
|
||||
|
||||
struct isert_portal *portal;
|
||||
void *priv_data; /* for connection tracking */
|
||||
};
|
||||
|
||||
|
||||
@@ -45,6 +45,8 @@
|
||||
|
||||
static DEFINE_MUTEX(dev_list_mutex);
|
||||
|
||||
void isert_portal_free(struct isert_portal *portal);
|
||||
|
||||
static int isert_num_recv_posted_on_err(struct ib_recv_wr *first_ib_wr,
|
||||
struct ib_recv_wr *bad_wr)
|
||||
{
|
||||
@@ -1141,6 +1143,8 @@ static void isert_kref_free(struct kref *kref)
|
||||
isert_dev->cq_qps[cq->idx]--;
|
||||
list_del(&isert_conn->portal_node);
|
||||
isert_deref_device(isert_dev);
|
||||
if (unlikely(isert_conn->portal->state == ISERT_PORTAL_INACTIVE))
|
||||
isert_portal_free(isert_conn->portal);
|
||||
mutex_unlock(&dev_list_mutex);
|
||||
|
||||
rdma_destroy_id(isert_conn->cm_id);
|
||||
@@ -1231,6 +1235,7 @@ static int isert_cm_conn_req_handler(struct rdma_cm_id *cm_id,
|
||||
}
|
||||
|
||||
isert_conn->state = ISER_CONN_HANDSHAKE;
|
||||
isert_conn->portal = portal;
|
||||
|
||||
mutex_lock(&dev_list_mutex);
|
||||
list_add_tail(&isert_conn->portal_node, &portal->conn_list);
|
||||
@@ -1636,6 +1641,17 @@ out:
|
||||
return err;
|
||||
}
|
||||
|
||||
void isert_portal_free(struct isert_portal *portal)
|
||||
{
|
||||
lockdep_assert_held(&dev_list_mutex);
|
||||
|
||||
if (!list_empty(&portal->conn_list))
|
||||
return;
|
||||
|
||||
kfree(portal);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
void isert_portal_release(struct isert_portal *portal)
|
||||
{
|
||||
struct isert_connection *conn;
|
||||
@@ -1647,15 +1663,14 @@ void isert_portal_release(struct isert_portal *portal)
|
||||
portal->cm_id = NULL;
|
||||
}
|
||||
|
||||
isert_portal_list_remove(portal);
|
||||
|
||||
mutex_lock(&dev_list_mutex);
|
||||
list_for_each_entry(conn, &portal->conn_list, portal_node)
|
||||
isert_conn_disconnect(conn);
|
||||
portal->state = ISERT_PORTAL_INACTIVE;
|
||||
isert_portal_free(portal);
|
||||
mutex_unlock(&dev_list_mutex);
|
||||
|
||||
isert_portal_list_remove(portal);
|
||||
|
||||
kfree(portal);
|
||||
module_put(THIS_MODULE);
|
||||
}
|
||||
|
||||
struct isert_portal *isert_portal_start(struct sockaddr *sa, size_t addr_len)
|
||||
|
||||
Reference in New Issue
Block a user