From nobody Tue Feb 22 23:56:54 2022 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 1C43819CF1A4; Tue, 22 Feb 2022 23:56:55 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "R3" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4K3GKz0Hf1z4Spy; Tue, 22 Feb 2022 23:56:55 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1645574215; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Lk0u58w0Oy4wh95w/CIz4NIPph50T2AgWhvW9WQ4dhM=; b=bCvfVnAub+Tsr9MJ3OYqgBJaRaLDFiOeJEO2TMoBLG1laIyAOufOPcLVJ5HDSxqpkVxW7c GXTB45/LvSCu9nT8jVbFbHfcAO40bXs74s5XP0ln8RBdDVQ3vrJKmgBEyt/OsORa7pVHWI bdGAYcUJbDZc0DT55HNRybPPA8/jFqV2fNx1SPX0c3F9hYPD8dUypQO/Uywt3e4F0c+suq wQPFGTfjwL8s3doKI46fjiTlL3iS/Sc4/elVeSc5JgVIEKmCf+0ijGrK99krvIwi3H0/d7 S17swO2i0VuLpkvCBl/SVYcUMad9+Eufb5uEsXwN4WIP3kZ9+EXZ481Xe9drow== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (Client did not present a certificate) by mxrelay.nyi.freebsd.org (Postfix) with ESMTPS id DDBCA5BC9; Tue, 22 Feb 2022 23:56:54 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from gitrepo.freebsd.org ([127.0.1.44]) by gitrepo.freebsd.org (8.16.1/8.16.1) with ESMTP id 21MNusEt051631; Tue, 22 Feb 2022 23:56:54 GMT (envelope-from git@gitrepo.freebsd.org) Received: (from git@localhost) by gitrepo.freebsd.org (8.16.1/8.16.1/Submit) id 21MNusMi051630; Tue, 22 Feb 2022 23:56:54 GMT (envelope-from git) Date: Tue, 22 Feb 2022 23:56:54 GMT Message-Id: <202202222356.21MNusMi051630@gitrepo.freebsd.org> To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-branches@FreeBSD.org From: Michael Tuexen Subject: git: ff4150b9a549 - stable/13 - sctp: cleanup the SCTP_MAXSEG socket option. List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: Sender: owner-dev-commits-src-all@freebsd.org X-BeenThere: dev-commits-src-all@freebsd.org MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: tuexen X-Git-Repository: src X-Git-Refname: refs/heads/stable/13 X-Git-Reftype: branch X-Git-Commit: ff4150b9a549c8641c063868b0ce63cd691da0fc Auto-Submitted: auto-generated ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1645574215; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=Lk0u58w0Oy4wh95w/CIz4NIPph50T2AgWhvW9WQ4dhM=; b=ZqD/zcDp99PXqkKoKhrruM4eUXETChI8Y0UNV+pm/D1dV4ZyFwSzKMn67xtTmFOPW33eVP 88H8ncG1t7eqt1/Jtzdy6IeCXPGaLiPzavMfmEkotclmObE18aJwg7d9QVZPfWgtqoO5cg rMcvyJzdLznU0mkl0VAXcTODOnOTjH/OR+ROPgUTyhMhynZ2Kbz/4AWr/534vDCpnQ3583 eP1xUzA4QpGo24w6KZW1wviuO74yvpjb6rA1vx7t1n7xw4qNEVt7Df3wyqxPJAyENMPKjp j5SJ7YOdUnB5/tnqd8F/NNpcW9Rv90jd8PKEEheNuHBaFbd1xHMVc1UoeVRDmg== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1645574215; a=rsa-sha256; cv=none; b=Un54mYicwfLdUcycdJoZFXaDh6YBAifvvsVRgq7gPnXDZczaJsd3HcOxFtw7NcX8/YtEDf DX137dMbQfdtWw0VCvdFw+BC77aHUwBu+MNLZqGS5+spwGbi7koqqA3UBa3zAGPexXbfxg ASQ0qP/7wpDwtpMcXjCbObVyzYux24EuNbr0hPU2Cv5cM8Fq5fpCGV8BboqYgQmsZJ2rf8 HpzOuqCl4OxkZulcVy/VOCCokBlk/IlciaH0hD4Ibg+JmYoYMEAtr0BuS+rRFaT2RvqtNf fqllB7uBamtSfyxPKfyo3dSlMbw6zxxgGZlnRCgdvQj4tThlc0Nl18u1va2x6g== ARC-Authentication-Results: i=1; mx1.freebsd.org; none X-ThisMailContainsUnwantedMimeParts: N The branch stable/13 has been updated by tuexen: URL: https://cgit.FreeBSD.org/src/commit/?id=ff4150b9a549c8641c063868b0ce63cd691da0fc commit ff4150b9a549c8641c063868b0ce63cd691da0fc Author: Michael Tuexen AuthorDate: 2021-12-27 22:40:31 +0000 Commit: Michael Tuexen CommitDate: 2022-02-22 23:55:23 +0000 sctp: cleanup the SCTP_MAXSEG socket option. This patch makes the handling of the SCTP_MAXSEG socket option compliant with RFC 6458 (SCTP socket API) and fixes an issue found by syzkaller. Reported by: syzbot+a2791b89ab99121e3333@syzkaller.appspotmail.com (cherry picked from commit 989453da0589b8dc5c1948fd81f986a37ea385eb) --- sys/netinet/sctp_constants.h | 2 - sys/netinet/sctp_output.c | 93 ++++++++++++++++++++++++-------------------- sys/netinet/sctp_output.h | 2 +- sys/netinet/sctp_pcb.c | 2 +- sys/netinet/sctp_usrreq.c | 37 +++--------------- sys/netinet/sctputil.c | 2 +- 6 files changed, 59 insertions(+), 79 deletions(-) diff --git a/sys/netinet/sctp_constants.h b/sys/netinet/sctp_constants.h index 1ff3f3918ef6..66f2cca5ab6d 100644 --- a/sys/netinet/sctp_constants.h +++ b/sys/netinet/sctp_constants.h @@ -673,8 +673,6 @@ __FBSDID("$FreeBSD$"); /* amount peer is obligated to have in rwnd or I will abort */ #define SCTP_MIN_RWND 1500 -#define SCTP_DEFAULT_MAXSEGMENT 65535 - #define SCTP_CHUNK_BUFFER_SIZE 512 #define SCTP_PARAM_BUFFER_SIZE 512 diff --git a/sys/netinet/sctp_output.c b/sys/netinet/sctp_output.c index 31742e661279..598831220033 100644 --- a/sys/netinet/sctp_output.c +++ b/sys/netinet/sctp_output.c @@ -6217,43 +6217,48 @@ sctp_prune_prsctp(struct sctp_tcb *stcb, } /* if enabled in asoc */ } -int -sctp_get_frag_point(struct sctp_tcb *stcb, - struct sctp_association *asoc) +uint32_t +sctp_get_frag_point(struct sctp_tcb *stcb) { - int siz, ovh; + struct sctp_association *asoc; + uint32_t frag_point, overhead; - /* - * For endpoints that have both v6 and v4 addresses we must reserve - * room for the ipv6 header, for those that are only dealing with V4 - * we use a larger frag point. - */ + asoc = &stcb->asoc; + /* Consider IP header and SCTP common header. */ if (stcb->sctp_ep->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MIN_OVERHEAD; + overhead = SCTP_MIN_OVERHEAD; } else { - ovh = SCTP_MIN_V4_OVERHEAD; + overhead = SCTP_MIN_V4_OVERHEAD; } - ovh += SCTP_DATA_CHUNK_OVERHEAD(stcb); - if (stcb->asoc.sctp_frag_point > asoc->smallest_mtu) - siz = asoc->smallest_mtu - ovh; - else - siz = (stcb->asoc.sctp_frag_point - ovh); - /* - * if (siz > (MCLBYTES-sizeof(struct sctp_data_chunk))) { - */ - /* A data chunk MUST fit in a cluster */ - /* siz = (MCLBYTES - sizeof(struct sctp_data_chunk)); */ - /* } */ - - /* adjust for an AUTH chunk if DATA requires auth */ - if (sctp_auth_is_required_chunk(SCTP_DATA, stcb->asoc.peer_auth_chunks)) - siz -= sctp_get_auth_chunk_len(stcb->asoc.peer_hmac_id); + /* Consider DATA/IDATA chunk header and AUTH header, if needed. */ + if (asoc->idata_supported) { + overhead += sizeof(struct sctp_idata_chunk); + if (sctp_auth_is_required_chunk(SCTP_IDATA, asoc->peer_auth_chunks)) { + overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); + } + } else { + overhead += sizeof(struct sctp_idata_chunk); + if (sctp_auth_is_required_chunk(SCTP_DATA, asoc->peer_auth_chunks)) { + overhead += sctp_get_auth_chunk_len(asoc->peer_hmac_id); + } + } + /* Consider padding. */ + if (asoc->smallest_mtu % 4) { + overhead += (asoc->smallest_mtu % 4); + } + KASSERT(overhead % 4 == 0, + ("overhead (%u) not a multiple of 4", overhead)); + KASSERT(asoc->smallest_mtu > overhead, + ("Association MTU (%u) too small for overhead (%u)", + asoc->smallest_mtu, overhead)); - if (siz % 4) { - /* make it an even word boundary please */ - siz -= (siz % 4); + frag_point = asoc->smallest_mtu - overhead; + /* Honor MAXSEG socket option. */ + if ((asoc->sctp_frag_point > 0) && + (asoc->sctp_frag_point < frag_point)) { + frag_point = asoc->sctp_frag_point; } - return (siz); + return (frag_point); } static void @@ -6571,7 +6576,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, int *num_out, int *reason_code, int control_only, int from_where, - struct timeval *now, int *now_filled, int frag_point, int so_locked); + struct timeval *now, int *now_filled, + uint32_t frag_point, int so_locked); static void sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, @@ -6740,13 +6746,13 @@ sctp_sendall_iterator(struct sctp_inpcb *inp, struct sctp_tcb *stcb, void *ptr, if (do_chunk_output) sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_NOT_LOCKED); else if (added_control) { - int num_out, reason, now_filled = 0; struct timeval now; - int frag_point; + int num_out, reason, now_filled = 0; - frag_point = sctp_get_frag_point(stcb, &stcb->asoc); (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, - &reason, 1, 1, &now, &now_filled, frag_point, SCTP_SO_NOT_LOCKED); + &reason, 1, 1, &now, &now_filled, + sctp_get_frag_point(stcb), + SCTP_SO_NOT_LOCKED); } no_chunk_output: if (ret) { @@ -7674,8 +7680,9 @@ out_of: } static void -sctp_fill_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, int frag_point, - int eeor_mode, int *quit_now, int so_locked) +sctp_fill_outqueue(struct sctp_tcb *stcb, struct sctp_nets *net, + uint32_t frag_point, int eeor_mode, int *quit_now, + int so_locked) { struct sctp_association *asoc; struct sctp_stream_out *strq; @@ -7794,7 +7801,8 @@ sctp_med_chunk_output(struct sctp_inpcb *inp, int *num_out, int *reason_code, int control_only, int from_where, - struct timeval *now, int *now_filled, int frag_point, int so_locked) + struct timeval *now, int *now_filled, + uint32_t frag_point, int so_locked) { /** * Ok this is the generic chunk service queue. we must do the @@ -9975,7 +9983,7 @@ sctp_chunk_output(struct sctp_inpcb *inp, struct timeval now; int now_filled = 0; int nagle_on; - int frag_point = sctp_get_frag_point(stcb, &stcb->asoc); + uint32_t frag_point = sctp_get_frag_point(stcb); int un_sent = 0; int fr_done; unsigned int tot_frs = 0; @@ -13663,16 +13671,17 @@ skip_out_eof: } sctp_chunk_output(inp, stcb, SCTP_OUTPUT_FROM_USR_SEND, SCTP_SO_LOCKED); } else if (some_on_control) { - int num_out, reason, frag_point; + int num_out, reason; /* Here we do control only */ if (hold_tcblock == 0) { hold_tcblock = 1; SCTP_TCB_LOCK(stcb); } - frag_point = sctp_get_frag_point(stcb, &stcb->asoc); (void)sctp_med_chunk_output(inp, stcb, &stcb->asoc, &num_out, - &reason, 1, 1, &now, &now_filled, frag_point, SCTP_SO_LOCKED); + &reason, 1, 1, &now, &now_filled, + sctp_get_frag_point(stcb), + SCTP_SO_LOCKED); } NET_EPOCH_EXIT(et); SCTPDBG(SCTP_DEBUG_OUTPUT1, "USR Send complete qo:%d prw:%d unsent:%d tf:%d cooq:%d toqs:%d err:%d\n", diff --git a/sys/netinet/sctp_output.h b/sys/netinet/sctp_output.h index 7d2cdc4071d8..e6ee80c41f1a 100644 --- a/sys/netinet/sctp_output.h +++ b/sys/netinet/sctp_output.h @@ -117,7 +117,7 @@ void sctp_send_asconf(struct sctp_tcb *, struct sctp_nets *, int addr_locked); void sctp_send_asconf_ack(struct sctp_tcb *); -int sctp_get_frag_point(struct sctp_tcb *, struct sctp_association *); +uint32_t sctp_get_frag_point(struct sctp_tcb *); void sctp_toss_old_cookies(struct sctp_tcb *, struct sctp_association *); diff --git a/sys/netinet/sctp_pcb.c b/sys/netinet/sctp_pcb.c index e2460eba636a..176a35220688 100644 --- a/sys/netinet/sctp_pcb.c +++ b/sys/netinet/sctp_pcb.c @@ -2423,7 +2423,7 @@ sctp_inpcb_alloc(struct socket *so, uint32_t vrf_id) #endif inp->sctp_associd_counter = 1; inp->partial_delivery_point = SCTP_SB_LIMIT_RCV(so) >> SCTP_PARTIAL_DELIVERY_SHIFT; - inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; + inp->sctp_frag_point = 0; inp->max_cwnd = 0; inp->sctp_cmt_on_off = SCTP_BASE_SYSCTL(sctp_cmt_on_off); inp->ecn_supported = (uint8_t)SCTP_BASE_SYSCTL(sctp_ecn_enable); diff --git a/sys/netinet/sctp_usrreq.c b/sys/netinet/sctp_usrreq.c index 2450bde02986..a49bebc7edec 100644 --- a/sys/netinet/sctp_usrreq.c +++ b/sys/netinet/sctp_usrreq.c @@ -2032,13 +2032,12 @@ flags_out: case SCTP_MAXSEG: { struct sctp_assoc_value *av; - int ovh; SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, *optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); if (stcb) { - av->assoc_value = sctp_get_frag_point(stcb, &stcb->asoc); + av->assoc_value = stcb->asoc.sctp_frag_point; SCTP_TCB_UNLOCK(stcb); } else { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -2046,15 +2045,7 @@ flags_out: ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && (av->assoc_id == SCTP_FUTURE_ASSOC))) { SCTP_INP_RLOCK(inp); - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MED_OVERHEAD; - } else { - ovh = SCTP_MED_V4_OVERHEAD; - } - if (inp->sctp_frag_point >= SCTP_DEFAULT_MAXSEGMENT) - av->assoc_value = 0; - else - av->assoc_value = inp->sctp_frag_point - ovh; + av->assoc_value = inp->sctp_frag_point; SCTP_INP_RUNLOCK(inp); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); @@ -2623,7 +2614,7 @@ flags_out: stcb->asoc.cnt_on_all_streams); sstat->sstat_instrms = stcb->asoc.streamincnt; sstat->sstat_outstrms = stcb->asoc.streamoutcnt; - sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb, &stcb->asoc); + sstat->sstat_fragmentation_point = sctp_get_frag_point(stcb); net = stcb->asoc.primary_destination; if (net != NULL) { memcpy(&sstat->sstat_primary.spinfo_address, @@ -4977,22 +4968,12 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, case SCTP_MAXSEG: { struct sctp_assoc_value *av; - int ovh; SCTP_CHECK_AND_CAST(av, optval, struct sctp_assoc_value, optsize); SCTP_FIND_STCB(inp, stcb, av->assoc_id); - if (inp->sctp_flags & SCTP_PCB_FLAGS_BOUND_V6) { - ovh = SCTP_MED_OVERHEAD; - } else { - ovh = SCTP_MED_V4_OVERHEAD; - } if (stcb) { - if (av->assoc_value) { - stcb->asoc.sctp_frag_point = (av->assoc_value + ovh); - } else { - stcb->asoc.sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; - } + stcb->asoc.sctp_frag_point = av->assoc_value; SCTP_TCB_UNLOCK(stcb); } else { if ((inp->sctp_flags & SCTP_PCB_FLAGS_TCPTYPE) || @@ -5000,15 +4981,7 @@ sctp_setopt(struct socket *so, int optname, void *optval, size_t optsize, ((inp->sctp_flags & SCTP_PCB_FLAGS_UDPTYPE) && (av->assoc_id == SCTP_FUTURE_ASSOC))) { SCTP_INP_WLOCK(inp); - /* - * FIXME MT: I think this is not in - * tune with the API ID - */ - if (av->assoc_value) { - inp->sctp_frag_point = (av->assoc_value + ovh); - } else { - inp->sctp_frag_point = SCTP_DEFAULT_MAXSEGMENT; - } + inp->sctp_frag_point = av->assoc_value; SCTP_INP_WUNLOCK(inp); } else { SCTP_LTRACE_ERR_RET(inp, NULL, NULL, SCTP_FROM_SCTP_USRREQ, EINVAL); diff --git a/sys/netinet/sctputil.c b/sys/netinet/sctputil.c index 6c58ad47f274..df3768ca2a35 100644 --- a/sys/netinet/sctputil.c +++ b/sys/netinet/sctputil.c @@ -1248,7 +1248,7 @@ sctp_init_asoc(struct sctp_inpcb *inp, struct sctp_tcb *stcb, asoc->my_rwnd = max(SCTP_SB_LIMIT_RCV(inp->sctp_socket), SCTP_MINIMAL_RWND); asoc->peers_rwnd = SCTP_SB_LIMIT_RCV(inp->sctp_socket); - asoc->smallest_mtu = inp->sctp_frag_point; + asoc->smallest_mtu = 0; asoc->minrto = inp->sctp_ep.sctp_minrto; asoc->maxrto = inp->sctp_ep.sctp_maxrto;