git: f14bdfefa41c - main - CHERI: add sooptcopyinptr to preserve pointer provenance

From: Brooks Davis <brooks_at_FreeBSD.org>
Date: Wed, 01 Jul 2026 11:49:35 UTC
The branch main has been updated by brooks:

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

commit f14bdfefa41c7d81dd1317e61b98de22dc03016c
Author:     Brooks Davis <brooks@FreeBSD.org>
AuthorDate: 2026-07-01 11:46:39 +0000
Commit:     Brooks Davis <brooks@FreeBSD.org>
CommitDate: 2026-07-01 11:48:10 +0000

    CHERI: add sooptcopyinptr to preserve pointer provenance
    
    Most socket options don't involve pointers so make the default
    sooptcopyin discard provenance and add a sooptcopyinptr that preserves.
    
    Reviewed by:    markj, emaste
    Effort:         CHERI upstreaming
    Sponsored by:   DARPA, AFRL, Innovate UK
    Differential Revision:  https://reviews.freebsd.org/D57665
---
 share/man/man9/socket.9 | 13 ++++++++++++-
 sys/kern/uipc_socket.c  | 34 ++++++++++++++++++++++++++++------
 sys/sys/sockopt.h       |  6 ++++++
 3 files changed, 46 insertions(+), 7 deletions(-)

diff --git a/share/man/man9/socket.9 b/share/man/man9/socket.9
index fb0ead0e20e1..c54716d8e155 100644
--- a/share/man/man9/socket.9
+++ b/share/man/man9/socket.9
@@ -24,7 +24,7 @@
 .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 .\" SUCH DAMAGE.
 .\"
-.Dd September 6, 2022
+.Dd July 1, 2026
 .Dt SOCKET 9
 .Os
 .Sh NAME
@@ -146,6 +146,8 @@
 .Ft int
 .Fn sooptcopyin "struct sockopt *sopt" "void *buf" "size_t len" "size_t minlen"
 .Ft int
+.Fn sooptcopyinptr "struct sockopt *sopt" "void *buf" "size_t len" "size_t minlen"
+.Ft int
 .Fn sooptcopyout "struct sockopt *sopt" "const void *buf" "size_t len"
 .Sh DESCRIPTION
 The kernel
@@ -577,6 +579,15 @@ and
 are useful for transferring
 .Vt struct sockopt
 data between user and kernel code.
+They do not preserve the provenance of pointers in copied objects
+.Pq see Xr memory_model 7 for further information .
+If the object to be copied contains pointers, the
+.Fn sooptcopyinptr
+function must be used to preserve the provenance of those pointers.
+There is no corresponding
+.Fn sooptcopyoutptr
+as the kernel does not typically return pointers to userspace objects
+and instead would update objects previously passed via sooptcopyinptr.
 .Sh SEE ALSO
 .Xr bind 2 ,
 .Xr close 2 ,
diff --git a/sys/kern/uipc_socket.c b/sys/kern/uipc_socket.c
index 47de87c1887c..dc4db57c07e2 100644
--- a/sys/kern/uipc_socket.c
+++ b/sys/kern/uipc_socket.c
@@ -3808,8 +3808,9 @@ hhook_run_socket(struct socket *so, void *hctx, int32_t h_id)
  * here, these functions are also called by the protocol-level pr_ctloutput()
  * routines.
  */
-int
-sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
+static int
+_sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen,
+    bool copycaps)
 {
 	size_t	valsize;
 
@@ -3824,13 +3825,34 @@ sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
 	if (valsize > len)
 		sopt->sopt_valsize = valsize = len;
 
-	if (sopt->sopt_td != NULL)
-		return (copyin(sopt->sopt_val, buf, valsize));
+	if (sopt->sopt_td != NULL) {
+		if (copycaps)
+			return (copyinptr(sopt->sopt_val, buf, valsize));
+		else
+			return (copyin(sopt->sopt_val, buf, valsize));
+	}
 
-	memcpy(buf, sopt->sopt_val, valsize);
+	if (copycaps)
+		memcpy(buf, sopt->sopt_val, valsize);
+	else
+		memcpy_data(buf, sopt->sopt_val, valsize);
 	return (0);
 }
 
+int
+sooptcopyin(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
+{
+	return (_sooptcopyin(sopt, buf, len, minlen, false));
+}
+
+#ifdef __CHERI__
+int
+sooptcopyinptr(struct sockopt *sopt, void *buf, size_t len, size_t minlen)
+{
+	return (_sooptcopyin(sopt, buf, len, minlen, true));
+}
+#endif
+
 /*
  * Kernel version of setsockopt(2).
  *
@@ -4118,7 +4140,7 @@ sooptcopyout(struct sockopt *sopt, const void *buf, size_t len)
 		if (sopt->sopt_td != NULL)
 			error = copyout(buf, sopt->sopt_val, valsize);
 		else
-			memcpy(sopt->sopt_val, buf, valsize);
+			memcpy_data(sopt->sopt_val, buf, valsize);
 	}
 	return (error);
 }
diff --git a/sys/sys/sockopt.h b/sys/sys/sockopt.h
index d2b0ff5ed2c8..54d0afe673d5 100644
--- a/sys/sys/sockopt.h
+++ b/sys/sys/sockopt.h
@@ -59,6 +59,12 @@ int	sosetopt(struct socket *so, struct sockopt *sopt);
 int	sogetopt(struct socket *so, struct sockopt *sopt);
 int __result_use_check sooptcopyin(struct sockopt *sopt, void *buf, size_t len,
     size_t minlen);
+#ifdef __CHERI__
+int __result_use_check sooptcopyinptr(struct sockopt *sopt, void *buf,
+    size_t len, size_t minlen);
+#else
+#define	sooptcopyinptr	sooptcopyin
+#endif
 int __result_use_check sooptcopyout(struct sockopt *sopt, const void *buf,
     size_t len);
 int	soopt_getm(struct sockopt *sopt, struct mbuf **mp);