diff options
Diffstat (limited to 'net/sctp/sm_statefuns.c')
| -rw-r--r-- | net/sctp/sm_statefuns.c | 86 |
1 files changed, 46 insertions, 40 deletions
diff --git a/net/sctp/sm_statefuns.c b/net/sctp/sm_statefuns.c index 28c070e187c2..c9ae3404b1bb 100644 --- a/net/sctp/sm_statefuns.c +++ b/net/sctp/sm_statefuns.c | |||
| @@ -153,10 +153,7 @@ static enum sctp_disposition sctp_sf_violation_chunk( | |||
| 153 | struct sctp_cmd_seq *commands); | 153 | struct sctp_cmd_seq *commands); |
| 154 | 154 | ||
| 155 | static enum sctp_ierror sctp_sf_authenticate( | 155 | static enum sctp_ierror sctp_sf_authenticate( |
| 156 | struct net *net, | ||
| 157 | const struct sctp_endpoint *ep, | ||
| 158 | const struct sctp_association *asoc, | 156 | const struct sctp_association *asoc, |
| 159 | const union sctp_subtype type, | ||
| 160 | struct sctp_chunk *chunk); | 157 | struct sctp_chunk *chunk); |
| 161 | 158 | ||
| 162 | static enum sctp_disposition __sctp_sf_do_9_1_abort( | 159 | static enum sctp_disposition __sctp_sf_do_9_1_abort( |
| @@ -626,6 +623,38 @@ enum sctp_disposition sctp_sf_do_5_1C_ack(struct net *net, | |||
| 626 | return SCTP_DISPOSITION_CONSUME; | 623 | return SCTP_DISPOSITION_CONSUME; |
| 627 | } | 624 | } |
| 628 | 625 | ||
| 626 | static bool sctp_auth_chunk_verify(struct net *net, struct sctp_chunk *chunk, | ||
| 627 | const struct sctp_association *asoc) | ||
| 628 | { | ||
| 629 | struct sctp_chunk auth; | ||
| 630 | |||
| 631 | if (!chunk->auth_chunk) | ||
| 632 | return true; | ||
| 633 | |||
| 634 | /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo | ||
| 635 | * is supposed to be authenticated and we have to do delayed | ||
| 636 | * authentication. We've just recreated the association using | ||
| 637 | * the information in the cookie and now it's much easier to | ||
| 638 | * do the authentication. | ||
| 639 | */ | ||
| 640 | |||
| 641 | /* Make sure that we and the peer are AUTH capable */ | ||
| 642 | if (!net->sctp.auth_enable || !asoc->peer.auth_capable) | ||
| 643 | return false; | ||
| 644 | |||
| 645 | /* set-up our fake chunk so that we can process it */ | ||
| 646 | auth.skb = chunk->auth_chunk; | ||
| 647 | auth.asoc = chunk->asoc; | ||
| 648 | auth.sctp_hdr = chunk->sctp_hdr; | ||
| 649 | auth.chunk_hdr = (struct sctp_chunkhdr *) | ||
| 650 | skb_push(chunk->auth_chunk, | ||
| 651 | sizeof(struct sctp_chunkhdr)); | ||
| 652 | skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr)); | ||
| 653 | auth.transport = chunk->transport; | ||
| 654 | |||
| 655 | return sctp_sf_authenticate(asoc, &auth) == SCTP_IERROR_NO_ERROR; | ||
| 656 | } | ||
| 657 | |||
| 629 | /* | 658 | /* |
| 630 | * Respond to a normal COOKIE ECHO chunk. | 659 | * Respond to a normal COOKIE ECHO chunk. |
| 631 | * We are the side that is being asked for an association. | 660 | * We are the side that is being asked for an association. |
| @@ -763,37 +792,9 @@ enum sctp_disposition sctp_sf_do_5_1D_ce(struct net *net, | |||
| 763 | if (error) | 792 | if (error) |
| 764 | goto nomem_init; | 793 | goto nomem_init; |
| 765 | 794 | ||
| 766 | /* SCTP-AUTH: auth_chunk pointer is only set when the cookie-echo | 795 | if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) { |
| 767 | * is supposed to be authenticated and we have to do delayed | 796 | sctp_association_free(new_asoc); |
| 768 | * authentication. We've just recreated the association using | 797 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
| 769 | * the information in the cookie and now it's much easier to | ||
| 770 | * do the authentication. | ||
| 771 | */ | ||
| 772 | if (chunk->auth_chunk) { | ||
| 773 | struct sctp_chunk auth; | ||
| 774 | enum sctp_ierror ret; | ||
| 775 | |||
| 776 | /* Make sure that we and the peer are AUTH capable */ | ||
| 777 | if (!net->sctp.auth_enable || !new_asoc->peer.auth_capable) { | ||
| 778 | sctp_association_free(new_asoc); | ||
| 779 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); | ||
| 780 | } | ||
| 781 | |||
| 782 | /* set-up our fake chunk so that we can process it */ | ||
| 783 | auth.skb = chunk->auth_chunk; | ||
| 784 | auth.asoc = chunk->asoc; | ||
| 785 | auth.sctp_hdr = chunk->sctp_hdr; | ||
| 786 | auth.chunk_hdr = (struct sctp_chunkhdr *) | ||
| 787 | skb_push(chunk->auth_chunk, | ||
| 788 | sizeof(struct sctp_chunkhdr)); | ||
| 789 | skb_pull(chunk->auth_chunk, sizeof(struct sctp_chunkhdr)); | ||
| 790 | auth.transport = chunk->transport; | ||
| 791 | |||
| 792 | ret = sctp_sf_authenticate(net, ep, new_asoc, type, &auth); | ||
| 793 | if (ret != SCTP_IERROR_NO_ERROR) { | ||
| 794 | sctp_association_free(new_asoc); | ||
| 795 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); | ||
| 796 | } | ||
| 797 | } | 798 | } |
| 798 | 799 | ||
| 799 | repl = sctp_make_cookie_ack(new_asoc, chunk); | 800 | repl = sctp_make_cookie_ack(new_asoc, chunk); |
| @@ -1797,13 +1798,15 @@ static enum sctp_disposition sctp_sf_do_dupcook_a( | |||
| 1797 | if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC)) | 1798 | if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC)) |
| 1798 | goto nomem; | 1799 | goto nomem; |
| 1799 | 1800 | ||
| 1801 | if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) | ||
| 1802 | return SCTP_DISPOSITION_DISCARD; | ||
| 1803 | |||
| 1800 | /* Make sure no new addresses are being added during the | 1804 | /* Make sure no new addresses are being added during the |
| 1801 | * restart. Though this is a pretty complicated attack | 1805 | * restart. Though this is a pretty complicated attack |
| 1802 | * since you'd have to get inside the cookie. | 1806 | * since you'd have to get inside the cookie. |
| 1803 | */ | 1807 | */ |
| 1804 | if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) { | 1808 | if (!sctp_sf_check_restart_addrs(new_asoc, asoc, chunk, commands)) |
| 1805 | return SCTP_DISPOSITION_CONSUME; | 1809 | return SCTP_DISPOSITION_CONSUME; |
| 1806 | } | ||
| 1807 | 1810 | ||
| 1808 | /* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes | 1811 | /* If the endpoint is in the SHUTDOWN-ACK-SENT state and recognizes |
| 1809 | * the peer has restarted (Action A), it MUST NOT setup a new | 1812 | * the peer has restarted (Action A), it MUST NOT setup a new |
| @@ -1912,6 +1915,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_b( | |||
| 1912 | if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC)) | 1915 | if (sctp_auth_asoc_init_active_key(new_asoc, GFP_ATOMIC)) |
| 1913 | goto nomem; | 1916 | goto nomem; |
| 1914 | 1917 | ||
| 1918 | if (!sctp_auth_chunk_verify(net, chunk, new_asoc)) | ||
| 1919 | return SCTP_DISPOSITION_DISCARD; | ||
| 1920 | |||
| 1915 | /* Update the content of current association. */ | 1921 | /* Update the content of current association. */ |
| 1916 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); | 1922 | sctp_add_cmd_sf(commands, SCTP_CMD_UPDATE_ASSOC, SCTP_ASOC(new_asoc)); |
| 1917 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, | 1923 | sctp_add_cmd_sf(commands, SCTP_CMD_NEW_STATE, |
| @@ -2009,6 +2015,9 @@ static enum sctp_disposition sctp_sf_do_dupcook_d( | |||
| 2009 | * a COOKIE ACK. | 2015 | * a COOKIE ACK. |
| 2010 | */ | 2016 | */ |
| 2011 | 2017 | ||
| 2018 | if (!sctp_auth_chunk_verify(net, chunk, asoc)) | ||
| 2019 | return SCTP_DISPOSITION_DISCARD; | ||
| 2020 | |||
| 2012 | /* Don't accidentally move back into established state. */ | 2021 | /* Don't accidentally move back into established state. */ |
| 2013 | if (asoc->state < SCTP_STATE_ESTABLISHED) { | 2022 | if (asoc->state < SCTP_STATE_ESTABLISHED) { |
| 2014 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, | 2023 | sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP, |
| @@ -4171,10 +4180,7 @@ gen_shutdown: | |||
| 4171 | * The return value is the disposition of the chunk. | 4180 | * The return value is the disposition of the chunk. |
| 4172 | */ | 4181 | */ |
| 4173 | static enum sctp_ierror sctp_sf_authenticate( | 4182 | static enum sctp_ierror sctp_sf_authenticate( |
| 4174 | struct net *net, | ||
| 4175 | const struct sctp_endpoint *ep, | ||
| 4176 | const struct sctp_association *asoc, | 4183 | const struct sctp_association *asoc, |
| 4177 | const union sctp_subtype type, | ||
| 4178 | struct sctp_chunk *chunk) | 4184 | struct sctp_chunk *chunk) |
| 4179 | { | 4185 | { |
| 4180 | struct sctp_shared_key *sh_key = NULL; | 4186 | struct sctp_shared_key *sh_key = NULL; |
| @@ -4275,7 +4281,7 @@ enum sctp_disposition sctp_sf_eat_auth(struct net *net, | |||
| 4275 | commands); | 4281 | commands); |
| 4276 | 4282 | ||
| 4277 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; | 4283 | auth_hdr = (struct sctp_authhdr *)chunk->skb->data; |
| 4278 | error = sctp_sf_authenticate(net, ep, asoc, type, chunk); | 4284 | error = sctp_sf_authenticate(asoc, chunk); |
| 4279 | switch (error) { | 4285 | switch (error) { |
| 4280 | case SCTP_IERROR_AUTH_BAD_HMAC: | 4286 | case SCTP_IERROR_AUTH_BAD_HMAC: |
| 4281 | /* Generate the ERROR chunk and discard the rest | 4287 | /* Generate the ERROR chunk and discard the rest |
