aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBill Kuzeja <William.Kuzeja@stratus.com>2018-03-23 10:37:25 -0400
committerMartin K. Petersen <martin.petersen@oracle.com>2018-04-09 16:35:49 -0400
commit6d6340672ba3a99c4cf7af79c2edf7aa25595c84 (patch)
treeea58bc8b94582c9bb30f3711173ee37013749da3
parent2ee5671e3ae35e53bb5a53a89ac8f033e4b1721f (diff)
scsi: qla2xxx: Fix small memory leak in qla2x00_probe_one on probe failure
The code that fixes the crashes in the following commit introduced a small memory leak: commit 6a2cf8d3663e ("scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure") Fixing this requires a bit of reworking, which I've explained. Also provide some code cleanup. There is a small window in qla2x00_probe_one where if qla2x00_alloc_queues fails, we end up never freeing req and rsp and leak 0xc0 and 0xc8 bytes respectively (the sizes of req and rsp). I originally put in checks to test for this condition which were based on the incorrect assumption that if ha->rsp_q_map and ha->req_q_map were allocated, then rsp and req were allocated as well. This is incorrect. There is a window between these allocations: ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp); goto probe_hw_failed; [if successful, both rsp and req allocated] base_vha = qla2x00_create_host(sht, ha); goto probe_hw_failed; ret = qla2x00_request_irqs(ha, rsp); goto probe_failed; if (qla2x00_alloc_queues(ha, req, rsp)) { goto probe_failed; [if successful, now ha->rsp_q_map and ha->req_q_map allocated] To simplify this, we should just set req and rsp to NULL after we free them. Sounds simple enough? The problem is that req and rsp are pointers defined in the qla2x00_probe_one and they are not always passed by reference to the routines that free them. Here are paths which can free req and rsp: PATH 1: qla2x00_probe_one ret = qla2x00_mem_alloc(ha, req_length, rsp_length, &req, &rsp); [req and rsp are passed by reference, but if this fails, we currently do not NULL out req and rsp. Easily fixed] PATH 2: qla2x00_probe_one failing in qla2x00_request_irqs or qla2x00_alloc_queues probe_failed: qla2x00_free_device(base_vha); qla2x00_free_req_que(ha, req) qla2x00_free_rsp_que(ha, rsp) PATH 3: qla2x00_probe_one: failing in qla2x00_mem_alloc or qla2x00_create_host probe_hw_failed: qla2x00_free_req_que(ha, req) qla2x00_free_rsp_que(ha, rsp) PATH 1: This should currently work, but it doesn't because rsp and rsp are not set to NULL in qla2x00_mem_alloc. Easily remedied. PATH 2: req and rsp aren't passed in at all to qla2x00_free_device but are derived from ha->req_q_map[0] and ha->rsp_q_map[0]. These are only set up if qla2x00_alloc_queues succeeds. In qla2x00_free_queues, we are protected from crashing if these don't exist because req_qid_map and rsp_qid_map are only set on their allocation. We are guarded in this way: for (cnt = 0; cnt < ha->max_req_queues; cnt++) { if (!test_bit(cnt, ha->req_qid_map)) continue; PATH 3: This works. We haven't freed req or rsp yet (or they were never allocated if qla2x00_mem_alloc failed), so we'll attempt to free them here. To summarize, there are a few small changes to make this work correctly and (and for some cleanup): 1) (For PATH 1) Set *rsp and *req to NULL in case of failure in qla2x00_mem_alloc so these are correctly set to NULL back in qla2x00_probe_one 2) After jumping to probe_failed: and calling qla2x00_free_device, explicitly set rsp and req to NULL so further calls with these pointers do not crash, i.e. the free queue calls in the probe_hw_failed section we fall through to. 3) Fix return code check in the call to qla2x00_alloc_queues. We currently drop the return code on the floor. The probe fails but the caller of the probe doesn't have an error code, so it attaches to pci. This can result in a crash on module shutdown. 4) Remove unnecessary NULL checks in qla2x00_free_req_que, qla2x00_free_rsp_que, and the egregious NULL checks before kfrees and vfrees in qla2x00_mem_free. I tested this out running a scenario where the card breaks at various times during initialization. I made sure I forced every error exit path in qla2x00_probe_one. Cc: <stable@vger.kernel.org> # v4.16 Fixes: 6a2cf8d3663e ("scsi: qla2xxx: Fix crashes in qla2x00_probe_one on probe failure") Signed-off-by: Bill Kuzeja <william.kuzeja@stratus.com> Acked-by: Himanshu Madhani <himanshu.madhani@cavium.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com>
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c44
1 files changed, 21 insertions, 23 deletions
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index 2bbf0bff0da0..15eaa6dded04 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -470,9 +470,6 @@ fail_req_map:
470 470
471static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req) 471static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
472{ 472{
473 if (!ha->req_q_map)
474 return;
475
476 if (IS_QLAFX00(ha)) { 473 if (IS_QLAFX00(ha)) {
477 if (req && req->ring_fx00) 474 if (req && req->ring_fx00)
478 dma_free_coherent(&ha->pdev->dev, 475 dma_free_coherent(&ha->pdev->dev,
@@ -483,17 +480,14 @@ static void qla2x00_free_req_que(struct qla_hw_data *ha, struct req_que *req)
483 (req->length + 1) * sizeof(request_t), 480 (req->length + 1) * sizeof(request_t),
484 req->ring, req->dma); 481 req->ring, req->dma);
485 482
486 if (req) { 483 if (req)
487 kfree(req->outstanding_cmds); 484 kfree(req->outstanding_cmds);
488 kfree(req); 485
489 } 486 kfree(req);
490} 487}
491 488
492static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp) 489static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
493{ 490{
494 if (!ha->rsp_q_map)
495 return;
496
497 if (IS_QLAFX00(ha)) { 491 if (IS_QLAFX00(ha)) {
498 if (rsp && rsp->ring_fx00) 492 if (rsp && rsp->ring_fx00)
499 dma_free_coherent(&ha->pdev->dev, 493 dma_free_coherent(&ha->pdev->dev,
@@ -504,8 +498,7 @@ static void qla2x00_free_rsp_que(struct qla_hw_data *ha, struct rsp_que *rsp)
504 (rsp->length + 1) * sizeof(response_t), 498 (rsp->length + 1) * sizeof(response_t),
505 rsp->ring, rsp->dma); 499 rsp->ring, rsp->dma);
506 } 500 }
507 if (rsp) 501 kfree(rsp);
508 kfree(rsp);
509} 502}
510 503
511static void qla2x00_free_queues(struct qla_hw_data *ha) 504static void qla2x00_free_queues(struct qla_hw_data *ha)
@@ -3106,7 +3099,8 @@ qla2x00_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
3106 goto probe_failed; 3099 goto probe_failed;
3107 3100
3108 /* Alloc arrays of request and response ring ptrs */ 3101 /* Alloc arrays of request and response ring ptrs */
3109 if (qla2x00_alloc_queues(ha, req, rsp)) { 3102 ret = qla2x00_alloc_queues(ha, req, rsp);
3103 if (ret) {
3110 ql_log(ql_log_fatal, base_vha, 0x003d, 3104 ql_log(ql_log_fatal, base_vha, 0x003d,
3111 "Failed to allocate memory for queue pointers..." 3105 "Failed to allocate memory for queue pointers..."
3112 "aborting.\n"); 3106 "aborting.\n");
@@ -3407,8 +3401,15 @@ probe_failed:
3407 } 3401 }
3408 3402
3409 qla2x00_free_device(base_vha); 3403 qla2x00_free_device(base_vha);
3410
3411 scsi_host_put(base_vha->host); 3404 scsi_host_put(base_vha->host);
3405 /*
3406 * Need to NULL out local req/rsp after
3407 * qla2x00_free_device => qla2x00_free_queues frees
3408 * what these are pointing to. Or else we'll
3409 * fall over below in qla2x00_free_req/rsp_que.
3410 */
3411 req = NULL;
3412 rsp = NULL;
3412 3413
3413probe_hw_failed: 3414probe_hw_failed:
3414 qla2x00_mem_free(ha); 3415 qla2x00_mem_free(ha);
@@ -4114,6 +4115,7 @@ fail_npiv_info:
4114 (*rsp)->dma = 0; 4115 (*rsp)->dma = 0;
4115fail_rsp_ring: 4116fail_rsp_ring:
4116 kfree(*rsp); 4117 kfree(*rsp);
4118 *rsp = NULL;
4117fail_rsp: 4119fail_rsp:
4118 dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) * 4120 dma_free_coherent(&ha->pdev->dev, ((*req)->length + 1) *
4119 sizeof(request_t), (*req)->ring, (*req)->dma); 4121 sizeof(request_t), (*req)->ring, (*req)->dma);
@@ -4121,6 +4123,7 @@ fail_rsp:
4121 (*req)->dma = 0; 4123 (*req)->dma = 0;
4122fail_req_ring: 4124fail_req_ring:
4123 kfree(*req); 4125 kfree(*req);
4126 *req = NULL;
4124fail_req: 4127fail_req:
4125 dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt), 4128 dma_free_coherent(&ha->pdev->dev, sizeof(struct ct_sns_pkt),
4126 ha->ct_sns, ha->ct_sns_dma); 4129 ha->ct_sns, ha->ct_sns_dma);
@@ -4508,16 +4511,11 @@ qla2x00_mem_free(struct qla_hw_data *ha)
4508 dma_free_coherent(&ha->pdev->dev, ha->init_cb_size, 4511 dma_free_coherent(&ha->pdev->dev, ha->init_cb_size,
4509 ha->init_cb, ha->init_cb_dma); 4512 ha->init_cb, ha->init_cb_dma);
4510 4513
4511 if (ha->optrom_buffer) 4514 vfree(ha->optrom_buffer);
4512 vfree(ha->optrom_buffer); 4515 kfree(ha->nvram);
4513 if (ha->nvram) 4516 kfree(ha->npiv_info);
4514 kfree(ha->nvram); 4517 kfree(ha->swl);
4515 if (ha->npiv_info) 4518 kfree(ha->loop_id_map);
4516 kfree(ha->npiv_info);
4517 if (ha->swl)
4518 kfree(ha->swl);
4519 if (ha->loop_id_map)
4520 kfree(ha->loop_id_map);
4521 4519
4522 ha->srb_mempool = NULL; 4520 ha->srb_mempool = NULL;
4523 ha->ctx_mempool = NULL; 4521 ha->ctx_mempool = NULL;