[SCSI] libfcoe: Handle duplicate critical descriptors
As per FC-BB-5 rev 2, section 7.8.6.2, malformed FIP frame shall be discarded. Drop discovery adv, ELS and CLV's with duplicate critical descriptors. [Resending after incorporating Joe's review comments] Signed-off-by: Bhanu Prakash Gollapudi <bprakash@broadcom.com> Signed-off-by: Robert Love <robert.w.love@intel.com> Signed-off-by: James Bottomley <James.Bottomley@suse.de>
This commit is contained in:
parent
c600fea2d8
commit
0a9c5d344d
1 changed files with 41 additions and 0 deletions
|
@ -640,6 +640,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
|
||||||
unsigned long t;
|
unsigned long t;
|
||||||
size_t rlen;
|
size_t rlen;
|
||||||
size_t dlen;
|
size_t dlen;
|
||||||
|
u32 desc_mask;
|
||||||
|
|
||||||
memset(fcf, 0, sizeof(*fcf));
|
memset(fcf, 0, sizeof(*fcf));
|
||||||
fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
|
fcf->fka_period = msecs_to_jiffies(FCOE_CTLR_DEF_FKA);
|
||||||
|
@ -647,6 +648,12 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
|
||||||
fiph = (struct fip_header *)skb->data;
|
fiph = (struct fip_header *)skb->data;
|
||||||
fcf->flags = ntohs(fiph->fip_flags);
|
fcf->flags = ntohs(fiph->fip_flags);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mask of required descriptors. validating each one clears its bit.
|
||||||
|
*/
|
||||||
|
desc_mask = BIT(FIP_DT_PRI) | BIT(FIP_DT_MAC) | BIT(FIP_DT_NAME) |
|
||||||
|
BIT(FIP_DT_FAB) | BIT(FIP_DT_FKA);
|
||||||
|
|
||||||
rlen = ntohs(fiph->fip_dl_len) * 4;
|
rlen = ntohs(fiph->fip_dl_len) * 4;
|
||||||
if (rlen + sizeof(*fiph) > skb->len)
|
if (rlen + sizeof(*fiph) > skb->len)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
@ -656,11 +663,19 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
|
||||||
dlen = desc->fip_dlen * FIP_BPW;
|
dlen = desc->fip_dlen * FIP_BPW;
|
||||||
if (dlen < sizeof(*desc) || dlen > rlen)
|
if (dlen < sizeof(*desc) || dlen > rlen)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
/* Drop Adv if there are duplicate critical descriptors */
|
||||||
|
if ((desc->fip_dtype < 32) &&
|
||||||
|
!(desc_mask & 1U << desc->fip_dtype)) {
|
||||||
|
LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
|
||||||
|
"Descriptors in FIP adv\n");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
switch (desc->fip_dtype) {
|
switch (desc->fip_dtype) {
|
||||||
case FIP_DT_PRI:
|
case FIP_DT_PRI:
|
||||||
if (dlen != sizeof(struct fip_pri_desc))
|
if (dlen != sizeof(struct fip_pri_desc))
|
||||||
goto len_err;
|
goto len_err;
|
||||||
fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
|
fcf->pri = ((struct fip_pri_desc *)desc)->fd_pri;
|
||||||
|
desc_mask &= ~BIT(FIP_DT_PRI);
|
||||||
break;
|
break;
|
||||||
case FIP_DT_MAC:
|
case FIP_DT_MAC:
|
||||||
if (dlen != sizeof(struct fip_mac_desc))
|
if (dlen != sizeof(struct fip_mac_desc))
|
||||||
|
@ -673,12 +688,14 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
|
||||||
"in FIP adv\n");
|
"in FIP adv\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
desc_mask &= ~BIT(FIP_DT_MAC);
|
||||||
break;
|
break;
|
||||||
case FIP_DT_NAME:
|
case FIP_DT_NAME:
|
||||||
if (dlen != sizeof(struct fip_wwn_desc))
|
if (dlen != sizeof(struct fip_wwn_desc))
|
||||||
goto len_err;
|
goto len_err;
|
||||||
wwn = (struct fip_wwn_desc *)desc;
|
wwn = (struct fip_wwn_desc *)desc;
|
||||||
fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
|
fcf->switch_name = get_unaligned_be64(&wwn->fd_wwn);
|
||||||
|
desc_mask &= ~BIT(FIP_DT_NAME);
|
||||||
break;
|
break;
|
||||||
case FIP_DT_FAB:
|
case FIP_DT_FAB:
|
||||||
if (dlen != sizeof(struct fip_fab_desc))
|
if (dlen != sizeof(struct fip_fab_desc))
|
||||||
|
@ -687,6 +704,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
|
||||||
fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
|
fcf->fabric_name = get_unaligned_be64(&fab->fd_wwn);
|
||||||
fcf->vfid = ntohs(fab->fd_vfid);
|
fcf->vfid = ntohs(fab->fd_vfid);
|
||||||
fcf->fc_map = ntoh24(fab->fd_map);
|
fcf->fc_map = ntoh24(fab->fd_map);
|
||||||
|
desc_mask &= ~BIT(FIP_DT_FAB);
|
||||||
break;
|
break;
|
||||||
case FIP_DT_FKA:
|
case FIP_DT_FKA:
|
||||||
if (dlen != sizeof(struct fip_fka_desc))
|
if (dlen != sizeof(struct fip_fka_desc))
|
||||||
|
@ -697,6 +715,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
|
||||||
t = ntohl(fka->fd_fka_period);
|
t = ntohl(fka->fd_fka_period);
|
||||||
if (t >= FCOE_CTLR_MIN_FKA)
|
if (t >= FCOE_CTLR_MIN_FKA)
|
||||||
fcf->fka_period = msecs_to_jiffies(t);
|
fcf->fka_period = msecs_to_jiffies(t);
|
||||||
|
desc_mask &= ~BIT(FIP_DT_FKA);
|
||||||
break;
|
break;
|
||||||
case FIP_DT_MAP_OUI:
|
case FIP_DT_MAP_OUI:
|
||||||
case FIP_DT_FCOE_SIZE:
|
case FIP_DT_FCOE_SIZE:
|
||||||
|
@ -719,6 +738,11 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip,
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (!fcf->switch_name || !fcf->fabric_name)
|
if (!fcf->switch_name || !fcf->fabric_name)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
if (desc_mask) {
|
||||||
|
LIBFCOE_FIP_DBG(fip, "adv missing descriptors mask %x\n",
|
||||||
|
desc_mask);
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
len_err:
|
len_err:
|
||||||
|
@ -847,6 +871,7 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
|
||||||
size_t els_len = 0;
|
size_t els_len = 0;
|
||||||
size_t rlen;
|
size_t rlen;
|
||||||
size_t dlen;
|
size_t dlen;
|
||||||
|
u32 dupl_desc = 0;
|
||||||
|
|
||||||
fiph = (struct fip_header *)skb->data;
|
fiph = (struct fip_header *)skb->data;
|
||||||
sub = fiph->fip_subcode;
|
sub = fiph->fip_subcode;
|
||||||
|
@ -862,6 +887,15 @@ static void fcoe_ctlr_recv_els(struct fcoe_ctlr *fip, struct sk_buff *skb)
|
||||||
dlen = desc->fip_dlen * FIP_BPW;
|
dlen = desc->fip_dlen * FIP_BPW;
|
||||||
if (dlen < sizeof(*desc) || dlen > rlen)
|
if (dlen < sizeof(*desc) || dlen > rlen)
|
||||||
goto drop;
|
goto drop;
|
||||||
|
/* Drop ELS if there are duplicate critical descriptors */
|
||||||
|
if (desc->fip_dtype < 32) {
|
||||||
|
if (dupl_desc & 1U << desc->fip_dtype) {
|
||||||
|
LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
|
||||||
|
"Descriptors in FIP ELS\n");
|
||||||
|
goto drop;
|
||||||
|
}
|
||||||
|
dupl_desc |= (1 << desc->fip_dtype);
|
||||||
|
}
|
||||||
switch (desc->fip_dtype) {
|
switch (desc->fip_dtype) {
|
||||||
case FIP_DT_MAC:
|
case FIP_DT_MAC:
|
||||||
if (dlen != sizeof(struct fip_mac_desc))
|
if (dlen != sizeof(struct fip_mac_desc))
|
||||||
|
@ -973,6 +1007,13 @@ static void fcoe_ctlr_recv_clr_vlink(struct fcoe_ctlr *fip,
|
||||||
dlen = desc->fip_dlen * FIP_BPW;
|
dlen = desc->fip_dlen * FIP_BPW;
|
||||||
if (dlen > rlen)
|
if (dlen > rlen)
|
||||||
return;
|
return;
|
||||||
|
/* Drop CVL if there are duplicate critical descriptors */
|
||||||
|
if ((desc->fip_dtype < 32) &&
|
||||||
|
!(desc_mask & 1U << desc->fip_dtype)) {
|
||||||
|
LIBFCOE_FIP_DBG(fip, "Duplicate Critical "
|
||||||
|
"Descriptors in FIP CVL\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
switch (desc->fip_dtype) {
|
switch (desc->fip_dtype) {
|
||||||
case FIP_DT_MAC:
|
case FIP_DT_MAC:
|
||||||
mp = (struct fip_mac_desc *)desc;
|
mp = (struct fip_mac_desc *)desc;
|
||||||
|
|
Loading…
Add table
Reference in a new issue