Skip to content

Commit b64691d

Browse files
CIQ Kernel Automationbmastbergen
authored andcommitted
scsi: ibmvfc: Remove BUG_ON in the case of an empty event pool
jira VULN-4654 cve CVE-2023-52811 commit-author Tyrel Datwyler <tyreld@linux.ibm.com> commit b39f2d1 In practice the driver should never send more commands than are allocated to a queue's event pool. In the unlikely event that this happens, the code asserts a BUG_ON, and in the case that the kernel is not configured to crash on panic returns a junk event pointer from the empty event list causing things to spiral from there. This BUG_ON is a historical artifact of the ibmvfc driver first being upstreamed, and it is well known now that the use of BUG_ON is bad practice except in the most unrecoverable scenario. There is nothing about this scenario that prevents the driver from recovering and carrying on. Remove the BUG_ON in question from ibmvfc_get_event() and return a NULL pointer in the case of an empty event pool. Update all call sites to ibmvfc_get_event() to check for a NULL pointer and perfrom the appropriate failure or recovery action. Signed-off-by: Tyrel Datwyler <tyreld@linux.ibm.com> Link: https://lore.kernel.org/r/20230921225435.3537728-2-tyreld@linux.ibm.com Reviewed-by: Brian King <brking@linux.vnet.ibm.com> Signed-off-by: Martin K. Petersen <martin.petersen@oracle.com> (cherry picked from commit b39f2d1) Signed-off-by: CIQ Kernel Automation <ciq_kernel_automation@ciq.com>
1 parent 3a6db40 commit b64691d

1 file changed

Lines changed: 122 additions & 2 deletions

File tree

drivers/scsi/ibmvscsi/ibmvfc.c

Lines changed: 122 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1514,7 +1514,11 @@ static struct ibmvfc_event *ibmvfc_get_event(struct ibmvfc_queue *queue)
15141514
unsigned long flags;
15151515

15161516
spin_lock_irqsave(&queue->l_lock, flags);
1517-
BUG_ON(list_empty(&queue->free));
1517+
if (list_empty(&queue->free)) {
1518+
ibmvfc_log(queue->vhost, 4, "empty event pool on queue:%ld\n", queue->hwq_id);
1519+
spin_unlock_irqrestore(&queue->l_lock, flags);
1520+
return NULL;
1521+
}
15181522
evt = list_entry(queue->free.next, struct ibmvfc_event, queue_list);
15191523
atomic_set(&evt->free, 0);
15201524
list_del(&evt->queue_list);
@@ -1943,9 +1947,15 @@ static int ibmvfc_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *cmnd)
19431947
if (vhost->using_channels) {
19441948
scsi_channel = hwq % vhost->scsi_scrqs.active_queues;
19451949
evt = ibmvfc_get_event(&vhost->scsi_scrqs.scrqs[scsi_channel]);
1950+
if (!evt)
1951+
return SCSI_MLQUEUE_HOST_BUSY;
1952+
19461953
evt->hwq = hwq % vhost->scsi_scrqs.active_queues;
1947-
} else
1954+
} else {
19481955
evt = ibmvfc_get_event(&vhost->crq);
1956+
if (!evt)
1957+
return SCSI_MLQUEUE_HOST_BUSY;
1958+
}
19491959

19501960
ibmvfc_init_event(evt, ibmvfc_scsi_done, IBMVFC_CMD_FORMAT);
19511961
evt->cmnd = cmnd;
@@ -2033,6 +2043,11 @@ static int ibmvfc_bsg_timeout(struct bsg_job *job)
20332043

20342044
vhost->aborting_passthru = 1;
20352045
evt = ibmvfc_get_event(&vhost->crq);
2046+
if (!evt) {
2047+
spin_unlock_irqrestore(vhost->host->host_lock, flags);
2048+
return -ENOMEM;
2049+
}
2050+
20362051
ibmvfc_init_event(evt, ibmvfc_bsg_timeout_done, IBMVFC_MAD_FORMAT);
20372052

20382053
tmf = &evt->iu.tmf;
@@ -2091,6 +2106,10 @@ static int ibmvfc_bsg_plogi(struct ibmvfc_host *vhost, unsigned int port_id)
20912106
goto unlock_out;
20922107

20932108
evt = ibmvfc_get_event(&vhost->crq);
2109+
if (!evt) {
2110+
rc = -ENOMEM;
2111+
goto unlock_out;
2112+
}
20942113
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
20952114
plogi = &evt->iu.plogi;
20962115
memset(plogi, 0, sizeof(*plogi));
@@ -2209,6 +2228,11 @@ static int ibmvfc_bsg_request(struct bsg_job *job)
22092228
}
22102229

22112230
evt = ibmvfc_get_event(&vhost->crq);
2231+
if (!evt) {
2232+
spin_unlock_irqrestore(vhost->host->host_lock, flags);
2233+
rc = -ENOMEM;
2234+
goto out;
2235+
}
22122236
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
22132237
mad = &evt->iu.passthru;
22142238

@@ -2297,6 +2321,11 @@ static int ibmvfc_reset_device(struct scsi_device *sdev, int type, char *desc)
22972321
else
22982322
evt = ibmvfc_get_event(&vhost->crq);
22992323

2324+
if (!evt) {
2325+
spin_unlock_irqrestore(vhost->host->host_lock, flags);
2326+
return -ENOMEM;
2327+
}
2328+
23002329
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT);
23012330
tmf = ibmvfc_init_vfc_cmd(evt, sdev);
23022331
iu = ibmvfc_get_fcp_iu(vhost, tmf);
@@ -2500,6 +2529,8 @@ static struct ibmvfc_event *ibmvfc_init_tmf(struct ibmvfc_queue *queue,
25002529
struct ibmvfc_tmf *tmf;
25012530

25022531
evt = ibmvfc_get_event(queue);
2532+
if (!evt)
2533+
return NULL;
25032534
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_MAD_FORMAT);
25042535

25052536
tmf = &evt->iu.tmf;
@@ -2556,6 +2587,11 @@ static int ibmvfc_cancel_all_mq(struct scsi_device *sdev, int type)
25562587

25572588
if (found_evt && vhost->logged_in) {
25582589
evt = ibmvfc_init_tmf(&queues[i], sdev, type);
2590+
if (!evt) {
2591+
spin_unlock(queues[i].q_lock);
2592+
spin_unlock_irqrestore(vhost->host->host_lock, flags);
2593+
return -ENOMEM;
2594+
}
25592595
evt->sync_iu = &queues[i].cancel_rsp;
25602596
ibmvfc_send_event(evt, vhost, default_timeout);
25612597
list_add_tail(&evt->cancel, &cancelq);
@@ -2769,6 +2805,10 @@ static int ibmvfc_abort_task_set(struct scsi_device *sdev)
27692805

27702806
if (vhost->state == IBMVFC_ACTIVE) {
27712807
evt = ibmvfc_get_event(&vhost->crq);
2808+
if (!evt) {
2809+
spin_unlock_irqrestore(vhost->host->host_lock, flags);
2810+
return -ENOMEM;
2811+
}
27722812
ibmvfc_init_event(evt, ibmvfc_sync_completion, IBMVFC_CMD_FORMAT);
27732813
tmf = ibmvfc_init_vfc_cmd(evt, sdev);
27742814
iu = ibmvfc_get_fcp_iu(vhost, tmf);
@@ -4018,6 +4058,12 @@ static void ibmvfc_tgt_send_prli(struct ibmvfc_target *tgt)
40184058

40194059
kref_get(&tgt->kref);
40204060
evt = ibmvfc_get_event(&vhost->crq);
4061+
if (!evt) {
4062+
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4063+
kref_put(&tgt->kref, ibmvfc_release_tgt);
4064+
__ibmvfc_reset_host(vhost);
4065+
return;
4066+
}
40214067
vhost->discovery_threads++;
40224068
ibmvfc_init_event(evt, ibmvfc_tgt_prli_done, IBMVFC_MAD_FORMAT);
40234069
evt->tgt = tgt;
@@ -4125,6 +4171,12 @@ static void ibmvfc_tgt_send_plogi(struct ibmvfc_target *tgt)
41254171
kref_get(&tgt->kref);
41264172
tgt->logo_rcvd = 0;
41274173
evt = ibmvfc_get_event(&vhost->crq);
4174+
if (!evt) {
4175+
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4176+
kref_put(&tgt->kref, ibmvfc_release_tgt);
4177+
__ibmvfc_reset_host(vhost);
4178+
return;
4179+
}
41284180
vhost->discovery_threads++;
41294181
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
41304182
ibmvfc_init_event(evt, ibmvfc_tgt_plogi_done, IBMVFC_MAD_FORMAT);
@@ -4201,6 +4253,8 @@ static struct ibmvfc_event *__ibmvfc_tgt_get_implicit_logout_evt(struct ibmvfc_t
42014253

42024254
kref_get(&tgt->kref);
42034255
evt = ibmvfc_get_event(&vhost->crq);
4256+
if (!evt)
4257+
return NULL;
42044258
ibmvfc_init_event(evt, done, IBMVFC_MAD_FORMAT);
42054259
evt->tgt = tgt;
42064260
mad = &evt->iu.implicit_logout;
@@ -4228,6 +4282,13 @@ static void ibmvfc_tgt_implicit_logout(struct ibmvfc_target *tgt)
42284282
vhost->discovery_threads++;
42294283
evt = __ibmvfc_tgt_get_implicit_logout_evt(tgt,
42304284
ibmvfc_tgt_implicit_logout_done);
4285+
if (!evt) {
4286+
vhost->discovery_threads--;
4287+
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4288+
kref_put(&tgt->kref, ibmvfc_release_tgt);
4289+
__ibmvfc_reset_host(vhost);
4290+
return;
4291+
}
42314292

42324293
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
42334294
if (ibmvfc_send_event(evt, vhost, default_timeout)) {
@@ -4367,6 +4428,12 @@ static void ibmvfc_tgt_move_login(struct ibmvfc_target *tgt)
43674428

43684429
kref_get(&tgt->kref);
43694430
evt = ibmvfc_get_event(&vhost->crq);
4431+
if (!evt) {
4432+
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_DEL_RPORT);
4433+
kref_put(&tgt->kref, ibmvfc_release_tgt);
4434+
__ibmvfc_reset_host(vhost);
4435+
return;
4436+
}
43704437
vhost->discovery_threads++;
43714438
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_INIT_WAIT);
43724439
ibmvfc_init_event(evt, ibmvfc_tgt_move_login_done, IBMVFC_MAD_FORMAT);
@@ -4533,6 +4600,14 @@ static void ibmvfc_adisc_timeout(struct timer_list *t)
45334600
vhost->abort_threads++;
45344601
kref_get(&tgt->kref);
45354602
evt = ibmvfc_get_event(&vhost->crq);
4603+
if (!evt) {
4604+
tgt_err(tgt, "Failed to get cancel event for ADISC.\n");
4605+
vhost->abort_threads--;
4606+
kref_put(&tgt->kref, ibmvfc_release_tgt);
4607+
__ibmvfc_reset_host(vhost);
4608+
spin_unlock_irqrestore(vhost->host->host_lock, flags);
4609+
return;
4610+
}
45364611
ibmvfc_init_event(evt, ibmvfc_tgt_adisc_cancel_done, IBMVFC_MAD_FORMAT);
45374612

45384613
evt->tgt = tgt;
@@ -4583,6 +4658,12 @@ static void ibmvfc_tgt_adisc(struct ibmvfc_target *tgt)
45834658

45844659
kref_get(&tgt->kref);
45854660
evt = ibmvfc_get_event(&vhost->crq);
4661+
if (!evt) {
4662+
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4663+
kref_put(&tgt->kref, ibmvfc_release_tgt);
4664+
__ibmvfc_reset_host(vhost);
4665+
return;
4666+
}
45864667
vhost->discovery_threads++;
45874668
ibmvfc_init_event(evt, ibmvfc_tgt_adisc_done, IBMVFC_MAD_FORMAT);
45884669
evt->tgt = tgt;
@@ -4686,6 +4767,12 @@ static void ibmvfc_tgt_query_target(struct ibmvfc_target *tgt)
46864767

46874768
kref_get(&tgt->kref);
46884769
evt = ibmvfc_get_event(&vhost->crq);
4770+
if (!evt) {
4771+
ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
4772+
kref_put(&tgt->kref, ibmvfc_release_tgt);
4773+
__ibmvfc_reset_host(vhost);
4774+
return;
4775+
}
46894776
vhost->discovery_threads++;
46904777
evt->tgt = tgt;
46914778
ibmvfc_init_event(evt, ibmvfc_tgt_query_target_done, IBMVFC_MAD_FORMAT);
@@ -4858,6 +4945,13 @@ static void ibmvfc_discover_targets(struct ibmvfc_host *vhost)
48584945
{
48594946
struct ibmvfc_discover_targets *mad;
48604947
struct ibmvfc_event *evt = ibmvfc_get_event(&vhost->crq);
4948+
int level = IBMVFC_DEFAULT_LOG_LEVEL;
4949+
4950+
if (!evt) {
4951+
ibmvfc_log(vhost, level, "Discover Targets failed: no available events\n");
4952+
ibmvfc_hard_reset_host(vhost);
4953+
return;
4954+
}
48614955

48624956
ibmvfc_init_event(evt, ibmvfc_discover_targets_done, IBMVFC_MAD_FORMAT);
48634957
mad = &evt->iu.discover_targets;
@@ -4935,8 +5029,15 @@ static void ibmvfc_channel_setup(struct ibmvfc_host *vhost)
49355029
struct ibmvfc_scsi_channels *scrqs = &vhost->scsi_scrqs;
49365030
unsigned int num_channels =
49375031
min(vhost->client_scsi_channels, vhost->max_vios_scsi_channels);
5032+
int level = IBMVFC_DEFAULT_LOG_LEVEL;
49385033
int i;
49395034

5035+
if (!evt) {
5036+
ibmvfc_log(vhost, level, "Channel Setup failed: no available events\n");
5037+
ibmvfc_hard_reset_host(vhost);
5038+
return;
5039+
}
5040+
49405041
memset(setup_buf, 0, sizeof(*setup_buf));
49415042
if (num_channels == 0)
49425043
setup_buf->flags = cpu_to_be32(IBMVFC_CANCEL_CHANNELS);
@@ -4998,6 +5099,13 @@ static void ibmvfc_channel_enquiry(struct ibmvfc_host *vhost)
49985099
{
49995100
struct ibmvfc_channel_enquiry *mad;
50005101
struct ibmvfc_event *evt = ibmvfc_get_event(&vhost->crq);
5102+
int level = IBMVFC_DEFAULT_LOG_LEVEL;
5103+
5104+
if (!evt) {
5105+
ibmvfc_log(vhost, level, "Channel Enquiry failed: no available events\n");
5106+
ibmvfc_hard_reset_host(vhost);
5107+
return;
5108+
}
50015109

50025110
ibmvfc_init_event(evt, ibmvfc_channel_enquiry_done, IBMVFC_MAD_FORMAT);
50035111
mad = &evt->iu.channel_enquiry;
@@ -5120,6 +5228,12 @@ static void ibmvfc_npiv_login(struct ibmvfc_host *vhost)
51205228
struct ibmvfc_npiv_login_mad *mad;
51215229
struct ibmvfc_event *evt = ibmvfc_get_event(&vhost->crq);
51225230

5231+
if (!evt) {
5232+
ibmvfc_dbg(vhost, "NPIV Login failed: no available events\n");
5233+
ibmvfc_hard_reset_host(vhost);
5234+
return;
5235+
}
5236+
51235237
ibmvfc_gather_partition_info(vhost);
51245238
ibmvfc_set_login_info(vhost);
51255239
ibmvfc_init_event(evt, ibmvfc_npiv_login_done, IBMVFC_MAD_FORMAT);
@@ -5184,6 +5298,12 @@ static void ibmvfc_npiv_logout(struct ibmvfc_host *vhost)
51845298
struct ibmvfc_event *evt;
51855299

51865300
evt = ibmvfc_get_event(&vhost->crq);
5301+
if (!evt) {
5302+
ibmvfc_dbg(vhost, "NPIV Logout failed: no available events\n");
5303+
ibmvfc_hard_reset_host(vhost);
5304+
return;
5305+
}
5306+
51875307
ibmvfc_init_event(evt, ibmvfc_npiv_logout_done, IBMVFC_MAD_FORMAT);
51885308

51895309
mad = &evt->iu.npiv_logout;

0 commit comments

Comments
 (0)