Commit 0a9c5d34 authored by Bhanu Prakash Gollapudi's avatar Bhanu Prakash Gollapudi Committed by James Bottomley

[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: default avatarBhanu Prakash Gollapudi <bprakash@broadcom.com>
Signed-off-by: default avatarRobert Love <robert.w.love@intel.com>
Signed-off-by: default avatarJames Bottomley <James.Bottomley@suse.de>
parent c600fea2
...@@ -640,6 +640,7 @@ static int fcoe_ctlr_parse_adv(struct fcoe_ctlr *fip, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment