Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/fs/udf Provide additional checks to udf_lookup and restr...



details:   https://anonhg.NetBSD.org/src/rev/2995756aedcb
branches:  trunk
changeset: 787828:2995756aedcb
user:      reinoud <reinoud%NetBSD.org@localhost>
date:      Fri Jul 05 20:04:57 2013 +0000

description:
Provide additional checks to udf_lookup and restructure it a bit.

Should fix PR 47988

diffstat:

 sys/fs/udf/udf_vnops.c |  122 +++++++++++++++++++++++++++++-------------------
 1 files changed, 73 insertions(+), 49 deletions(-)

diffs (175 lines):

diff -r 455d708b127d -r 2995756aedcb sys/fs/udf/udf_vnops.c
--- a/sys/fs/udf/udf_vnops.c    Fri Jul 05 15:45:17 2013 +0000
+++ b/sys/fs/udf/udf_vnops.c    Fri Jul 05 20:04:57 2013 +0000
@@ -1,4 +1,4 @@
-/* $NetBSD: udf_vnops.c,v 1.79 2013/07/03 15:39:22 reinoud Exp $ */
+/* $NetBSD: udf_vnops.c,v 1.80 2013/07/05 20:04:57 reinoud Exp $ */
 
 /*
  * Copyright (c) 2006, 2008 Reinoud Zandijk
@@ -32,7 +32,7 @@
 
 #include <sys/cdefs.h>
 #ifndef lint
-__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.79 2013/07/03 15:39:22 reinoud Exp $");
+__KERNEL_RCSID(0, "$NetBSD: udf_vnops.c,v 1.80 2013/07/05 20:04:57 reinoud Exp $");
 #endif /* not lint */
 
 
@@ -656,9 +656,11 @@
        struct udf_node  *dir_node, *res_node;
        struct udf_mount *ump;
        struct long_ad    icb_loc;
+       mode_t mode;
+       uid_t d_uid;
+       gid_t d_gid;
        const char *name;
        int namelen, nameiop, islastcn, mounted_ro;
-       int vnodetp;
        int error, found;
 
        dir_node = VTOI(dvp);
@@ -706,9 +708,14 @@
        if ((cnp->cn_namelen == 1) && (cnp->cn_nameptr[0] == '.')) {
                DPRINTF(LOOKUP, ("\tlookup '.'\n"));
                /* special case 1 '.' */
+               if (islastcn && cnp->cn_nameiop == RENAME) {
+                       error = EISDIR;
+                       goto out;
+               }
                vref(dvp);
                *vpp = dvp;
                /* done */
+               goto done;
        } else if (cnp->cn_flags & ISDOTDOT) {
                /* special case 2 '..' */
                DPRINTF(LOOKUP, ("\tlookup '..'\n"));
@@ -740,58 +747,74 @@
 
                /* try to relock parent */
                vn_lock(dvp, LK_EXCLUSIVE | LK_RETRY);
-       } else {
-               DPRINTF(LOOKUP, ("\tlookup file\n"));
-               /* all other files */
-               /* lookup filename in the directory; location icb_loc */
-               name    = cnp->cn_nameptr;
-               namelen = cnp->cn_namelen;
-               error = udf_lookup_name_in_dir(dvp, name, namelen,
-                               &icb_loc, &found);
+               goto out;
+       }
+
+       /* all other files */
+       DPRINTF(LOOKUP, ("\tlookup file/dir in directory\n"));
+
+       /* lookup filename in the directory; location icb_loc */
+       name    = cnp->cn_nameptr;
+       namelen = cnp->cn_namelen;
+       error = udf_lookup_name_in_dir(dvp, name, namelen,
+                       &icb_loc, &found);
+       if (error)
+               goto out;
+       if (!found) {
+               DPRINTF(LOOKUP, ("\tNOT found\n"));
+               /*
+                * The entry was not found in the directory.  This is
+                * valid if we are creating or renaming an entry and
+                * are working on the last component of the path name.
+                */
+               if (islastcn && (cnp->cn_nameiop == CREATE ||
+                                cnp->cn_nameiop == RENAME)) {
+                       error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
+                       if (error) {
+                               goto out;
+                       }
+                       error = EJUSTRETURN;
+               } else {
+                       error = ENOENT;
+               }
+               /* done */
+               goto done;
+       }
+
+       /*
+        * XXX NOTE tmpfs has a test here that tests that intermediate
+        * components i.e. not the last one ought to be either a directory or
+        * a link. It seems to function well without this code.
+        */
+
+       /* check the permissions */
+       if (islastcn && (cnp->cn_nameiop == DELETE ||
+                        cnp->cn_nameiop == RENAME)  ) {
+               error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
                if (error)
                        goto out;
-               if (!found) {
-                       DPRINTF(LOOKUP, ("\tNOT found\n"));
-                       /*
-                        * UGH, didn't find name. If we're creating or
-                        * renaming on the last name this is OK and we ought
-                        * to return EJUSTRETURN if its allowed to be created.
-                        */
-                       error = ENOENT;
-                       if (islastcn &&
-                               (nameiop == CREATE || nameiop == RENAME))
-                                       error = 0;
-                       if (!error) {
-                               error = VOP_ACCESS(dvp, VWRITE, cnp->cn_cred);
-                               if (!error) {
-                                       error = EJUSTRETURN;
-                               }
-                       }
-                       /* done */
-               } else {
-                       /* try to create/reuse the node */
-                       error = udf_get_node(ump, &icb_loc, &res_node);
-                       if (!error) {
-                               /*
-                                * If we are not at the last path component
-                                * and found a non-directory or non-link entry
-                                * (which may itself be pointing to a
-                                * directory), raise an error.
-                                */
-                               vnodetp = res_node->vnode->v_type;
-                               if ((vnodetp != VDIR) && (vnodetp != VLNK)) {
-                                       if (!islastcn)
-                                               error = ENOTDIR;
-                               }
 
-                       }
-                       if (!error) {
-                               *vpp = res_node->vnode;
+               /* get node attributes */
+               mode = udf_getaccessmode(dir_node);
+               udf_getownership(dir_node, &d_uid, &d_gid);
+               if ((mode & S_ISTXT) != 0) {
+                       error = kauth_authorize_vnode(cnp->cn_cred,
+                           KAUTH_VNODE_DELETE, res_node->vnode,
+                           dir_node->vnode, genfs_can_sticky(cnp->cn_cred,
+                           d_uid, d_uid));
+                       if (error) {
+                               error = EPERM;
+                               goto out;
                        }
                }
-       }       
+       }
+       /* try to create/reuse the node */
+       error = udf_get_node(ump, &icb_loc, &res_node);
+       if (error)
+               goto out;
+       *vpp = res_node->vnode;
 
-out:
+done:
        /*
         * Store result in the cache if requested. If we are creating a file,
         * the file might not be found and thus putting it into the namecache
@@ -801,6 +824,7 @@
                cache_enter(dvp, *vpp, cnp->cn_nameptr, cnp->cn_namelen,
                            cnp->cn_flags);
 
+out:
        DPRINTFIF(LOOKUP, error, ("udf_lookup returing error %d\n", error));
 
        return error;



Home | Main Index | Thread Index | Old Index