aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/net/sctp/sm.h3
-rw-r--r--include/net/sctp/structs.h1
-rw-r--r--net/sctp/sm_make_chunk.c46
-rw-r--r--net/sctp/sm_statefuns.c50
4 files changed, 100 insertions, 0 deletions
diff --git a/include/net/sctp/sm.h b/include/net/sctp/sm.h
index cc71f366d1cd..e8e3a64eb322 100644
--- a/include/net/sctp/sm.h
+++ b/include/net/sctp/sm.h
@@ -246,6 +246,9 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *,
246 int, __be16); 246 int, __be16);
247struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, 247struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc,
248 union sctp_addr *addr); 248 union sctp_addr *addr);
249int sctp_verify_asconf(const struct sctp_association *asoc,
250 struct sctp_paramhdr *param_hdr, void *chunk_end,
251 struct sctp_paramhdr **errp);
249struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, 252struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc,
250 struct sctp_chunk *asconf); 253 struct sctp_chunk *asconf);
251int sctp_process_asconf_ack(struct sctp_association *asoc, 254int sctp_process_asconf_ack(struct sctp_association *asoc,
diff --git a/include/net/sctp/structs.h b/include/net/sctp/structs.h
index c2fe2dcc9afc..490a2928817c 100644
--- a/include/net/sctp/structs.h
+++ b/include/net/sctp/structs.h
@@ -421,6 +421,7 @@ struct sctp_signed_cookie {
421 * internally. 421 * internally.
422 */ 422 */
423union sctp_addr_param { 423union sctp_addr_param {
424 struct sctp_paramhdr p;
424 struct sctp_ipv4addr_param v4; 425 struct sctp_ipv4addr_param v4;
425 struct sctp_ipv6addr_param v6; 426 struct sctp_ipv6addr_param v6;
426}; 427};
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c
index 2e34220d94cd..23ae37ec8711 100644
--- a/net/sctp/sm_make_chunk.c
+++ b/net/sctp/sm_make_chunk.c
@@ -2499,6 +2499,52 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
2499 return SCTP_ERROR_NO_ERROR; 2499 return SCTP_ERROR_NO_ERROR;
2500} 2500}
2501 2501
2502/* Verify the ASCONF packet before we process it. */
2503int sctp_verify_asconf(const struct sctp_association *asoc,
2504 struct sctp_paramhdr *param_hdr, void *chunk_end,
2505 struct sctp_paramhdr **errp) {
2506 sctp_addip_param_t *asconf_param;
2507 union sctp_params param;
2508 int length, plen;
2509
2510 param.v = (sctp_paramhdr_t *) param_hdr;
2511 while (param.v <= chunk_end - sizeof(sctp_paramhdr_t)) {
2512 length = ntohs(param.p->length);
2513 *errp = param.p;
2514
2515 if (param.v > chunk_end - length ||
2516 length < sizeof(sctp_paramhdr_t))
2517 return 0;
2518
2519 switch (param.p->type) {
2520 case SCTP_PARAM_ADD_IP:
2521 case SCTP_PARAM_DEL_IP:
2522 case SCTP_PARAM_SET_PRIMARY:
2523 asconf_param = (sctp_addip_param_t *)param.v;
2524 plen = ntohs(asconf_param->param_hdr.length);
2525 if (plen < sizeof(sctp_addip_param_t) +
2526 sizeof(sctp_paramhdr_t))
2527 return 0;
2528 break;
2529 case SCTP_PARAM_SUCCESS_REPORT:
2530 case SCTP_PARAM_ADAPTATION_LAYER_IND:
2531 if (length != sizeof(sctp_addip_param_t))
2532 return 0;
2533
2534 break;
2535 default:
2536 break;
2537 }
2538
2539 param.v += WORD_ROUND(length);
2540 }
2541
2542 if (param.v != chunk_end)
2543 return 0;
2544
2545 return 1;
2546}
2547
2502/* Process an incoming ASCONF chunk with the next expected serial no. and 2548/* Process an incoming ASCONF chunk with the next expected serial no. and
2503 * return an ASCONF_ACK chunk to be sent in response. 2549 * return an ASCONF_ACK chunk to be sent in response.
2504 */ 2550 */
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c
index caed19d90d06..a583d67cab63 100644
--- a/net/sctp/sm_statefuns.c
+++ b/net/sctp/sm_statefuns.c
@@ -117,6 +117,13 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
117 void *arg, 117 void *arg,
118 sctp_cmd_seq_t *commands); 118 sctp_cmd_seq_t *commands);
119 119
120static sctp_disposition_t sctp_sf_violation_paramlen(
121 const struct sctp_endpoint *ep,
122 const struct sctp_association *asoc,
123 const sctp_subtype_t type,
124 void *arg,
125 sctp_cmd_seq_t *commands);
126
120static sctp_disposition_t sctp_sf_violation_ctsn( 127static sctp_disposition_t sctp_sf_violation_ctsn(
121 const struct sctp_endpoint *ep, 128 const struct sctp_endpoint *ep,
122 const struct sctp_association *asoc, 129 const struct sctp_association *asoc,
@@ -3296,8 +3303,11 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
3296{ 3303{
3297 struct sctp_chunk *chunk = arg; 3304 struct sctp_chunk *chunk = arg;
3298 struct sctp_chunk *asconf_ack = NULL; 3305 struct sctp_chunk *asconf_ack = NULL;
3306 struct sctp_paramhdr *err_param = NULL;
3299 sctp_addiphdr_t *hdr; 3307 sctp_addiphdr_t *hdr;
3308 union sctp_addr_param *addr_param;
3300 __u32 serial; 3309 __u32 serial;
3310 int length;
3301 3311
3302 if (!sctp_vtag_verify(chunk, asoc)) { 3312 if (!sctp_vtag_verify(chunk, asoc)) {
3303 sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG, 3313 sctp_add_cmd_sf(commands, SCTP_CMD_REPORT_BAD_TAG,
@@ -3313,6 +3323,20 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep,
3313 hdr = (sctp_addiphdr_t *)chunk->skb->data; 3323 hdr = (sctp_addiphdr_t *)chunk->skb->data;
3314 serial = ntohl(hdr->serial); 3324 serial = ntohl(hdr->serial);
3315 3325
3326 addr_param = (union sctp_addr_param *)hdr->params;
3327 length = ntohs(addr_param->p.length);
3328 if (length < sizeof(sctp_paramhdr_t))
3329 return sctp_sf_violation_paramlen(ep, asoc, type,
3330 (void *)addr_param, commands);
3331
3332 /* Verify the ASCONF chunk before processing it. */
3333 if (!sctp_verify_asconf(asoc,
3334 (sctp_paramhdr_t *)((void *)addr_param + length),
3335 (void *)chunk->chunk_end,
3336 &err_param))
3337 return sctp_sf_violation_paramlen(ep, asoc, type,
3338 (void *)&err_param, commands);
3339
3316 /* ADDIP 4.2 C1) Compare the value of the serial number to the value 3340 /* ADDIP 4.2 C1) Compare the value of the serial number to the value
3317 * the endpoint stored in a new association variable 3341 * the endpoint stored in a new association variable
3318 * 'Peer-Serial-Number'. 3342 * 'Peer-Serial-Number'.
@@ -3367,6 +3391,7 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
3367 struct sctp_chunk *asconf_ack = arg; 3391 struct sctp_chunk *asconf_ack = arg;
3368 struct sctp_chunk *last_asconf = asoc->addip_last_asconf; 3392 struct sctp_chunk *last_asconf = asoc->addip_last_asconf;
3369 struct sctp_chunk *abort; 3393 struct sctp_chunk *abort;
3394 struct sctp_paramhdr *err_param = NULL;
3370 sctp_addiphdr_t *addip_hdr; 3395 sctp_addiphdr_t *addip_hdr;
3371 __u32 sent_serial, rcvd_serial; 3396 __u32 sent_serial, rcvd_serial;
3372 3397
@@ -3384,6 +3409,14 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep,
3384 addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data; 3409 addip_hdr = (sctp_addiphdr_t *)asconf_ack->skb->data;
3385 rcvd_serial = ntohl(addip_hdr->serial); 3410 rcvd_serial = ntohl(addip_hdr->serial);
3386 3411
3412 /* Verify the ASCONF-ACK chunk before processing it. */
3413 if (!sctp_verify_asconf(asoc,
3414 (sctp_paramhdr_t *)addip_hdr->params,
3415 (void *)asconf_ack->chunk_end,
3416 &err_param))
3417 return sctp_sf_violation_paramlen(ep, asoc, type,
3418 (void *)&err_param, commands);
3419
3387 if (last_asconf) { 3420 if (last_asconf) {
3388 addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr; 3421 addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr;
3389 sent_serial = ntohl(addip_hdr->serial); 3422 sent_serial = ntohl(addip_hdr->serial);
@@ -3870,6 +3903,23 @@ static sctp_disposition_t sctp_sf_violation_chunklen(
3870 sizeof(err_str)); 3903 sizeof(err_str));
3871} 3904}
3872 3905
3906/*
3907 * Handle a protocol violation when the parameter length is invalid.
3908 * "Invalid" length is identified as smaller then the minimal length a
3909 * given parameter can be.
3910 */
3911static sctp_disposition_t sctp_sf_violation_paramlen(
3912 const struct sctp_endpoint *ep,
3913 const struct sctp_association *asoc,
3914 const sctp_subtype_t type,
3915 void *arg,
3916 sctp_cmd_seq_t *commands) {
3917 char err_str[] = "The following parameter had invalid length:";
3918
3919 return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str,
3920 sizeof(err_str));
3921}
3922
3873/* Handle a protocol violation when the peer trying to advance the 3923/* Handle a protocol violation when the peer trying to advance the
3874 * cumulative tsn ack to a point beyond the max tsn currently sent. 3924 * cumulative tsn ack to a point beyond the max tsn currently sent.
3875 * 3925 *