git: 9a7d03c7df35 - main - sendfile: cover the entire sendfile operation under CURVNET_SET()

From: Gleb Smirnoff <glebius_at_FreeBSD.org>
Date: Tue, 06 May 2025 19:34:40 UTC
The branch main has been updated by glebius:

URL: https://cgit.FreeBSD.org/src/commit/?id=9a7d03c7df3536cdb5faf0848c6dab4a5d7bcef8

commit 9a7d03c7df3536cdb5faf0848c6dab4a5d7bcef8
Author:     Gleb Smirnoff <glebius@FreeBSD.org>
AuthorDate: 2025-05-06 18:15:15 +0000
Commit:     Gleb Smirnoff <glebius@FreeBSD.org>
CommitDate: 2025-05-06 19:34:26 +0000

    sendfile: cover the entire sendfile operation under CURVNET_SET()
    
    There is no reason to set/restore for every single pr_send(), as it never
    changes.  Also, cover call into pr_sendfile_wait with CURVNET_SET() fixing
    recent regression in unix(4).
    
    Now we would enter sendfile_iodone() with curvnet set, when called
    synchronously.  Although, it is easy to tell a syncronous call from I/O
    completion, unfortunately the vnet(9) macros do not support conditional
    invocation, so just change CURVNET_SET() to CURVNET_SET_QUIET() and add a
    comment that we are aware of the recursion.
    
    Reported-by:    syzbot+7b0b20cf2c672c181d98@syzkaller.appspotmail.com
---
 sys/kern/kern_sendfile.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/sys/kern/kern_sendfile.c b/sys/kern/kern_sendfile.c
index 1fd1828c37c7..c428d80e0e1a 100644
--- a/sys/kern/kern_sendfile.c
+++ b/sys/kern/kern_sendfile.c
@@ -285,6 +285,11 @@ sendfile_iowait(struct sf_io *sfio, const char *wmesg)
 
 /*
  * I/O completion callback.
+ *
+ * When called via I/O path, the curvnet is not set and should be obtained
+ * from the socket.  When called synchronously from vn_sendfile(), usually
+ * to report error or just release the reference (all pages are valid), then
+ * curvnet shall be already set.
  */
 static void
 sendfile_iodone(void *arg, vm_page_t *pa, int count, int error)
@@ -365,7 +370,7 @@ sendfile_iodone(void *arg, vm_page_t *pa, int count, int error)
 		    ("non-ext_pgs mbuf with TLS session"));
 #endif
 	so = sfio->so;
-	CURVNET_SET(so->so_vnet);
+	CURVNET_SET_QUIET(so->so_vnet);
 	if (__predict_false(sfio->error)) {
 		/*
 		 * I/O operation failed.  The state of data in the socket
@@ -782,6 +787,7 @@ vn_sendfile(struct file *fp, int sockfd, struct uio *hdr_uio,
 	error = sendfile_getsock(td, sockfd, &sock_fp, &so);
 	if (error != 0)
 		goto out;
+	CURVNET_SET(so->so_vnet);
 	pr = so->so_proto;
 
 #ifdef MAC
@@ -1161,7 +1167,6 @@ prepend_header:
 		    ("%s: mlen %u space %d hdrlen %d",
 		    __func__, m_length(m, NULL), space, hdrlen));
 
-		CURVNET_SET(so->so_vnet);
 #ifdef KERN_TLS
 		if (tls != NULL)
 			ktls_frame(m, tls, &tls_enq_cnt, TLS_RLTYPE_APP);
@@ -1203,8 +1208,6 @@ prepend_header:
 			tcp_log_sendfile(so, offset, nbytes, flags);
 		}
 #endif
-		CURVNET_RESTORE();
-
 		m = NULL;
 		if (error)
 			goto done;
@@ -1265,9 +1268,9 @@ out:
 	if (tls != NULL)
 		ktls_free(tls);
 #endif
-
 	if (error == ERESTART)
 		error = EINTR;
+	CURVNET_RESTORE();
 
 	return (error);
 }