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
This commit is contained in:
Mark Johnston 2024-07-08 11:46:33 -04:00
parent bdf2c8fff9
commit e2e771deec
2 changed files with 9 additions and 2 deletions

View file

@ -1220,6 +1220,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;
@ -1245,8 +1246,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);
@ -1284,6 +1287,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;
@ -1309,8 +1313,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;

View file

@ -35,6 +35,7 @@
#error "no user-serviceable parts inside"
#endif
struct cap_rights;
struct thread;
struct socket;
@ -50,6 +51,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 */
};