git: 75683ed20b70 - stable/13 - Fix handling of errors from pru_send(PRUS_NOTREADY)

Mark Johnston markj at FreeBSD.org
Fri Jun 4 01:09:33 UTC 2021


The branch stable/13 has been updated by markj:

URL: https://cgit.FreeBSD.org/src/commit/?id=75683ed20b70da2b813e5a9da220cfee94c0b307

commit 75683ed20b70da2b813e5a9da220cfee94c0b307
Author:     Mark Johnston <markj at FreeBSD.org>
AuthorDate: 2021-05-21 21:44:46 +0000
Commit:     Mark Johnston <markj at FreeBSD.org>
CommitDate: 2021-06-04 01:02:02 +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
    Sponsored by:   The FreeBSD Foundation
    
    (cherry picked from commit 916c61a5ed37da8ecdedd3c5512813d8dcec9a24)
---
 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 77ce876fd20f..852132e45e58 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -1763,18 +1763,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;


More information about the dev-commits-src-all mailing list