Commit 89f0091e authored by Jon Grimm's avatar Jon Grimm

[SCTP] Fix SACK bundling bug.

sctp_packet_bundle_sack() modifies packet->size, but the local copy 
of this value is not updated.  The bug is that we can "put" too much
data to the skb and segfault.  Also, once DATA is in the packet, set
has_sack, so we don't inadvertantly bundle a SACK after DATA. 
parent c425b68c
...@@ -196,11 +196,13 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -196,11 +196,13 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
{ {
sctp_xmit_t retval = SCTP_XMIT_OK; sctp_xmit_t retval = SCTP_XMIT_OK;
__u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length)); __u16 chunk_len = WORD_ROUND(ntohs(chunk->chunk_hdr->length));
size_t psize = packet->size; size_t psize;
size_t pmtu; size_t pmtu;
int too_big; int too_big;
retval = sctp_packet_bundle_sack(packet, chunk); retval = sctp_packet_bundle_sack(packet, chunk);
psize = packet->size;
if (retval != SCTP_XMIT_OK) if (retval != SCTP_XMIT_OK)
goto finish; goto finish;
...@@ -251,6 +253,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet, ...@@ -251,6 +253,8 @@ sctp_xmit_t sctp_packet_append_chunk(struct sctp_packet *packet,
*/ */
if (sctp_chunk_is_data(chunk)) { if (sctp_chunk_is_data(chunk)) {
retval = sctp_packet_append_data(packet, chunk); retval = sctp_packet_append_data(packet, chunk);
/* Disallow SACK bundling after DATA. */
packet->has_sack = 1;
if (SCTP_XMIT_OK != retval) if (SCTP_XMIT_OK != retval)
goto finish; goto finish;
} else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type) } else if (SCTP_CID_COOKIE_ECHO == chunk->chunk_hdr->type)
......
...@@ -1031,21 +1031,18 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc, ...@@ -1031,21 +1031,18 @@ sctp_chunk_t *sctp_make_chunk(const sctp_association_t *asoc,
struct sk_buff *skb; struct sk_buff *skb;
struct sock *sk; struct sock *sk;
skb = dev_alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen)); /* No need to allocate LL here, as this is only a chunk. */
skb = alloc_skb(WORD_ROUND(sizeof(sctp_chunkhdr_t) + paylen),
GFP_ATOMIC);
if (!skb) if (!skb)
goto nodata; goto nodata;
/* Make room for the chunk header. */ /* Make room for the chunk header. */
chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t)); chunk_hdr = (sctp_chunkhdr_t *)skb_put(skb, sizeof(sctp_chunkhdr_t));
skb_pull(skb, sizeof(sctp_chunkhdr_t));
chunk_hdr->type = type; chunk_hdr->type = type;
chunk_hdr->flags = flags; chunk_hdr->flags = flags;
chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t)); chunk_hdr->length = htons(sizeof(sctp_chunkhdr_t));
/* Move the data pointer back up to the start of the chunk. */
skb_push(skb, sizeof(sctp_chunkhdr_t));
sk = asoc ? asoc->base.sk : NULL; sk = asoc ? asoc->base.sk : NULL;
retval = sctp_chunkify(skb, asoc, sk); retval = sctp_chunkify(skb, asoc, sk);
if (!retval) { if (!retval) {
......
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