diff --git a/sys/netinet/tcp_timewait.c b/sys/netinet/tcp_timewait.c index eaa2fa336a94..4f4ca445fa46 100644 --- a/sys/netinet/tcp_timewait.c +++ b/sys/netinet/tcp_timewait.c @@ -1,308 +1,318 @@ /*- * SPDX-License-Identifier: BSD-3-Clause * * Copyright (c) 1982, 1986, 1988, 1990, 1993, 1995 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "opt_inet.h" #include "opt_inet6.h" #include "opt_ipsec.h" +#include "opt_kern_tls.h" #include #include #include #include +#ifdef KERN_TLS +#include +#endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef INET6 #include #include #include #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include static u_int tcp_eff_msl(struct tcpcb *tp) { struct inpcb *inp = tptoinpcb(tp); #ifdef INET6 bool isipv6 = inp->inp_inc.inc_flags & INC_ISIPV6; #endif if ( #ifdef INET6 isipv6 ? in6_localip(&inp->in6p_faddr) : #endif #ifdef INET in_localip(inp->inp_faddr)) #else false) #endif return (V_tcp_msl_local); else return (V_tcp_msl); } /* * Move a TCP connection into TIME_WAIT state. * inp is locked, and is unlocked before returning. * * This function used to free tcpcb and allocate a compressed TCP time-wait * structure tcptw. This served well for 20 years but is no longer relevant * on modern machines in the modern internet. However, the function remains * so that TCP stacks require less modification and we don't burn the bridge * to go back to using compressed time-wait. */ void tcp_twstart(struct tcpcb *tp) { struct inpcb *inp = tptoinpcb(tp); NET_EPOCH_ASSERT(); INP_WLOCK_ASSERT(inp); MPASS(!(tp->t_flags & TF_DISCONNECTED)); tcp_state_change(tp, TCPS_TIME_WAIT); tcp_free_sackholes(tp); soisdisconnected(inp->inp_socket); +#ifdef KERN_TLS + /* release ktls snd tag now that no more data can be sent */ + if (tptosocket(tp)->so_snd.sb_tls_info != NULL) { + ktls_release_snd_tag(tptosocket(tp)->so_snd.sb_tls_info); + } +#endif if (tp->t_flags & TF_ACKNOW) (void) tcp_output(tp); tcp_timer_activate(tp, TT_2MSL, 2 * tcp_eff_msl(tp)); INP_WUNLOCK(inp); } /* * Returns true if the TIME_WAIT state was killed and we should start over, * looking for a pcb in the listen state. Otherwise returns false and frees * the mbuf. * * For pure SYN-segments the PCB shall be read-locked and the tcpopt pointer * may be NULL. For the rest write-lock and valid tcpopt. */ bool tcp_twcheck(struct inpcb *inp, struct tcpopt *to, struct tcphdr *th, struct mbuf *m, int tlen) { struct tcpcb *tp = intotcpcb(inp); char *s; int thflags; tcp_seq seq; NET_EPOCH_ASSERT(); INP_LOCK_ASSERT(inp); thflags = tcp_get_flags(th); #ifdef INVARIANTS if ((thflags & (TH_SYN | TH_ACK)) == TH_SYN) INP_RLOCK_ASSERT(inp); else { INP_WLOCK_ASSERT(inp); KASSERT(to != NULL, ("%s: called without options on a non-SYN segment", __func__)); } #endif /* * NOTE: for FIN_WAIT_2 (to be added later), * must validate sequence number before accepting RST */ /* * If the segment contains RST: * Drop the segment - see Stevens, vol. 2, p. 964 and * RFC 1337. */ if (thflags & TH_RST) goto drop; #if 0 /* PAWS not needed at the moment */ /* * RFC 1323 PAWS: If we have a timestamp reply on this segment * and it's less than ts_recent, drop it. */ if ((to.to_flags & TOF_TS) != 0 && tp->ts_recent && TSTMP_LT(to.to_tsval, tp->ts_recent)) { if ((thflags & TH_ACK) == 0) goto drop; goto ack; } /* * ts_recent is never updated because we never accept new segments. */ #endif /* Honor the drop_synfin sysctl variable. */ if ((thflags & TH_SYN) && (thflags & TH_FIN) && V_drop_synfin) { if ((s = tcp_log_addrs(&inp->inp_inc, th, NULL, NULL))) { log(LOG_DEBUG, "%s; %s: " "SYN|FIN segment ignored (based on " "sysctl setting)\n", s, __func__); free(s, M_TCPLOG); } goto drop; } /* * If a new connection request is received * while in TIME_WAIT, drop the old connection * and start over if allowed by RFC 6191. * Allow UDP port number changes in this case. */ if (((thflags & (TH_SYN | TH_ACK)) == TH_SYN) && ((((tp->t_flags & TF_RCVD_TSTMP) != 0) && ((to->to_flags & TOF_TS) != 0) && TSTMP_LT(tp->ts_recent, to->to_tsval)) || (((tp->t_flags & TF_RCVD_TSTMP) == 0) && ((to->to_flags & TOF_TS) != 0) && (V_tcp_tolerate_missing_ts == 0)) || SEQ_GT(th->th_seq, tp->rcv_nxt))) { /* * In case we can't upgrade our lock just pretend we have * lost this packet. */ if (INP_TRY_UPGRADE(inp) == 0) goto drop; if ((tp = tcp_close(tp)) != NULL) INP_WUNLOCK(inp); TCPSTAT_INC(tcps_tw_recycles); return (true); } /* * Send RST if UDP port numbers don't match */ if (tp->t_port != m->m_pkthdr.tcp_tun_port) { if (tcp_get_flags(th) & TH_ACK) { tcp_respond(tp, mtod(m, void *), th, m, (tcp_seq)0, th->th_ack, TH_RST); } else { if (tcp_get_flags(th) & TH_SYN) tlen++; if (tcp_get_flags(th) & TH_FIN) tlen++; tcp_respond(tp, mtod(m, void *), th, m, th->th_seq+tlen, (tcp_seq)0, TH_RST|TH_ACK); } INP_UNLOCK(inp); TCPSTAT_INC(tcps_tw_resets); return (false); } /* * Drop the segment if it does not contain an ACK. */ if ((thflags & TH_ACK) == 0) goto drop; INP_WLOCK_ASSERT(inp); /* * If timestamps were negotiated during SYN/ACK and a * segment without a timestamp is received, silently drop * the segment, unless the missing timestamps are tolerated. * See section 3.2 of RFC 7323. */ if (((to->to_flags & TOF_TS) == 0) && (tp->ts_recent != 0) && (V_tcp_tolerate_missing_ts == 0)) { goto drop; } /* * Reset the 2MSL timer if this is a duplicate FIN. */ if (thflags & TH_FIN) { seq = th->th_seq + tlen + (thflags & TH_SYN ? 1 : 0); if (seq + 1 == tp->rcv_nxt) tcp_timer_activate(tp, TT_2MSL, 2 * tcp_eff_msl(tp)); } /* * Acknowledge the segment if it has data or is not a duplicate ACK. */ if ((thflags & (TH_SYN | TH_FIN)) != 0 || tlen != 0 || th->th_seq != tp->rcv_nxt || th->th_ack != tp->snd_nxt) { TCP_LOG_EVENT(tp, th, NULL, NULL, TCP_LOG_IN, 0, tlen, NULL, true); TCP_PROBE5(receive, NULL, NULL, m, NULL, th); tcp_respond(tp, mtod(m, void *), th, m, tp->rcv_nxt, tp->snd_nxt, TH_ACK); INP_UNLOCK(inp); TCPSTAT_INC(tcps_tw_responds); return (false); } drop: TCP_PROBE5(receive, NULL, NULL, m, NULL, th); INP_UNLOCK(inp); m_freem(m); return (false); } diff --git a/sys/sys/ktls.h b/sys/sys/ktls.h index 6c7e7d3c5ee3..3e3f0b77e4a2 100644 --- a/sys/sys/ktls.h +++ b/sys/sys/ktls.h @@ -1,294 +1,306 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * * Copyright (c) 2014-2019 Netflix Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #ifndef _SYS_KTLS_H_ #define _SYS_KTLS_H_ #ifdef _KERNEL +#include #include #include #include #include #endif struct tls_record_layer { uint8_t tls_type; uint8_t tls_vmajor; uint8_t tls_vminor; uint16_t tls_length; uint8_t tls_data[0]; } __attribute__ ((packed)); #define TLS_MAX_MSG_SIZE_V10_2 16384 #define TLS_MAX_PARAM_SIZE 1024 /* Max key/mac/iv in sockopt */ #define TLS_AEAD_GCM_LEN 4 #define TLS_1_3_GCM_IV_LEN 12 #define TLS_CHACHA20_IV_LEN 12 #define TLS_CBC_IMPLICIT_IV_LEN 16 /* Type values for the record layer */ #define TLS_RLTYPE_ALERT 21 #define TLS_RLTYPE_HANDSHAKE 22 #define TLS_RLTYPE_APP 23 /* * Nonce for GCM for TLS 1.2 per RFC 5288. */ struct tls_nonce_data { uint8_t fixed[TLS_AEAD_GCM_LEN]; uint64_t seq; } __packed; /* * AEAD additional data format for TLS 1.2 per RFC 5246. */ struct tls_aead_data { uint64_t seq; /* In network order */ uint8_t type; uint8_t tls_vmajor; uint8_t tls_vminor; uint16_t tls_length; } __packed; /* * AEAD additional data format for TLS 1.3 per RFC 8446. */ struct tls_aead_data_13 { uint8_t type; uint8_t tls_vmajor; uint8_t tls_vminor; uint16_t tls_length; } __packed; /* * Stream Cipher MAC additional data input. This does not match the * exact data on the wire (the sequence number is not placed on the * wire, and any explicit IV after the record header is not covered by * the MAC). */ struct tls_mac_data { uint64_t seq; uint8_t type; uint8_t tls_vmajor; uint8_t tls_vminor; uint16_t tls_length; } __packed; #define TLS_MAJOR_VER_ONE 3 #define TLS_MINOR_VER_ZERO 1 /* 3, 1 */ #define TLS_MINOR_VER_ONE 2 /* 3, 2 */ #define TLS_MINOR_VER_TWO 3 /* 3, 3 */ #define TLS_MINOR_VER_THREE 4 /* 3, 4 */ /* For TCP_TXTLS_ENABLE and TCP_RXTLS_ENABLE. */ #ifdef _KERNEL struct tls_enable_v0 { const uint8_t *cipher_key; const uint8_t *iv; /* Implicit IV. */ const uint8_t *auth_key; int cipher_algorithm; /* e.g. CRYPTO_AES_CBC */ int cipher_key_len; int iv_len; int auth_algorithm; /* e.g. CRYPTO_SHA2_256_HMAC */ int auth_key_len; int flags; uint8_t tls_vmajor; uint8_t tls_vminor; }; #endif struct tls_enable { const uint8_t *cipher_key; const uint8_t *iv; /* Implicit IV. */ const uint8_t *auth_key; int cipher_algorithm; /* e.g. CRYPTO_AES_CBC */ int cipher_key_len; int iv_len; int auth_algorithm; /* e.g. CRYPTO_SHA2_256_HMAC */ int auth_key_len; int flags; uint8_t tls_vmajor; uint8_t tls_vminor; uint8_t rec_seq[8]; }; /* Structure for TLS_GET_RECORD. */ struct tls_get_record { /* TLS record header. */ uint8_t tls_type; uint8_t tls_vmajor; uint8_t tls_vminor; uint16_t tls_length; }; #define XKTLS_SESSION_IV_BUF_LEN 32 struct xktls_session_onedir { uint64_t gen; uint64_t rsrv1[8]; uint32_t rsrv2[8]; uint8_t iv[XKTLS_SESSION_IV_BUF_LEN]; int cipher_algorithm; int auth_algorithm; uint16_t cipher_key_len; uint16_t iv_len; uint16_t auth_key_len; uint16_t max_frame_len; uint8_t tls_vmajor; uint8_t tls_vminor; uint8_t tls_hlen; uint8_t tls_tlen; uint8_t tls_bs; uint8_t flags; uint16_t drv_st_len; char ifnet[16]; /* IFNAMSIZ */ }; #ifdef _KERNEL struct tls_session_params { uint8_t *cipher_key; uint8_t *auth_key; uint8_t iv[TLS_CBC_IMPLICIT_IV_LEN]; int cipher_algorithm; int auth_algorithm; uint16_t cipher_key_len; uint16_t iv_len; uint16_t auth_key_len; uint16_t max_frame_len; uint8_t tls_vmajor; uint8_t tls_vminor; uint8_t tls_hlen; uint8_t tls_tlen; uint8_t tls_bs; uint8_t flags; }; /* Used in APIs to request RX vs TX sessions. */ #define KTLS_TX 1 #define KTLS_RX 2 struct iovec; struct ktls_ocf_encrypt_state; struct ktls_ocf_session; struct ktls_session; struct m_snd_tag; struct mbuf; struct sockbuf; struct socket; struct sockopt; struct ktls_session { struct ktls_ocf_session *ocf_session; struct m_snd_tag *snd_tag; struct tls_session_params params; u_int wq_index; volatile u_int refcount; int mode; struct task reset_tag_task; struct task disable_ifnet_task; union { struct inpcb *inp; /* Used by transmit tasks. */ struct socket *so; /* Used by receive task. */ }; struct ifnet *rx_ifp; u_short rx_vlan_id; bool reset_pending; bool tx; bool sync_dispatch; bool sequential_records; union { /* Only used for TLS 1.0. */ uint64_t next_seqno; /* Needed by some ktls offload NICs */ uint64_t initial_offload_seqno; }; STAILQ_HEAD(, mbuf) pending_records; /* Used to destroy any kTLS session */ struct task destroy_task; uint64_t gen; } __aligned(CACHE_LINE_SIZE); extern unsigned int ktls_ifnet_max_rexmit_pct; typedef enum { KTLS_MBUF_CRYPTO_ST_MIXED = 0, KTLS_MBUF_CRYPTO_ST_ENCRYPTED = 1, KTLS_MBUF_CRYPTO_ST_DECRYPTED = -1, } ktls_mbuf_crypto_st_t; void ktls_check_rx(struct sockbuf *sb); void ktls_cleanup_tls_enable(struct tls_enable *tls); int ktls_copyin_tls_enable(struct sockopt *sopt, struct tls_enable *tls); void ktls_disable_ifnet(void *arg); int ktls_enable_rx(struct socket *so, struct tls_enable *en); int ktls_enable_tx(struct socket *so, struct tls_enable *en); void ktls_enqueue(struct mbuf *m, struct socket *so, int page_count); void ktls_enqueue_to_free(struct mbuf *m); void ktls_destroy(struct ktls_session *tls); void ktls_frame(struct mbuf *m, struct ktls_session *tls, int *enqueue_cnt, uint8_t record_type); int ktls_get_rx_mode(struct socket *so, int *modep); int ktls_get_tx_mode(struct socket *so, int *modep); int ktls_get_rx_sequence(struct inpcb *inp, uint32_t *tcpseq, uint64_t *tlsseq); void ktls_input_ifp_mismatch(struct sockbuf *sb, struct ifnet *ifp); ktls_mbuf_crypto_st_t ktls_mbuf_crypto_state(struct mbuf *mb, int offset, int len); #ifdef RATELIMIT int ktls_modify_txrtlmt(struct ktls_session *tls, uint64_t max_pacing_rate); #endif int ktls_output_eagain(struct inpcb *inp, struct ktls_session *tls); bool ktls_pending_rx_info(struct sockbuf *sb, uint64_t *seqnop, size_t *residp); bool ktls_permit_empty_frames(struct ktls_session *tls); void ktls_seq(struct sockbuf *sb, struct mbuf *m); int ktls_set_tx_mode(struct socket *so, int mode); static inline struct ktls_session * ktls_hold(struct ktls_session *tls) { if (tls != NULL) refcount_acquire(&tls->refcount); return (tls); } static inline void ktls_free(struct ktls_session *tls) { if (refcount_release(&tls->refcount)) ktls_destroy(tls); } +static inline void +ktls_release_snd_tag(struct ktls_session *tls) +{ + struct m_snd_tag *mst; + + mst = tls->snd_tag; + tls->snd_tag = NULL; + if (mst != NULL) + m_snd_tag_rele(mst); +} + void ktls_session_to_xktls_onedir(const struct ktls_session *ks, bool export_keys, struct xktls_session_onedir *xktls_od); void ktls_session_copy_keys(const struct ktls_session *ktls, uint8_t *data, size_t *sz); #endif /* !_KERNEL */ #endif /* !_SYS_KTLS_H_ */