diff options
Diffstat (limited to 'sys/kern/kern_descrip.c')
-rw-r--r-- | sys/kern/kern_descrip.c | 185 |
1 files changed, 102 insertions, 83 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c index 30cd545..48c6db9 100644 --- a/sys/kern/kern_descrip.c +++ b/sys/kern/kern_descrip.c @@ -67,7 +67,6 @@ __FBSDID("$FreeBSD$"); #include <sys/resourcevar.h> #include <sys/sbuf.h> #include <sys/signalvar.h> -#include <sys/socketvar.h> #include <sys/kdb.h> #include <sys/stat.h> #include <sys/sx.h> @@ -517,28 +516,26 @@ kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) break; case F_GETFD: + error = EBADF; FILEDESC_SLOCK(fdp); - if (fget_locked(fdp, fd) == NULL) { - FILEDESC_SUNLOCK(fdp); - error = EBADF; - break; + fde = fdeget_locked(fdp, fd); + if (fde != NULL) { + td->td_retval[0] = + (fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0; + error = 0; } - fde = &fdp->fd_ofiles[fd]; - td->td_retval[0] = - (fde->fde_flags & UF_EXCLOSE) ? FD_CLOEXEC : 0; FILEDESC_SUNLOCK(fdp); break; case F_SETFD: + error = EBADF; FILEDESC_XLOCK(fdp); - if (fget_locked(fdp, fd) == NULL) { - FILEDESC_XUNLOCK(fdp); - error = EBADF; - break; + fde = fdeget_locked(fdp, fd); + if (fde != NULL) { + fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) | + (arg & FD_CLOEXEC ? UF_EXCLOSE : 0); + error = 0; } - fde = &fdp->fd_ofiles[fd]; - fde->fde_flags = (fde->fde_flags & ~UF_EXCLOSE) | - (arg & FD_CLOEXEC ? UF_EXCLOSE : 0); FILEDESC_XUNLOCK(fdp); break; @@ -2450,6 +2447,82 @@ finit(struct file *fp, u_int flag, short type, void *data, struct fileops *ops) } int +fget_cap_locked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, + struct file **fpp, struct filecaps *havecapsp) +{ + struct filedescent *fde; + int error; + + FILEDESC_LOCK_ASSERT(fdp); + + fde = fdeget_locked(fdp, fd); + if (fde == NULL) { + error = EBADF; + goto out; + } + +#ifdef CAPABILITIES + error = cap_check(cap_rights_fde(fde), needrightsp); + if (error != 0) + goto out; +#endif + + if (havecapsp != NULL) + filecaps_copy(&fde->fde_caps, havecapsp, true); + + *fpp = fde->fde_file; + + error = 0; +out: + return (error); +} + +int +fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp, + struct file **fpp, struct filecaps *havecapsp) +{ + struct filedesc *fdp = td->td_proc->p_fd; + int error; +#ifndef CAPABILITIES + error = fget_unlocked(fdp, fd, needrightsp, fpp, NULL); + if (error == 0 && havecapsp != NULL) + filecaps_fill(havecapsp); +#else + struct file *fp; + seq_t seq; + + for (;;) { + error = fget_unlocked(fdp, fd, needrightsp, &fp, &seq); + if (error != 0) + return (error); + + if (havecapsp != NULL) { + if (!filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, + havecapsp, false)) { + fdrop(fp, td); + goto get_locked; + } + } + + if (!fd_modified(fdp, fd, seq)) + break; + fdrop(fp, td); + } + + *fpp = fp; + return (0); + +get_locked: + FILEDESC_SLOCK(fdp); + error = fget_cap_locked(fdp, fd, needrightsp, fpp, havecapsp); + if (error == 0) + fhold(*fpp); + FILEDESC_SUNLOCK(fdp); +#endif + return (error); +} + +int fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp, struct file **fpp, seq_t *seqp) { @@ -2712,30 +2785,31 @@ fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp, struct filecaps *havecaps, struct vnode **vpp) { struct filedesc *fdp; + struct filecaps caps; struct file *fp; -#ifdef CAPABILITIES int error; -#endif fdp = td->td_proc->p_fd; - fp = fget_locked(fdp, fd); - if (fp == NULL || fp->f_ops == &badfileops) - return (EBADF); - -#ifdef CAPABILITIES - error = cap_check(cap_rights(fdp, fd), needrightsp); + error = fget_cap_locked(fdp, fd, needrightsp, &fp, &caps); if (error != 0) return (error); -#endif - - if (fp->f_vnode == NULL) - return (EINVAL); + if (fp->f_ops == &badfileops) { + error = EBADF; + goto out; + } + if (fp->f_vnode == NULL) { + error = EINVAL; + goto out; + } + *havecaps = caps; *vpp = fp->f_vnode; vrefact(*vpp); - filecaps_copy(&fdp->fd_ofiles[fd].fde_caps, havecaps, true); return (0); +out: + filecaps_free(&caps); + return (error); } int @@ -2763,61 +2837,6 @@ fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp, #endif /* - * Like fget() but loads the underlying socket, or returns an error if the - * descriptor does not represent a socket. - * - * We bump the ref count on the returned socket. XXX Also obtain the SX lock - * in the future. - * - * Note: fgetsock() and fputsock() are deprecated, as consumers should rely - * on their file descriptor reference to prevent the socket from being free'd - * during use. - */ -int -fgetsock(struct thread *td, int fd, cap_rights_t *rightsp, struct socket **spp, - u_int *fflagp) -{ - struct file *fp; - int error; - - *spp = NULL; - if (fflagp != NULL) - *fflagp = 0; - if ((error = _fget(td, fd, &fp, 0, rightsp, NULL)) != 0) - return (error); - if (fp->f_type != DTYPE_SOCKET) { - error = ENOTSOCK; - } else { - *spp = fp->f_data; - if (fflagp) - *fflagp = fp->f_flag; - SOCK_LOCK(*spp); - soref(*spp); - SOCK_UNLOCK(*spp); - } - fdrop(fp, td); - - return (error); -} - -/* - * Drop the reference count on the socket and XXX release the SX lock in the - * future. The last reference closes the socket. - * - * Note: fputsock() is deprecated, see comment for fgetsock(). - */ -void -fputsock(struct socket *so) -{ - - ACCEPT_LOCK(); - SOCK_LOCK(so); - CURVNET_SET(so->so_vnet); - sorele(so); - CURVNET_RESTORE(); -} - -/* * Handle the last reference to a file being closed. */ int |