aboutsummaryrefslogtreecommitdiff
path: root/sys/kern
diff options
context:
space:
mode:
Diffstat (limited to 'sys/kern')
-rw-r--r--sys/kern/kern_descrip.c57
-rw-r--r--sys/kern/sys_procdesc.c5
-rw-r--r--sys/kern/uipc_mqueue.c8
-rw-r--r--sys/kern/uipc_sem.c6
-rw-r--r--sys/kern/uipc_syscalls.c4
-rw-r--r--sys/kern/vfs_cache.c19
-rw-r--r--sys/kern/vfs_lookup.c46
-rw-r--r--sys/kern/vfs_syscalls.c5
-rw-r--r--sys/kern/vfs_vnops.c22
9 files changed, 97 insertions, 75 deletions
diff --git a/sys/kern/kern_descrip.c b/sys/kern/kern_descrip.c
index f51a1092114d..f073fc64e0bc 100644
--- a/sys/kern/kern_descrip.c
+++ b/sys/kern/kern_descrip.c
@@ -114,7 +114,8 @@ static void fdgrowtable_exp(struct filedesc *fdp, int nfd);
static void fdunused(struct filedesc *fdp, int fd);
static void fdused(struct filedesc *fdp, int fd);
static int fget_unlocked_seq(struct filedesc *fdp, int fd,
- cap_rights_t *needrightsp, struct file **fpp, seqc_t *seqp);
+ const cap_rights_t *needrightsp, struct file **fpp,
+ seqc_t *seqp);
static int getmaxfd(struct thread *td);
static u_long *filecaps_copy_prep(const struct filecaps *src);
static void filecaps_copy_finish(const struct filecaps *src,
@@ -2978,7 +2979,7 @@ finit_vnode(struct file *fp, u_int flag, void *data, struct fileops *ops)
}
int
-fget_cap_locked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
+fget_cap_locked(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
struct file **fpp, struct filecaps *havecapsp)
{
struct filedescent *fde;
@@ -3010,7 +3011,7 @@ out:
}
int
-fget_cap(struct thread *td, int fd, cap_rights_t *needrightsp,
+fget_cap(struct thread *td, int fd, const cap_rights_t *needrightsp,
struct file **fpp, struct filecaps *havecapsp)
{
struct filedesc *fdp = td->td_proc->p_fd;
@@ -3256,7 +3257,7 @@ out_free:
}
static int
-fget_unlocked_seq(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
+fget_unlocked_seq(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
struct file **fpp, seqc_t *seqp)
{
#ifdef CAPABILITIES
@@ -3339,7 +3340,7 @@ fget_unlocked_seq(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
* racing with itself.
*/
int
-fget_unlocked(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
+fget_unlocked(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
struct file **fpp)
{
#ifdef CAPABILITIES
@@ -3406,7 +3407,7 @@ out_fallback:
*/
#ifdef CAPABILITIES
int
-fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
+fget_only_user(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
struct file **fpp)
{
const struct filedescent *fde;
@@ -3436,7 +3437,7 @@ fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
}
#else
int
-fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
+fget_only_user(struct filedesc *fdp, int fd, const cap_rights_t *needrightsp,
struct file **fpp)
{
struct file *fp;
@@ -3472,7 +3473,7 @@ fget_only_user(struct filedesc *fdp, int fd, cap_rights_t *needrightsp,
*/
static __inline int
_fget(struct thread *td, int fd, struct file **fpp, int flags,
- cap_rights_t *needrightsp)
+ const cap_rights_t *needrightsp)
{
struct filedesc *fdp;
struct file *fp;
@@ -3520,15 +3521,15 @@ _fget(struct thread *td, int fd, struct file **fpp, int flags,
}
int
-fget(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
+fget(struct thread *td, int fd, const cap_rights_t *rightsp, struct file **fpp)
{
return (_fget(td, fd, fpp, 0, rightsp));
}
int
-fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, vm_prot_t *maxprotp,
- struct file **fpp)
+fget_mmap(struct thread *td, int fd, const cap_rights_t *rightsp,
+ vm_prot_t *maxprotp, struct file **fpp)
{
int error;
#ifndef CAPABILITIES
@@ -3571,22 +3572,24 @@ fget_mmap(struct thread *td, int fd, cap_rights_t *rightsp, vm_prot_t *maxprotp,
}
int
-fget_read(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
+fget_read(struct thread *td, int fd, const cap_rights_t *rightsp,
+ struct file **fpp)
{
return (_fget(td, fd, fpp, FREAD, rightsp));
}
int
-fget_write(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
+fget_write(struct thread *td, int fd, const cap_rights_t *rightsp,
+ struct file **fpp)
{
return (_fget(td, fd, fpp, FWRITE, rightsp));
}
int
-fget_fcntl(struct thread *td, int fd, cap_rights_t *rightsp, int needfcntl,
- struct file **fpp)
+fget_fcntl(struct thread *td, int fd, const cap_rights_t *rightsp,
+ int needfcntl, struct file **fpp)
{
struct filedesc *fdp = td->td_proc->p_fd;
#ifndef CAPABILITIES
@@ -3624,7 +3627,7 @@ fget_fcntl(struct thread *td, int fd, cap_rights_t *rightsp, int needfcntl,
* XXX: what about the unused flags ?
*/
static __inline int
-_fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp,
+_fgetvp(struct thread *td, int fd, int flags, const cap_rights_t *needrightsp,
struct vnode **vpp)
{
struct file *fp;
@@ -3646,14 +3649,15 @@ _fgetvp(struct thread *td, int fd, int flags, cap_rights_t *needrightsp,
}
int
-fgetvp(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
+fgetvp(struct thread *td, int fd, const cap_rights_t *rightsp,
+ struct vnode **vpp)
{
return (_fgetvp(td, fd, 0, rightsp, vpp));
}
int
-fgetvp_rights(struct thread *td, int fd, cap_rights_t *needrightsp,
+fgetvp_rights(struct thread *td, int fd, const cap_rights_t *needrightsp,
struct filecaps *havecaps, struct vnode **vpp)
{
struct filecaps caps;
@@ -3685,14 +3689,16 @@ out:
}
int
-fgetvp_read(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
+fgetvp_read(struct thread *td, int fd, const cap_rights_t *rightsp,
+ struct vnode **vpp)
{
return (_fgetvp(td, fd, FREAD, rightsp, vpp));
}
int
-fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp)
+fgetvp_exec(struct thread *td, int fd, const cap_rights_t *rightsp,
+ struct vnode **vpp)
{
return (_fgetvp(td, fd, FEXEC, rightsp, vpp));
@@ -3700,7 +3706,7 @@ fgetvp_exec(struct thread *td, int fd, cap_rights_t *rightsp, struct vnode **vpp
#ifdef notyet
int
-fgetvp_write(struct thread *td, int fd, cap_rights_t *rightsp,
+fgetvp_write(struct thread *td, int fd, const cap_rights_t *rightsp,
struct vnode **vpp)
{
@@ -3718,13 +3724,10 @@ int __noinline
_fdrop(struct file *fp, struct thread *td)
{
int error;
-#ifdef INVARIANTS
- int count;
- count = refcount_load(&fp->f_count);
- if (count != 0)
- panic("fdrop: fp %p count %d", fp, count);
-#endif
+ KASSERT(refcount_load(&fp->f_count) == 0,
+ ("fdrop: fp %p count %d", fp, refcount_load(&fp->f_count)));
+
error = fo_close(fp, td);
atomic_subtract_int(&openfiles, 1);
crfree(fp->f_cred);
diff --git a/sys/kern/sys_procdesc.c b/sys/kern/sys_procdesc.c
index aab7b1616594..4665dc2c0421 100644
--- a/sys/kern/sys_procdesc.c
+++ b/sys/kern/sys_procdesc.c
@@ -121,7 +121,7 @@ static struct fileops procdesc_ops = {
* died.
*/
int
-procdesc_find(struct thread *td, int fd, cap_rights_t *rightsp,
+procdesc_find(struct thread *td, int fd, const cap_rights_t *rightsp,
struct proc **p)
{
struct procdesc *pd;
@@ -168,7 +168,8 @@ procdesc_pid(struct file *fp_procdesc)
* Retrieve the PID associated with a process descriptor.
*/
int
-kern_pdgetpid(struct thread *td, int fd, cap_rights_t *rightsp, pid_t *pidp)
+kern_pdgetpid(struct thread *td, int fd, const cap_rights_t *rightsp,
+ pid_t *pidp)
{
struct file *fp;
int error;
diff --git a/sys/kern/uipc_mqueue.c b/sys/kern/uipc_mqueue.c
index be3e3fefa749..926a9d311b67 100644
--- a/sys/kern/uipc_mqueue.c
+++ b/sys/kern/uipc_mqueue.c
@@ -846,7 +846,8 @@ mqfs_lookupx(struct vop_cachedlookup_args *ap)
struct mqfs_node *pd;
struct mqfs_node *pn;
struct mqfs_info *mqfs;
- int nameiop, flags, error, namelen;
+ uint64_t flags;
+ int nameiop, error, namelen;
char *pname;
struct thread *td;
@@ -2159,13 +2160,14 @@ sys_kmq_unlink(struct thread *td, struct kmq_unlink_args *uap)
return (error);
}
-typedef int (*_fgetf)(struct thread *, int, cap_rights_t *, struct file **);
+typedef int (*_fgetf)(struct thread *, int, const cap_rights_t *,
+ struct file **);
/*
* Get message queue by giving file slot
*/
static int
-_getmq(struct thread *td, int fd, cap_rights_t *rightsp, _fgetf func,
+_getmq(struct thread *td, int fd, const cap_rights_t *rightsp, _fgetf func,
struct file **fpp, struct mqfs_node **ppn, struct mqueue **pmq)
{
struct mqfs_node *pn;
diff --git a/sys/kern/uipc_sem.c b/sys/kern/uipc_sem.c
index 7cb25749ad9c..9871c0528338 100644
--- a/sys/kern/uipc_sem.c
+++ b/sys/kern/uipc_sem.c
@@ -123,8 +123,8 @@ static int ksem_create(struct thread *td, const char *path,
semid_t *semidp, mode_t mode, unsigned int value,
int flags, int compat32);
static void ksem_drop(struct ksem *ks);
-static int ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
- struct file **fpp);
+static int ksem_get(struct thread *td, semid_t id,
+ const cap_rights_t *rightsp, struct file **fpp);
static struct ksem *ksem_hold(struct ksem *ks);
static void ksem_insert(char *path, Fnv32_t fnv, struct ksem *ks);
static struct ksem *ksem_lookup(char *path, Fnv32_t fnv);
@@ -588,7 +588,7 @@ ksem_create(struct thread *td, const char *name, semid_t *semidp, mode_t mode,
}
static int
-ksem_get(struct thread *td, semid_t id, cap_rights_t *rightsp,
+ksem_get(struct thread *td, semid_t id, const cap_rights_t *rightsp,
struct file **fpp)
{
struct ksem *ks;
diff --git a/sys/kern/uipc_syscalls.c b/sys/kern/uipc_syscalls.c
index ef3ebeb58176..336a0dd77d5c 100644
--- a/sys/kern/uipc_syscalls.c
+++ b/sys/kern/uipc_syscalls.c
@@ -91,7 +91,7 @@ static int sockargs(struct mbuf **, char *, socklen_t, int);
* A reference on the file entry is held upon returning.
*/
int
-getsock_cap(struct thread *td, int fd, cap_rights_t *rightsp,
+getsock_cap(struct thread *td, int fd, const cap_rights_t *rightsp,
struct file **fpp, u_int *fflagp, struct filecaps *havecapsp)
{
struct file *fp;
@@ -727,7 +727,7 @@ kern_sendit(struct thread *td, int s, struct msghdr *mp, int flags,
struct uio auio;
struct iovec *iov;
struct socket *so;
- cap_rights_t *rights;
+ const cap_rights_t *rights;
#ifdef KTRACE
struct uio *ktruio = NULL;
#endif
diff --git a/sys/kern/vfs_cache.c b/sys/kern/vfs_cache.c
index aacbd43403e1..e6cf39c09f19 100644
--- a/sys/kern/vfs_cache.c
+++ b/sys/kern/vfs_cache.c
@@ -4006,7 +4006,7 @@ SYSCTL_PROC(_vfs_cache_param, OID_AUTO, fast_lookup, CTLTYPE_INT|CTLFLAG_RW|CTLF
*/
struct nameidata_outer {
size_t ni_pathlen;
- int cn_flags;
+ uint64_t cn_flags;
};
struct nameidata_saved {
@@ -4292,7 +4292,7 @@ cache_fpl_terminated(struct cache_fpl *fpl)
(NC_NOMAKEENTRY | NC_KEEPPOSENTRY | LOCKLEAF | LOCKPARENT | WANTPARENT | \
FAILIFEXISTS | FOLLOW | EMPTYPATH | LOCKSHARED | SAVENAME | SAVESTART | \
WILLBEDIR | ISOPEN | NOMACCHECK | AUDITVNODE1 | AUDITVNODE2 | NOCAPCHECK | \
- WANTIOCTLCAPS)
+ WANTIOCTLCAPS | NAMEILOOKUP)
#define CACHE_FPL_INTERNAL_CN_FLAGS \
(ISDOTDOT | MAKEENTRY | ISLASTCN)
@@ -5126,30 +5126,19 @@ static int __noinline
cache_fplookup_dotdot(struct cache_fpl *fpl)
{
struct nameidata *ndp;
- struct componentname *cnp;
struct namecache *ncp;
struct vnode *dvp;
- struct prison *pr;
u_char nc_flag;
ndp = fpl->ndp;
- cnp = fpl->cnp;
dvp = fpl->dvp;
- MPASS(cache_fpl_isdotdot(cnp));
+ MPASS(cache_fpl_isdotdot(fpl->cnp));
/*
* XXX this is racy the same way regular lookup is
*/
- for (pr = cnp->cn_cred->cr_prison; pr != NULL;
- pr = pr->pr_parent)
- if (dvp == pr->pr_root)
- break;
-
- if (dvp == ndp->ni_rootdir ||
- dvp == ndp->ni_topdir ||
- dvp == rootvnode ||
- pr != NULL) {
+ if (lookup_isroot(ndp, dvp)) {
fpl->tvp = dvp;
fpl->tvp_seqc = vn_seqc_read_any(dvp);
if (seqc_in_modify(fpl->tvp_seqc)) {
diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c
index cb013eb7ff83..dc8b7b92ccd4 100644
--- a/sys/kern/vfs_lookup.c
+++ b/sys/kern/vfs_lookup.c
@@ -530,12 +530,12 @@ namei(struct nameidata *ndp)
cnp->cn_origflags = cnp->cn_flags;
#endif
ndp->ni_cnd.cn_cred = ndp->ni_cnd.cn_thread->td_ucred;
- KASSERT(ndp->ni_resflags == 0, ("%s: garbage in ni_resflags: %x\n",
+ KASSERT(ndp->ni_resflags == 0, ("%s: garbage in ni_resflags: %x",
__func__, ndp->ni_resflags));
KASSERT(cnp->cn_cred && td->td_proc, ("namei: bad cred/proc"));
KASSERT((cnp->cn_flags & NAMEI_INTERNAL_FLAGS) == 0,
- ("namei: unexpected flags: %" PRIx64 "\n",
- cnp->cn_flags & NAMEI_INTERNAL_FLAGS));
+ ("namei: unexpected flags: %#jx",
+ (uintmax_t)(cnp->cn_flags & NAMEI_INTERNAL_FLAGS)));
if (cnp->cn_flags & NOCACHE)
KASSERT(cnp->cn_nameiop != LOOKUP,
("%s: NOCACHE passed with LOOKUP", __func__));
@@ -761,6 +761,31 @@ needs_exclusive_leaf(struct mount *mp, int flags)
_Static_assert(MAXNAMLEN == NAME_MAX,
"MAXNAMLEN and NAME_MAX have different values");
+
+struct nameidata *
+lookup_nameidata(struct componentname *cnp)
+{
+ if ((cnp->cn_flags & NAMEILOOKUP) == 0)
+ return (NULL);
+ return (__containerof(cnp, struct nameidata, ni_cnd));
+}
+
+/*
+ * Would a dotdot lookup relative to dvp cause this lookup to cross a jail or
+ * chroot boundary?
+ */
+bool
+lookup_isroot(struct nameidata *ndp, struct vnode *dvp)
+{
+ for (struct prison *pr = ndp->ni_cnd.cn_cred->cr_prison; pr != NULL;
+ pr = pr->pr_parent) {
+ if (dvp == pr->pr_root)
+ return (true);
+ }
+ return (dvp == ndp->ni_rootdir || dvp == ndp->ni_topdir ||
+ dvp == rootvnode);
+}
+
/*
* Search a pathname.
* This is a very central and rather complicated routine.
@@ -808,7 +833,6 @@ lookup(struct nameidata *ndp)
struct vnode *dp = NULL; /* the directory we are searching */
struct vnode *tdp; /* saved dp */
struct mount *mp; /* mount table entry */
- struct prison *pr;
size_t prev_ni_pathlen; /* saved ndp->ni_pathlen */
int docache; /* == 0 do not cache last component */
int wantparent; /* 1 => wantparent or lockparent flag */
@@ -1008,15 +1032,11 @@ dirloop:
goto bad;
}
for (;;) {
- for (pr = cnp->cn_cred->cr_prison; pr != NULL;
- pr = pr->pr_parent)
- if (dp == pr->pr_root)
- break;
- bool isroot = dp == ndp->ni_rootdir ||
- dp == ndp->ni_topdir || dp == rootvnode ||
- pr != NULL;
- if (isroot && (ndp->ni_lcf &
- NI_LCF_STRICTRELATIVE) != 0) {
+ bool isroot;
+
+ isroot = lookup_isroot(ndp, dp);
+ if (__predict_false(isroot && (ndp->ni_lcf &
+ NI_LCF_STRICTRELATIVE) != 0)) {
error = ENOTCAPABLE;
goto capdotdot;
}
diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c
index 7dcdaa66adb8..51f26b843c45 100644
--- a/sys/kern/vfs_syscalls.c
+++ b/sys/kern/vfs_syscalls.c
@@ -4315,7 +4315,7 @@ out:
* semantics.
*/
int
-getvnode_path(struct thread *td, int fd, cap_rights_t *rightsp,
+getvnode_path(struct thread *td, int fd, const cap_rights_t *rightsp,
struct file **fpp)
{
struct file *fp;
@@ -4353,7 +4353,8 @@ getvnode_path(struct thread *td, int fd, cap_rights_t *rightsp,
* A reference on the file entry is held upon returning.
*/
int
-getvnode(struct thread *td, int fd, cap_rights_t *rightsp, struct file **fpp)
+getvnode(struct thread *td, int fd, const cap_rights_t *rightsp,
+ struct file **fpp)
{
int error;
diff --git a/sys/kern/vfs_vnops.c b/sys/kern/vfs_vnops.c
index 6591b543ddea..e685d581733b 100644
--- a/sys/kern/vfs_vnops.c
+++ b/sys/kern/vfs_vnops.c
@@ -195,21 +195,26 @@ vn_open(struct nameidata *ndp, int *flagp, int cmode, struct file *fp)
}
static uint64_t
-open2nameif(int fmode, u_int vn_open_flags)
+open2nameif(int fmode, u_int vn_open_flags, uint64_t cn_flags)
{
uint64_t res;
- res = ISOPEN | LOCKLEAF;
+ res = ISOPEN | LOCKLEAF | cn_flags;
if ((fmode & O_RESOLVE_BENEATH) != 0)
res |= RBENEATH;
if ((fmode & O_EMPTY_PATH) != 0)
res |= EMPTYPATH;
+ if ((fmode & O_NOFOLLOW) != 0)
+ res &= ~FOLLOW;
if ((vn_open_flags & VN_OPEN_NOAUDIT) == 0)
res |= AUDITVNODE1;
+ else
+ res &= ~AUDITVNODE1;
if ((vn_open_flags & VN_OPEN_NOCAPCHECK) != 0)
res |= NOCAPCHECK;
if ((vn_open_flags & VN_OPEN_WANTIOCTLCAPS) != 0)
res |= WANTIOCTLCAPS;
+
return (res);
}
@@ -242,7 +247,9 @@ restart:
return (EINVAL);
else if ((fmode & (O_CREAT | O_DIRECTORY)) == O_CREAT) {
ndp->ni_cnd.cn_nameiop = CREATE;
- ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags);
+ ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags,
+ ndp->ni_cnd.cn_flags);
+
/*
* Set NOCACHE to avoid flushing the cache when
* rolling in many files at once.
@@ -251,8 +258,8 @@ restart:
* exist despite NOCACHE.
*/
ndp->ni_cnd.cn_flags |= LOCKPARENT | NOCACHE | NC_KEEPPOSENTRY;
- if ((fmode & O_EXCL) == 0 && (fmode & O_NOFOLLOW) == 0)
- ndp->ni_cnd.cn_flags |= FOLLOW;
+ if ((fmode & O_EXCL) != 0)
+ ndp->ni_cnd.cn_flags &= ~FOLLOW;
if ((vn_open_flags & VN_OPEN_INVFS) == 0)
bwillwrite();
if ((error = namei(ndp)) != 0)
@@ -320,9 +327,8 @@ restart:
}
} else {
ndp->ni_cnd.cn_nameiop = LOOKUP;
- ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags);
- ndp->ni_cnd.cn_flags |= (fmode & O_NOFOLLOW) != 0 ? NOFOLLOW :
- FOLLOW;
+ ndp->ni_cnd.cn_flags = open2nameif(fmode, vn_open_flags,
+ ndp->ni_cnd.cn_flags);
if ((fmode & FWRITE) == 0)
ndp->ni_cnd.cn_flags |= LOCKSHARED;
if ((error = namei(ndp)) != 0)