Skip to content

Commit 13bd441

Browse files
committed
Merge tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi
Pull SCSI fixes from James Bottomley: "Two core changes, the only one of significance being the change to kick queues in SDEV_CANCEL which had a small window for stuck requests. The major driver fixes are the one to the FC transport class to widen the FPIN counter to counter a theoretical (and privileged) fabric traffic injection attack and the other is an iscsi fix where a malicious target could trick the kernel into an output buffer overrun. Both the driver fixes were AI assisted" * tag 'scsi-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/jejb/scsi: scsi: target: iscsi: Validate CHAP_R length before base64 decode scsi: target: iscsi: Bound iscsi_encode_text_output() appends to rsp_buf scsi: target: iscsi: Fix CRC overread and double-free in iscsit_handle_text_cmd() scsi: fcoe: Reject FIP descriptors with zero fip_dlen in CVL walker scsi: scsi_transport_fc: Widen FPIN pname walker counter to u32 scsi: scsi_debug: Add missing newline in scsi_debug_device_reset() scsi: megaraid_sas: Fix NULL pointer dereference on firmware duplicate completion scsi: devinfo: Add BLIST_NO_RSOC for Promise VTrak E310f scsi: core: Run queues for all non-SDEV_DEL devices from scsi_run_host_queues
2 parents 9cf1afe + 85db739 commit 13bd441

11 files changed

Lines changed: 155 additions & 58 deletions

drivers/scsi/fcoe/fcoe_ctlr.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1385,7 +1385,7 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
13851385

13861386
while (rlen >= sizeof(*desc)) {
13871387
dlen = desc->fip_dlen * FIP_BPW;
1388-
if (dlen > rlen)
1388+
if (dlen < sizeof(*desc) || dlen > rlen)
13891389
goto err;
13901390
/* Drop CVL if there are duplicate critical descriptors */
13911391
if ((desc->fip_dtype < 32) &&

drivers/scsi/megaraid/megaraid_sas_fusion.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,6 +3612,15 @@ complete_cmd_fusion(struct megasas_instance *instance, u32 MSIxIndex,
36123612
complete(&cmd_fusion->done);
36133613
break;
36143614
case MPI2_FUNCTION_SCSI_IO_REQUEST: /*Fast Path IO.*/
3615+
/*
3616+
* Firmware can send stale/duplicate completions for
3617+
* commands already returned to the pool. scmd_local
3618+
* would be NULL for such cases. Skip processing to
3619+
* avoid NULL pointer access.
3620+
*/
3621+
if (!scmd_local)
3622+
break;
3623+
36153624
/* Update load balancing info */
36163625
if (fusion->load_balance_info &&
36173626
(megasas_priv(cmd_fusion->scmd)->status &

drivers/scsi/scsi_debug.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6953,7 +6953,7 @@ static int scsi_debug_device_reset(struct scsi_cmnd *SCpnt)
69536953
++num_dev_resets;
69546954

69556955
if (SDEBUG_OPT_ALL_NOISE & sdebug_opts)
6956-
sdev_printk(KERN_INFO, sdp, "doing device reset");
6956+
sdev_printk(KERN_INFO, sdp, "doing device reset\n");
69576957

69586958
scsi_debug_stop_all_queued(sdp);
69596959
if (devip) {

drivers/scsi/scsi_devinfo.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -218,6 +218,7 @@ static struct {
218218
{"PIONEER", "CD-ROM DRM-602X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
219219
{"PIONEER", "CD-ROM DRM-604X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
220220
{"PIONEER", "CD-ROM DRM-624X", NULL, BLIST_FORCELUN | BLIST_SINGLELUN},
221+
{"Promise", "VTrak E310f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC},
221222
{"Promise", "VTrak E610f", NULL, BLIST_SPARSELUN | BLIST_NO_RSOC},
222223
{"Promise", "", NULL, BLIST_SPARSELUN},
223224
{"QEMU", "QEMU CD-ROM", NULL, BLIST_SKIP_VPD_PAGES},

drivers/scsi/scsi_lib.c

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -575,10 +575,33 @@ void scsi_requeue_run_queue(struct work_struct *work)
575575

576576
void scsi_run_host_queues(struct Scsi_Host *shost)
577577
{
578-
struct scsi_device *sdev;
578+
struct scsi_device *sdev, *prev = NULL;
579+
unsigned long flags;
579580

580-
shost_for_each_device(sdev, shost)
581+
spin_lock_irqsave(shost->host_lock, flags);
582+
__shost_for_each_device(sdev, shost) {
583+
/*
584+
* Only skip devices so deep into removal they will never need
585+
* another kick to their queues. Thus scsi_device_get() cannot
586+
* be used as it would skip devices in SDEV_CANCEL state which
587+
* may need a queue kick.
588+
*/
589+
if (sdev->sdev_state == SDEV_DEL ||
590+
!get_device(&sdev->sdev_gendev))
591+
continue;
592+
spin_unlock_irqrestore(shost->host_lock, flags);
593+
594+
if (prev)
595+
put_device(&prev->sdev_gendev);
581596
scsi_run_queue(sdev->request_queue);
597+
598+
prev = sdev;
599+
600+
spin_lock_irqsave(shost->host_lock, flags);
601+
}
602+
spin_unlock_irqrestore(shost->host_lock, flags);
603+
if (prev)
604+
put_device(&prev->sdev_gendev);
582605
}
583606

584607
static void scsi_uninit_cmd(struct scsi_cmnd *cmd)

drivers/scsi/scsi_transport_fc.c

Lines changed: 41 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -737,6 +737,37 @@ fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats)
737737
}
738738
}
739739

740+
static void
741+
fc_fpin_pname_stats_update(struct Scsi_Host *shost,
742+
struct fc_rport *attach_rport, u16 event_type,
743+
u32 desc_len, u32 fixed_len, u32 pname_count,
744+
__be64 *pname_list,
745+
void (*stats_update)(u16 event_type,
746+
struct fc_fpin_stats *stats))
747+
{
748+
u32 i;
749+
struct fc_rport *rport;
750+
u64 wwpn;
751+
752+
if (desc_len < fixed_len)
753+
pname_count = 0;
754+
else
755+
pname_count = min(pname_count, (desc_len - fixed_len) /
756+
sizeof(pname_list[0]));
757+
758+
for (i = 0; i < pname_count; i++) {
759+
wwpn = be64_to_cpu(pname_list[i]);
760+
rport = fc_find_rport_by_wwpn(shost, wwpn);
761+
if (rport &&
762+
(rport->roles & FC_PORT_ROLE_FCP_TARGET ||
763+
rport->roles & FC_PORT_ROLE_NVME_TARGET)) {
764+
if (rport == attach_rport)
765+
continue;
766+
stats_update(event_type, &rport->fpin_stats);
767+
}
768+
}
769+
}
770+
740771
/*
741772
* fc_fpin_li_stats_update - routine to update Link Integrity
742773
* event statistics.
@@ -747,13 +778,11 @@ fc_cn_stats_update(u16 event_type, struct fc_fpin_stats *stats)
747778
static void
748779
fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv)
749780
{
750-
u8 i;
751781
struct fc_rport *rport = NULL;
752782
struct fc_rport *attach_rport = NULL;
753783
struct fc_host_attrs *fc_host = shost_to_fc_host(shost);
754784
struct fc_fn_li_desc *li_desc = (struct fc_fn_li_desc *)tlv;
755785
u16 event_type = be16_to_cpu(li_desc->event_type);
756-
u64 wwpn;
757786

758787
rport = fc_find_rport_by_wwpn(shost,
759788
be64_to_cpu(li_desc->attached_wwpn));
@@ -764,22 +793,11 @@ fc_fpin_li_stats_update(struct Scsi_Host *shost, struct fc_tlv_desc *tlv)
764793
fc_li_stats_update(event_type, &attach_rport->fpin_stats);
765794
}
766795

767-
if (be32_to_cpu(li_desc->pname_count) > 0) {
768-
for (i = 0;
769-
i < be32_to_cpu(li_desc->pname_count);
770-
i++) {
771-
wwpn = be64_to_cpu(li_desc->pname_list[i]);
772-
rport = fc_find_rport_by_wwpn(shost, wwpn);
773-
if (rport &&
774-
(rport->roles & FC_PORT_ROLE_FCP_TARGET ||
775-
rport->roles & FC_PORT_ROLE_NVME_TARGET)) {
776-
if (rport == attach_rport)
777-
continue;
778-
fc_li_stats_update(event_type,
779-
&rport->fpin_stats);
780-
}
781-
}
782-
}
796+
fc_fpin_pname_stats_update(shost, attach_rport, event_type,
797+
be32_to_cpu(li_desc->desc_len),
798+
FC_TLV_DESC_LENGTH_FROM_SZ(*li_desc),
799+
be32_to_cpu(li_desc->pname_count),
800+
li_desc->pname_list, fc_li_stats_update);
783801

784802
if (fc_host->port_name == be64_to_cpu(li_desc->attached_wwpn))
785803
fc_li_stats_update(event_type, &fc_host->fpin_stats);
@@ -827,13 +845,11 @@ static void
827845
fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost,
828846
struct fc_tlv_desc *tlv)
829847
{
830-
u8 i;
831848
struct fc_rport *rport = NULL;
832849
struct fc_rport *attach_rport = NULL;
833850
struct fc_fn_peer_congn_desc *pc_desc =
834851
(struct fc_fn_peer_congn_desc *)tlv;
835852
u16 event_type = be16_to_cpu(pc_desc->event_type);
836-
u64 wwpn;
837853

838854
rport = fc_find_rport_by_wwpn(shost,
839855
be64_to_cpu(pc_desc->attached_wwpn));
@@ -844,22 +860,11 @@ fc_fpin_peer_congn_stats_update(struct Scsi_Host *shost,
844860
fc_cn_stats_update(event_type, &attach_rport->fpin_stats);
845861
}
846862

847-
if (be32_to_cpu(pc_desc->pname_count) > 0) {
848-
for (i = 0;
849-
i < be32_to_cpu(pc_desc->pname_count);
850-
i++) {
851-
wwpn = be64_to_cpu(pc_desc->pname_list[i]);
852-
rport = fc_find_rport_by_wwpn(shost, wwpn);
853-
if (rport &&
854-
(rport->roles & FC_PORT_ROLE_FCP_TARGET ||
855-
rport->roles & FC_PORT_ROLE_NVME_TARGET)) {
856-
if (rport == attach_rport)
857-
continue;
858-
fc_cn_stats_update(event_type,
859-
&rport->fpin_stats);
860-
}
861-
}
862-
}
863+
fc_fpin_pname_stats_update(shost, attach_rport, event_type,
864+
be32_to_cpu(pc_desc->desc_len),
865+
FC_TLV_DESC_LENGTH_FROM_SZ(*pc_desc),
866+
be32_to_cpu(pc_desc->pname_count),
867+
pc_desc->pname_list, fc_cn_stats_update);
863868
}
864869

865870
/*

drivers/target/iscsi/iscsi_target.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2295,7 +2295,9 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
22952295
goto reject;
22962296

22972297
if (conn->conn_ops->DataDigest) {
2298-
data_crc = iscsit_crc_buf(text_in, rx_size, 0, NULL);
2298+
data_crc = iscsit_crc_buf(text_in,
2299+
ALIGN(payload_length, 4),
2300+
0, NULL);
22992301
if (checksum != data_crc) {
23002302
pr_err("Text data CRC32C DataDigest"
23012303
" 0x%08x does not match computed"
@@ -2314,6 +2316,7 @@ iscsit_handle_text_cmd(struct iscsit_conn *conn, struct iscsit_cmd *cmd,
23142316
" Command CmdSN: 0x%08x due to"
23152317
" DataCRC error.\n", hdr->cmdsn);
23162318
kfree(text_in);
2319+
cmd->text_in_ptr = NULL;
23172320
return 0;
23182321
}
23192322
} else {

drivers/target/iscsi/iscsi_target_auth.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -340,13 +340,22 @@ static int chap_server_compute_hash(
340340
goto out;
341341
}
342342
break;
343-
case BASE64:
343+
case BASE64: {
344+
size_t r_len = strlen(chap_r);
345+
346+
while (r_len > 0 && chap_r[r_len - 1] == '=')
347+
r_len--;
348+
if (r_len > DIV_ROUND_UP(chap->digest_size * 4, 3)) {
349+
pr_err("Malformed CHAP_R: base64 payload too long\n");
350+
goto out;
351+
}
344352
if (chap_base64_decode(client_digest, chap_r, strlen(chap_r)) !=
345353
chap->digest_size) {
346354
pr_err("Malformed CHAP_R: invalid BASE64\n");
347355
goto out;
348356
}
349357
break;
358+
}
350359
default:
351360
pr_err("Could not find CHAP_R\n");
352361
goto out;
@@ -473,6 +482,14 @@ static int chap_server_compute_hash(
473482
}
474483
break;
475484
case BASE64:
485+
/*
486+
* No overflow check needed: initiatorchg_binhex is
487+
* CHAP_CHALLENGE_STR_LEN bytes and extract_param() caps
488+
* initiatorchg at CHAP_CHALLENGE_STR_LEN characters, so
489+
* the decoded output is at most DIV_ROUND_UP(
490+
* (CHAP_CHALLENGE_STR_LEN - 1) * 3, 4) bytes, which is
491+
* less than CHAP_CHALLENGE_STR_LEN.
492+
*/
476493
initiatorchg_len = chap_base64_decode(initiatorchg_binhex,
477494
initiatorchg,
478495
strlen(initiatorchg));

drivers/target/iscsi/iscsi_target_nego.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -899,10 +899,14 @@ static int iscsi_target_handle_csg_zero(
899899
SENDER_TARGET,
900900
login->rsp_buf,
901901
&login->rsp_length,
902+
MAX_KEY_VALUE_PAIRS,
902903
conn->param_list,
903904
conn->tpg->tpg_attrib.login_keys_workaround);
904-
if (ret < 0)
905+
if (ret < 0) {
906+
iscsit_tx_login_rsp(conn, ISCSI_STATUS_CLS_INITIATOR_ERR,
907+
ISCSI_LOGIN_STATUS_INIT_ERR);
905908
return -1;
909+
}
906910

907911
if (!iscsi_check_negotiated_keys(conn->param_list)) {
908912
bool auth_required = iscsi_conn_auth_required(conn);
@@ -986,6 +990,7 @@ static int iscsi_target_handle_csg_one(struct iscsit_conn *conn, struct iscsi_lo
986990
SENDER_TARGET,
987991
login->rsp_buf,
988992
&login->rsp_length,
993+
MAX_KEY_VALUE_PAIRS,
989994
conn->param_list,
990995
conn->tpg->tpg_attrib.login_keys_workaround);
991996
if (ret < 0) {

drivers/target/iscsi/iscsi_target_parameters.c

Lines changed: 48 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1371,19 +1371,42 @@ int iscsi_decode_text_input(
13711371
return -1;
13721372
}
13731373

1374+
/*
1375+
* Append "key=value" plus a trailing NUL into @textbuf at *@length.
1376+
* Returns 0 on success and advances *@length, or -EMSGSIZE if the
1377+
* record (including the NUL) would not fit in the remaining buffer.
1378+
*/
1379+
static int iscsi_encode_text_record(char *textbuf, u32 *length,
1380+
u32 textbuf_size,
1381+
const char *key, const char *value)
1382+
{
1383+
int n;
1384+
u32 avail;
1385+
1386+
if (*length >= textbuf_size)
1387+
return -EMSGSIZE;
1388+
1389+
avail = textbuf_size - *length;
1390+
n = snprintf(textbuf + *length, avail, "%s=%s", key, value);
1391+
if (n < 0 || (u32)n + 1 > avail)
1392+
return -EMSGSIZE;
1393+
1394+
*length += n + 1;
1395+
return 0;
1396+
}
1397+
13741398
int iscsi_encode_text_output(
13751399
u8 phase,
13761400
u8 sender,
13771401
char *textbuf,
13781402
u32 *length,
1403+
u32 textbuf_size,
13791404
struct iscsi_param_list *param_list,
13801405
bool keys_workaround)
13811406
{
1382-
char *output_buf = NULL;
13831407
struct iscsi_extra_response *er;
13841408
struct iscsi_param *param;
1385-
1386-
output_buf = textbuf + *length;
1409+
int ret;
13871410

13881411
if (iscsi_enforce_integrity_rules(phase, param_list) < 0)
13891412
return -1;
@@ -1395,10 +1418,12 @@ int iscsi_encode_text_output(
13951418
!IS_PSTATE_RESPONSE_SENT(param) &&
13961419
!IS_PSTATE_REPLY_OPTIONAL(param) &&
13971420
(param->phase & phase)) {
1398-
*length += sprintf(output_buf, "%s=%s",
1399-
param->name, param->value);
1400-
*length += 1;
1401-
output_buf = textbuf + *length;
1421+
ret = iscsi_encode_text_record(textbuf, length,
1422+
textbuf_size,
1423+
param->name,
1424+
param->value);
1425+
if (ret < 0)
1426+
goto err_overflow;
14021427
SET_PSTATE_RESPONSE_SENT(param);
14031428
pr_debug("Sending key: %s=%s\n",
14041429
param->name, param->value);
@@ -1408,10 +1433,12 @@ int iscsi_encode_text_output(
14081433
!IS_PSTATE_ACCEPTOR(param) &&
14091434
!IS_PSTATE_PROPOSER(param) &&
14101435
(param->phase & phase)) {
1411-
*length += sprintf(output_buf, "%s=%s",
1412-
param->name, param->value);
1413-
*length += 1;
1414-
output_buf = textbuf + *length;
1436+
ret = iscsi_encode_text_record(textbuf, length,
1437+
textbuf_size,
1438+
param->name,
1439+
param->value);
1440+
if (ret < 0)
1441+
goto err_overflow;
14151442
SET_PSTATE_PROPOSER(param);
14161443
iscsi_check_proposer_for_optional_reply(param,
14171444
keys_workaround);
@@ -1421,14 +1448,21 @@ int iscsi_encode_text_output(
14211448
}
14221449

14231450
list_for_each_entry(er, &param_list->extra_response_list, er_list) {
1424-
*length += sprintf(output_buf, "%s=%s", er->key, er->value);
1425-
*length += 1;
1426-
output_buf = textbuf + *length;
1451+
ret = iscsi_encode_text_record(textbuf, length, textbuf_size,
1452+
er->key, er->value);
1453+
if (ret < 0)
1454+
goto err_overflow;
14271455
pr_debug("Sending key: %s=%s\n", er->key, er->value);
14281456
}
14291457
iscsi_release_extra_responses(param_list);
14301458

14311459
return 0;
1460+
1461+
err_overflow:
1462+
pr_err("iSCSI login response buffer (%u bytes) exhausted, dropping login.\n",
1463+
textbuf_size);
1464+
iscsi_release_extra_responses(param_list);
1465+
return -1;
14321466
}
14331467

14341468
int iscsi_check_negotiated_keys(struct iscsi_param_list *param_list)

0 commit comments

Comments
 (0)