--- /dev/null
+From: Chris Leech <christopher.leech@intel.com>
+Subject: [FcOE] fix frame length validation in the early receive path
+References: bnc #459142
+
+Validation of the frame length was missing before accessing the FC and FCoE
+headers. Some of the later checks were bogus, because of the way the fr_len
+variable and skb->len were being manipulated they could never fail.
+
+Signed-off-by: Chris Leech <christopher.leech@intel.com>
+Acked-by: Bernhard Walle <bwalle@suse.de>
+---
+
+ drivers/scsi/fcoe/libfcoe.c | 48 +++++++++++++++++++++-----------------------
+ include/scsi/fc/fc_fcoe.h | 12 +++++++++++
+ include/scsi/fc_frame.h | 2 -
+ 3 files changed, 36 insertions(+), 26 deletions(-)
+
+
+--- a/drivers/scsi/fcoe/libfcoe.c
++++ b/drivers/scsi/fcoe/libfcoe.c
+@@ -184,7 +184,6 @@ int fcoe_rcv(struct sk_buff *skb, struct
+ struct fcoe_rcv_info *fr;
+ struct fcoe_softc *fc;
+ struct fcoe_dev_stats *stats;
+- u8 *data;
+ struct fc_frame_header *fh;
+ unsigned short oxid;
+ int cpu_idx;
+@@ -211,9 +210,18 @@ int fcoe_rcv(struct sk_buff *skb, struct
+ FC_DBG("wrong FC type frame");
+ goto err;
+ }
+- data = skb->data;
+- data += sizeof(struct fcoe_hdr);
+- fh = (struct fc_frame_header *)data;
++
++ /*
++ * Check for minimum frame length, and make sure required FCoE
++ * and FC headers are pulled into the linear data area.
++ */
++ if (unlikely((skb->len < FCOE_MIN_FRAME) ||
++ !pskb_may_pull(skb, FCOE_HEADER_LEN)))
++ goto err;
++
++ skb_set_transport_header(skb, sizeof(struct fcoe_hdr));
++ fh = (struct fc_frame_header *) skb_transport_header(skb);
++
+ oxid = ntohs(fh->fh_ox_id);
+
+ fr = fcoe_dev_from_skb(skb);
+@@ -514,8 +522,6 @@ int fcoe_percpu_receive_thread(void *arg
+ {
+ struct fcoe_percpu_s *p = arg;
+ u32 fr_len;
+- unsigned int hlen;
+- unsigned int tlen;
+ struct fc_lport *lp;
+ struct fcoe_rcv_info *fr;
+ struct fcoe_dev_stats *stats;
+@@ -572,10 +578,12 @@ int fcoe_percpu_receive_thread(void *arg
+ skb_linearize(skb); /* not ideal */
+
+ /*
+- * Check the header and pull it off.
++ * Frame length checks and setting up the header pointers
++ * was done in fcoe_rcv already.
+ */
+- hlen = sizeof(struct fcoe_hdr);
+- hp = (struct fcoe_hdr *)skb->data;
++ hp = (struct fcoe_hdr *) skb_network_header(skb);
++ fh = (struct fc_frame_header *) skb_transport_header(skb);
++
+ if (unlikely(FC_FCOE_DECAPS_VER(hp) != FC_FCOE_VER)) {
+ if (stats) {
+ if (stats->ErrorFrames < 5)
+@@ -586,22 +594,10 @@ int fcoe_percpu_receive_thread(void *arg
+ kfree_skb(skb);
+ continue;
+ }
++
+ skb_pull(skb, sizeof(struct fcoe_hdr));
+- tlen = sizeof(struct fcoe_crc_eof);
+- fr_len = skb->len - tlen;
+- skb_trim(skb, fr_len);
++ fr_len = skb->len - sizeof(struct fcoe_crc_eof);
+
+- if (unlikely(fr_len > skb->len)) {
+- if (stats) {
+- if (stats->ErrorFrames < 5)
+- FC_DBG("length error fr_len 0x%x "
+- "skb->len 0x%x", fr_len,
+- skb->len);
+- stats->ErrorFrames++;
+- }
+- kfree_skb(skb);
+- continue;
+- }
+ if (stats) {
+ stats->RxFrames++;
+ stats->RxWords += fr_len / FCOE_WORD_TO_BYTE;
+@@ -610,9 +606,11 @@ int fcoe_percpu_receive_thread(void *arg
+ fp = (struct fc_frame *)skb;
+ cp = (struct fcoe_crc_eof *)(skb->data + fr_len);
+ fc_frame_init(fp);
+- fr_eof(fp) = cp->fcoe_eof;
+- fr_sof(fp) = hp->fcoe_sof;
+ fr_dev(fp) = lp;
++ fr_sof(fp) = hp->fcoe_sof;
++ fr_eof(fp) = cp->fcoe_eof;
++ /* trim off the CRC and EOF trailer*/
++ skb_trim(skb, fr_len);
+
+ /*
+ * We only check CRC if no offload is available and if it is
+--- a/include/scsi/fc/fc_fcoe.h
++++ b/include/scsi/fc/fc_fcoe.h
+@@ -85,6 +85,18 @@ struct fcoe_crc_eof {
+ } __attribute__((packed));
+
+ /*
++ * Minimum FCoE + FC header length
++ * 14 bytes FCoE header + 24 byte FC header = 38 bytes
++ */
++#define FCOE_HEADER_LEN 38
++
++/*
++ * Minimum FCoE frame size
++ * 14 bytes FCoE header + 24 byte FC header + 8 byte FCoE trailer = 46 bytes
++ */
++#define FCOE_MIN_FRAME 46
++
++/*
+ * fc_fcoe_set_mac - Store OUI + DID into MAC address field.
+ * @mac: mac address to be set
+ * @did: fc dest id to use
+--- a/include/scsi/fc_frame.h
++++ b/include/scsi/fc_frame.h
+@@ -66,10 +66,10 @@ struct fcoe_rcv_info {
+ struct fc_lport *fr_dev; /* transport layer private pointer */
+ struct fc_seq *fr_seq; /* for use with exchange manager */
+ struct scsi_cmnd *fr_cmd; /* for use of scsi command */
++ u16 fr_max_payload; /* max FC payload */
+ enum fc_sof fr_sof; /* start of frame delimiter */
+ enum fc_eof fr_eof; /* end of frame delimiter */
+ u8 fr_flags; /* flags - see below */
+- u16 fr_max_payload; /* max FC payload */
+ };
+
+ /*