git: 69542f26820b - main - ktls: Close a race with setting so_error when dropping a connection.

From: John Baldwin <jhb_at_FreeBSD.org>
Date: Thu, 15 Dec 2022 20:07:00 UTC
The branch main has been updated by jhb:

URL: https://cgit.FreeBSD.org/src/commit/?id=69542f26820b7edb8351398b36edda5299c1db56

commit 69542f26820b7edb8351398b36edda5299c1db56
Author:     John Baldwin <jhb@FreeBSD.org>
AuthorDate: 2022-12-15 20:06:26 +0000
Commit:     John Baldwin <jhb@FreeBSD.org>
CommitDate: 2022-12-15 20:06:26 +0000

    ktls: Close a race with setting so_error when dropping a connection.
    
    pr_abort calls tcp_usr_abort which calls tcp_drop with ECONNABORTED.
    After pr_abort returns, the so_error is then set to a more specific
    error.  However, a reader can observe and return the ECONNABORTED
    error before so_error is set to the desired error value.  This is
    resulting in spurious test failures of recently added tests for
    invalid conditions such as invalid headers.
    
    To fix, refactor the code to abort a connection to call tcp_drop
    directly with the desired error value.  ktls_reset_send_tag already
    calls tcp_drop directly when it aborts a connection due to an error.
    
    Reviewed by:    gallatin
    Reported by:    CI (jenkins), gallatin, olivier
    Sponsored by:   Chelsio Communications
    Differential Revision:  https://reviews.freebsd.org/D37692
---
 sys/kern/uipc_ktls.c | 35 +++++++++++++++++++++++++----------
 1 file changed, 25 insertions(+), 10 deletions(-)

diff --git a/sys/kern/uipc_ktls.c b/sys/kern/uipc_ktls.c
index ae9201976988..5648598e2b0a 100644
--- a/sys/kern/uipc_ktls.c
+++ b/sys/kern/uipc_ktls.c
@@ -2301,6 +2301,27 @@ ktls_resync_ifnet(struct socket *so, uint32_t tls_len, uint64_t tls_rcd_num)
 	return (mst->sw->snd_tag_modify(mst, &params));
 }
 
+static void
+ktls_drop(struct socket *so, int error)
+{
+	struct epoch_tracker et;
+	struct inpcb *inp = sotoinpcb(so);
+	struct tcpcb *tp;
+
+	NET_EPOCH_ENTER(et);
+	INP_WLOCK(inp);
+	if (!(inp->inp_flags & INP_DROPPED)) {
+		tp = intotcpcb(inp);
+		CURVNET_SET(inp->inp_vnet);
+		tp = tcp_drop(tp, error);
+		CURVNET_RESTORE();
+		if (tp != NULL)
+			INP_WUNLOCK(inp);
+	} else
+		INP_WUNLOCK(inp);
+	NET_EPOCH_EXIT(et);
+}
+
 static void
 ktls_decrypt(struct socket *so)
 {
@@ -2358,10 +2379,7 @@ ktls_decrypt(struct socket *so)
 			SOCKBUF_UNLOCK(sb);
 			counter_u64_add(ktls_offload_corrupted_records, 1);
 
-			CURVNET_SET(so->so_vnet);
-			so->so_proto->pr_abort(so);
-			so->so_error = error;
-			CURVNET_RESTORE();
+			ktls_drop(so, error);
 			goto deref;
 		}
 
@@ -2887,8 +2905,7 @@ ktls_encrypt(struct ktls_wq *wq, struct mbuf *top)
 	if (error == 0) {
 		(void)so->so_proto->pr_ready(so, top, npages);
 	} else {
-		so->so_proto->pr_abort(so);
-		so->so_error = EIO;
+		ktls_drop(so, EIO);
 		mb_free_notready(top, total_pages);
 	}
 
@@ -2931,8 +2948,7 @@ ktls_encrypt_cb(struct ktls_ocf_encrypt_state *state, int error)
 	if (error == 0) {
 		(void)so->so_proto->pr_ready(so, m, npages);
 	} else {
-		so->so_proto->pr_abort(so);
-		so->so_error = EIO;
+		ktls_drop(so, EIO);
 		mb_free_notready(m, npages);
 	}
 
@@ -2996,8 +3012,7 @@ ktls_encrypt_async(struct ktls_wq *wq, struct mbuf *top)
 
 	CURVNET_SET(so->so_vnet);
 	if (error != 0) {
-		so->so_proto->pr_abort(so);
-		so->so_error = EIO;
+		ktls_drop(so, EIO);
 		mb_free_notready(m, total_pages - npages);
 	}