bdev_iscsi: fix crash when connecting to a non existing iqn
When connecting to an iscsi url that effectively does not exist we free the data structures of the very context we are processing. This results in a use after free and subsequently in a crash. Signed-off-by: Jeffry Molanus <jeffry.molanus@gmail.com> Change-Id: I67cab1efb161bfa23fa1022e150661080d90b556 Reviewed-on: https://review.gerrithub.io/c/spdk/spdk/+/462614 Reviewed-by: Jim Harris <james.r.harris@intel.com> Reviewed-by: Jeffry Molanus <Jeffry.molanus@gmail.com> Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com> Reviewed-by: Darek Stojaczyk <dariusz.stojaczyk@intel.com> Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
This commit is contained in:
parent
ed56a3d482
commit
bc315deae3
@ -98,9 +98,10 @@ struct bdev_iscsi_conn_req {
|
||||
char *initiator_iqn;
|
||||
struct iscsi_context *context;
|
||||
spdk_bdev_iscsi_create_cb create_cb;
|
||||
spdk_bdev_iscsi_create_cb create_cb_arg;
|
||||
void *create_cb_arg;
|
||||
bool unmap_supported;
|
||||
int lun;
|
||||
int status;
|
||||
TAILQ_ENTRY(bdev_iscsi_conn_req) link;
|
||||
};
|
||||
|
||||
@ -110,17 +111,12 @@ complete_conn_req(struct bdev_iscsi_conn_req *req, struct spdk_bdev *bdev,
|
||||
{
|
||||
TAILQ_REMOVE(&g_iscsi_conn_req, req, link);
|
||||
req->create_cb(req->create_cb_arg, bdev, status);
|
||||
if (status) {
|
||||
/* if the request failed and no iscsi lun was
|
||||
* created then we could not hand over this
|
||||
* memory and have to free it manually now.
|
||||
*/
|
||||
iscsi_destroy_context(req->context);
|
||||
free(req->initiator_iqn);
|
||||
free(req->bdev_name);
|
||||
free(req->url);
|
||||
}
|
||||
free(req);
|
||||
|
||||
/*
|
||||
* we are still running in the context of iscsi_service()
|
||||
* so do not tear down its data structures here
|
||||
*/
|
||||
req->status = status;
|
||||
}
|
||||
|
||||
static int
|
||||
@ -145,14 +141,29 @@ _iscsi_free_lun(void *arg)
|
||||
free(lun);
|
||||
}
|
||||
|
||||
static void
|
||||
_bdev_iscsi_conn_req_free(struct bdev_iscsi_conn_req *req)
|
||||
{
|
||||
|
||||
free(req->initiator_iqn);
|
||||
free(req->bdev_name);
|
||||
free(req->url);
|
||||
/* destroy will call iscsi_disconnect() implicitly if connected */
|
||||
iscsi_destroy_context(req->context);
|
||||
free(req);
|
||||
}
|
||||
|
||||
static void
|
||||
bdev_iscsi_finish(void)
|
||||
{
|
||||
struct bdev_iscsi_conn_req *req;
|
||||
struct bdev_iscsi_conn_req *req, *tmp;
|
||||
|
||||
while (!TAILQ_EMPTY(&g_iscsi_conn_req)) {
|
||||
req = TAILQ_FIRST(&g_iscsi_conn_req);
|
||||
complete_conn_req(req, NULL, -EINTR);
|
||||
/* clear out pending connection requests here. We cannot
|
||||
* simply set the state to a non SCSI_STATUS_GOOD state as
|
||||
* the connection poller wont run anymore
|
||||
*/
|
||||
TAILQ_FOREACH_SAFE(req, &g_iscsi_conn_req, link, tmp) {
|
||||
_bdev_iscsi_conn_req_free(req);
|
||||
}
|
||||
|
||||
if (g_conn_poller) {
|
||||
@ -725,8 +736,16 @@ iscsi_bdev_conn_poll(void *arg)
|
||||
SPDK_ERRLOG("iscsi_service failed: %s\n", iscsi_get_error(context));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (req->status != SCSI_STATUS_GOOD) {
|
||||
/*
|
||||
* An error has occurred during connecting. This req has already
|
||||
* been removed from the g_iscsi_conn_req list, but we needed to
|
||||
* wait until iscsi_service unwound before we could free the req.
|
||||
*/
|
||||
_bdev_iscsi_conn_req_free(req);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
@ -748,6 +767,7 @@ create_iscsi_disk(const char *bdev_name, const char *url, const char *initiator_
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
req->status = SCSI_STATUS_GOOD;
|
||||
req->bdev_name = strdup(bdev_name);
|
||||
req->url = strdup(url);
|
||||
req->initiator_iqn = strdup(initiator_iqn);
|
||||
|
Loading…
Reference in New Issue
Block a user