summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSona Sarmadi <sona.sarmadi@enea.com>2015-01-27 14:04:07 +0100
committerZhenhua Luo <zhenhua.luo@freescale.com>2015-02-03 10:06:33 +0800
commit60e5148ce3f0098db100b08b70dc5e20154a8116 (patch)
tree676889d4a827917da936f5763092ce55951be256
parentcea3ea75de5952985a87c0039120373c20e5ed40 (diff)
downloadmeta-fsl-ppc-60e5148ce3f0098db100b08b70dc5e20154a8116.tar.gz
net-sctp: CVE-2014-3673, CVE-2014-3687, CVE-2014-3688
CVE-2014-3673 skb_over_panic when receiving malformed ASCONF chunks Fixes: b896b82be4ae ("[SCTP] ADDIP: Support for processing incoming ASCONF_ACK chunks.") CVE-2014-3687 panic on duplicate ASCONF chunks Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") CVE-2014-3688 remote memory pressure from excessive queueing Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") References: http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3673 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3687 http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2014-3688 http://www.openwall.com/lists/oss-security/2014/11/13/8 Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
-rw-r--r--recipes-kernel/linux/files/0001-net-sctp-CVE-2014-3673.patch348
-rw-r--r--recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch102
-rw-r--r--recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch160
-rw-r--r--recipes-kernel/linux/linux-qoriq_3.12.bb3
4 files changed, 613 insertions, 0 deletions
diff --git a/recipes-kernel/linux/files/0001-net-sctp-CVE-2014-3673.patch b/recipes-kernel/linux/files/0001-net-sctp-CVE-2014-3673.patch
new file mode 100644
index 0000000..68289f2
--- /dev/null
+++ b/recipes-kernel/linux/files/0001-net-sctp-CVE-2014-3673.patch
@@ -0,0 +1,348 @@
1From bbd951a21e0fd555cd9ede44c7196af09d04d171 Mon Sep 17 00:00:00 2001
2From: Daniel Borkmann <dborkman@redhat.com>
3Date: Thu, 9 Oct 2014 22:55:31 +0200
4Subject: [PATCH] net: sctp: fix skb_over_panic when receiving malformed ASCONF
5 chunks
6
7commit 9de7922bc709eee2f609cd01d98aaedc4cf5ea74 upstream.
8
9Commit 6f4c618ddb0 ("SCTP : Add paramters validity check for
10ASCONF chunk") added basic verification of ASCONF chunks, however,
11it is still possible to remotely crash a server by sending a
12special crafted ASCONF chunk, even up to pre 2.6.12 kernels:
13
14skb_over_panic: text:ffffffffa01ea1c3 len:31056 put:30768
15 head:ffff88011bd81800 data:ffff88011bd81800 tail:0x7950
16 end:0x440 dev:<NULL>
17 ------------[ cut here ]------------
18kernel BUG at net/core/skbuff.c:129!
19[...]
20Call Trace:
21 <IRQ>
22 [<ffffffff8144fb1c>] skb_put+0x5c/0x70
23 [<ffffffffa01ea1c3>] sctp_addto_chunk+0x63/0xd0 [sctp]
24 [<ffffffffa01eadaf>] sctp_process_asconf+0x1af/0x540 [sctp]
25 [<ffffffff8152d025>] ? _read_unlock_bh+0x15/0x20
26 [<ffffffffa01e0038>] sctp_sf_do_asconf+0x168/0x240 [sctp]
27 [<ffffffffa01e3751>] sctp_do_sm+0x71/0x1210 [sctp]
28 [<ffffffff8147645d>] ? fib_rules_lookup+0xad/0xf0
29 [<ffffffffa01e6b22>] ? sctp_cmp_addr_exact+0x32/0x40 [sctp]
30 [<ffffffffa01e8393>] sctp_assoc_bh_rcv+0xd3/0x180 [sctp]
31 [<ffffffffa01ee986>] sctp_inq_push+0x56/0x80 [sctp]
32 [<ffffffffa01fcc42>] sctp_rcv+0x982/0xa10 [sctp]
33 [<ffffffffa01d5123>] ? ipt_local_in_hook+0x23/0x28 [iptable_filter]
34 [<ffffffff8148bdc9>] ? nf_iterate+0x69/0xb0
35 [<ffffffff81496d10>] ? ip_local_deliver_finish+0x0/0x2d0
36 [<ffffffff8148bf86>] ? nf_hook_slow+0x76/0x120
37 [<ffffffff81496d10>] ? ip_local_deliver_finish+0x0/0x2d0
38 [<ffffffff81496ded>] ip_local_deliver_finish+0xdd/0x2d0
39 [<ffffffff81497078>] ip_local_deliver+0x98/0xa0
40 [<ffffffff8149653d>] ip_rcv_finish+0x12d/0x440
41 [<ffffffff81496ac5>] ip_rcv+0x275/0x350
42 [<ffffffff8145c88b>] __netif_receive_skb+0x4ab/0x750
43 [<ffffffff81460588>] netif_receive_skb+0x58/0x60
44
45This can be triggered e.g., through a simple scripted nmap
46connection scan injecting the chunk after the handshake, for
47example, ...
48
49 -------------- INIT[ASCONF; ASCONF_ACK] ------------->
50 <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------
51 -------------------- COOKIE-ECHO -------------------->
52 <-------------------- COOKIE-ACK ---------------------
53 ------------------ ASCONF; UNKNOWN ------------------>
54
55... where ASCONF chunk of length 280 contains 2 parameters ...
56
57 1) Add IP address parameter (param length: 16)
58 2) Add/del IP address parameter (param length: 255)
59
60... followed by an UNKNOWN chunk of e.g. 4 bytes. Here, the
61Address Parameter in the ASCONF chunk is even missing, too.
62This is just an example and similarly-crafted ASCONF chunks
63could be used just as well.
64
65The ASCONF chunk passes through sctp_verify_asconf() as all
66parameters passed sanity checks, and after walking, we ended
67up successfully at the chunk end boundary, and thus may invoke
68sctp_process_asconf(). Parameter walking is done with
69WORD_ROUND() to take padding into account.
70
71In sctp_process_asconf()'s TLV processing, we may fail in
72sctp_process_asconf_param() e.g., due to removal of the IP
73address that is also the source address of the packet containing
74the ASCONF chunk, and thus we need to add all TLVs after the
75failure to our ASCONF response to remote via helper function
76sctp_add_asconf_response(), which basically invokes a
77sctp_addto_chunk() adding the error parameters to the given
78skb.
79
80When walking to the next parameter this time, we proceed
81with ...
82
83 length = ntohs(asconf_param->param_hdr.length);
84 asconf_param = (void *)asconf_param + length;
85
86... instead of the WORD_ROUND()'ed length, thus resulting here
87in an off-by-one that leads to reading the follow-up garbage
88parameter length of 12336, and thus throwing an skb_over_panic
89for the reply when trying to sctp_addto_chunk() next time,
90which implicitly calls the skb_put() with that length.
91
92Fix it by using sctp_walk_params() [ which is also used in
93INIT parameter processing ] macro in the verification *and*
94in ASCONF processing: it will make sure we don't spill over,
95that we walk parameters WORD_ROUND()'ed. Moreover, we're being
96more defensive and guard against unknown parameter types and
97missized addresses.
98
99Joint work with Vlad Yasevich.
100
101Fixes CVE-2014-3673
102Upstream-Status: Backport
103
104Fixes: b896b82be4ae ("[SCTP] ADDIP: Support for processing incoming ASCONF_ACK chunks.")
105Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
106Signed-off-by: Vlad Yasevich <vyasevich@gmail.com>
107Acked-by: Neil Horman <nhorman@tuxdriver.com>
108Signed-off-by: David S. Miller <davem@davemloft.net>
109Cc: Josh Boyer <jwboyer@fedoraproject.org>
110Signed-off-by: Jiri Slaby <jslaby@suse.cz>
111Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
112---
113 include/net/sctp/sm.h | 6 +--
114 net/sctp/sm_make_chunk.c | 99 +++++++++++++++++++++++++++---------------------
115 net/sctp/sm_statefuns.c | 18 +--------
116 3 files changed, 60 insertions(+), 63 deletions(-)
117
118diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
119index 4ef75af..c91b6f5 100644
120--- a/include/net/sctp/sm.h
121+++ b/include/net/sctp/sm.h
122@@ -249,9 +249,9 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
123 int, __be16);
124 struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
125 union sctp_addr *addr);
126-int sctp_verify_asconf(const struct sctp_association *asoc,
127- struct sctp_paramhdr *param_hdr, void *chunk_end,
128- struct sctp_paramhdr **errp);
129+bool sctp_verify_asconf(const struct sctp_association *asoc,
130+ struct sctp_chunk *chunk, bool addr_param_needed,
131+ struct sctp_paramhdr **errp);
132 struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
133 struct sctp_chunk *asconf);
134 int sctp_process_asconf_ack(struct sctp_association *asoc,
135diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
136index e342387..d800160 100644
137--- a/net/sctp/sm_make_chunk.c
138+++ b/net/sctp/sm_make_chunk.c
139@@ -3126,50 +3126,63 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
140 return SCTP_ERROR_NO_ERROR;
141 }
142
143-/* Verify the ASCONF packet before we process it. */
144-int sctp_verify_asconf(const struct sctp_association *asoc,
145- struct sctp_paramhdr *param_hdr, void *chunk_end,
146- struct sctp_paramhdr **errp) {
147- sctp_addip_param_t *asconf_param;
148+/* Verify the ASCONF packet before we process it. */
149+bool sctp_verify_asconf(const struct sctp_association *asoc,
150+ struct sctp_chunk *chunk, bool addr_param_needed,
151+ struct sctp_paramhdr **errp)
152+{
153+ sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) chunk->chunk_hdr;
154 union sctp_params param;
155- int length, plen;
156-
157- param.v = (sctp_paramhdr_t *) param_hdr;
158- while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) {
159- length = ntohs(param.p->length);
160- *errp = param.p;
161+ bool addr_param_seen = false;
162
163- if (param.v > chunk_end - length ||
164- length < sizeof(sctp_paramhdr_t))
165- return 0;
166+ sctp_walk_params(param, addip, addip_hdr.params) {
167+ size_t length = ntohs(param.p->length);
168
169+ *errp = param.p;
170 switch (param.p->type) {
171+ case SCTP_PARAM_ERR_CAUSE:
172+ break;
173+ case SCTP_PARAM_IPV4_ADDRESS:
174+ if (length != sizeof(sctp_ipv4addr_param_t))
175+ return false;
176+ addr_param_seen = true;
177+ break;
178+ case SCTP_PARAM_IPV6_ADDRESS:
179+ if (length != sizeof(sctp_ipv6addr_param_t))
180+ return false;
181+ addr_param_seen = true;
182+ break;
183 case SCTP_PARAM_ADD_IP:
184 case SCTP_PARAM_DEL_IP:
185 case SCTP_PARAM_SET_PRIMARY:
186- asconf_param = (sctp_addip_param_t *)param.v;
187- plen = ntohs(asconf_param->param_hdr.length);
188- if (plen < sizeof(sctp_addip_param_t) +
189- sizeof(sctp_paramhdr_t))
190- return 0;
191+ /* In ASCONF chunks, these need to be first. */
192+ if (addr_param_needed && !addr_param_seen)
193+ return false;
194+ length = ntohs(param.addip->param_hdr.length);
195+ if (length < sizeof(sctp_addip_param_t) +
196+ sizeof(sctp_paramhdr_t))
197+ return false;
198 break;
199 case SCTP_PARAM_SUCCESS_REPORT:
200 case SCTP_PARAM_ADAPTATION_LAYER_IND:
201 if (length != sizeof(sctp_addip_param_t))
202- return 0;
203-
204+ return false;
205 break;
206 default:
207- break;
208+ /* This is unkown to us, reject! */
209+ return false;
210 }
211-
212- param.v += WORD_ROUND(length);
213 }
214
215- if (param.v != chunk_end)
216- return 0;
217+ /* Remaining sanity checks. */
218+ if (addr_param_needed && !addr_param_seen)
219+ return false;
220+ if (!addr_param_needed && addr_param_seen)
221+ return false;
222+ if (param.v != chunk->chunk_end)
223+ return false;
224
225- return 1;
226+ return true;
227 }
228
229 /* Process an incoming ASCONF chunk with the next expected serial no. and
230@@ -3178,16 +3191,17 @@ int sctp_verify_asconf(const struct sctp_association *asoc,
231 struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
232 struct sctp_chunk *asconf)
233 {
234+ sctp_addip_chunk_t *addip = (sctp_addip_chunk_t *) asconf->chunk_hdr;
235+ bool all_param_pass = true;
236+ union sctp_params param;
237 sctp_addiphdr_t *hdr;
238 union sctp_addr_param *addr_param;
239 sctp_addip_param_t *asconf_param;
240 struct sctp_chunk *asconf_ack;
241-
242 __be16 err_code;
243 int length = 0;
244 int chunk_len;
245 __u32 serial;
246- int all_param_pass = 1;
247
248 chunk_len = ntohs(asconf->chunk_hdr->length) - sizeof(sctp_chunkhdr_t);
249 hdr = (sctp_addiphdr_t *)asconf->skb->data;
250@@ -3215,9 +3229,14 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
251 goto done;
252
253 /* Process the TLVs contained within the ASCONF chunk. */
254- while (chunk_len > 0) {
255+ sctp_walk_params(param, addip, addip_hdr.params) {
256+ /* Skip preceeding address parameters. */
257+ if (param.p->type == SCTP_PARAM_IPV4_ADDRESS ||
258+ param.p->type == SCTP_PARAM_IPV6_ADDRESS)
259+ continue;
260+
261 err_code = sctp_process_asconf_param(asoc, asconf,
262- asconf_param);
263+ param.addip);
264 /* ADDIP 4.1 A7)
265 * If an error response is received for a TLV parameter,
266 * all TLVs with no response before the failed TLV are
267@@ -3225,28 +3244,20 @@ struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
268 * the failed response are considered unsuccessful unless
269 * a specific success indication is present for the parameter.
270 */
271- if (SCTP_ERROR_NO_ERROR != err_code)
272- all_param_pass = 0;
273-
274+ if (err_code != SCTP_ERROR_NO_ERROR)
275+ all_param_pass = false;
276 if (!all_param_pass)
277- sctp_add_asconf_response(asconf_ack,
278- asconf_param->crr_id, err_code,
279- asconf_param);
280+ sctp_add_asconf_response(asconf_ack, param.addip->crr_id,
281+ err_code, param.addip);
282
283 /* ADDIP 4.3 D11) When an endpoint receiving an ASCONF to add
284 * an IP address sends an 'Out of Resource' in its response, it
285 * MUST also fail any subsequent add or delete requests bundled
286 * in the ASCONF.
287 */
288- if (SCTP_ERROR_RSRC_LOW == err_code)
289+ if (err_code == SCTP_ERROR_RSRC_LOW)
290 goto done;
291-
292- /* Move to the next ASCONF param. */
293- length = ntohs(asconf_param->param_hdr.length);
294- asconf_param = (void *)asconf_param + length;
295- chunk_len -= length;
296 }
297-
298 done:
299 asoc->peer.addip_serial++;
300
301diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
302index 62623cc..bf12098 100644
303--- a/net/sctp/sm_statefuns.c
304+++ b/net/sctp/sm_statefuns.c
305@@ -3595,9 +3595,7 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net,
306 struct sctp_chunk *asconf_ack = NULL;
307 struct sctp_paramhdr *err_param = NULL;
308 sctp_addiphdr_t *hdr;
309- union sctp_addr_param *addr_param;
310 __u32 serial;
311- int length;
312
313 if (!sctp_vtag_verify(chunk, asoc)) {
314 sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
315@@ -3622,17 +3620,8 @@ sctp_disposition_t sctp_sf_do_asconf(struct net *net,
316 hdr = (sctp_addiphdr_t *)chunk->skb->data;
317 serial = ntohl(hdr->serial);
318
319- addr_param = (union sctp_addr_param *)hdr->params;
320- length = ntohs(addr_param->p.length);
321- if (length < sizeof(sctp_paramhdr_t))
322- return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
323- (void *)addr_param, commands);
324-
325 /* Verify the ASCONF chunk before processing it. */
326- if (!sctp_verify_asconf(asoc,
327- (sctp_paramhdr_t *)((void *)addr_param + length),
328- (void *)chunk->chunk_end,
329- &err_param))
330+ if (!sctp_verify_asconf(asoc, chunk, true, &err_param))
331 return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
332 (void *)err_param, commands);
333
334@@ -3750,10 +3739,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(struct net *net,
335 rcvd_serial = ntohl(addip_hdr->serial);
336
337 /* Verify the ASCONF-ACK chunk before processing it. */
338- if (!sctp_verify_asconf(asoc,
339- (sctp_paramhdr_t *)addip_hdr->params,
340- (void *)asconf_ack->chunk_end,
341- &err_param))
342+ if (!sctp_verify_asconf(asoc, asconf_ack, false, &err_param))
343 return sctp_sf_violation_paramlen(net, ep, asoc, type, arg,
344 (void *)err_param, commands);
345
346--
3471.9.1
348
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 @@
1From a723db0be941b8aebaa1a98b33d17a91b16603e4 Mon Sep 17 00:00:00 2001
2From: Daniel Borkmann <dborkman@redhat.com>
3Date: Thu, 9 Oct 2014 22:55:32 +0200
4Subject: [PATCH] net: sctp: fix panic on duplicate ASCONF chunks
5
6commit b69040d8e39f20d5215a03502a8e8b4c6ab78395 upstream.
7
8When receiving a e.g. semi-good formed connection scan in the
9form 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
18need to be equal), we panic an SCTP server!
19
20The problem is that good-formed ASCONF chunks that we reply with
21ASCONF_ACK chunks are cached per serial. Thus, when we receive a
22same ASCONF chunk twice (e.g. through a lost ASCONF_ACK), we do
23not need to process them again on the server side (that was the
24idea, also proposed in the RFC). Instead, we know it was cached
25and we just resend the cached chunk instead. So far, so good.
26
27Where things get nasty is in SCTP's side effect interpreter, that
28is, sctp_cmd_interpreter():
29
30While incoming ASCONF_a (chunk = event_arg) is being marked
31!end_of_packet and !singleton, and we have an association context,
32we do not flush the outqueue the first time after processing the
33ASCONF_ACK singleton chunk via SCTP_CMD_REPLY. Instead, we keep it
34queued up, although we set local_cork to 1. Commit 2e3216cd54b1
35changed the precedence, so that as long as we get bundled, incoming
36chunks we try possible bundling on outgoing queue as well. Before
37this commit, we would just flush the output queue.
38
39Now, while ASCONF_a's ASCONF_ACK sits in the corked outq, we
40continue to process the same ASCONF_b chunk from the packet. As
41we have cached the previous ASCONF_ACK, we find it, grab it and
42do another SCTP_CMD_REPLY command on it. So, effectively, we rip
43the chunk->list pointers and requeue the same ASCONF_ACK chunk
44another time. Since we process ASCONF_b, it's correctly marked
45with end_of_packet and we enforce an uncork, and thus flush, thus
46crashing the kernel.
47
48Fix it by testing if the ASCONF_ACK is currently pending and if
49that is the case, do not requeue it. When flushing the output
50queue we may relink the chunk for preparing an outgoing packet,
51but eventually unlink it when it's copied into the skb right
52before transmission.
53
54Joint work with Vlad Yasevich.
55
56Fixes CVE-2014-3687
57Upstream-Status: Backport
58
59Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet")
60Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
61Signed-off-by: Vlad Yasevich <vyasevich@gmail.com>
62Signed-off-by: David S. Miller <davem@davemloft.net>
63Cc: Josh Boyer <jwboyer@fedoraproject.org>
64Signed-off-by: Jiri Slaby <jslaby@suse.cz>
65Signed-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
71diff --git a/include/net/sctp/sctp.h b/include/net/sctp/sctp.h
72index 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
87diff --git a/net/sctp/associola.c b/net/sctp/associola.c
88index 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--
1011.9.1
102
diff --git a/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch b/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch
new file mode 100644
index 0000000..1b4716d
--- /dev/null
+++ b/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch
@@ -0,0 +1,160 @@
1From e476841415c1b7b54e4118d8a219f5db71878675 Mon Sep 17 00:00:00 2001
2From: Daniel Borkmann <dborkman@redhat.com>
3Date: Thu, 9 Oct 2014 22:55:33 +0200
4Subject: [PATCH] net: sctp: fix remote memory pressure from excessive queueing
5
6commit 26b87c7881006311828bb0ab271a551a62dcceb4 upstream.
7
8This scenario is not limited to ASCONF, just taken as one
9example triggering the issue. When receiving ASCONF probes
10in the form of ...
11
12 -------------- INIT[ASCONF; ASCONF_ACK] ------------->
13 <----------- INIT-ACK[ASCONF; ASCONF_ACK] ------------
14 -------------------- COOKIE-ECHO -------------------->
15 <-------------------- COOKIE-ACK ---------------------
16 ---- ASCONF_a; [ASCONF_b; ...; ASCONF_n;] JUNK ------>
17 [...]
18 ---- ASCONF_m; [ASCONF_o; ...; ASCONF_z;] JUNK ------>
19
20... where ASCONF_a, ASCONF_b, ..., ASCONF_z are good-formed
21ASCONFs and have increasing serial numbers, we process such
22ASCONF chunk(s) marked with !end_of_packet and !singleton,
23since we have not yet reached the SCTP packet end. SCTP does
24only do verification on a chunk by chunk basis, as an SCTP
25packet is nothing more than just a container of a stream of
26chunks which it eats up one by one.
27
28We could run into the case that we receive a packet with a
29malformed tail, above marked as trailing JUNK. All previous
30chunks are here goodformed, so the stack will eat up all
31previous chunks up to this point. In case JUNK does not fit
32into a chunk header and there are no more other chunks in
33the input queue, or in case JUNK contains a garbage chunk
34header, but the encoded chunk length would exceed the skb
35tail, or we came here from an entirely different scenario
36and the chunk has pdiscard=1 mark (without having had a flush
37point), it will happen, that we will excessively queue up
38the association's output queue (a correct final chunk may
39then turn it into a response flood when flushing the
40queue ;)): I ran a simple script with incremental ASCONF
41serial numbers and could see the server side consuming
42excessive amount of RAM [before/after: up to 2GB and more].
43
44The issue at heart is that the chunk train basically ends
45with !end_of_packet and !singleton markers and since commit
462e3216cd54b1 ("sctp: Follow security requirement of responding
47with 1 packet") therefore preventing an output queue flush
48point in sctp_do_sm() -> sctp_cmd_interpreter() on the input
49chunk (chunk = event_arg) even though local_cork is set,
50but its precedence has changed since then. In the normal
51case, the last chunk with end_of_packet=1 would trigger the
52queue flush to accommodate possible outgoing bundling.
53
54In the input queue, sctp_inq_pop() seems to do the right thing
55in terms of discarding invalid chunks. So, above JUNK will
56not enter the state machine and instead be released and exit
57the sctp_assoc_bh_rcv() chunk processing loop. It's simply
58the flush point being missing at loop exit. Adding a try-flush
59approach on the output queue might not work as the underlying
60infrastructure might be long gone at this point due to the
61side-effect interpreter run.
62
63One possibility, albeit a bit of a kludge, would be to defer
64invalid chunk freeing into the state machine in order to
65possibly trigger packet discards and thus indirectly a queue
66flush on error. It would surely be better to discard chunks
67as in the current, perhaps better controlled environment, but
68going back and forth, it's simply architecturally not possible.
69I tried various trailing JUNK attack cases and it seems to
70look good now.
71
72Joint work with Vlad Yasevich.
73
74Fixes CVE-2014-3688
75Upstream-Status: Backport
76
77Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet")
78Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
79Signed-off-by: Vlad Yasevich <vyasevich@gmail.com>
80Signed-off-by: David S. Miller <davem@davemloft.net>
81Cc: Josh Boyer <jwboyer@fedoraproject.org>
82Signed-off-by: Jiri Slaby <jslaby@suse.cz>
83Signed-off-by: Sona Sarmadi <sona.sarmadi@enea.com>
84---
85 net/sctp/inqueue.c | 33 +++++++--------------------------
86 net/sctp/sm_statefuns.c | 3 +++
87 2 files changed, 10 insertions(+), 26 deletions(-)
88
89diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c
90index 5856932..560cd41 100644
91--- a/net/sctp/inqueue.c
92+++ b/net/sctp/inqueue.c
93@@ -141,18 +141,9 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
94 } else {
95 /* Nothing to do. Next chunk in the packet, please. */
96 ch = (sctp_chunkhdr_t *) chunk->chunk_end;
97-
98 /* Force chunk->skb->data to chunk->chunk_end. */
99- skb_pull(chunk->skb,
100- chunk->chunk_end - chunk->skb->data);
101-
102- /* Verify that we have at least chunk headers
103- * worth of buffer left.
104- */
105- if (skb_headlen(chunk->skb) < sizeof(sctp_chunkhdr_t)) {
106- sctp_chunk_free(chunk);
107- chunk = queue->in_progress = NULL;
108- }
109+ skb_pull(chunk->skb, chunk->chunk_end - chunk->skb->data);
110+ /* We are guaranteed to pull a SCTP header. */
111 }
112 }
113
114@@ -188,24 +179,14 @@ struct sctp_chunk *sctp_inq_pop(struct sctp_inq *queue)
115 skb_pull(chunk->skb, sizeof(sctp_chunkhdr_t));
116 chunk->subh.v = NULL; /* Subheader is no longer valid. */
117
118- if (chunk->chunk_end < skb_tail_pointer(chunk->skb)) {
119+ if (chunk->chunk_end + sizeof(sctp_chunkhdr_t) <
120+ skb_tail_pointer(chunk->skb)) {
121 /* This is not a singleton */
122 chunk->singleton = 0;
123 } else if (chunk->chunk_end > skb_tail_pointer(chunk->skb)) {
124- /* RFC 2960, Section 6.10 Bundling
125- *
126- * Partial chunks MUST NOT be placed in an SCTP packet.
127- * If the receiver detects a partial chunk, it MUST drop
128- * the chunk.
129- *
130- * Since the end of the chunk is past the end of our buffer
131- * (which contains the whole packet, we can freely discard
132- * the whole packet.
133- */
134- sctp_chunk_free(chunk);
135- chunk = queue->in_progress = NULL;
136-
137- return NULL;
138+ /* Discard inside state machine. */
139+ chunk->pdiscard = 1;
140+ chunk->chunk_end = skb_tail_pointer(chunk->skb);
141 } else {
142 /* We are at the end of the packet, so mark the chunk
143 * in case we need to send a SACK.
144diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
145index 1dbcc6a..62623cc 100644
146--- a/net/sctp/sm_statefuns.c
147+++ b/net/sctp/sm_statefuns.c
148@@ -171,6 +171,9 @@ sctp_chunk_length_valid(struct sctp_chunk *chunk,
149 {
150 __u16 chunk_length = ntohs(chunk->chunk_hdr->length);
151
152+ /* Previously already marked? */
153+ if (unlikely(chunk->pdiscard))
154+ return 0;
155 if (unlikely(chunk_length < required_length))
156 return 0;
157
158--
1591.9.1
160
diff --git a/recipes-kernel/linux/linux-qoriq_3.12.bb b/recipes-kernel/linux/linux-qoriq_3.12.bb
index 5993b59..9665632 100644
--- a/recipes-kernel/linux/linux-qoriq_3.12.bb
+++ b/recipes-kernel/linux/linux-qoriq_3.12.bb
@@ -19,6 +19,9 @@ SRC_URI = "git://git.freescale.com/ppc/sdk/linux.git;nobranch=1 \
19 file://0004-USB-CVE-2014-3185.patch \ 19 file://0004-USB-CVE-2014-3185.patch \
20 file://0001-kvm-iommu-CVE-2014-3601.patch \ 20 file://0001-kvm-iommu-CVE-2014-3601.patch \
21 file://0002-kvm-iommu-CVE-2014-8369.patch \ 21 file://0002-kvm-iommu-CVE-2014-8369.patch \
22 file://0001-net-sctp-CVE-2014-3673.patch \
23 file://0002-net-sctp-CVE-2014-3687.patch \
24 file://0003-net-sctp-CVE-2014-3688.patch \
22" 25"
23SRCREV = "6619b8b55796cdf0cec04b66a71288edd3057229" 26SRCREV = "6619b8b55796cdf0cec04b66a71288edd3057229"
24 27