git: 88c041e4870c - stable/14 - socket: Pass capsicum rights down to socket option handlers

From: Mark Johnston <markj_at_FreeBSD.org>
Date: Tue, 23 Jul 2024 13:19:30 UTC
The branch stable/14 has been updated by markj:

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

commit 88c041e4870c278fe7c326e8ac0880cb76586c29
Author:     Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2024-07-08 15:46:33 +0000
Commit:     Mark Johnston <markj@FreeBSD.org>
CommitDate: 2024-07-23 13:01:29 +0000

    socket: Pass capsicum rights down to socket option handlers
    
    One needs the CAP_GETSOCKOPT and CAP_SETSOCKOPT rights to call
    getsockopt(2) and setsockopt(2) on a socket descriptor, respectively.
    The syscall layer checks this, but individual socket option handlers
    have no access to the file descriptor and so can't check for additional
    rights, should the want to do so.  In particular, a forthcoming
    implementation of SO_SPLICE logically requires at least CAP_RECV and
    CAP_SEND rights.
    
    Modify the syscall layer to look up Capsicum rights on the descriptor
    and pass that along to socket option handlers; this way, the handlers
    can check for additional rights if they need to.
    
    Reviewed by:    gallatin, glebius
    MFC after:      2 weeks
    Sponsored by:   Klara, Inc.
    Sponsored by:   Stormshield
    Differential Revision:  https://reviews.freebsd.org/D45673
    
    (cherry picked from commit e2e771deeca7c10eaa46f380a9b64079468ec209)
---
 sys/kern/uipc_syscalls.c | 9 +++++++--
 sys/sys/sockopt.h        | 2 ++
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index 6c13740d8094..6121bde4c574 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -1236,6 +1236,7 @@ kern_setsockopt(struct thread *td, int s, int level, int name, const void *val,
 {
 	struct socket *so;
 	struct file *fp;
+	struct filecaps fcaps;
 	struct sockopt sopt;
 	int error;
 
@@ -1261,8 +1262,10 @@ kern_setsockopt(struct thread *td, int s, int level, int name, const void *val,
 	}
 
 	AUDIT_ARG_FD(s);
-	error = getsock(td, s, &cap_setsockopt_rights, &fp);
+	error = getsock_cap(td, s, &cap_setsockopt_rights, &fp,
+	    &fcaps);
 	if (error == 0) {
+		sopt.sopt_rights = &fcaps.fc_rights;
 		so = fp->f_data;
 		error = sosetopt(so, &sopt);
 		fdrop(fp, td);
@@ -1300,6 +1303,7 @@ kern_getsockopt(struct thread *td, int s, int level, int name, void *val,
 {
 	struct socket *so;
 	struct file *fp;
+	struct filecaps fcaps;
 	struct sockopt sopt;
 	int error;
 
@@ -1325,8 +1329,9 @@ kern_getsockopt(struct thread *td, int s, int level, int name, void *val,
 	}
 
 	AUDIT_ARG_FD(s);
-	error = getsock(td, s, &cap_getsockopt_rights, &fp);
+	error = getsock_cap(td, s, &cap_getsockopt_rights, &fp, &fcaps);
 	if (error == 0) {
+		sopt.sopt_rights = &fcaps.fc_rights;
 		so = fp->f_data;
 		error = sogetopt(so, &sopt);
 		*valsize = sopt.sopt_valsize;
diff --git a/sys/sys/sockopt.h b/sys/sys/sockopt.h
index 11799dde4883..b139062cf492 100644
--- a/sys/sys/sockopt.h
+++ b/sys/sys/sockopt.h
@@ -37,6 +37,7 @@
 #error "no user-serviceable parts inside"
 #endif
 
+struct cap_rights;
 struct thread;
 struct socket;
 
@@ -52,6 +53,7 @@ struct	sockopt {
 	int	sopt_name;	/* third arg of [gs]etsockopt */
 	void   *sopt_val;	/* fourth arg of [gs]etsockopt */
 	size_t	sopt_valsize;	/* (almost) fifth arg of [gs]etsockopt */
+	struct cap_rights *sopt_rights; /* Capsicum rights attached to the fd */
 	struct	thread *sopt_td; /* calling thread or null if kernel */
 };