| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
|---|
| 1 | 2 | /* SCTP kernel implementation |
|---|
| 2 | 3 | * (C) Copyright IBM Corp. 2001, 2004 |
|---|
| 3 | 4 | * Copyright (c) 1999-2000 Cisco, Inc. |
|---|
| .. | .. |
|---|
| 8 | 9 | * This is part of the SCTP Linux Kernel Implementation. |
|---|
| 9 | 10 | * |
|---|
| 10 | 11 | * These are the state functions for the state machine. |
|---|
| 11 | | - * |
|---|
| 12 | | - * This SCTP implementation is free software; |
|---|
| 13 | | - * you can redistribute it and/or modify it under the terms of |
|---|
| 14 | | - * the GNU General Public License as published by |
|---|
| 15 | | - * the Free Software Foundation; either version 2, or (at your option) |
|---|
| 16 | | - * any later version. |
|---|
| 17 | | - * |
|---|
| 18 | | - * This SCTP implementation is distributed in the hope that it |
|---|
| 19 | | - * will be useful, but WITHOUT ANY WARRANTY; without even the implied |
|---|
| 20 | | - * ************************ |
|---|
| 21 | | - * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. |
|---|
| 22 | | - * See the GNU General Public License for more details. |
|---|
| 23 | | - * |
|---|
| 24 | | - * You should have received a copy of the GNU General Public License |
|---|
| 25 | | - * along with GNU CC; see the file COPYING. If not, see |
|---|
| 26 | | - * <http://www.gnu.org/licenses/>. |
|---|
| 27 | 12 | * |
|---|
| 28 | 13 | * Please send any bug reports or fixes you make to the |
|---|
| 29 | 14 | * email address(es): |
|---|
| .. | .. |
|---|
| 163 | 148 | const union sctp_subtype type, |
|---|
| 164 | 149 | void *arg, |
|---|
| 165 | 150 | struct sctp_cmd_seq *commands); |
|---|
| 151 | + |
|---|
| 152 | +static enum sctp_disposition |
|---|
| 153 | +__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep, |
|---|
| 154 | + const struct sctp_association *asoc, |
|---|
| 155 | + const union sctp_subtype type, void *arg, |
|---|
| 156 | + struct sctp_cmd_seq *commands); |
|---|
| 166 | 157 | |
|---|
| 167 | 158 | /* Small helper function that checks if the chunk length |
|---|
| 168 | 159 | * is of the appropriate length. The 'required_length' argument |
|---|
| .. | .. |
|---|
| 345 | 336 | if (!chunk->singleton) |
|---|
| 346 | 337 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 347 | 338 | |
|---|
| 339 | + /* Make sure that the INIT chunk has a valid length. |
|---|
| 340 | + * Normally, this would cause an ABORT with a Protocol Violation |
|---|
| 341 | + * error, but since we don't have an association, we'll |
|---|
| 342 | + * just discard the packet. |
|---|
| 343 | + */ |
|---|
| 344 | + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk))) |
|---|
| 345 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 346 | + |
|---|
| 348 | 347 | /* If the packet is an OOTB packet which is temporarily on the |
|---|
| 349 | 348 | * control endpoint, respond with an ABORT. |
|---|
| 350 | 349 | */ |
|---|
| .. | .. |
|---|
| 358 | 357 | */ |
|---|
| 359 | 358 | if (chunk->sctp_hdr->vtag != 0) |
|---|
| 360 | 359 | return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands); |
|---|
| 361 | | - |
|---|
| 362 | | - /* Make sure that the INIT chunk has a valid length. |
|---|
| 363 | | - * Normally, this would cause an ABORT with a Protocol Violation |
|---|
| 364 | | - * error, but since we don't have an association, we'll |
|---|
| 365 | | - * just discard the packet. |
|---|
| 366 | | - */ |
|---|
| 367 | | - if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk))) |
|---|
| 368 | | - return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 369 | 360 | |
|---|
| 370 | 361 | /* If the INIT is coming toward a closing socket, we'll send back |
|---|
| 371 | 362 | * and ABORT. Essentially, this catches the race of INIT being |
|---|
| .. | .. |
|---|
| 1349 | 1340 | struct sctp_chunk *init, |
|---|
| 1350 | 1341 | struct sctp_cmd_seq *commands) |
|---|
| 1351 | 1342 | { |
|---|
| 1352 | | - struct net *net = sock_net(new_asoc->base.sk); |
|---|
| 1343 | + struct net *net = new_asoc->base.net; |
|---|
| 1353 | 1344 | struct sctp_transport *new_addr; |
|---|
| 1354 | 1345 | int ret = 1; |
|---|
| 1355 | 1346 | |
|---|
| .. | .. |
|---|
| 1499 | 1490 | if (!chunk->singleton) |
|---|
| 1500 | 1491 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 1501 | 1492 | |
|---|
| 1493 | + /* Make sure that the INIT chunk has a valid length. */ |
|---|
| 1494 | + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk))) |
|---|
| 1495 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 1496 | + |
|---|
| 1502 | 1497 | /* 3.1 A packet containing an INIT chunk MUST have a zero Verification |
|---|
| 1503 | 1498 | * Tag. |
|---|
| 1504 | 1499 | */ |
|---|
| 1505 | 1500 | if (chunk->sctp_hdr->vtag != 0) |
|---|
| 1506 | 1501 | return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands); |
|---|
| 1507 | 1502 | |
|---|
| 1508 | | - /* Make sure that the INIT chunk has a valid length. |
|---|
| 1509 | | - * In this case, we generate a protocol violation since we have |
|---|
| 1510 | | - * an association established. |
|---|
| 1511 | | - */ |
|---|
| 1512 | | - if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk))) |
|---|
| 1513 | | - return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, |
|---|
| 1514 | | - commands); |
|---|
| 1515 | 1503 | /* Grab the INIT header. */ |
|---|
| 1516 | 1504 | chunk->subh.init_hdr = (struct sctp_inithdr *)chunk->skb->data; |
|---|
| 1517 | 1505 | |
|---|
| .. | .. |
|---|
| 1829 | 1817 | * its peer. |
|---|
| 1830 | 1818 | */ |
|---|
| 1831 | 1819 | if (sctp_state(asoc, SHUTDOWN_ACK_SENT)) { |
|---|
| 1832 | | - disposition = sctp_sf_do_9_2_reshutack(net, ep, asoc, |
|---|
| 1833 | | - SCTP_ST_CHUNK(chunk->chunk_hdr->type), |
|---|
| 1834 | | - chunk, commands); |
|---|
| 1820 | + disposition = __sctp_sf_do_9_2_reshutack(net, ep, asoc, |
|---|
| 1821 | + SCTP_ST_CHUNK(chunk->chunk_hdr->type), |
|---|
| 1822 | + chunk, commands); |
|---|
| 1835 | 1823 | if (SCTP_DISPOSITION_NOMEM == disposition) |
|---|
| 1836 | 1824 | goto nomem; |
|---|
| 1837 | 1825 | |
|---|
| .. | .. |
|---|
| 2301 | 2289 | */ |
|---|
| 2302 | 2290 | if (SCTP_ADDR_DEL == |
|---|
| 2303 | 2291 | sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest)) |
|---|
| 2304 | | - return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands); |
|---|
| 2292 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 2305 | 2293 | |
|---|
| 2306 | 2294 | if (!sctp_err_chunk_valid(chunk)) |
|---|
| 2307 | 2295 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| .. | .. |
|---|
| 2347 | 2335 | */ |
|---|
| 2348 | 2336 | if (SCTP_ADDR_DEL == |
|---|
| 2349 | 2337 | sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest)) |
|---|
| 2350 | | - return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands); |
|---|
| 2338 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 2351 | 2339 | |
|---|
| 2352 | 2340 | if (!sctp_err_chunk_valid(chunk)) |
|---|
| 2353 | 2341 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| .. | .. |
|---|
| 2617 | 2605 | */ |
|---|
| 2618 | 2606 | if (SCTP_ADDR_DEL == |
|---|
| 2619 | 2607 | sctp_bind_addr_state(&asoc->base.bind_addr, &chunk->dest)) |
|---|
| 2620 | | - return sctp_sf_discard_chunk(net, ep, asoc, type, arg, commands); |
|---|
| 2608 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 2621 | 2609 | |
|---|
| 2622 | 2610 | if (!sctp_err_chunk_valid(chunk)) |
|---|
| 2623 | 2611 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| .. | .. |
|---|
| 2930 | 2918 | * that belong to this association, it should discard the INIT chunk and |
|---|
| 2931 | 2919 | * retransmit the SHUTDOWN ACK chunk. |
|---|
| 2932 | 2920 | */ |
|---|
| 2933 | | -enum sctp_disposition sctp_sf_do_9_2_reshutack( |
|---|
| 2934 | | - struct net *net, |
|---|
| 2935 | | - const struct sctp_endpoint *ep, |
|---|
| 2936 | | - const struct sctp_association *asoc, |
|---|
| 2937 | | - const union sctp_subtype type, |
|---|
| 2938 | | - void *arg, |
|---|
| 2939 | | - struct sctp_cmd_seq *commands) |
|---|
| 2921 | +static enum sctp_disposition |
|---|
| 2922 | +__sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep, |
|---|
| 2923 | + const struct sctp_association *asoc, |
|---|
| 2924 | + const union sctp_subtype type, void *arg, |
|---|
| 2925 | + struct sctp_cmd_seq *commands) |
|---|
| 2940 | 2926 | { |
|---|
| 2941 | 2927 | struct sctp_chunk *chunk = arg; |
|---|
| 2942 | 2928 | struct sctp_chunk *reply; |
|---|
| .. | .. |
|---|
| 2968 | 2954 | return SCTP_DISPOSITION_CONSUME; |
|---|
| 2969 | 2955 | nomem: |
|---|
| 2970 | 2956 | return SCTP_DISPOSITION_NOMEM; |
|---|
| 2957 | +} |
|---|
| 2958 | + |
|---|
| 2959 | +enum sctp_disposition |
|---|
| 2960 | +sctp_sf_do_9_2_reshutack(struct net *net, const struct sctp_endpoint *ep, |
|---|
| 2961 | + const struct sctp_association *asoc, |
|---|
| 2962 | + const union sctp_subtype type, void *arg, |
|---|
| 2963 | + struct sctp_cmd_seq *commands) |
|---|
| 2964 | +{ |
|---|
| 2965 | + struct sctp_chunk *chunk = arg; |
|---|
| 2966 | + |
|---|
| 2967 | + if (!chunk->singleton) |
|---|
| 2968 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 2969 | + |
|---|
| 2970 | + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_init_chunk))) |
|---|
| 2971 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 2972 | + |
|---|
| 2973 | + if (chunk->sctp_hdr->vtag != 0) |
|---|
| 2974 | + return sctp_sf_tabort_8_4_8(net, ep, asoc, type, arg, commands); |
|---|
| 2975 | + |
|---|
| 2976 | + return __sctp_sf_do_9_2_reshutack(net, ep, asoc, type, arg, commands); |
|---|
| 2971 | 2977 | } |
|---|
| 2972 | 2978 | |
|---|
| 2973 | 2979 | /* |
|---|
| .. | .. |
|---|
| 3330 | 3336 | struct sctp_sackhdr *sackh; |
|---|
| 3331 | 3337 | __u32 ctsn; |
|---|
| 3332 | 3338 | |
|---|
| 3333 | | - trace_sctp_probe(ep, asoc, chunk); |
|---|
| 3334 | | - |
|---|
| 3335 | 3339 | if (!sctp_vtag_verify(chunk, asoc)) |
|---|
| 3336 | 3340 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 3337 | 3341 | |
|---|
| .. | .. |
|---|
| 3348 | 3352 | chunk->subh.sack_hdr = sackh; |
|---|
| 3349 | 3353 | ctsn = ntohl(sackh->cum_tsn_ack); |
|---|
| 3350 | 3354 | |
|---|
| 3355 | + /* If Cumulative TSN Ack beyond the max tsn currently |
|---|
| 3356 | + * send, terminating the association and respond to the |
|---|
| 3357 | + * sender with an ABORT. |
|---|
| 3358 | + */ |
|---|
| 3359 | + if (TSN_lte(asoc->next_tsn, ctsn)) |
|---|
| 3360 | + return sctp_sf_violation_ctsn(net, ep, asoc, type, arg, commands); |
|---|
| 3361 | + |
|---|
| 3362 | + trace_sctp_probe(ep, asoc, chunk); |
|---|
| 3363 | + |
|---|
| 3351 | 3364 | /* i) If Cumulative TSN Ack is less than the Cumulative TSN |
|---|
| 3352 | 3365 | * Ack Point, then drop the SACK. Since Cumulative TSN |
|---|
| 3353 | 3366 | * Ack is monotonically increasing, a SACK whose |
|---|
| .. | .. |
|---|
| 3360 | 3373 | |
|---|
| 3361 | 3374 | return SCTP_DISPOSITION_DISCARD; |
|---|
| 3362 | 3375 | } |
|---|
| 3363 | | - |
|---|
| 3364 | | - /* If Cumulative TSN Ack beyond the max tsn currently |
|---|
| 3365 | | - * send, terminating the association and respond to the |
|---|
| 3366 | | - * sender with an ABORT. |
|---|
| 3367 | | - */ |
|---|
| 3368 | | - if (!TSN_lt(ctsn, asoc->next_tsn)) |
|---|
| 3369 | | - return sctp_sf_violation_ctsn(net, ep, asoc, type, arg, commands); |
|---|
| 3370 | 3376 | |
|---|
| 3371 | 3377 | /* Return this SACK for further processing. */ |
|---|
| 3372 | 3378 | sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_SACK, SCTP_CHUNK(chunk)); |
|---|
| .. | .. |
|---|
| 3766 | 3772 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 3767 | 3773 | } |
|---|
| 3768 | 3774 | |
|---|
| 3775 | + /* Make sure that the ASCONF ADDIP chunk has a valid length. */ |
|---|
| 3776 | + if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_addip_chunk))) |
|---|
| 3777 | + return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, |
|---|
| 3778 | + commands); |
|---|
| 3779 | + |
|---|
| 3769 | 3780 | /* ADD-IP: Section 4.1.1 |
|---|
| 3770 | 3781 | * This chunk MUST be sent in an authenticated way by using |
|---|
| 3771 | 3782 | * the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk |
|---|
| 3772 | 3783 | * is received unauthenticated it MUST be silently discarded as |
|---|
| 3773 | 3784 | * described in [I-D.ietf-tsvwg-sctp-auth]. |
|---|
| 3774 | 3785 | */ |
|---|
| 3775 | | - if (!net->sctp.addip_noauth && !chunk->auth) |
|---|
| 3776 | | - return sctp_sf_discard_chunk(net, ep, asoc, type, arg, |
|---|
| 3777 | | - commands); |
|---|
| 3778 | | - |
|---|
| 3779 | | - /* Make sure that the ASCONF ADDIP chunk has a valid length. */ |
|---|
| 3780 | | - if (!sctp_chunk_length_valid(chunk, sizeof(struct sctp_addip_chunk))) |
|---|
| 3781 | | - return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, |
|---|
| 3782 | | - commands); |
|---|
| 3786 | + if (!asoc->peer.asconf_capable || |
|---|
| 3787 | + (!net->sctp.addip_noauth && !chunk->auth)) |
|---|
| 3788 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 3783 | 3789 | |
|---|
| 3784 | 3790 | hdr = (struct sctp_addiphdr *)chunk->skb->data; |
|---|
| 3785 | 3791 | serial = ntohl(hdr->serial); |
|---|
| .. | .. |
|---|
| 3908 | 3914 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 3909 | 3915 | } |
|---|
| 3910 | 3916 | |
|---|
| 3917 | + /* Make sure that the ADDIP chunk has a valid length. */ |
|---|
| 3918 | + if (!sctp_chunk_length_valid(asconf_ack, |
|---|
| 3919 | + sizeof(struct sctp_addip_chunk))) |
|---|
| 3920 | + return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, |
|---|
| 3921 | + commands); |
|---|
| 3922 | + |
|---|
| 3911 | 3923 | /* ADD-IP, Section 4.1.2: |
|---|
| 3912 | 3924 | * This chunk MUST be sent in an authenticated way by using |
|---|
| 3913 | 3925 | * the mechanism defined in [I-D.ietf-tsvwg-sctp-auth]. If this chunk |
|---|
| 3914 | 3926 | * is received unauthenticated it MUST be silently discarded as |
|---|
| 3915 | 3927 | * described in [I-D.ietf-tsvwg-sctp-auth]. |
|---|
| 3916 | 3928 | */ |
|---|
| 3917 | | - if (!net->sctp.addip_noauth && !asconf_ack->auth) |
|---|
| 3918 | | - return sctp_sf_discard_chunk(net, ep, asoc, type, arg, |
|---|
| 3919 | | - commands); |
|---|
| 3920 | | - |
|---|
| 3921 | | - /* Make sure that the ADDIP chunk has a valid length. */ |
|---|
| 3922 | | - if (!sctp_chunk_length_valid(asconf_ack, |
|---|
| 3923 | | - sizeof(struct sctp_addip_chunk))) |
|---|
| 3924 | | - return sctp_sf_violation_chunklen(net, ep, asoc, type, arg, |
|---|
| 3925 | | - commands); |
|---|
| 3929 | + if (!asoc->peer.asconf_capable || |
|---|
| 3930 | + (!net->sctp.addip_noauth && !asconf_ack->auth)) |
|---|
| 3931 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 3926 | 3932 | |
|---|
| 3927 | 3933 | addip_hdr = (struct sctp_addiphdr *)asconf_ack->skb->data; |
|---|
| 3928 | 3934 | rcvd_serial = ntohl(addip_hdr->serial); |
|---|
| .. | .. |
|---|
| 4350 | 4356 | sctp_add_cmd_sf(commands, SCTP_CMD_REPLY, |
|---|
| 4351 | 4357 | SCTP_CHUNK(err_chunk)); |
|---|
| 4352 | 4358 | } |
|---|
| 4353 | | - /* Fall Through */ |
|---|
| 4359 | + fallthrough; |
|---|
| 4354 | 4360 | case SCTP_IERROR_AUTH_BAD_KEYID: |
|---|
| 4355 | 4361 | case SCTP_IERROR_BAD_SIG: |
|---|
| 4356 | 4362 | return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| .. | .. |
|---|
| 4493 | 4499 | struct sctp_cmd_seq *commands) |
|---|
| 4494 | 4500 | { |
|---|
| 4495 | 4501 | struct sctp_chunk *chunk = arg; |
|---|
| 4502 | + |
|---|
| 4503 | + if (asoc && !sctp_vtag_verify(chunk, asoc)) |
|---|
| 4504 | + return sctp_sf_pdiscard(net, ep, asoc, type, arg, commands); |
|---|
| 4496 | 4505 | |
|---|
| 4497 | 4506 | /* Make sure that the chunk has a valid length. |
|---|
| 4498 | 4507 | * Since we don't know the chunk type, we use a general |
|---|
| .. | .. |
|---|
| 6471 | 6480 | * in sctp_ulpevent_make_rcvmsg will drop the frame if we grow our |
|---|
| 6472 | 6481 | * memory usage too much |
|---|
| 6473 | 6482 | */ |
|---|
| 6474 | | - if (*sk->sk_prot_creator->memory_pressure) { |
|---|
| 6483 | + if (sk_under_memory_pressure(sk)) { |
|---|
| 6475 | 6484 | if (sctp_tsnmap_has_gap(map) && |
|---|
| 6476 | 6485 | (sctp_tsnmap_get_ctsn(map) + 1) == tsn) { |
|---|
| 6477 | 6486 | pr_debug("%s: under pressure, reneging for tsn:%u\n", |
|---|
| 6478 | 6487 | __func__, tsn); |
|---|
| 6479 | 6488 | deliver = SCTP_CMD_RENEGE; |
|---|
| 6480 | | - } |
|---|
| 6489 | + } else { |
|---|
| 6490 | + sk_mem_reclaim(sk); |
|---|
| 6491 | + } |
|---|
| 6481 | 6492 | } |
|---|
| 6482 | 6493 | |
|---|
| 6483 | 6494 | /* |
|---|