Add an UNVEIL_USERSET flag which is set when a unveil node is added via
authorclaudio <claudio@openbsd.org>
Sun, 9 Jan 2022 10:28:07 +0000 (10:28 +0000)
committerclaudio <claudio@openbsd.org>
Sun, 9 Jan 2022 10:28:07 +0000 (10:28 +0000)
unveil(2). It is not set for nodes that are added as a result of a file
being added via unveil(2). Use this flag to test if backtracking should
be done or not. Also introduce UNVEIL_MASK which checks if any user flags
are set and is used to properly return EACCES vs ENOENT.

This fixes a problem where unveil("/", "r") & unveil("/usr/bin/id", "rx")
cause an error when read accessing "/usr/bin". It also makes sure that
unveil(path, "") will return ENOENT for any access of anything under path.

Reported by and OK semarie@

sys/kern/kern_unveil.c
sys/sys/namei.h

index 801c210..50a043e 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: kern_unveil.c,v 1.51 2021/09/09 13:02:36 claudio Exp $        */
+/*     $OpenBSD: kern_unveil.c,v 1.52 2022/01/09 10:28:07 claudio Exp $        */
 
 /*
  * Copyright (c) 2017-2019 Bob Beck <beck@openbsd.org>
@@ -345,7 +345,7 @@ unveil_parsepermissions(const char *permissions, u_char *perms)
        size_t i = 0;
        char c;
 
-       *perms = 0;
+       *perms = UNVEIL_USERSET;
        while ((c = permissions[i++]) != '\0') {
                switch (c) {
                case 'r':
@@ -708,11 +708,13 @@ unveil_check_final(struct proc *p, struct nameidata *ni)
        if (ni->ni_vp != NULL && ni->ni_vp->v_type == VDIR) {
                /* We are matching a directory terminal component */
                uv = unveil_lookup(ni->ni_vp, pr, NULL);
-               if (uv == NULL) {
+               if (uv == NULL || (uv->uv_flags & UNVEIL_USERSET) == 0) {
 #ifdef DEBUG_UNVEIL
                        printf("unveil: %s(%d) no match for vnode %p\n",
                            pr->ps_comm, pr->ps_pid, ni->ni_vp);
 #endif
+                       if (uv != NULL)
+                               ni->ni_unveil_match = uv;
                        goto done;
                }
                if (!unveil_flagmatch(ni, uv->uv_flags)) {
@@ -722,7 +724,7 @@ unveil_check_final(struct proc *p, struct nameidata *ni)
                            pr->ps_comm, pr->ps_pid, ni->ni_vp);
 #endif
                        pr->ps_acflag |= AUNVEIL;
-                       if (uv->uv_flags & UNVEIL_USERSET)
+                       if (uv->uv_flags & UNVEIL_MASK)
                                return EACCES;
                        else
                                return ENOENT;
@@ -764,12 +766,15 @@ unveil_check_final(struct proc *p, struct nameidata *ni)
 #endif
                        /*
                         * If dir has user set restrictions fail with
-                        * EACCES. Otherwise, use any covering match
-                        * that we found above this dir.
+                        * EACCES or ENOENT. Otherwise, use any covering
+                        * match that we found above this dir.
                         */
                        if (uv->uv_flags & UNVEIL_USERSET) {
                                pr->ps_acflag |= AUNVEIL;
-                               return EACCES;
+                               if (uv->uv_flags & UNVEIL_MASK)
+                                       return EACCES;
+                               else
+                                       return ENOENT;
                        }
                        /* start backtrack from this node */
                        ni->ni_unveil_match = uv;
@@ -820,7 +825,10 @@ done:
                            pr->ps_comm, pr->ps_pid, uv->uv_vp);
 #endif
                        pr->ps_acflag |= AUNVEIL;
-                       return EACCES;
+                       if (uv->uv_flags & UNVEIL_MASK)
+                               return EACCES;
+                       else
+                               return ENOENT;
                }
 #ifdef DEBUG_UNVEIL
                printf("unveil: %s(%d) check cover for vnode %p, uv_cover %zd\n",
index 7c7e7c9..7e52ed0 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: namei.h,v 1.48 2021/09/02 12:35:23 claudio Exp $      */
+/*     $OpenBSD: namei.h,v 1.49 2022/01/09 10:28:07 claudio Exp $      */
 /*     $NetBSD: namei.h,v 1.11 1996/02/09 18:25:20 christos Exp $      */
 
 /*
@@ -268,6 +268,7 @@ struct      nchstats {
 #define        UNVEIL_WRITE    0x02
 #define        UNVEIL_CREATE   0x04
 #define        UNVEIL_EXEC     0x08
-#define        UNVEIL_USERSET  0x0F
+#define        UNVEIL_USERSET  0x10
+#define        UNVEIL_MASK     0x0F
 
 #endif /* !_SYS_NAMEI_H_ */