diff options
author | Bob Beck <beck@cvs.openbsd.org> | 2019-09-11 15:01:41 +0000 |
---|---|---|
committer | Bob Beck <beck@cvs.openbsd.org> | 2019-09-11 15:01:41 +0000 |
commit | f75a014c0238c72040557df6e22be5a01eb8712a (patch) | |
tree | 5c069402a10b214dd6ae93491bb14961bca1baaa | |
parent | 8e93f11dfb8d73f15e084a3da8ef2b7bec018ea3 (diff) |
Fix unveil for relative lookups in the non AT_FDCWD case
Issue spotted by Benjamin Baier <programmer@netzbasis.de> with relative
path lookups from openat(2). Lacking a current working directory unveil,
operations using the *at functions could fail when not crossing an unveil,
since an initial covering unveil was not found.
This corrects this so we walk up from the directory vnode to find a
covering unveil at the start of non AT_FDCWD lookups, and adds regress
for this case.
ok bluhm@
-rw-r--r-- | regress/sys/kern/unveil/syscalls.c | 5 | ||||
-rw-r--r-- | sys/kern/kern_unveil.c | 50 | ||||
-rw-r--r-- | sys/kern/vfs_lookup.c | 5 | ||||
-rw-r--r-- | sys/sys/namei.h | 4 |
4 files changed, 46 insertions, 18 deletions
diff --git a/regress/sys/kern/unveil/syscalls.c b/regress/sys/kern/unveil/syscalls.c index 813fd7e5c04..7c8d96ce967 100644 --- a/regress/sys/kern/unveil/syscalls.c +++ b/regress/sys/kern/unveil/syscalls.c @@ -1,4 +1,4 @@ -/* $OpenBSD: syscalls.c,v 1.24 2019/09/08 22:43:14 beck Exp $ */ +/* $OpenBSD: syscalls.c,v 1.25 2019/09/11 15:01:40 beck Exp $ */ /* * Copyright (c) 2017-2019 Bob Beck <beck@openbsd.org> @@ -172,8 +172,7 @@ test_openat(int do_uv) UV_SHOULD_SUCCEED((openat(dirfd2after, "../derp", O_RDWR|O_CREAT) == -1), "openat"); UV_SHOULD_ENOENT((openat(dirfd2after, "../../derpyluvs", O_RDWR|O_CREAT) == -1), "openat"); UV_SHOULD_ENOENT((openat(dirfd2after, "/etc/hosts", O_RDONLY) == -1), "openat"); - /* XXX won't work until fix in */ - /* UV_SHOULD_SUCCEED((openat(dirfd2after, "hooray", O_RDWR|O_CREAT) == -1), "openat"); */ + UV_SHOULD_SUCCEED((openat(dirfd2after, "hooray", O_RDWR|O_CREAT) == -1), "openat"); UV_SHOULD_SUCCEED((openat(dirfd2after, uv_file1, O_RDWR|O_CREAT) == -1), "openat"); UV_SHOULD_ENOENT((openat(dirfd2after, uv_file2, O_RDWR|O_CREAT) == -1), "openat"); return 0; diff --git a/sys/kern/kern_unveil.c b/sys/kern/kern_unveil.c index a7442427543..1a887590c53 100644 --- a/sys/kern/kern_unveil.c +++ b/sys/kern/kern_unveil.c @@ -1,4 +1,4 @@ -/* $OpenBSD: kern_unveil.c,v 1.32 2019/08/05 13:31:07 bluhm Exp $ */ +/* $OpenBSD: kern_unveil.c,v 1.33 2019/09/11 15:01:40 beck Exp $ */ /* * Copyright (c) 2017-2019 Bob Beck <beck@openbsd.org> @@ -711,21 +711,49 @@ unveil_covered(struct unveil *uv, struct vnode *dvp, struct process *pr) { /* - * Start a relative path lookup from current working directory unveil. + * Start a relative path lookup. Ensure we find whatever unveil covered + * where we start from, either by having a saved current working directory + * unveil, or by walking up and finding a cover the hard way if we are + * doing a non AT_FDCWD relative lookup. Caller passes a NULL dp + * if we are using AT_FDCWD. */ void -unveil_start_relative(struct proc *p, struct nameidata *ni) +unveil_start_relative(struct proc *p, struct nameidata *ni, struct vnode *dp) { - struct unveil *uv = p->p_p->ps_uvpcwd; + struct unveil *uv = NULL; + + if (dp != NULL && p->p_p->ps_uvpaths != NULL) { + ssize_t uvi; + /* + * XXX + * This is a non AT_FDCWD relative lookup starting + * from a file descriptor. As such, we can't use the + * saved current working directory unveil. We walk up + * and find what we are covered by. + */ + uv = unveil_lookup(dp, p, NULL); + if (uv == NULL) { + uvi = unveil_find_cover(dp, p); + if (uvi >= 0) { + KASSERT(uvi < p->p_p->ps_uvvcount); + uv = &p->p_p->ps_uvpaths[uvi]; + } + } + } else { + /* + * Check saved cwd unveil match. + * + * Since ps_uvpcwd is set on chdir (UNVEIL_READ) we + * don't need to go up any further as in the above + * case. + */ + uv = p->p_p->ps_uvpcwd; + } /* - * Check saved cwd unveil match. - * - * Since ps_uvpcwd is set on chdir (UNVEIL_READ) - * we don't need to go up any further, if the flags - * don't match, the cwd is not a match, and unless - * we find a matching unveil later on a later component - * of this lookup, we'll be out of luck + * If the flags don't match, we have no match from our + * starting point. If we do not find a matching unveil later + * on a later component of this lookup, we'll be out of luck */ if (uv && (unveil_flagmatch(ni, uv->uv_flags))) { #ifdef DEBUG_UNVEIL diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c index 933ca2b0279..da3048f0f18 100644 --- a/sys/kern/vfs_lookup.c +++ b/sys/kern/vfs_lookup.c @@ -1,4 +1,4 @@ -/* $OpenBSD: vfs_lookup.c,v 1.82 2019/07/29 12:35:19 bluhm Exp $ */ +/* $OpenBSD: vfs_lookup.c,v 1.83 2019/09/11 15:01:40 beck Exp $ */ /* $NetBSD: vfs_lookup.c,v 1.17 1996/02/09 19:00:59 christos Exp $ */ /* @@ -217,7 +217,7 @@ fail: } else if (ndp->ni_dirfd == AT_FDCWD) { dp = fdp->fd_cdir; vref(dp); - unveil_start_relative(p, ndp); + unveil_start_relative(p, ndp, NULL); unveil_check_component(p, ndp, dp); } else { struct file *fp = fd_getfile(fdp, ndp->ni_dirfd); @@ -232,6 +232,7 @@ fail: return (ENOTDIR); } vref(dp); + unveil_start_relative(p, ndp, dp); unveil_check_component(p, ndp, dp); FRELE(fp, p); } diff --git a/sys/sys/namei.h b/sys/sys/namei.h index 593432ebf70..6408988f673 100644 --- a/sys/sys/namei.h +++ b/sys/sys/namei.h @@ -1,4 +1,4 @@ -/* $OpenBSD: namei.h,v 1.42 2019/08/02 08:12:35 bluhm Exp $ */ +/* $OpenBSD: namei.h,v 1.43 2019/09/11 15:01:40 beck Exp $ */ /* $NetBSD: namei.h,v 1.11 1996/02/09 18:25:20 christos Exp $ */ /* @@ -209,7 +209,7 @@ void unveil_removevnode(struct vnode *); void unveil_free_traversed_vnodes(struct nameidata *); ssize_t unveil_find_cover(struct vnode *, struct proc *); struct unveil *unveil_lookup(struct vnode *, struct proc *, ssize_t *); -void unveil_start_relative(struct proc *, struct nameidata *); +void unveil_start_relative(struct proc *, struct nameidata *, struct vnode *); void unveil_check_component(struct proc *, struct nameidata *, struct vnode *); int unveil_check_final(struct proc *, struct nameidata *); |