summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>2016-07-07 15:39:29 +0300
committerDavid S. Miller <davem@davemloft.net>2016-07-09 07:08:21 +0300
commitf1533cce60d1f84378c1dd925f9ef1038fa93507 (patch)
tree51a8e7832f2f0c851b7a592ef5e1215c86d163a3
parent09a7636a5b151670072de60767ddf096dc7bd12e (diff)
downloadlinux-f1533cce60d1f84378c1dd925f9ef1038fa93507.tar.xz
sctp: fix panic when sending auth chunks
When we introduced GSO support, if using auth the auth chunk was being left queued on the packet even after the final segment was generated. Later on sctp_transmit_packet it calls sctp_packet_reset, which zeroed the packet len while not accounting for this left-over. This caused more space to be used the next packet due to the chunk still being queued, but space which wasn't allocated as its size wasn't accounted. The fix is to only queue it back when we know that we are going to generate another segment. Fixes: 90017accff61 ("sctp: Add GSO support") Signed-off-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/sctp/output.c18
1 files changed, 15 insertions, 3 deletions
diff --git a/net/sctp/output.c b/net/sctp/output.c
index 1541a91d6d9d..2e9223bb1b3a 100644
--- a/net/sctp/output.c
+++ b/net/sctp/output.c
@@ -582,9 +582,7 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
*/
pkt_size -= WORD_ROUND(chunk->skb->len);
- if (chunk == packet->auth && !list_empty(&packet->chunk_list))
- list_add(&chunk->list, &packet->chunk_list);
- else if (!sctp_chunk_is_data(chunk))
+ if (!sctp_chunk_is_data(chunk) && chunk != packet->auth)
sctp_chunk_free(chunk);
if (!pkt_size)
@@ -605,6 +603,18 @@ int sctp_packet_transmit(struct sctp_packet *packet, gfp_t gfp)
(struct sctp_auth_chunk *)auth,
gfp);
+ if (packet->auth) {
+ if (!list_empty(&packet->chunk_list)) {
+ /* We will generate more packets, so re-queue
+ * auth chunk.
+ */
+ list_add(&chunk->list, &packet->chunk_list);
+ } else {
+ sctp_chunk_free(packet->auth);
+ packet->auth = NULL;
+ }
+ }
+
if (!gso)
break;
@@ -735,6 +745,8 @@ err:
}
goto out;
nomem:
+ if (packet->auth && list_empty(&packet->auth->list))
+ sctp_chunk_free(packet->auth);
err = -ENOMEM;
goto err;
}