|
@@ -112,7 +112,6 @@ int sctp_rcv(struct sk_buff *skb)
|
|
|
struct sctp_ep_common *rcvr;
|
|
|
struct sctp_transport *transport = NULL;
|
|
|
struct sctp_chunk *chunk;
|
|
|
- struct sctphdr *sh;
|
|
|
union sctp_addr src;
|
|
|
union sctp_addr dest;
|
|
|
int family;
|
|
@@ -124,15 +123,18 @@ int sctp_rcv(struct sk_buff *skb)
|
|
|
|
|
|
__SCTP_INC_STATS(net, SCTP_MIB_INSCTPPACKS);
|
|
|
|
|
|
- if (skb_linearize(skb))
|
|
|
+ /* If packet is too small to contain a single chunk, let's not
|
|
|
+ * waste time on it anymore.
|
|
|
+ */
|
|
|
+ if (skb->len < sizeof(struct sctphdr) + sizeof(struct sctp_chunkhdr) +
|
|
|
+ skb_transport_offset(skb))
|
|
|
goto discard_it;
|
|
|
|
|
|
- sh = sctp_hdr(skb);
|
|
|
+ if (!pskb_may_pull(skb, sizeof(struct sctphdr)))
|
|
|
+ goto discard_it;
|
|
|
|
|
|
- /* Pull up the IP and SCTP headers. */
|
|
|
+ /* Pull up the IP header. */
|
|
|
__skb_pull(skb, skb_transport_offset(skb));
|
|
|
- if (skb->len < sizeof(struct sctphdr))
|
|
|
- goto discard_it;
|
|
|
|
|
|
skb->csum_valid = 0; /* Previous value not applicable */
|
|
|
if (skb_csum_unnecessary(skb))
|
|
@@ -141,11 +143,7 @@ int sctp_rcv(struct sk_buff *skb)
|
|
|
goto discard_it;
|
|
|
skb->csum_valid = 1;
|
|
|
|
|
|
- skb_pull(skb, sizeof(struct sctphdr));
|
|
|
-
|
|
|
- /* Make sure we at least have chunk headers worth of data left. */
|
|
|
- if (skb->len < sizeof(struct sctp_chunkhdr))
|
|
|
- goto discard_it;
|
|
|
+ __skb_pull(skb, sizeof(struct sctphdr));
|
|
|
|
|
|
family = ipver2af(ip_hdr(skb)->version);
|
|
|
af = sctp_get_af_specific(family);
|
|
@@ -230,7 +228,7 @@ int sctp_rcv(struct sk_buff *skb)
|
|
|
chunk->rcvr = rcvr;
|
|
|
|
|
|
/* Remember the SCTP header. */
|
|
|
- chunk->sctp_hdr = sh;
|
|
|
+ chunk->sctp_hdr = sctp_hdr(skb);
|
|
|
|
|
|
/* Set the source and destination addresses of the incoming chunk. */
|
|
|
sctp_init_addrs(chunk, &src, &dest);
|
|
@@ -660,19 +658,23 @@ out_unlock:
|
|
|
*/
|
|
|
static int sctp_rcv_ootb(struct sk_buff *skb)
|
|
|
{
|
|
|
- sctp_chunkhdr_t *ch;
|
|
|
- __u8 *ch_end;
|
|
|
-
|
|
|
- ch = (sctp_chunkhdr_t *) skb->data;
|
|
|
+ sctp_chunkhdr_t *ch, _ch;
|
|
|
+ int ch_end, offset = 0;
|
|
|
|
|
|
/* Scan through all the chunks in the packet. */
|
|
|
do {
|
|
|
+ /* Make sure we have at least the header there */
|
|
|
+ if (offset + sizeof(sctp_chunkhdr_t) > skb->len)
|
|
|
+ break;
|
|
|
+
|
|
|
+ ch = skb_header_pointer(skb, offset, sizeof(*ch), &_ch);
|
|
|
+
|
|
|
/* Break out if chunk length is less then minimal. */
|
|
|
if (ntohs(ch->length) < sizeof(sctp_chunkhdr_t))
|
|
|
break;
|
|
|
|
|
|
- ch_end = ((__u8 *)ch) + WORD_ROUND(ntohs(ch->length));
|
|
|
- if (ch_end > skb_tail_pointer(skb))
|
|
|
+ ch_end = offset + WORD_ROUND(ntohs(ch->length));
|
|
|
+ if (ch_end > skb->len)
|
|
|
break;
|
|
|
|
|
|
/* RFC 8.4, 2) If the OOTB packet contains an ABORT chunk, the
|
|
@@ -697,8 +699,8 @@ static int sctp_rcv_ootb(struct sk_buff *skb)
|
|
|
if (SCTP_CID_INIT == ch->type && (void *)ch != skb->data)
|
|
|
goto discard;
|
|
|
|
|
|
- ch = (sctp_chunkhdr_t *) ch_end;
|
|
|
- } while (ch_end < skb_tail_pointer(skb));
|
|
|
+ offset = ch_end;
|
|
|
+ } while (ch_end < skb->len);
|
|
|
|
|
|
return 0;
|
|
|
|
|
@@ -1173,6 +1175,9 @@ static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net,
|
|
|
{
|
|
|
sctp_chunkhdr_t *ch;
|
|
|
|
|
|
+ if (skb_linearize(skb))
|
|
|
+ return NULL;
|
|
|
+
|
|
|
ch = (sctp_chunkhdr_t *) skb->data;
|
|
|
|
|
|
/* The code below will attempt to walk the chunk and extract
|