Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 21 May 2021 21:45:31 GMT
From:      Mark Johnston <markj@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: 916c61a5ed37 - main - Fix handling of errors from pru_send(PRUS_NOTREADY)
Message-ID:  <202105212145.14LLjVq5055475@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=916c61a5ed37da8ecdedd3c5512813d8dcec9a24

commit 916c61a5ed37da8ecdedd3c5512813d8dcec9a24
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2021-05-21 21:44:46 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2021-05-21 21:45:19 +0000

    Fix handling of errors from pru_send(PRUS_NOTREADY)
    
    PRUS_NOTREADY indicates that the caller has not yet populated the chain
    with data, and so it is not ready for transmission.  This is used by
    sendfile (for async I/O) and KTLS (for encryption).  In particular, if
    pru_send returns an error, the caller is responsible for freeing the
    chain since other implicit references to the data buffers exist.
    
    For async sendfile, it happens that an error will only be returned if
    the connection was dropped, in which case tcp_usr_ready() will handle
    freeing the chain.  But since KTLS can be used in conjunction with the
    regular socket I/O system calls, many more error cases - which do not
    result in the connection being dropped - are reachable.  In these cases,
    KTLS was effectively assuming success.
    
    So:
    - Change sosend_generic() to free the mbuf chain if
      pru_send(PRUS_NOTREADY) fails.  Nothing else owns a reference to the
      chain at that point.
    - Similarly, in vn_sendfile() change the !async I/O && KTLS case to free
      the chain.
    - If async I/O is still outstanding when pru_send fails in
      vn_sendfile(), set an error in the sfio structure so that the
      connection is aborted and the mbuf chain is freed.
    
    Reviewed by:    gallatin, tuexen
    Discussed with: jhb
    MFC after:      2 weeks
    Sponsored by:   The FreeBSD Foundation
    Differential Revision:  https://reviews.freebsd.org/D30349
---
 sys/kern/kern_sendfile.c | 12 ++++++++----
 sys/kern/uipc_socket.c   | 19 +++++++------------
 2 files changed, 15 insertions(+), 16 deletions(-)

diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c
index 520b7c9c62d0..ac1072ca2406 100644
--- a/sys/kern/kern_sendfile.c
+++ b/sys/kern/kern_sendfile.c
@@ -1175,8 +1175,12 @@ prepend_header:
 			if (tls != NULL && tls->mode == TCP_TLS_MODE_SW) {
 				error = (*so->so_proto->pr_usrreqs->pru_send)
 				    (so, PRUS_NOTREADY, m, NULL, NULL, td);
-				soref(so);
-				ktls_enqueue(m, so, tls_enq_cnt);
+				if (error != 0) {
+					m_freem(m);
+				} else {
+					soref(so);
+					ktls_enqueue(m, so, tls_enq_cnt);
+				}
 			} else
 #endif
 				error = (*so->so_proto->pr_usrreqs->pru_send)
@@ -1187,11 +1191,11 @@ prepend_header:
 			soref(so);
 			error = (*so->so_proto->pr_usrreqs->pru_send)
 			    (so, PRUS_NOTREADY, m, NULL, NULL, td);
-			sendfile_iodone(sfio, NULL, 0, 0);
+			sendfile_iodone(sfio, NULL, 0, error);
 		}
 		CURVNET_RESTORE();
 
-		m = NULL;	/* pru_send always consumes */
+		m = NULL;
 		if (error)
 			goto done;
 		sbytes += space + hdrlen;
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 2a167eb68a22..0ca87bfc522a 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1767,18 +1767,13 @@ restart:
 
 #ifdef KERN_TLS
 			if (tls != NULL && tls->mode == TCP_TLS_MODE_SW) {
-				/*
-				 * Note that error is intentionally
-				 * ignored.
-				 *
-				 * Like sendfile(), we rely on the
-				 * completion routine (pru_ready())
-				 * to free the mbufs in the event that
-				 * pru_send() encountered an error and
-				 * did not append them to the sockbuf.
-				 */
-				soref(so);
-				ktls_enqueue(top, so, tls_enq_cnt);
+				if (error != 0) {
+					m_freem(top);
+					top = NULL;
+				} else {
+					soref(so);
+					ktls_enqueue(top, so, tls_enq_cnt);
+				}
 			}
 #endif
 			clen = 0;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202105212145.14LLjVq5055475>