diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c --- a/sys/kern/uipc_ktls.c +++ b/sys/kern/uipc_ktls.c @@ -1320,12 +1320,23 @@ return (error); } + /* + * Serialize with soreceive_generic() and make sure that we're not + * operating on a listening socket. + */ + error = SOCK_IO_RECV_LOCK(so, SBL_WAIT); + if (error) { + ktls_free(tls); + return (error); + } + /* Mark the socket as using TLS offload. */ SOCK_RECVBUF_LOCK(so); - if (SOLISTENING(so)) { + if (__predict_false(so->so_rcv.sb_tls_info != NULL)) { SOCK_RECVBUF_UNLOCK(so); + SOCK_IO_RECV_UNLOCK(so); ktls_free(tls); - return (EINVAL); + return (EALREADY); } so->so_rcv.sb_tls_seqno = be64dec(en->rec_seq); so->so_rcv.sb_tls_info = tls; @@ -1335,6 +1346,7 @@ sb_mark_notready(&so->so_rcv); ktls_check_rx(&so->so_rcv); SOCK_RECVBUF_UNLOCK(so); + SOCK_IO_RECV_UNLOCK(so); /* Prefer TOE -> ifnet TLS -> software TLS. */ #ifdef TCP_OFFLOAD @@ -1420,6 +1432,13 @@ inp = so->so_pcb; INP_WLOCK(inp); SOCK_SENDBUF_LOCK(so); + if (__predict_false(so->so_snd.sb_tls_info != NULL)) { + SOCK_SENDBUF_UNLOCK(so); + INP_WUNLOCK(inp); + SOCK_IO_SEND_UNLOCK(so); + ktls_free(tls); + return (EALREADY); + } so->so_snd.sb_tls_seqno = be64dec(en->rec_seq); so->so_snd.sb_tls_info = tls; if (tls->mode != TCP_TLS_MODE_SW) { diff --git a/sys/sys/sockbuf.h b/sys/sys/sockbuf.h --- a/sys/sys/sockbuf.h +++ b/sys/sys/sockbuf.h @@ -128,7 +128,8 @@ struct mbuf *sb_mtls; /* TLS mbuf chain */ struct mbuf *sb_mtlstail; /* last mbuf in TLS chain */ uint64_t sb_tls_seqno; /* TLS seqno */ - struct ktls_session *sb_tls_info; /* TLS state */ + /* TLS state, locked by sockbuf and sock I/O mutexes. */ + struct ktls_session *sb_tls_info; }; /* * PF_UNIX/SOCK_DGRAM diff --git a/tests/sys/kern/ktls_test.c b/tests/sys/kern/ktls_test.c --- a/tests/sys/kern/ktls_test.c +++ b/tests/sys/kern/ktls_test.c @@ -2812,7 +2812,7 @@ TLS_MINOR_VER_THREE, (uint64_t)random(), &en); ATF_REQUIRE_ERRNO(ENOTCONN, setsockopt(s, IPPROTO_TCP, TCP_TXTLS_ENABLE, &en, sizeof(en)) != 0); - ATF_REQUIRE_ERRNO(EINVAL, + ATF_REQUIRE_ERRNO(ENOTCONN, setsockopt(s, IPPROTO_TCP, TCP_RXTLS_ENABLE, &en, sizeof(en)) != 0); ATF_REQUIRE(close(s) == 0); }