diff options
Diffstat (limited to 'recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch')
-rw-r--r-- | recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch | 102 |
1 files changed, 102 insertions, 0 deletions
diff --git a/recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch b/recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch new file mode 100644 index 0000000..b05aaf2 --- /dev/null +++ b/recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch | |||
@@ -0,0 +1,102 @@ | |||
1 | From a723db0be941b8aebaa1a98b33d17a91b16603e4 Mon Sep 17 00:00:00 2001 | ||
2 | From: Daniel Borkmann <dborkman@redhat.com> | ||
3 | Date: Thu, 9 Oct 2014 22:55:32 +0200 | ||
4 | Subject: [PATCH] net: sctp: fix panic on duplicate ASCONF chunks | ||
5 | |||
6 | commit b69040d8e39f20d5215a03502a8e8b4c6ab78395 upstream. | ||
7 | |||
8 | When receiving a e.g. semi-good formed connection scan in the | ||
9 | form of ... | ||
10 | |||
11 | -------------- INIT[ASCONF; ASCONF_ACK] -------------> | ||
12 | <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------ | ||
13 | -------------------- COOKIE-ECHO --------------------> | ||
14 | <-------------------- COOKIE-ACK --------------------- | ||
15 | ---------------- ASCONF_a; ASCONF_b -----------------> | ||
16 | |||
17 | ... where ASCONF_a equals ASCONF_b chunk (at least both serials | ||
18 | need to be equal), we panic an SCTP server! | ||
19 | |||
20 | The problem is that good-formed ASCONF chunks that we reply with | ||
21 | ASCONF_ACK chunks are cached per serial. Thus, when we receive a | ||
22 | same ASCONF chunk twice (e.g. through a lost ASCONF_ACK), we do | ||
23 | not need to process them again on the server side (that was the | ||
24 | idea, also proposed in the RFC). Instead, we know it was cached | ||
25 | and we just resend the cached chunk instead. So far, so good. | ||
26 | |||
27 | Where things get nasty is in SCTP's side effect interpreter, that | ||
28 | is, sctp_cmd_interpreter(): | ||
29 | |||
30 | While incoming ASCONF_a (chunk = event_arg) is being marked | ||
31 | !end_of_packet and !singleton, and we have an association context, | ||
32 | we do not flush the outqueue the first time after processing the | ||
33 | ASCONF_ACK singleton chunk via SCTP_CMD_REPLY. Instead, we keep it | ||
34 | queued up, although we set local_cork to 1. Commit 2e3216cd54b1 | ||
35 | changed the precedence, so that as long as we get bundled, incoming | ||
36 | chunks we try possible bundling on outgoing queue as well. Before | ||
37 | this commit, we would just flush the output queue. | ||
38 | |||
39 | Now, while ASCONF_a's ASCONF_ACK sits in the corked outq, we | ||
40 | continue to process the same ASCONF_b chunk from the packet. As | ||
41 | we have cached the previous ASCONF_ACK, we find it, grab it and | ||
42 | do another SCTP_CMD_REPLY command on it. So, effectively, we rip | ||
43 | the chunk->list pointers and requeue the same ASCONF_ACK chunk | ||
44 | another time. Since we process ASCONF_b, it's correctly marked | ||
45 | with end_of_packet and we enforce an uncork, and thus flush, thus | ||
46 | crashing the kernel. | ||
47 | |||
48 | Fix it by testing if the ASCONF_ACK is currently pending and if | ||
49 | that is the case, do not requeue it. When flushing the output | ||
50 | queue we may relink the chunk for preparing an outgoing packet, | ||
51 | but eventually unlink it when it's copied into the skb right | ||
52 | before transmission. | ||
53 | |||
54 | Joint work with Vlad Yasevich. | ||
55 | |||
56 | Fixes CVE-2014-3687 | ||
57 | Upstream-Status: Backport | ||
58 | |||
59 | Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") | ||
60 | Signed-off-by: Daniel Borkmann <dborkman@redhat.com> | ||
61 | Signed-off-by: Vlad Yasevich <vyasevich@gmail.com> | ||
62 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
63 | Cc: Josh Boyer <jwboyer@fedoraproject.org> | ||
64 | Signed-off-by: Jiri Slaby <jslaby@suse.cz> | ||
65 | Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com> | ||
66 | --- | ||
67 | include/net/sctp/sctp.h | 5 +++++ | ||
68 | net/sctp/associola.c | 2 ++ | ||
69 | 2 files changed, 7 insertions(+) | ||
70 | |||
71 | diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h | ||
72 | index 3794c5a..3848934 100644 | ||
73 | --- a/include/net/sctp/sctp.h | ||
74 | +++ b/include/net/sctp/sctp.h | ||
75 | @@ -454,6 +454,11 @@ static inline void sctp_assoc_pending_pmtu(struct sock *sk, struct sctp_associat | ||
76 | asoc->pmtu_pending = 0; | ||
77 | } | ||
78 | |||
79 | +static inline bool sctp_chunk_pending(const struct sctp_chunk *chunk) | ||
80 | +{ | ||
81 | + return !list_empty(&chunk->list); | ||
82 | +} | ||
83 | + | ||
84 | /* Walk through a list of TLV parameters. Don't trust the | ||
85 | * individual parameter lengths and instead depend on | ||
86 | * the chunk length to indicate when to stop. Make sure | ||
87 | diff --git a/net/sctp/associola.c b/net/sctp/associola.c | ||
88 | index ad5cd6f..737050f 100644 | ||
89 | --- a/net/sctp/associola.c | ||
90 | +++ b/net/sctp/associola.c | ||
91 | @@ -1645,6 +1645,8 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack( | ||
92 | * ack chunk whose serial number matches that of the request. | ||
93 | */ | ||
94 | list_for_each_entry(ack, &asoc->asconf_ack_list, transmitted_list) { | ||
95 | + if (sctp_chunk_pending(ack)) | ||
96 | + continue; | ||
97 | if (ack->subh.addip_hdr->serial == serial) { | ||
98 | sctp_chunk_hold(ack); | ||
99 | return ack; | ||
100 | -- | ||
101 | 1.9.1 | ||
102 | |||