Index: sys/compat/cloudabi/cloudabi_sock.c =================================================================== --- sys/compat/cloudabi/cloudabi_sock.c +++ sys/compat/cloudabi/cloudabi_sock.c @@ -210,7 +210,7 @@ int error; error = getsock_cap(td, uap->sock, cap_rights_init(&rights, - CAP_GETSOCKOPT, CAP_GETPEERNAME, CAP_GETSOCKNAME), &fp, NULL); + CAP_GETSOCKOPT, CAP_GETPEERNAME, CAP_GETSOCKNAME), &fp, NULL, NULL); if (error != 0) return (error); so = fp->f_data; Index: sys/compat/linux/linux_socket.c =================================================================== --- sys/compat/linux/linux_socket.c +++ sys/compat/linux/linux_socket.c @@ -855,7 +855,7 @@ if (error == EFAULT && namelen != sizeof(struct sockaddr_in)) return (EINVAL); if (error == EINVAL) { - error1 = getsock_cap(td, s, &rights, &fp, NULL); + error1 = getsock_cap(td, s, &rights, &fp, NULL, NULL); if (error1 != 0) return (error1); so = fp->f_data; Index: sys/kern/kern_sendfile.c =================================================================== --- sys/kern/kern_sendfile.c +++ sys/kern/kern_sendfile.c @@ -502,7 +502,7 @@ * The socket must be a stream socket and connected. */ error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SEND), - sock_fp, NULL); + sock_fp, NULL, NULL); if (error != 0) return (error); *so = (*sock_fp)->f_data; Index: sys/kern/uipc_syscalls.c =================================================================== --- sys/kern/uipc_syscalls.c +++ sys/kern/uipc_syscalls.c @@ -89,26 +89,52 @@ /* * Convert a user file descriptor to a kernel file entry and check if required * capability rights are present. + * If required copy of current set of capability rights is returned. * A reference on the file entry is held upon returning. */ int getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp, - struct file **fpp, u_int *fflagp) + struct file **fpp, u_int *fflagp, struct filecaps *havecaps) { struct file *fp; + struct filedesc *fdp; int error; - - error = fget_unlocked(td->td_proc->p_fd, fd, rightsp, &fp, NULL); - if (error != 0) - return (error); - if (fp->f_type != DTYPE_SOCKET) { + bool locked; + seq_t seq; + + error = 0; + locked = false; + fdp = td->td_proc->p_fd; + for (;;) { + error = fget_unlocked(fdp, fd, rightsp, &fp, &seq); + if (error != 0) + goto out; + if (fp->f_type != DTYPE_SOCKET) { + fdrop(fp, td); + error = ENOTSOCK; + goto out; + } + if (havecaps != NULL) { + if (filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, + havecaps, locked)) { + fdrop(fp, td); + FILEDESC_SLOCK(fdp); + locked = true; + continue; + } + } + if (locked || !fd_modified(fdp, fd, seq)) + break; fdrop(fp, td); - return (ENOTSOCK); } + if (fflagp != NULL) *fflagp = fp->f_flag; *fpp = fp; - return (0); +out: + if (locked) + FILEDESC_SUNLOCK(fdp); + return (error); } /* @@ -201,7 +227,7 @@ AUDIT_ARG_FD(fd); AUDIT_ARG_SOCKADDR(td, dirfd, sa); error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_BIND), - &fp, NULL); + &fp, NULL, NULL); if (error != 0) return (error); so = fp->f_data; @@ -262,7 +288,7 @@ AUDIT_ARG_FD(uap->s); error = getsock_cap(td, uap->s, cap_rights_init(&rights, CAP_LISTEN), - &fp, NULL); + &fp, NULL, NULL); if (error == 0) { so = fp->f_data; #ifdef MAC @@ -335,6 +361,7 @@ struct file *headfp, *nfp = NULL; struct sockaddr *sa = NULL; struct socket *head, *so; + struct filecaps fcaps; cap_rights_t rights; u_int fflag; pid_t pgid; @@ -345,7 +372,7 @@ AUDIT_ARG_FD(s); error = getsock_cap(td, s, cap_rights_init(&rights, CAP_ACCEPT), - &headfp, &fflag); + &headfp, &fflag, &fcaps); if (error != 0) return (error); head = headfp->f_data; @@ -358,7 +385,8 @@ if (error != 0) goto done; #endif - error = falloc(td, &nfp, &fd, (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0); + error = falloc_caps(td, &nfp, &fd, + (flags & SOCK_CLOEXEC) ? O_CLOEXEC : 0, &fcaps); if (error != 0) goto done; ACCEPT_LOCK(); @@ -467,6 +495,8 @@ * a reference on nfp to the caller on success if they request it. */ done: + if (nfp == NULL) + filecaps_free(&fcaps); if (fp != NULL) { if (error == 0) { *fp = nfp; @@ -545,7 +575,7 @@ AUDIT_ARG_FD(fd); AUDIT_ARG_SOCKADDR(td, dirfd, sa); error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_CONNECT), - &fp, NULL); + &fp, NULL, NULL); if (error != 0) return (error); so = fp->f_data; @@ -805,7 +835,7 @@ AUDIT_ARG_SOCKADDR(td, AT_FDCWD, mp->msg_name); cap_rights_set(&rights, CAP_CONNECT); } - error = getsock_cap(td, s, &rights, &fp, NULL); + error = getsock_cap(td, s, &rights, &fp, NULL, NULL); if (error != 0) return (error); so = (struct socket *)fp->f_data; @@ -1006,7 +1036,7 @@ AUDIT_ARG_FD(s); error = getsock_cap(td, s, cap_rights_init(&rights, CAP_RECV), - &fp, NULL); + &fp, NULL, NULL); if (error != 0) return (error); so = fp->f_data; @@ -1321,7 +1351,7 @@ AUDIT_ARG_FD(uap->s); error = getsock_cap(td, uap->s, cap_rights_init(&rights, CAP_SHUTDOWN), - &fp, NULL); + &fp, NULL, NULL); if (error == 0) { so = fp->f_data; error = soshutdown(so, uap->how); @@ -1395,7 +1425,7 @@ AUDIT_ARG_FD(s); error = getsock_cap(td, s, cap_rights_init(&rights, CAP_SETSOCKOPT), - &fp, NULL); + &fp, NULL, NULL); if (error == 0) { so = fp->f_data; error = sosetopt(so, &sopt); @@ -1476,7 +1506,7 @@ AUDIT_ARG_FD(s); error = getsock_cap(td, s, cap_rights_init(&rights, CAP_GETSOCKOPT), - &fp, NULL); + &fp, NULL, NULL); if (error == 0) { so = fp->f_data; error = sogetopt(so, &sopt); @@ -1537,7 +1567,7 @@ AUDIT_ARG_FD(fd); error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETSOCKNAME), - &fp, NULL); + &fp, NULL, NULL); if (error != 0) return (error); so = fp->f_data; @@ -1636,7 +1666,7 @@ AUDIT_ARG_FD(fd); error = getsock_cap(td, fd, cap_rights_init(&rights, CAP_GETPEERNAME), - &fp, NULL); + &fp, NULL, NULL); if (error != 0) return (error); so = fp->f_data; Index: sys/netinet/sctp_syscalls.c =================================================================== --- sys/netinet/sctp_syscalls.c +++ sys/netinet/sctp_syscalls.c @@ -248,7 +248,7 @@ } AUDIT_ARG_FD(uap->sd); - error = getsock_cap(td, uap->sd, &rights, &fp, NULL); + error = getsock_cap(td, uap->sd, &rights, &fp, NULL, NULL); if (error != 0) goto sctp_bad; #ifdef KTRACE @@ -361,7 +361,7 @@ } AUDIT_ARG_FD(uap->sd); - error = getsock_cap(td, uap->sd, &rights, &fp, NULL); + error = getsock_cap(td, uap->sd, &rights, &fp, NULL, NULL); if (error != 0) goto sctp_bad1; @@ -477,7 +477,7 @@ AUDIT_ARG_FD(uap->sd); error = getsock_cap(td, uap->sd, cap_rights_init(&rights, CAP_RECV), - &fp, NULL); + &fp, NULL, NULL); if (error != 0) return (error); #ifdef COMPAT_FREEBSD32 Index: sys/sys/socketvar.h =================================================================== --- sys/sys/socketvar.h +++ sys/sys/socketvar.h @@ -321,6 +321,7 @@ extern so_gen_t so_gencnt; struct file; +struct filecaps; struct filedesc; struct mbuf; struct sockaddr; @@ -340,7 +341,7 @@ */ int getsockaddr(struct sockaddr **namp, caddr_t uaddr, size_t len); int getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp, - struct file **fpp, u_int *fflagp); + struct file **fpp, u_int *fflagp, struct filecaps *havecaps); void soabort(struct socket *so); int soaccept(struct socket *so, struct sockaddr **nam); void soaio_enqueue(struct task *task);