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:
Yan Burman
2014-11-16 13:24:04 +00:00
parent 88339b14dd
commit 270559b509
2 changed files with 27 additions and 5 deletions
+7
View File
@@ -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 */
};
+20 -5
View File
@@ -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)