projects
/
cascardo
/
linux.git
/ blobdiff
commit
grep
author
committer
pickaxe
?
search:
re
summary
|
shortlog
|
log
|
commit
|
commitdiff
|
tree
raw
|
inline
| side by side
sctp: delay as much as possible skb_linearize
[cascardo/linux.git]
/
net
/
sctp
/
input.c
diff --git
a/net/sctp/input.c
b/net/sctp/input.c
index
a701527
..
5cff254
100644
(file)
--- a/
net/sctp/input.c
+++ b/
net/sctp/input.c
@@
-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 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;
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);
__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;
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));
__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))
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;
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);
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->rcvr = rcvr;
/* Remember the SCTP header. */
- chunk->sctp_hdr = s
h
;
+ chunk->sctp_hdr = s
ctp_hdr(skb)
;
/* Set the source and destination addresses of the incoming chunk. */
sctp_init_addrs(chunk, &src, &dest);
/* 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)
{
*/
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 {
/* 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;
/* 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
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;
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;
return 0;
@@
-1173,6
+1175,9
@@
static struct sctp_association *__sctp_rcv_lookup_harder(struct net *net,
{
sctp_chunkhdr_t *ch;
{
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
ch = (sctp_chunkhdr_t *) skb->data;
/* The code below will attempt to walk the chunk and extract