diff options
-rw-r--r-- | include/net/sctp/sm.h | 3 | ||||
-rw-r--r-- | include/net/sctp/structs.h | 1 | ||||
-rw-r--r-- | net/sctp/sm_make_chunk.c | 46 | ||||
-rw-r--r-- | net/sctp/sm_statefuns.c | 50 |
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); |
247 | struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, | 247 | struct sctp_chunk *sctp_make_asconf_set_prim(struct sctp_association *asoc, |
248 | union sctp_addr *addr); | 248 | union sctp_addr *addr); |
249 | int sctp_verify_asconf(const struct sctp_association *asoc, | ||
250 | struct sctp_paramhdr *param_hdr, void *chunk_end, | ||
251 | struct sctp_paramhdr **errp); | ||
249 | struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, | 252 | struct sctp_chunk *sctp_process_asconf(struct sctp_association *asoc, |
250 | struct sctp_chunk *asconf); | 253 | struct sctp_chunk *asconf); |
251 | int sctp_process_asconf_ack(struct sctp_association *asoc, | 254 | int 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 | */ |
423 | union sctp_addr_param { | 423 | union 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. */ | ||
2503 | int 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 | ||
120 | static 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 | |||
120 | static sctp_disposition_t sctp_sf_violation_ctsn( | 127 | static 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 | */ | ||
3911 | static 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 | * |