diff options
Diffstat (limited to 'meta-fsl-ppc/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch')
-rw-r--r-- | meta-fsl-ppc/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch | 160 |
1 files changed, 160 insertions, 0 deletions
diff --git a/meta-fsl-ppc/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch b/meta-fsl-ppc/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch new file mode 100644 index 00000000..1b4716d0 --- /dev/null +++ b/meta-fsl-ppc/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch @@ -0,0 +1,160 @@ +From e476841415c1b7b54e4118d8a219f5db71878675 Mon Sep 17 00:00:00 2001 +From: Daniel Borkmann <dborkman@redhat.com> +Date: Thu, 9 Oct 2014 22:55:33 +0200 +Subject: [PATCH] net: sctp: fix remote memory pressure from excessive queueing + +commit 26b87c7881006311828bb0ab271a551a62dcceb4 upstream. + +This scenario is not limited to ASCONF, just taken as one +example triggering the issue. When receiving ASCONF probes +in the form of ... + + -------------- INIT[ASCONF; ASCONF_ACK] -------------> + <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ + -------------------- COOKIE-ECHO --------------------> + <-------------------- COOKIE-ACK --------------------- + ---- ASCONF_a; [ASCONF_b; ...; ASCONF_n;] JUNK ------> + [...] + ---- ASCONF_m; [ASCONF_o; ...; ASCONF_z;] JUNK ------> + +... where ASCONF_a, ASCONF_b, ..., ASCONF_z are good-formed +ASCONFs and have increasing serial numbers, we process such +ASCONF chunk(s) marked with !end_of_packet and !singleton, +since we have not yet reached the SCTP packet end. SCTP does +only do verification on a chunk by chunk basis, as an SCTP +packet is nothing more than just a container of a stream of +chunks which it eats up one by one. + +We could run into the case that we receive a packet with a +malformed tail, above marked as trailing JUNK. All previous +chunks are here goodformed, so the stack will eat up all +previous chunks up to this point. In case JUNK does not fit +into a chunk header and there are no more other chunks in +the input queue, or in case JUNK contains a garbage chunk +header, but the encoded chunk length would exceed the skb +tail, or we came here from an entirely different scenario +and the chunk has pdiscard=1 mark (without having had a flush +point), it will happen, that we will excessively queue up +the association's output queue (a correct final chunk may +then turn it into a response flood when flushing the +queue ;)): I ran a simple script with incremental ASCONF +serial numbers and could see the server side consuming +excessive amount of RAM [before/after: up to 2GB and more]. + +The issue at heart is that the chunk train basically ends +with !end_of_packet and !singleton markers and since commit +2e3216cd54b1 ("sctp: Follow security requirement of responding +with 1 packet") therefore preventing an output queue flush +point in sctp_do_sm() -> sctp_cmd_interpreter() on the input +chunk (chunk = event_arg) even though local_cork is set, +but its precedence has changed since then. In the normal +case, the last chunk with end_of_packet=1 would trigger the +queue flush to accommodate possible outgoing bundling. + +In the input queue, sctp_inq_pop() seems to do the right thing +in terms of discarding invalid chunks. So, above JUNK will +not enter the state machine and instead be released and exit +the sctp_assoc_bh_rcv() chunk processing loop. It's simply +the flush point being missing at loop exit. Adding a try-flush +approach on the output queue might not work as the underlying +infrastructure might be long gone at this point due to the +side-effect interpreter run. + +One possibility, albeit a bit of a kludge, would be to defer +invalid chunk freeing into the state machine in order to +possibly trigger packet discards and thus indirectly a queue +flush on error. It would surely be better to discard chunks +as in the current, perhaps better controlled environment, but +going back and forth, it's simply architecturally not possible. +I tried various trailing JUNK attack cases and it seems to +look good now. + +Joint work with Vlad Yasevich. + +Fixes CVE-2014-3688 +Upstream-Status: Backport + +Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") +Signed-off-by: Daniel Borkmann <dborkman@redhat.com> +Signed-off-by: Vlad Yasevich <vyasevich@gmail.com> +Signed-off-by: David S. Miller <davem@davemloft.net> +Cc: Josh Boyer <jwboyer@fedoraproject.org> +Signed-off-by: Jiri Slaby <jslaby@suse.cz> +Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> +--- + net/sctp/inqueue.c | 33 +++++++-------------------------- + net/sctp/sm_statefuns.c | 3 +++ + 2 files changed, 10 insertions(+), 26 deletions(-) + +diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c +index 5856932..560cd41 100644 +--- a/net/sctp/inqueue.c ++++ b/net/sctp/inqueue.c +@@ -141,18 +141,9 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + } else { + /* Nothing to do. Next chunk in the packet, please. */ + ch = (sctp_chunkhdr_t *) chunk->chunk_end; +- + /* Force chunk->skb->data to chunk->chunk_end. */ +- skb_pull(chunk->skb, +- chunk->chunk_end - chunk->skb->data); +- +- /* Verify that we have at least chunk headers +- * worth of buffer left. +- */ +- if (skb_headlen(chunk->skb) < sizeof(sctp_chunkhdr_t)) { +- sctp_chunk_free(chunk); +- chunk = queue->in_progress = NULL; +- } ++ skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data); ++ /* We are guaranteed to pull a SCTP header. */ + } + } + +@@ -188,24 +179,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue) + skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t)); + chunk->subh.v = NULL; /* Subheader is no longer valid. */ + +- if (chunk->chunk_end < skb_tail_pointer(chunk->skb)) { ++ if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) < ++ skb_tail_pointer(chunk->skb)) { + /* This is not a singleton */ + chunk->singleton = 0; + } else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) { +- /* RFC 2960, Section 6.10 Bundling +- * +- * Partial chunks MUST NOT be placed in an SCTP packet. +- * If the receiver detects a partial chunk, it MUST drop +- * the chunk. +- * +- * Since the end of the chunk is past the end of our buffer +- * (which contains the whole packet, we can freely discard +- * the whole packet. +- */ +- sctp_chunk_free(chunk); +- chunk = queue->in_progress = NULL; +- +- return NULL; ++ /* Discard inside state machine. */ ++ chunk->pdiscard = 1; ++ chunk->chunk_end = skb_tail_pointer(chunk->skb); + } else { + /* We are at the end of the packet, so mark the chunk + * in case we need to send a SACK. +diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c +index 1dbcc6a..62623cc 100644 +--- a/net/sctp/sm_statefuns.c ++++ b/net/sctp/sm_statefuns.c +@@ -171,6 +171,9 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk, + { + __u16 chunk_length = ntohs(chunk->chunk_hdr->length); + ++ /* Previously already marked? */ ++ if (unlikely(chunk->pdiscard)) ++ return 0; + if (unlikely(chunk_length < required_length)) + return 0; + +-- +1.9.1 + |