summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBob Beck <beck@cvs.openbsd.org>2019-09-11 15:01:41 +0000
committerBob Beck <beck@cvs.openbsd.org>2019-09-11 15:01:41 +0000
commitf75a014c0238c72040557df6e22be5a01eb8712a (patch)
tree5c069402a10b214dd6ae93491bb14961bca1baaa
parent8e93f11dfb8d73f15e084a3da8ef2b7bec018ea3 (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.c5
-rw-r--r--sys/kern/kern_unveil.c50
-rw-r--r--sys/kern/vfs_lookup.c5
-rw-r--r--sys/sys/namei.h4
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 *);