diff options
| author | Sona Sarmadi <sona.sarmadi@enea.com> | 2015-01-27 14:04:07 +0100 |
|---|---|---|
| committer | Zhenhua Luo <zhenhua.luo@freescale.com> | 2015-02-03 10:06:33 +0800 |
| commit | 26303c11e8502a997caee96a4b342fdf084bd4ab (patch) | |
| tree | b8b0f809d11bcfedad18f4cfea8238d7e3599cf2 | |
| parent | 8cde62241772c928769ae77344325e741c414e0f (diff) | |
| download | meta-freescale-26303c11e8502a997caee96a4b342fdf084bd4ab.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>
4 files changed, 613 insertions, 0 deletions
diff --git a/meta-fsl-ppc/recipes-kernel/linux/files/0001-net-sctp-CVE-2014-3673.patch b/meta-fsl-ppc/recipes-kernel/linux/files/0001-net-sctp-CVE-2014-3673.patch new file mode 100644 index 000000000..68289f288 --- /dev/null +++ b/meta-fsl-ppc/recipes-kernel/linux/files/0001-net-sctp-CVE-2014-3673.patch | |||
| @@ -0,0 +1,348 @@ | |||
| 1 | From bbd951a21e0fd555cd9ede44c7196af09d04d171 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Daniel Borkmann <dborkman@redhat.com> | ||
| 3 | Date: Thu, 9 Oct 2014 22:55:31 +0200 | ||
| 4 | Subject: [PATCH] net: sctp: fix skb_over_panic when receiving malformed ASCONF | ||
| 5 | chunks | ||
| 6 | |||
| 7 | commit 9de7922bc709eee2f609cd01d98aaedc4cf5ea74 upstream. | ||
| 8 | |||
| 9 | Commit 6f4c618ddb0 ("SCTP : Add paramters validity check for | ||
| 10 | ASCONF chunk") added basic verification of ASCONF chunks, however, | ||
| 11 | it is still possible to remotely crash a server by sending a | ||
| 12 | special crafted ASCONF chunk, even up to pre 2.6.12 kernels: | ||
| 13 | |||
| 14 | skb_over_panic: text:ffffffffa01ea1c3 len:31056 put:30768 | ||
| 15 | head:ffff88011bd81800 data:ffff88011bd81800 tail:0x7950 | ||
| 16 | end:0x440 dev:<NULL> | ||
| 17 | ------------[ cut here ]------------ | ||
| 18 | kernel BUG at net/core/skbuff.c:129! | ||
| 19 | [...] | ||
| 20 | Call 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 | |||
| 45 | This can be triggered e.g., through a simple scripted nmap | ||
| 46 | connection scan injecting the chunk after the handshake, for | ||
| 47 | example, ... | ||
| 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 | ||
| 61 | Address Parameter in the ASCONF chunk is even missing, too. | ||
| 62 | This is just an example and similarly-crafted ASCONF chunks | ||
| 63 | could be used just as well. | ||
| 64 | |||
| 65 | The ASCONF chunk passes through sctp_verify_asconf() as all | ||
| 66 | parameters passed sanity checks, and after walking, we ended | ||
| 67 | up successfully at the chunk end boundary, and thus may invoke | ||
| 68 | sctp_process_asconf(). Parameter walking is done with | ||
| 69 | WORD_ROUND() to take padding into account. | ||
| 70 | |||
| 71 | In sctp_process_asconf()'s TLV processing, we may fail in | ||
| 72 | sctp_process_asconf_param() e.g., due to removal of the IP | ||
| 73 | address that is also the source address of the packet containing | ||
| 74 | the ASCONF chunk, and thus we need to add all TLVs after the | ||
| 75 | failure to our ASCONF response to remote via helper function | ||
| 76 | sctp_add_asconf_response(), which basically invokes a | ||
| 77 | sctp_addto_chunk() adding the error parameters to the given | ||
| 78 | skb. | ||
| 79 | |||
| 80 | When walking to the next parameter this time, we proceed | ||
| 81 | with ... | ||
| 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 | ||
| 87 | in an off-by-one that leads to reading the follow-up garbage | ||
| 88 | parameter length of 12336, and thus throwing an skb_over_panic | ||
| 89 | for the reply when trying to sctp_addto_chunk() next time, | ||
| 90 | which implicitly calls the skb_put() with that length. | ||
| 91 | |||
| 92 | Fix it by using sctp_walk_params() [ which is also used in | ||
| 93 | INIT parameter processing ] macro in the verification *and* | ||
| 94 | in ASCONF processing: it will make sure we don't spill over, | ||
| 95 | that we walk parameters WORD_ROUND()'ed. Moreover, we're being | ||
| 96 | more defensive and guard against unknown parameter types and | ||
| 97 | missized addresses. | ||
| 98 | |||
| 99 | Joint work with Vlad Yasevich. | ||
| 100 | |||
| 101 | Fixes CVE-2014-3673 | ||
| 102 | Upstream-Status: Backport | ||
| 103 | |||
| 104 | Fixes: b896b82be4ae ("[SCTP] ADDIP: Support for processing incoming ASCONF_ACK chunks.") | ||
| 105 | Signed-off-by: Daniel Borkmann <dborkman@redhat.com> | ||
| 106 | Signed-off-by: Vlad Yasevich <vyasevich@gmail.com> | ||
| 107 | Acked-by: Neil Horman <nhorman@tuxdriver.com> | ||
| 108 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
| 109 | Cc: Josh Boyer <jwboyer@fedoraproject.org> | ||
| 110 | Signed-off-by: Jiri Slaby <jslaby@suse.cz> | ||
| 111 | Signed-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 | |||
| 118 | diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h | ||
| 119 | index 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, | ||
| 135 | diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c | ||
| 136 | index 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 | |||
| 301 | diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c | ||
| 302 | index 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 | -- | ||
| 347 | 1.9.1 | ||
| 348 | |||
diff --git a/meta-fsl-ppc/recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch b/meta-fsl-ppc/recipes-kernel/linux/files/0002-net-sctp-CVE-2014-3687.patch new file mode 100644 index 000000000..b05aaf2bd --- /dev/null +++ b/meta-fsl-ppc/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 | |||
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 000000000..1b4716d00 --- /dev/null +++ b/meta-fsl-ppc/recipes-kernel/linux/files/0003-net-sctp-CVE-2014-3688.patch | |||
| @@ -0,0 +1,160 @@ | |||
| 1 | From e476841415c1b7b54e4118d8a219f5db71878675 Mon Sep 17 00:00:00 2001 | ||
| 2 | From: Daniel Borkmann <dborkman@redhat.com> | ||
| 3 | Date: Thu, 9 Oct 2014 22:55:33 +0200 | ||
| 4 | Subject: [PATCH] net: sctp: fix remote memory pressure from excessive queueing | ||
| 5 | |||
| 6 | commit 26b87c7881006311828bb0ab271a551a62dcceb4 upstream. | ||
| 7 | |||
| 8 | This scenario is not limited to ASCONF, just taken as one | ||
| 9 | example triggering the issue. When receiving ASCONF probes | ||
| 10 | in 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 | ||
| 21 | ASCONFs and have increasing serial numbers, we process such | ||
| 22 | ASCONF chunk(s) marked with !end_of_packet and !singleton, | ||
| 23 | since we have not yet reached the SCTP packet end. SCTP does | ||
| 24 | only do verification on a chunk by chunk basis, as an SCTP | ||
| 25 | packet is nothing more than just a container of a stream of | ||
| 26 | chunks which it eats up one by one. | ||
| 27 | |||
| 28 | We could run into the case that we receive a packet with a | ||
| 29 | malformed tail, above marked as trailing JUNK. All previous | ||
| 30 | chunks are here goodformed, so the stack will eat up all | ||
| 31 | previous chunks up to this point. In case JUNK does not fit | ||
| 32 | into a chunk header and there are no more other chunks in | ||
| 33 | the input queue, or in case JUNK contains a garbage chunk | ||
| 34 | header, but the encoded chunk length would exceed the skb | ||
| 35 | tail, or we came here from an entirely different scenario | ||
| 36 | and the chunk has pdiscard=1 mark (without having had a flush | ||
| 37 | point), it will happen, that we will excessively queue up | ||
| 38 | the association's output queue (a correct final chunk may | ||
| 39 | then turn it into a response flood when flushing the | ||
| 40 | queue ;)): I ran a simple script with incremental ASCONF | ||
| 41 | serial numbers and could see the server side consuming | ||
| 42 | excessive amount of RAM [before/after: up to 2GB and more]. | ||
| 43 | |||
| 44 | The issue at heart is that the chunk train basically ends | ||
| 45 | with !end_of_packet and !singleton markers and since commit | ||
| 46 | 2e3216cd54b1 ("sctp: Follow security requirement of responding | ||
| 47 | with 1 packet") therefore preventing an output queue flush | ||
| 48 | point in sctp_do_sm() -> sctp_cmd_interpreter() on the input | ||
| 49 | chunk (chunk = event_arg) even though local_cork is set, | ||
| 50 | but its precedence has changed since then. In the normal | ||
| 51 | case, the last chunk with end_of_packet=1 would trigger the | ||
| 52 | queue flush to accommodate possible outgoing bundling. | ||
| 53 | |||
| 54 | In the input queue, sctp_inq_pop() seems to do the right thing | ||
| 55 | in terms of discarding invalid chunks. So, above JUNK will | ||
| 56 | not enter the state machine and instead be released and exit | ||
| 57 | the sctp_assoc_bh_rcv() chunk processing loop. It's simply | ||
| 58 | the flush point being missing at loop exit. Adding a try-flush | ||
| 59 | approach on the output queue might not work as the underlying | ||
| 60 | infrastructure might be long gone at this point due to the | ||
| 61 | side-effect interpreter run. | ||
| 62 | |||
| 63 | One possibility, albeit a bit of a kludge, would be to defer | ||
| 64 | invalid chunk freeing into the state machine in order to | ||
| 65 | possibly trigger packet discards and thus indirectly a queue | ||
| 66 | flush on error. It would surely be better to discard chunks | ||
| 67 | as in the current, perhaps better controlled environment, but | ||
| 68 | going back and forth, it's simply architecturally not possible. | ||
| 69 | I tried various trailing JUNK attack cases and it seems to | ||
| 70 | look good now. | ||
| 71 | |||
| 72 | Joint work with Vlad Yasevich. | ||
| 73 | |||
| 74 | Fixes CVE-2014-3688 | ||
| 75 | Upstream-Status: Backport | ||
| 76 | |||
| 77 | Fixes: 2e3216cd54b1 ("sctp: Follow security requirement of responding with 1 packet") | ||
| 78 | Signed-off-by: Daniel Borkmann <dborkman@redhat.com> | ||
| 79 | Signed-off-by: Vlad Yasevich <vyasevich@gmail.com> | ||
| 80 | Signed-off-by: David S. Miller <davem@davemloft.net> | ||
| 81 | Cc: Josh Boyer <jwboyer@fedoraproject.org> | ||
| 82 | Signed-off-by: Jiri Slaby <jslaby@suse.cz> | ||
| 83 | Signed-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 | |||
| 89 | diff --git a/net/sctp/inqueue.c b/net/sctp/inqueue.c | ||
| 90 | index 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. | ||
| 144 | diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c | ||
| 145 | index 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 | -- | ||
| 159 | 1.9.1 | ||
| 160 | |||
diff --git a/meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb b/meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb index 5993b59a5..966563227 100644 --- a/meta-fsl-ppc/recipes-kernel/linux/linux-qoriq_3.12.bb +++ b/meta-fsl-ppc/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 | " |
| 23 | SRCREV = "6619b8b55796cdf0cec04b66a71288edd3057229" | 26 | SRCREV = "6619b8b55796cdf0cec04b66a71288edd3057229" |
| 24 | 27 | ||
