]> err.no Git - linux-2.6/blobdiff - fs/namei.c
pid namespaces: round up the API
[linux-2.6] / fs / namei.c
index bab0d19a2e3651db9c70860d77b76f54fe1829da..1e5c7166916415b53abf5908e045dcb28f6bc072 100644 (file)
@@ -30,7 +30,6 @@
 #include <linux/capability.h>
 #include <linux/file.h>
 #include <linux/fcntl.h>
-#include <linux/namei.h>
 #include <asm/namei.h>
 #include <asm/uaccess.h>
 
@@ -228,10 +227,14 @@ int generic_permission(struct inode *inode, int mask,
 
 int permission(struct inode *inode, int mask, struct nameidata *nd)
 {
-       umode_t mode = inode->i_mode;
        int retval, submask;
+       struct vfsmount *mnt = NULL;
+
+       if (nd)
+               mnt = nd->mnt;
 
        if (mask & MAY_WRITE) {
+               umode_t mode = inode->i_mode;
 
                /*
                 * Nobody gets write access to a read-only fs.
@@ -247,22 +250,34 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
                        return -EACCES;
        }
 
-
-       /*
-        * MAY_EXEC on regular files requires special handling: We override
-        * filesystem execute permissions if the mode bits aren't set or
-        * the fs is mounted with the "noexec" flag.
-        */
-       if ((mask & MAY_EXEC) && S_ISREG(mode) && (!(mode & S_IXUGO) ||
-                       (nd && nd->mnt && (nd->mnt->mnt_flags & MNT_NOEXEC))))
-               return -EACCES;
+       if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode)) {
+               /*
+                * MAY_EXEC on regular files is denied if the fs is mounted
+                * with the "noexec" flag.
+                */
+               if (mnt && (mnt->mnt_flags & MNT_NOEXEC))
+                       return -EACCES;
+       }
 
        /* Ordinary permission routines do not understand MAY_APPEND. */
        submask = mask & ~MAY_APPEND;
-       if (inode->i_op && inode->i_op->permission)
+       if (inode->i_op && inode->i_op->permission) {
                retval = inode->i_op->permission(inode, submask, nd);
-       else
+               if (!retval) {
+                       /*
+                        * Exec permission on a regular file is denied if none
+                        * of the execute bits are set.
+                        *
+                        * This check should be done by the ->permission()
+                        * method.
+                        */
+                       if ((mask & MAY_EXEC) && S_ISREG(inode->i_mode) &&
+                           !(inode->i_mode & S_IXUGO))
+                               return -EACCES;
+               }
+       } else {
                retval = generic_permission(inode, submask, NULL);
+       }
        if (retval)
                return retval;
 
@@ -1593,10 +1608,6 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
        if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
                return -EISDIR;
 
-       error = vfs_permission(nd, acc_mode);
-       if (error)
-               return error;
-
        /*
         * FIFO's, sockets and device files are special: they don't
         * actually live on the filesystem itself, and as such you
@@ -1611,6 +1622,10 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
                flag &= ~O_TRUNC;
        } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
                return -EROFS;
+
+       error = vfs_permission(nd, acc_mode);
+       if (error)
+               return error;
        /*
         * An append-only file must be opened in append mode for writing.
         */
@@ -1644,8 +1659,10 @@ int may_open(struct nameidata *nd, int acc_mode, int flag)
                error = locks_verify_locked(inode);
                if (!error) {
                        DQUOT_INIT(inode);
-                       
-                       error = do_truncate(dentry, 0, ATTR_MTIME|ATTR_CTIME, NULL);
+
+                       error = do_truncate(dentry, 0,
+                                           ATTR_MTIME|ATTR_CTIME|ATTR_OPEN,
+                                           NULL);
                }
                put_write_access(inode);
                if (error)