Changeset View
Standalone View
sys/kern/kern_descrip.c
Show First 20 Lines • Show All 55 Lines • ▼ Show 20 Lines | ||||||||||
#include <sys/kernel.h> | #include <sys/kernel.h> | |||||||||
#include <sys/limits.h> | #include <sys/limits.h> | |||||||||
#include <sys/lock.h> | #include <sys/lock.h> | |||||||||
#include <sys/malloc.h> | #include <sys/malloc.h> | |||||||||
#include <sys/mount.h> | #include <sys/mount.h> | |||||||||
#include <sys/mutex.h> | #include <sys/mutex.h> | |||||||||
#include <sys/namei.h> | #include <sys/namei.h> | |||||||||
#include <sys/selinfo.h> | #include <sys/selinfo.h> | |||||||||
#include <sys/poll.h> | ||||||||||
#include <sys/priv.h> | #include <sys/priv.h> | |||||||||
#include <sys/proc.h> | #include <sys/proc.h> | |||||||||
#include <sys/protosw.h> | #include <sys/protosw.h> | |||||||||
#include <sys/racct.h> | #include <sys/racct.h> | |||||||||
#include <sys/resourcevar.h> | #include <sys/resourcevar.h> | |||||||||
#include <sys/sbuf.h> | #include <sys/sbuf.h> | |||||||||
#include <sys/signalvar.h> | #include <sys/signalvar.h> | |||||||||
#include <sys/kdb.h> | #include <sys/kdb.h> | |||||||||
▲ Show 20 Lines • Show All 475 Lines • ▼ Show 20 Lines | case F_SETFL: | |||||||||
if (error != 0) | if (error != 0) | |||||||||
break; | break; | |||||||||
do { | do { | |||||||||
tmp = flg = fp->f_flag; | tmp = flg = fp->f_flag; | |||||||||
tmp &= ~FCNTLFLAGS; | tmp &= ~FCNTLFLAGS; | |||||||||
tmp |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS; | tmp |= FFLAGS(arg & ~O_ACCMODE) & FCNTLFLAGS; | |||||||||
} while(atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0); | } while(atomic_cmpset_int(&fp->f_flag, flg, tmp) == 0); | |||||||||
tmp = fp->f_flag & FNONBLOCK; | tmp = fp->f_flag & FNONBLOCK; | |||||||||
error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td); | error = fo_ioctl(fp, FIONBIO, &tmp, td->td_ucred, td); | |||||||||
markj: This case is a bit strange. The ioctl will always fail for O_PATH fds, but the flags may be… | ||||||||||
if (error != 0) { | if (error != 0) { | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
break; | break; | |||||||||
} | } | |||||||||
tmp = fp->f_flag & FASYNC; | tmp = fp->f_flag & FASYNC; | |||||||||
error = fo_ioctl(fp, FIOASYNC, &tmp, td->td_ucred, td); | error = fo_ioctl(fp, FIOASYNC, &tmp, td->td_ucred, td); | |||||||||
if (error == 0) { | if (error == 0) { | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | do_setlk: | |||||||||
if ((flg & F_REMOTE) != 0 && flp->l_sysid == 0) { | if ((flg & F_REMOTE) != 0 && flp->l_sysid == 0) { | |||||||||
error = EINVAL; | error = EINVAL; | |||||||||
break; | break; | |||||||||
} | } | |||||||||
error = fget_unlocked(fdp, fd, &cap_flock_rights, &fp); | error = fget_unlocked(fdp, fd, &cap_flock_rights, &fp); | |||||||||
if (error != 0) | if (error != 0) | |||||||||
break; | break; | |||||||||
if (fp->f_type != DTYPE_VNODE) { | if (fp->f_type != DTYPE_VNODE || fp->f_ops == &path_fileops) { | |||||||||
error = EBADF; | error = EBADF; | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
break; | break; | |||||||||
} | } | |||||||||
if (flp->l_whence == SEEK_CUR) { | if (flp->l_whence == SEEK_CUR) { | |||||||||
foffset = foffset_get(fp); | foffset = foffset_get(fp); | |||||||||
if (foffset < 0 || | if (foffset < 0 || | |||||||||
▲ Show 20 Lines • Show All 88 Lines • ▼ Show 20 Lines | do_setlk: | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
fdrop(fp2, td); | fdrop(fp2, td); | |||||||||
break; | break; | |||||||||
case F_GETLK: | case F_GETLK: | |||||||||
error = fget_unlocked(fdp, fd, &cap_flock_rights, &fp); | error = fget_unlocked(fdp, fd, &cap_flock_rights, &fp); | |||||||||
if (error != 0) | if (error != 0) | |||||||||
break; | break; | |||||||||
if (fp->f_type != DTYPE_VNODE) { | if (fp->f_type != DTYPE_VNODE || fp->f_ops == &path_fileops) { | |||||||||
Done Inline ActionsDoes it make sense to permit F_GETLK for O_PATH descriptors? markj: Does it make sense to permit F_GETLK for O_PATH descriptors? | ||||||||||
Done Inline ActionsDisabled. kib: Disabled. | ||||||||||
error = EBADF; | error = EBADF; | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
break; | break; | |||||||||
} | } | |||||||||
flp = (struct flock *)arg; | flp = (struct flock *)arg; | |||||||||
if (flp->l_type != F_RDLCK && flp->l_type != F_WRLCK && | if (flp->l_type != F_RDLCK && flp->l_type != F_WRLCK && | |||||||||
flp->l_type != F_UNLCK) { | flp->l_type != F_UNLCK) { | |||||||||
error = EINVAL; | error = EINVAL; | |||||||||
Show All 39 Lines | kern_fcntl(struct thread *td, int fd, int cmd, intptr_t arg) | |||||||||
case F_RDAHEAD: | case F_RDAHEAD: | |||||||||
arg = arg ? 128 * 1024: 0; | arg = arg ? 128 * 1024: 0; | |||||||||
/* FALLTHROUGH */ | /* FALLTHROUGH */ | |||||||||
case F_READAHEAD: | case F_READAHEAD: | |||||||||
error = fget_unlocked(fdp, fd, &cap_no_rights, &fp); | error = fget_unlocked(fdp, fd, &cap_no_rights, &fp); | |||||||||
if (error != 0) | if (error != 0) | |||||||||
break; | break; | |||||||||
if (fp->f_type != DTYPE_VNODE) { | if (fp->f_type != DTYPE_VNODE) { | |||||||||
Done Inline ActionsI doubt we should permit O_PATH fds here, we disallow posix_fadvise() already. markj: I doubt we should permit O_PATH fds here, we disallow posix_fadvise() already. | ||||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
error = EBADF; | error = EBADF; | |||||||||
break; | break; | |||||||||
} | } | |||||||||
vp = fp->f_vnode; | vp = fp->f_vnode; | |||||||||
if (vp->v_type != VREG) { | if (vp->v_type != VREG) { | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
error = ENOTTY; | error = ENOTTY; | |||||||||
▲ Show 20 Lines • Show All 2,636 Lines • ▼ Show 20 Lines | _fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp, | |||||||||
*vpp = NULL; | *vpp = NULL; | |||||||||
error = _fget(td, fd, &fp, flags, needrightsp); | error = _fget(td, fd, &fp, flags, needrightsp); | |||||||||
if (error != 0) | if (error != 0) | |||||||||
return (error); | return (error); | |||||||||
if (fp->f_vnode == NULL) { | if (fp->f_vnode == NULL) { | |||||||||
error = EINVAL; | error = EINVAL; | |||||||||
} else { | } else { | |||||||||
*vpp = fp->f_vnode; | *vpp = fp->f_vnode; | |||||||||
vrefact(*vpp); | vref(*vpp); | |||||||||
} | } | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
return (error); | return (error); | |||||||||
} | } | |||||||||
int | int | |||||||||
fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) | fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp) | |||||||||
Show All 19 Lines | fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp, | |||||||||
} | } | |||||||||
if (fp->f_vnode == NULL) { | if (fp->f_vnode == NULL) { | |||||||||
error = EINVAL; | error = EINVAL; | |||||||||
goto out; | goto out; | |||||||||
} | } | |||||||||
*havecaps = caps; | *havecaps = caps; | |||||||||
*vpp = fp->f_vnode; | *vpp = fp->f_vnode; | |||||||||
vrefact(*vpp); | vref(*vpp); | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
return (0); | return (0); | |||||||||
out: | out: | |||||||||
filecaps_free(&caps); | filecaps_free(&caps); | |||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
return (error); | return (error); | |||||||||
} | } | |||||||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | sys_flock(struct thread *td, struct flock_args *uap) | |||||||||
struct file *fp; | struct file *fp; | |||||||||
struct vnode *vp; | struct vnode *vp; | |||||||||
struct flock lf; | struct flock lf; | |||||||||
int error; | int error; | |||||||||
error = fget(td, uap->fd, &cap_flock_rights, &fp); | error = fget(td, uap->fd, &cap_flock_rights, &fp); | |||||||||
if (error != 0) | if (error != 0) | |||||||||
return (error); | return (error); | |||||||||
if (fp->f_type != DTYPE_VNODE) { | if (fp->f_type != DTYPE_VNODE || fp->f_ops == &path_fileops) { | |||||||||
Done Inline ActionsShould it be permitted for O_PATH? markj: Should it be permitted for O_PATH? | ||||||||||
Done Inline ActionsDisabled. kib: Disabled. | ||||||||||
fdrop(fp, td); | fdrop(fp, td); | |||||||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | |||||||||
} | } | |||||||||
vp = fp->f_vnode; | vp = fp->f_vnode; | |||||||||
lf.l_whence = SEEK_SET; | lf.l_whence = SEEK_SET; | |||||||||
lf.l_start = 0; | lf.l_start = 0; | |||||||||
lf.l_len = 0; | lf.l_len = 0; | |||||||||
▲ Show 20 Lines • Show All 1,397 Lines • ▼ Show 20 Lines | struct fileops badfileops = { | |||||||||
.fo_poll = badfo_poll, | .fo_poll = badfo_poll, | |||||||||
.fo_kqfilter = badfo_kqfilter, | .fo_kqfilter = badfo_kqfilter, | |||||||||
.fo_stat = badfo_stat, | .fo_stat = badfo_stat, | |||||||||
.fo_close = badfo_close, | .fo_close = badfo_close, | |||||||||
.fo_chmod = badfo_chmod, | .fo_chmod = badfo_chmod, | |||||||||
.fo_chown = badfo_chown, | .fo_chown = badfo_chown, | |||||||||
.fo_sendfile = badfo_sendfile, | .fo_sendfile = badfo_sendfile, | |||||||||
.fo_fill_kinfo = badfo_fill_kinfo, | .fo_fill_kinfo = badfo_fill_kinfo, | |||||||||
}; | ||||||||||
static int | ||||||||||
path_poll(struct file *fp, int events, struct ucred *active_cred, | ||||||||||
struct thread *td) | ||||||||||
{ | ||||||||||
return (POLLNVAL); | ||||||||||
} | ||||||||||
static int | ||||||||||
path_close(struct file *fp, struct thread *td) | ||||||||||
{ | ||||||||||
MPASS(fp->f_type == DTYPE_VNODE); | ||||||||||
fp->f_ops = &badfileops; | ||||||||||
vdrop(fp->f_vnode); | ||||||||||
return (0); | ||||||||||
} | ||||||||||
struct fileops path_fileops = { | ||||||||||
.fo_read = badfo_readwrite, | ||||||||||
.fo_write = badfo_readwrite, | ||||||||||
.fo_truncate = badfo_truncate, | ||||||||||
.fo_ioctl = badfo_ioctl, | ||||||||||
.fo_poll = path_poll, | ||||||||||
.fo_kqfilter = vn_kqfilter_opath, | ||||||||||
Done Inline Actions
markj: | ||||||||||
Done Inline ActionsThe Linux documentation implies that file locking should not be implemented for O_PATH descriptors. For instance, "When O_PATH is specified in flags, flag bits other than O_CLOEXEC, O_DIRECTORY, and O_NOFOLLOW are ignored." So O_SHLOCK/EXLOCK should be ignored, but I believe they are currently handled, and we also permit fcntl(F_SETLK) and flock(2) on O_PATH descriptors. These are operations on the file, not on the descriptor, so it indeed seems like they should be prohibited. markj: The Linux documentation implies that file locking should not be implemented for O_PATH… | ||||||||||
Done Inline ActionsYou mean O_EXLOCK is handled in my implementation? Yes I kept them explicitly, patch would be simpler if adv locking is ignored for O_PATH descriptors. Do you prefer to have adv locking ignored? I did not see a reason to disable that. kib: You mean O_EXLOCK is handled in my implementation? Yes I kept them explicitly, patch would be… | ||||||||||
Done Inline ActionsCould we leave vn_kqfilter here? It looks like O_PATH is very helpful for kqueue-based file monitors. Especially for watching for file systems which have expensive open() like fuse and nfs. wulf: Could we leave vn_kqfilter here? It looks like O_PATH is very helpful for kqueue-based file… | ||||||||||
.fo_stat = vn_statfile, | ||||||||||
.fo_close = path_close, | ||||||||||
.fo_chmod = badfo_chmod, | ||||||||||
.fo_chown = badfo_chown, | ||||||||||
.fo_sendfile = badfo_sendfile, | ||||||||||
.fo_fill_kinfo = vn_fill_kinfo, | ||||||||||
.fo_flags = DFLAG_PASSABLE, | ||||||||||
}; | }; | |||||||||
int | int | |||||||||
invfo_rdwr(struct file *fp, struct uio *uio, struct ucred *active_cred, | invfo_rdwr(struct file *fp, struct uio *uio, struct ucred *active_cred, | |||||||||
int flags, struct thread *td) | int flags, struct thread *td) | |||||||||
{ | { | |||||||||
return (EOPNOTSUPP); | return (EOPNOTSUPP); | |||||||||
▲ Show 20 Lines • Show All 111 Lines • Show Last 20 Lines |
This case is a bit strange. The ioctl will always fail for O_PATH fds, but the flags may be modified by the loop above, in principle. Perhaps we should check for path_fileops before that and unconditionally fail. All flags settable with F_SETFL are related to I/O operations on the file.