diff options
Diffstat (limited to 'net/sctp')
| -rw-r--r-- | net/sctp/associola.c | 9 | ||||
| -rw-r--r-- | net/sctp/auth.c | 7 | ||||
| -rw-r--r-- | net/sctp/endpointola.c | 4 | ||||
| -rw-r--r-- | net/sctp/ipv6.c | 3 | ||||
| -rw-r--r-- | net/sctp/output.c | 3 | ||||
| -rw-r--r-- | net/sctp/sm_make_chunk.c | 52 | ||||
| -rw-r--r-- | net/sctp/sm_statefuns.c | 48 | ||||
| -rw-r--r-- | net/sctp/socket.c | 96 |
8 files changed, 162 insertions, 60 deletions
diff --git a/net/sctp/associola.c b/net/sctp/associola.c index 8472b8b349c4..abd51cef2413 100644 --- a/net/sctp/associola.c +++ b/net/sctp/associola.c | |||
| @@ -599,11 +599,12 @@ struct sctp_transport *sctp_assoc_add_peer(struct sctp_association *asoc, | |||
| 599 | /* Check to see if this is a duplicate. */ | 599 | /* Check to see if this is a duplicate. */ |
| 600 | peer = sctp_assoc_lookup_paddr(asoc, addr); | 600 | peer = sctp_assoc_lookup_paddr(asoc, addr); |
| 601 | if (peer) { | 601 | if (peer) { |
| 602 | /* An UNKNOWN state is only set on transports added by | ||
| 603 | * user in sctp_connectx() call. Such transports should be | ||
| 604 | * considered CONFIRMED per RFC 4960, Section 5.4. | ||
| 605 | */ | ||
| 602 | if (peer->state == SCTP_UNKNOWN) { | 606 | if (peer->state == SCTP_UNKNOWN) { |
| 603 | if (peer_state == SCTP_ACTIVE) | 607 | peer->state = SCTP_ACTIVE; |
| 604 | peer->state = SCTP_ACTIVE; | ||
| 605 | if (peer_state == SCTP_UNCONFIRMED) | ||
| 606 | peer->state = SCTP_UNCONFIRMED; | ||
| 607 | } | 608 | } |
| 608 | return peer; | 609 | return peer; |
| 609 | } | 610 | } |
diff --git a/net/sctp/auth.c b/net/sctp/auth.c index 675a5c3e68a6..52db5f60daa0 100644 --- a/net/sctp/auth.c +++ b/net/sctp/auth.c | |||
| @@ -80,6 +80,10 @@ static struct sctp_auth_bytes *sctp_auth_create_key(__u32 key_len, gfp_t gfp) | |||
| 80 | { | 80 | { |
| 81 | struct sctp_auth_bytes *key; | 81 | struct sctp_auth_bytes *key; |
| 82 | 82 | ||
| 83 | /* Verify that we are not going to overflow INT_MAX */ | ||
| 84 | if ((INT_MAX - key_len) < sizeof(struct sctp_auth_bytes)) | ||
| 85 | return NULL; | ||
| 86 | |||
| 83 | /* Allocate the shared key */ | 87 | /* Allocate the shared key */ |
| 84 | key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); | 88 | key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); |
| 85 | if (!key) | 89 | if (!key) |
| @@ -782,6 +786,9 @@ int sctp_auth_ep_set_hmacs(struct sctp_endpoint *ep, | |||
| 782 | for (i = 0; i < hmacs->shmac_num_idents; i++) { | 786 | for (i = 0; i < hmacs->shmac_num_idents; i++) { |
| 783 | id = hmacs->shmac_idents[i]; | 787 | id = hmacs->shmac_idents[i]; |
| 784 | 788 | ||
| 789 | if (id > SCTP_AUTH_HMAC_ID_MAX) | ||
| 790 | return -EOPNOTSUPP; | ||
| 791 | |||
| 785 | if (SCTP_AUTH_HMAC_ID_SHA1 == id) | 792 | if (SCTP_AUTH_HMAC_ID_SHA1 == id) |
| 786 | has_sha1 = 1; | 793 | has_sha1 = 1; |
| 787 | 794 | ||
diff --git a/net/sctp/endpointola.c b/net/sctp/endpointola.c index e39a0cdef184..4c8d9f45ce09 100644 --- a/net/sctp/endpointola.c +++ b/net/sctp/endpointola.c | |||
| @@ -103,6 +103,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, | |||
| 103 | 103 | ||
| 104 | /* Initialize the CHUNKS parameter */ | 104 | /* Initialize the CHUNKS parameter */ |
| 105 | auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; | 105 | auth_chunks->param_hdr.type = SCTP_PARAM_CHUNKS; |
| 106 | auth_chunks->param_hdr.length = htons(sizeof(sctp_paramhdr_t)); | ||
| 106 | 107 | ||
| 107 | /* If the Add-IP functionality is enabled, we must | 108 | /* If the Add-IP functionality is enabled, we must |
| 108 | * authenticate, ASCONF and ASCONF-ACK chunks | 109 | * authenticate, ASCONF and ASCONF-ACK chunks |
| @@ -110,8 +111,7 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep, | |||
| 110 | if (sctp_addip_enable) { | 111 | if (sctp_addip_enable) { |
| 111 | auth_chunks->chunks[0] = SCTP_CID_ASCONF; | 112 | auth_chunks->chunks[0] = SCTP_CID_ASCONF; |
| 112 | auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; | 113 | auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK; |
| 113 | auth_chunks->param_hdr.length = | 114 | auth_chunks->param_hdr.length += htons(2); |
| 114 | htons(sizeof(sctp_paramhdr_t) + 2); | ||
| 115 | } | 115 | } |
| 116 | } | 116 | } |
| 117 | 117 | ||
diff --git a/net/sctp/ipv6.c b/net/sctp/ipv6.c index 483a01d0740a..47f91afa0211 100644 --- a/net/sctp/ipv6.c +++ b/net/sctp/ipv6.c | |||
| @@ -319,7 +319,8 @@ static void sctp_v6_get_saddr(struct sctp_sock *sk, | |||
| 319 | __func__, asoc, dst, NIP6(daddr->v6.sin6_addr)); | 319 | __func__, asoc, dst, NIP6(daddr->v6.sin6_addr)); |
| 320 | 320 | ||
| 321 | if (!asoc) { | 321 | if (!asoc) { |
| 322 | ipv6_dev_get_saddr(dst ? ip6_dst_idev(dst)->dev : NULL, | 322 | ipv6_dev_get_saddr(sock_net(sctp_opt2sk(sk)), |
| 323 | dst ? ip6_dst_idev(dst)->dev : NULL, | ||
| 323 | &daddr->v6.sin6_addr, | 324 | &daddr->v6.sin6_addr, |
| 324 | inet6_sk(&sk->inet.sk)->srcprefs, | 325 | inet6_sk(&sk->inet.sk)->srcprefs, |
| 325 | &saddr->v6.sin6_addr); | 326 | &saddr->v6.sin6_addr); |
diff --git a/net/sctp/output.c b/net/sctp/output.c index 0dc4a7dfb234..225c7123c41f 100644 --- a/net/sctp/output.c +++ b/net/sctp/output.c | |||
| @@ -533,7 +533,8 @@ int sctp_packet_transmit(struct sctp_packet *packet) | |||
| 533 | if (!(dst->dev->features & NETIF_F_NO_CSUM)) { | 533 | if (!(dst->dev->features & NETIF_F_NO_CSUM)) { |
| 534 | crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); | 534 | crc32 = sctp_start_cksum((__u8 *)sh, cksum_buf_len); |
| 535 | crc32 = sctp_end_cksum(crc32); | 535 | crc32 = sctp_end_cksum(crc32); |
| 536 | } | 536 | } else |
| 537 | nskb->ip_summed = CHECKSUM_UNNECESSARY; | ||
| 537 | 538 | ||
| 538 | /* 3) Put the resultant value into the checksum field in the | 539 | /* 3) Put the resultant value into the checksum field in the |
| 539 | * common header, and leave the rest of the bits unchanged. | 540 | * common header, and leave the rest of the bits unchanged. |
diff --git a/net/sctp/sm_make_chunk.c b/net/sctp/sm_make_chunk.c index e8ca4e54981f..d68869f966c3 100644 --- a/net/sctp/sm_make_chunk.c +++ b/net/sctp/sm_make_chunk.c | |||
| @@ -1012,6 +1012,29 @@ end: | |||
| 1012 | return retval; | 1012 | return retval; |
| 1013 | } | 1013 | } |
| 1014 | 1014 | ||
| 1015 | struct sctp_chunk *sctp_make_violation_paramlen( | ||
| 1016 | const struct sctp_association *asoc, | ||
| 1017 | const struct sctp_chunk *chunk, | ||
| 1018 | struct sctp_paramhdr *param) | ||
| 1019 | { | ||
| 1020 | struct sctp_chunk *retval; | ||
| 1021 | static const char error[] = "The following parameter had invalid length:"; | ||
| 1022 | size_t payload_len = sizeof(error) + sizeof(sctp_errhdr_t) + | ||
| 1023 | sizeof(sctp_paramhdr_t); | ||
| 1024 | |||
| 1025 | retval = sctp_make_abort(asoc, chunk, payload_len); | ||
| 1026 | if (!retval) | ||
| 1027 | goto nodata; | ||
| 1028 | |||
| 1029 | sctp_init_cause(retval, SCTP_ERROR_PROTO_VIOLATION, | ||
| 1030 | sizeof(error) + sizeof(sctp_paramhdr_t)); | ||
| 1031 | sctp_addto_chunk(retval, sizeof(error), error); | ||
| 1032 | sctp_addto_param(retval, sizeof(sctp_paramhdr_t), param); | ||
| 1033 | |||
| 1034 | nodata: | ||
| 1035 | return retval; | ||
| 1036 | } | ||
| 1037 | |||
| 1015 | /* Make a HEARTBEAT chunk. */ | 1038 | /* Make a HEARTBEAT chunk. */ |
| 1016 | struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, | 1039 | struct sctp_chunk *sctp_make_heartbeat(const struct sctp_association *asoc, |
| 1017 | const struct sctp_transport *transport, | 1040 | const struct sctp_transport *transport, |
| @@ -1782,11 +1805,6 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc, | |||
| 1782 | const struct sctp_chunk *chunk, | 1805 | const struct sctp_chunk *chunk, |
| 1783 | struct sctp_chunk **errp) | 1806 | struct sctp_chunk **errp) |
| 1784 | { | 1807 | { |
| 1785 | static const char error[] = "The following parameter had invalid length:"; | ||
| 1786 | size_t payload_len = WORD_ROUND(sizeof(error)) + | ||
| 1787 | sizeof(sctp_paramhdr_t); | ||
| 1788 | |||
| 1789 | |||
| 1790 | /* This is a fatal error. Any accumulated non-fatal errors are | 1808 | /* This is a fatal error. Any accumulated non-fatal errors are |
| 1791 | * not reported. | 1809 | * not reported. |
| 1792 | */ | 1810 | */ |
| @@ -1794,14 +1812,7 @@ static int sctp_process_inv_paramlength(const struct sctp_association *asoc, | |||
| 1794 | sctp_chunk_free(*errp); | 1812 | sctp_chunk_free(*errp); |
| 1795 | 1813 | ||
| 1796 | /* Create an error chunk and fill it in with our payload. */ | 1814 | /* Create an error chunk and fill it in with our payload. */ |
| 1797 | *errp = sctp_make_op_error_space(asoc, chunk, payload_len); | 1815 | *errp = sctp_make_violation_paramlen(asoc, chunk, param); |
| 1798 | |||
| 1799 | if (*errp) { | ||
| 1800 | sctp_init_cause(*errp, SCTP_ERROR_PROTO_VIOLATION, | ||
| 1801 | sizeof(error) + sizeof(sctp_paramhdr_t)); | ||
| 1802 | sctp_addto_chunk(*errp, sizeof(error), error); | ||
| 1803 | sctp_addto_param(*errp, sizeof(sctp_paramhdr_t), param); | ||
| 1804 | } | ||
| 1805 | 1816 | ||
| 1806 | return 0; | 1817 | return 0; |
| 1807 | } | 1818 | } |
| @@ -1886,11 +1897,13 @@ static void sctp_process_ext_param(struct sctp_association *asoc, | |||
| 1886 | /* if the peer reports AUTH, assume that he | 1897 | /* if the peer reports AUTH, assume that he |
| 1887 | * supports AUTH. | 1898 | * supports AUTH. |
| 1888 | */ | 1899 | */ |
| 1889 | asoc->peer.auth_capable = 1; | 1900 | if (sctp_auth_enable) |
| 1901 | asoc->peer.auth_capable = 1; | ||
| 1890 | break; | 1902 | break; |
| 1891 | case SCTP_CID_ASCONF: | 1903 | case SCTP_CID_ASCONF: |
| 1892 | case SCTP_CID_ASCONF_ACK: | 1904 | case SCTP_CID_ASCONF_ACK: |
| 1893 | asoc->peer.asconf_capable = 1; | 1905 | if (sctp_addip_enable) |
| 1906 | asoc->peer.asconf_capable = 1; | ||
| 1894 | break; | 1907 | break; |
| 1895 | default: | 1908 | default: |
| 1896 | break; | 1909 | break; |
| @@ -2319,12 +2332,10 @@ clean_up: | |||
| 2319 | /* Release the transport structures. */ | 2332 | /* Release the transport structures. */ |
| 2320 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { | 2333 | list_for_each_safe(pos, temp, &asoc->peer.transport_addr_list) { |
| 2321 | transport = list_entry(pos, struct sctp_transport, transports); | 2334 | transport = list_entry(pos, struct sctp_transport, transports); |
| 2322 | list_del_init(pos); | 2335 | if (transport->state != SCTP_ACTIVE) |
| 2323 | sctp_transport_free(transport); | 2336 | sctp_assoc_rm_peer(asoc, transport); |
| 2324 | } | 2337 | } |
| 2325 | 2338 | ||
| 2326 | asoc->peer.transport_count = 0; | ||
| 2327 | |||
| 2328 | nomem: | 2339 | nomem: |
| 2329 | return 0; | 2340 | return 0; |
| 2330 | } | 2341 | } |
| @@ -2460,6 +2471,9 @@ do_addr_param: | |||
| 2460 | break; | 2471 | break; |
| 2461 | 2472 | ||
| 2462 | case SCTP_PARAM_SET_PRIMARY: | 2473 | case SCTP_PARAM_SET_PRIMARY: |
| 2474 | if (!sctp_addip_enable) | ||
| 2475 | goto fall_through; | ||
| 2476 | |||
| 2463 | addr_param = param.v + sizeof(sctp_addip_param_t); | 2477 | addr_param = param.v + sizeof(sctp_addip_param_t); |
| 2464 | 2478 | ||
| 2465 | af = sctp_get_af_specific(param_type2af(param.p->type)); | 2479 | af = sctp_get_af_specific(param_type2af(param.p->type)); |
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 8848d329aa2c..7c622af2ce55 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -119,7 +119,7 @@ static sctp_disposition_t sctp_sf_violation_paramlen( | |||
| 119 | const struct sctp_endpoint *ep, | 119 | const struct sctp_endpoint *ep, |
| 120 | const struct sctp_association *asoc, | 120 | const struct sctp_association *asoc, |
| 121 | const sctp_subtype_t type, | 121 | const sctp_subtype_t type, |
| 122 | void *arg, | 122 | void *arg, void *ext, |
| 123 | sctp_cmd_seq_t *commands); | 123 | sctp_cmd_seq_t *commands); |
| 124 | 124 | ||
| 125 | static sctp_disposition_t sctp_sf_violation_ctsn( | 125 | static sctp_disposition_t sctp_sf_violation_ctsn( |
| @@ -3425,7 +3425,7 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, | |||
| 3425 | addr_param = (union sctp_addr_param *)hdr->params; | 3425 | addr_param = (union sctp_addr_param *)hdr->params; |
| 3426 | length = ntohs(addr_param->p.length); | 3426 | length = ntohs(addr_param->p.length); |
| 3427 | if (length < sizeof(sctp_paramhdr_t)) | 3427 | if (length < sizeof(sctp_paramhdr_t)) |
| 3428 | return sctp_sf_violation_paramlen(ep, asoc, type, | 3428 | return sctp_sf_violation_paramlen(ep, asoc, type, arg, |
| 3429 | (void *)addr_param, commands); | 3429 | (void *)addr_param, commands); |
| 3430 | 3430 | ||
| 3431 | /* Verify the ASCONF chunk before processing it. */ | 3431 | /* Verify the ASCONF chunk before processing it. */ |
| @@ -3433,8 +3433,8 @@ sctp_disposition_t sctp_sf_do_asconf(const struct sctp_endpoint *ep, | |||
| 3433 | (sctp_paramhdr_t *)((void *)addr_param + length), | 3433 | (sctp_paramhdr_t *)((void *)addr_param + length), |
| 3434 | (void *)chunk->chunk_end, | 3434 | (void *)chunk->chunk_end, |
| 3435 | &err_param)) | 3435 | &err_param)) |
| 3436 | return sctp_sf_violation_paramlen(ep, asoc, type, | 3436 | return sctp_sf_violation_paramlen(ep, asoc, type, arg, |
| 3437 | (void *)&err_param, commands); | 3437 | (void *)err_param, commands); |
| 3438 | 3438 | ||
| 3439 | /* ADDIP 5.2 E1) Compare the value of the serial number to the value | 3439 | /* ADDIP 5.2 E1) Compare the value of the serial number to the value |
| 3440 | * the endpoint stored in a new association variable | 3440 | * the endpoint stored in a new association variable |
| @@ -3542,8 +3542,8 @@ sctp_disposition_t sctp_sf_do_asconf_ack(const struct sctp_endpoint *ep, | |||
| 3542 | (sctp_paramhdr_t *)addip_hdr->params, | 3542 | (sctp_paramhdr_t *)addip_hdr->params, |
| 3543 | (void *)asconf_ack->chunk_end, | 3543 | (void *)asconf_ack->chunk_end, |
| 3544 | &err_param)) | 3544 | &err_param)) |
| 3545 | return sctp_sf_violation_paramlen(ep, asoc, type, | 3545 | return sctp_sf_violation_paramlen(ep, asoc, type, arg, |
| 3546 | (void *)&err_param, commands); | 3546 | (void *)err_param, commands); |
| 3547 | 3547 | ||
| 3548 | if (last_asconf) { | 3548 | if (last_asconf) { |
| 3549 | addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr; | 3549 | addip_hdr = (sctp_addiphdr_t *)last_asconf->subh.addip_hdr; |
| @@ -4240,12 +4240,38 @@ static sctp_disposition_t sctp_sf_violation_paramlen( | |||
| 4240 | const struct sctp_endpoint *ep, | 4240 | const struct sctp_endpoint *ep, |
| 4241 | const struct sctp_association *asoc, | 4241 | const struct sctp_association *asoc, |
| 4242 | const sctp_subtype_t type, | 4242 | const sctp_subtype_t type, |
| 4243 | void *arg, | 4243 | void *arg, void *ext, |
| 4244 | sctp_cmd_seq_t *commands) { | 4244 | sctp_cmd_seq_t *commands) |
| 4245 | static const char err_str[] = "The following parameter had invalid length:"; | 4245 | { |
| 4246 | struct sctp_chunk *chunk = arg; | ||
| 4247 | struct sctp_paramhdr *param = ext; | ||
| 4248 | struct sctp_chunk *abort = NULL; | ||
| 4246 | 4249 | ||
| 4247 | return sctp_sf_abort_violation(ep, asoc, arg, commands, err_str, | 4250 | if (sctp_auth_recv_cid(SCTP_CID_ABORT, asoc)) |
| 4248 | sizeof(err_str)); | 4251 | goto discard; |
| 4252 | |||
| 4253 | /* Make the abort chunk. */ | ||
| 4254 | abort = sctp_make_violation_paramlen(asoc, chunk, param); | ||
| 4255 | if (!abort) | ||
| 4256 | goto nomem; | ||
| 4257 | |||
| 4258 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, SCTP_CHUNK(abort)); | ||
| 4259 | SCTP_INC_STATS(SCTP_MIB_OUTCTRLCHUNKS); | ||
| 4260 | |||
| 4261 | sctp_add_cmd_sf(commands, SCTP_CMD_SET_SK_ERR, | ||
| 4262 | SCTP_ERROR(ECONNABORTED)); | ||
| 4263 | sctp_add_cmd_sf(commands, SCTP_CMD_ASSOC_FAILED, | ||
| 4264 | SCTP_PERR(SCTP_ERROR_PROTO_VIOLATION)); | ||
| 4265 | SCTP_DEC_STATS(SCTP_MIB_CURRESTAB); | ||
| 4266 | |||
| 4267 | discard: | ||
| 4268 | sctp_sf_pdiscard(ep, asoc, SCTP_ST_CHUNK(0), arg, commands); | ||
| 4269 | |||
| 4270 | SCTP_INC_STATS(SCTP_MIB_ABORTEDS); | ||
| 4271 | |||
| 4272 | return SCTP_DISPOSITION_ABORT; | ||
| 4273 | nomem: | ||
| 4274 | return SCTP_DISPOSITION_NOMEM; | ||
| 4249 | } | 4275 | } |
| 4250 | 4276 | ||
| 4251 | /* Handle a protocol violation when the peer trying to advance the | 4277 | /* Handle a protocol violation when the peer trying to advance the |
diff --git a/net/sctp/socket.c b/net/sctp/socket.c index dbb79adf8f3c..5ffb9dec1c3f 100644 --- a/net/sctp/socket.c +++ b/net/sctp/socket.c | |||
| @@ -3055,6 +3055,9 @@ static int sctp_setsockopt_auth_chunk(struct sock *sk, | |||
| 3055 | { | 3055 | { |
| 3056 | struct sctp_authchunk val; | 3056 | struct sctp_authchunk val; |
| 3057 | 3057 | ||
| 3058 | if (!sctp_auth_enable) | ||
| 3059 | return -EACCES; | ||
| 3060 | |||
| 3058 | if (optlen != sizeof(struct sctp_authchunk)) | 3061 | if (optlen != sizeof(struct sctp_authchunk)) |
| 3059 | return -EINVAL; | 3062 | return -EINVAL; |
| 3060 | if (copy_from_user(&val, optval, optlen)) | 3063 | if (copy_from_user(&val, optval, optlen)) |
| @@ -3083,8 +3086,12 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, | |||
| 3083 | int optlen) | 3086 | int optlen) |
| 3084 | { | 3087 | { |
| 3085 | struct sctp_hmacalgo *hmacs; | 3088 | struct sctp_hmacalgo *hmacs; |
| 3089 | u32 idents; | ||
| 3086 | int err; | 3090 | int err; |
| 3087 | 3091 | ||
| 3092 | if (!sctp_auth_enable) | ||
| 3093 | return -EACCES; | ||
| 3094 | |||
| 3088 | if (optlen < sizeof(struct sctp_hmacalgo)) | 3095 | if (optlen < sizeof(struct sctp_hmacalgo)) |
| 3089 | return -EINVAL; | 3096 | return -EINVAL; |
| 3090 | 3097 | ||
| @@ -3097,8 +3104,9 @@ static int sctp_setsockopt_hmac_ident(struct sock *sk, | |||
| 3097 | goto out; | 3104 | goto out; |
| 3098 | } | 3105 | } |
| 3099 | 3106 | ||
| 3100 | if (hmacs->shmac_num_idents == 0 || | 3107 | idents = hmacs->shmac_num_idents; |
| 3101 | hmacs->shmac_num_idents > SCTP_AUTH_NUM_HMACS) { | 3108 | if (idents == 0 || idents > SCTP_AUTH_NUM_HMACS || |
| 3109 | (idents * sizeof(u16)) > (optlen - sizeof(struct sctp_hmacalgo))) { | ||
| 3102 | err = -EINVAL; | 3110 | err = -EINVAL; |
| 3103 | goto out; | 3111 | goto out; |
| 3104 | } | 3112 | } |
| @@ -3123,6 +3131,9 @@ static int sctp_setsockopt_auth_key(struct sock *sk, | |||
| 3123 | struct sctp_association *asoc; | 3131 | struct sctp_association *asoc; |
| 3124 | int ret; | 3132 | int ret; |
| 3125 | 3133 | ||
| 3134 | if (!sctp_auth_enable) | ||
| 3135 | return -EACCES; | ||
| 3136 | |||
| 3126 | if (optlen <= sizeof(struct sctp_authkey)) | 3137 | if (optlen <= sizeof(struct sctp_authkey)) |
| 3127 | return -EINVAL; | 3138 | return -EINVAL; |
| 3128 | 3139 | ||
| @@ -3135,6 +3146,11 @@ static int sctp_setsockopt_auth_key(struct sock *sk, | |||
| 3135 | goto out; | 3146 | goto out; |
| 3136 | } | 3147 | } |
| 3137 | 3148 | ||
| 3149 | if (authkey->sca_keylength > optlen - sizeof(struct sctp_authkey)) { | ||
| 3150 | ret = -EINVAL; | ||
| 3151 | goto out; | ||
| 3152 | } | ||
| 3153 | |||
| 3138 | asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); | 3154 | asoc = sctp_id2assoc(sk, authkey->sca_assoc_id); |
| 3139 | if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { | 3155 | if (!asoc && authkey->sca_assoc_id && sctp_style(sk, UDP)) { |
| 3140 | ret = -EINVAL; | 3156 | ret = -EINVAL; |
| @@ -3160,6 +3176,9 @@ static int sctp_setsockopt_active_key(struct sock *sk, | |||
| 3160 | struct sctp_authkeyid val; | 3176 | struct sctp_authkeyid val; |
| 3161 | struct sctp_association *asoc; | 3177 | struct sctp_association *asoc; |
| 3162 | 3178 | ||
| 3179 | if (!sctp_auth_enable) | ||
| 3180 | return -EACCES; | ||
| 3181 | |||
| 3163 | if (optlen != sizeof(struct sctp_authkeyid)) | 3182 | if (optlen != sizeof(struct sctp_authkeyid)) |
| 3164 | return -EINVAL; | 3183 | return -EINVAL; |
| 3165 | if (copy_from_user(&val, optval, optlen)) | 3184 | if (copy_from_user(&val, optval, optlen)) |
| @@ -3185,6 +3204,9 @@ static int sctp_setsockopt_del_key(struct sock *sk, | |||
| 3185 | struct sctp_authkeyid val; | 3204 | struct sctp_authkeyid val; |
| 3186 | struct sctp_association *asoc; | 3205 | struct sctp_association *asoc; |
| 3187 | 3206 | ||
| 3207 | if (!sctp_auth_enable) | ||
| 3208 | return -EACCES; | ||
| 3209 | |||
| 3188 | if (optlen != sizeof(struct sctp_authkeyid)) | 3210 | if (optlen != sizeof(struct sctp_authkeyid)) |
| 3189 | return -EINVAL; | 3211 | return -EINVAL; |
| 3190 | if (copy_from_user(&val, optval, optlen)) | 3212 | if (copy_from_user(&val, optval, optlen)) |
| @@ -5197,19 +5219,29 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len, | |||
| 5197 | static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, | 5219 | static int sctp_getsockopt_hmac_ident(struct sock *sk, int len, |
| 5198 | char __user *optval, int __user *optlen) | 5220 | char __user *optval, int __user *optlen) |
| 5199 | { | 5221 | { |
| 5222 | struct sctp_hmacalgo __user *p = (void __user *)optval; | ||
| 5200 | struct sctp_hmac_algo_param *hmacs; | 5223 | struct sctp_hmac_algo_param *hmacs; |
| 5201 | __u16 param_len; | 5224 | __u16 data_len = 0; |
| 5225 | u32 num_idents; | ||
| 5226 | |||
| 5227 | if (!sctp_auth_enable) | ||
| 5228 | return -EACCES; | ||
| 5202 | 5229 | ||
| 5203 | hmacs = sctp_sk(sk)->ep->auth_hmacs_list; | 5230 | hmacs = sctp_sk(sk)->ep->auth_hmacs_list; |
| 5204 | param_len = ntohs(hmacs->param_hdr.length); | 5231 | data_len = ntohs(hmacs->param_hdr.length) - sizeof(sctp_paramhdr_t); |
| 5205 | 5232 | ||
| 5206 | if (len < param_len) | 5233 | if (len < sizeof(struct sctp_hmacalgo) + data_len) |
| 5207 | return -EINVAL; | 5234 | return -EINVAL; |
| 5235 | |||
| 5236 | len = sizeof(struct sctp_hmacalgo) + data_len; | ||
| 5237 | num_idents = data_len / sizeof(u16); | ||
| 5238 | |||
| 5208 | if (put_user(len, optlen)) | 5239 | if (put_user(len, optlen)) |
| 5209 | return -EFAULT; | 5240 | return -EFAULT; |
| 5210 | if (copy_to_user(optval, hmacs->hmac_ids, len)) | 5241 | if (put_user(num_idents, &p->shmac_num_idents)) |
| 5242 | return -EFAULT; | ||
| 5243 | if (copy_to_user(p->shmac_idents, hmacs->hmac_ids, data_len)) | ||
| 5211 | return -EFAULT; | 5244 | return -EFAULT; |
| 5212 | |||
| 5213 | return 0; | 5245 | return 0; |
| 5214 | } | 5246 | } |
| 5215 | 5247 | ||
| @@ -5219,6 +5251,9 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len, | |||
| 5219 | struct sctp_authkeyid val; | 5251 | struct sctp_authkeyid val; |
| 5220 | struct sctp_association *asoc; | 5252 | struct sctp_association *asoc; |
| 5221 | 5253 | ||
| 5254 | if (!sctp_auth_enable) | ||
| 5255 | return -EACCES; | ||
| 5256 | |||
| 5222 | if (len < sizeof(struct sctp_authkeyid)) | 5257 | if (len < sizeof(struct sctp_authkeyid)) |
| 5223 | return -EINVAL; | 5258 | return -EINVAL; |
| 5224 | if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) | 5259 | if (copy_from_user(&val, optval, sizeof(struct sctp_authkeyid))) |
| @@ -5233,6 +5268,12 @@ static int sctp_getsockopt_active_key(struct sock *sk, int len, | |||
| 5233 | else | 5268 | else |
| 5234 | val.scact_keynumber = sctp_sk(sk)->ep->active_key_id; | 5269 | val.scact_keynumber = sctp_sk(sk)->ep->active_key_id; |
| 5235 | 5270 | ||
| 5271 | len = sizeof(struct sctp_authkeyid); | ||
| 5272 | if (put_user(len, optlen)) | ||
| 5273 | return -EFAULT; | ||
| 5274 | if (copy_to_user(optval, &val, len)) | ||
| 5275 | return -EFAULT; | ||
| 5276 | |||
| 5236 | return 0; | 5277 | return 0; |
| 5237 | } | 5278 | } |
| 5238 | 5279 | ||
| @@ -5243,13 +5284,16 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, | |||
| 5243 | struct sctp_authchunks val; | 5284 | struct sctp_authchunks val; |
| 5244 | struct sctp_association *asoc; | 5285 | struct sctp_association *asoc; |
| 5245 | struct sctp_chunks_param *ch; | 5286 | struct sctp_chunks_param *ch; |
| 5246 | u32 num_chunks; | 5287 | u32 num_chunks = 0; |
| 5247 | char __user *to; | 5288 | char __user *to; |
| 5248 | 5289 | ||
| 5249 | if (len <= sizeof(struct sctp_authchunks)) | 5290 | if (!sctp_auth_enable) |
| 5291 | return -EACCES; | ||
| 5292 | |||
| 5293 | if (len < sizeof(struct sctp_authchunks)) | ||
| 5250 | return -EINVAL; | 5294 | return -EINVAL; |
| 5251 | 5295 | ||
| 5252 | if (copy_from_user(&val, p, sizeof(struct sctp_authchunks))) | 5296 | if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) |
| 5253 | return -EFAULT; | 5297 | return -EFAULT; |
| 5254 | 5298 | ||
| 5255 | to = p->gauth_chunks; | 5299 | to = p->gauth_chunks; |
| @@ -5258,20 +5302,21 @@ static int sctp_getsockopt_peer_auth_chunks(struct sock *sk, int len, | |||
| 5258 | return -EINVAL; | 5302 | return -EINVAL; |
| 5259 | 5303 | ||
| 5260 | ch = asoc->peer.peer_chunks; | 5304 | ch = asoc->peer.peer_chunks; |
| 5305 | if (!ch) | ||
| 5306 | goto num; | ||
| 5261 | 5307 | ||
| 5262 | /* See if the user provided enough room for all the data */ | 5308 | /* See if the user provided enough room for all the data */ |
| 5263 | num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); | 5309 | num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); |
| 5264 | if (len < num_chunks) | 5310 | if (len < num_chunks) |
| 5265 | return -EINVAL; | 5311 | return -EINVAL; |
| 5266 | 5312 | ||
| 5267 | len = num_chunks; | 5313 | if (copy_to_user(to, ch->chunks, num_chunks)) |
| 5268 | if (put_user(len, optlen)) | ||
| 5269 | return -EFAULT; | 5314 | return -EFAULT; |
| 5315 | num: | ||
| 5316 | len = sizeof(struct sctp_authchunks) + num_chunks; | ||
| 5317 | if (put_user(len, optlen)) return -EFAULT; | ||
| 5270 | if (put_user(num_chunks, &p->gauth_number_of_chunks)) | 5318 | if (put_user(num_chunks, &p->gauth_number_of_chunks)) |
| 5271 | return -EFAULT; | 5319 | return -EFAULT; |
| 5272 | if (copy_to_user(to, ch->chunks, len)) | ||
| 5273 | return -EFAULT; | ||
| 5274 | |||
| 5275 | return 0; | 5320 | return 0; |
| 5276 | } | 5321 | } |
| 5277 | 5322 | ||
| @@ -5282,13 +5327,16 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, | |||
| 5282 | struct sctp_authchunks val; | 5327 | struct sctp_authchunks val; |
| 5283 | struct sctp_association *asoc; | 5328 | struct sctp_association *asoc; |
| 5284 | struct sctp_chunks_param *ch; | 5329 | struct sctp_chunks_param *ch; |
| 5285 | u32 num_chunks; | 5330 | u32 num_chunks = 0; |
| 5286 | char __user *to; | 5331 | char __user *to; |
| 5287 | 5332 | ||
| 5288 | if (len <= sizeof(struct sctp_authchunks)) | 5333 | if (!sctp_auth_enable) |
| 5334 | return -EACCES; | ||
| 5335 | |||
| 5336 | if (len < sizeof(struct sctp_authchunks)) | ||
| 5289 | return -EINVAL; | 5337 | return -EINVAL; |
| 5290 | 5338 | ||
| 5291 | if (copy_from_user(&val, p, sizeof(struct sctp_authchunks))) | 5339 | if (copy_from_user(&val, optval, sizeof(struct sctp_authchunks))) |
| 5292 | return -EFAULT; | 5340 | return -EFAULT; |
| 5293 | 5341 | ||
| 5294 | to = p->gauth_chunks; | 5342 | to = p->gauth_chunks; |
| @@ -5301,17 +5349,21 @@ static int sctp_getsockopt_local_auth_chunks(struct sock *sk, int len, | |||
| 5301 | else | 5349 | else |
| 5302 | ch = sctp_sk(sk)->ep->auth_chunk_list; | 5350 | ch = sctp_sk(sk)->ep->auth_chunk_list; |
| 5303 | 5351 | ||
| 5352 | if (!ch) | ||
| 5353 | goto num; | ||
| 5354 | |||
| 5304 | num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); | 5355 | num_chunks = ntohs(ch->param_hdr.length) - sizeof(sctp_paramhdr_t); |
| 5305 | if (len < num_chunks) | 5356 | if (len < sizeof(struct sctp_authchunks) + num_chunks) |
| 5306 | return -EINVAL; | 5357 | return -EINVAL; |
| 5307 | 5358 | ||
| 5308 | len = num_chunks; | 5359 | if (copy_to_user(to, ch->chunks, num_chunks)) |
| 5360 | return -EFAULT; | ||
| 5361 | num: | ||
| 5362 | len = sizeof(struct sctp_authchunks) + num_chunks; | ||
| 5309 | if (put_user(len, optlen)) | 5363 | if (put_user(len, optlen)) |
| 5310 | return -EFAULT; | 5364 | return -EFAULT; |
| 5311 | if (put_user(num_chunks, &p->gauth_number_of_chunks)) | 5365 | if (put_user(num_chunks, &p->gauth_number_of_chunks)) |
| 5312 | return -EFAULT; | 5366 | return -EFAULT; |
| 5313 | if (copy_to_user(to, ch->chunks, len)) | ||
| 5314 | return -EFAULT; | ||
| 5315 | 5367 | ||
| 5316 | return 0; | 5368 | return 0; |
| 5317 | } | 5369 | } |
