]> bbs.cooldavid.org Git - net-next-2.6.git/blobdiff - fs/open.c
[PATCH] preparation to __user_walk_fd cleanup
[net-next-2.6.git] / fs / open.c
index bb98d2fe809f09fa382a9d6224231206e1161962..e94266700eda26efea0fe57afd41b18f3b01e23d 100644 (file)
--- a/fs/open.c
+++ b/fs/open.c
@@ -251,12 +251,12 @@ static long do_sys_truncate(const char __user * path, loff_t length)
        if (error)
                goto dput_and_out;
 
-       error = vfs_permission(&nd, MAY_WRITE);
+       error = inode_permission(inode, MAY_WRITE);
        if (error)
                goto mnt_drop_write_and_out;
 
        error = -EPERM;
-       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+       if (IS_APPEND(inode))
                goto mnt_drop_write_and_out;
 
        error = get_write_access(inode);
@@ -426,6 +426,7 @@ out:
 asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
 {
        struct nameidata nd;
+       struct inode *inode;
        int old_fsuid, old_fsgid;
        kernel_cap_t uninitialized_var(old_cap);  /* !SECURE_NO_SETUID_FIXUP */
        int res;
@@ -457,14 +458,25 @@ asmlinkage long sys_faccessat(int dfd, const char __user *filename, int mode)
                        old_cap = cap_set_effective(current->cap_permitted);
        }
 
-       res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW|LOOKUP_ACCESS, &nd);
+       res = __user_walk_fd(dfd, filename, LOOKUP_FOLLOW, &nd);
        if (res)
                goto out;
 
-       res = vfs_permission(&nd, mode);
+       inode = nd.path.dentry->d_inode;
+
+       if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
+               /*
+                * MAY_EXEC on regular files is denied if the fs is mounted
+                * with the "noexec" flag.
+                */
+               res = -EACCES;
+               if (nd.path.mnt->mnt_flags & MNT_NOEXEC)
+                       goto out_path_release;
+       }
+
+       res = inode_permission(inode, mode | MAY_ACCESS);
        /* SuS v2 requires we report a read only fs too */
-       if(res || !(mode & S_IWOTH) ||
-          special_file(nd.path.dentry->d_inode->i_mode))
+       if (res || !(mode & S_IWOTH) || special_file(inode->i_mode))
                goto out_path_release;
        /*
         * This is a rare case where using __mnt_is_readonly()
@@ -501,12 +513,11 @@ asmlinkage long sys_chdir(const char __user * filename)
        struct nameidata nd;
        int error;
 
-       error = __user_walk(filename,
-                           LOOKUP_FOLLOW|LOOKUP_DIRECTORY|LOOKUP_CHDIR, &nd);
+       error = __user_walk(filename, LOOKUP_FOLLOW|LOOKUP_DIRECTORY, &nd);
        if (error)
                goto out;
 
-       error = vfs_permission(&nd, MAY_EXEC);
+       error = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
        if (error)
                goto dput_and_out;
 
@@ -535,7 +546,7 @@ asmlinkage long sys_fchdir(unsigned int fd)
        if (!S_ISDIR(inode->i_mode))
                goto out_putf;
 
-       error = file_permission(file, MAY_EXEC);
+       error = inode_permission(inode, MAY_EXEC | MAY_ACCESS);
        if (!error)
                set_fs_pwd(current->fs, &file->f_path);
 out_putf:
@@ -549,11 +560,11 @@ asmlinkage long sys_chroot(const char __user * filename)
        struct nameidata nd;
        int error;
 
-       error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY | LOOKUP_NOALT, &nd);
+       error = __user_walk(filename, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &nd);
        if (error)
                goto out;
 
-       error = vfs_permission(&nd, MAY_EXEC);
+       error = inode_permission(nd.path.dentry->d_inode, MAY_EXEC | MAY_ACCESS);
        if (error)
                goto dput_and_out;
 
@@ -562,7 +573,6 @@ asmlinkage long sys_chroot(const char __user * filename)
                goto dput_and_out;
 
        set_fs_root(current->fs, &nd.path);
-       set_fs_altroot();
        error = 0;
 dput_and_out:
        path_put(&nd.path);
@@ -590,9 +600,6 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
        err = mnt_want_write(file->f_path.mnt);
        if (err)
                goto out_putf;
-       err = -EPERM;
-       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-               goto out_drop_write;
        mutex_lock(&inode->i_mutex);
        if (mode == (mode_t) -1)
                mode = inode->i_mode;
@@ -600,8 +607,6 @@ asmlinkage long sys_fchmod(unsigned int fd, mode_t mode)
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
        err = notify_change(dentry, &newattrs);
        mutex_unlock(&inode->i_mutex);
-
-out_drop_write:
        mnt_drop_write(file->f_path.mnt);
 out_putf:
        fput(file);
@@ -625,11 +630,6 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
        error = mnt_want_write(nd.path.mnt);
        if (error)
                goto dput_and_out;
-
-       error = -EPERM;
-       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-               goto out_drop_write;
-
        mutex_lock(&inode->i_mutex);
        if (mode == (mode_t) -1)
                mode = inode->i_mode;
@@ -637,8 +637,6 @@ asmlinkage long sys_fchmodat(int dfd, const char __user *filename,
        newattrs.ia_valid = ATTR_MODE | ATTR_CTIME;
        error = notify_change(nd.path.dentry, &newattrs);
        mutex_unlock(&inode->i_mutex);
-
-out_drop_write:
        mnt_drop_write(nd.path.mnt);
 dput_and_out:
        path_put(&nd.path);
@@ -653,18 +651,10 @@ asmlinkage long sys_chmod(const char __user *filename, mode_t mode)
 
 static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
 {
-       struct inode * inode;
+       struct inode *inode = dentry->d_inode;
        int error;
        struct iattr newattrs;
 
-       error = -ENOENT;
-       if (!(inode = dentry->d_inode)) {
-               printk(KERN_ERR "chown_common: NULL inode\n");
-               goto out;
-       }
-       error = -EPERM;
-       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-               goto out;
        newattrs.ia_valid =  ATTR_CTIME;
        if (user != (uid_t) -1) {
                newattrs.ia_valid |= ATTR_UID;
@@ -680,7 +670,7 @@ static int chown_common(struct dentry * dentry, uid_t user, gid_t group)
        mutex_lock(&inode->i_mutex);
        error = notify_change(dentry, &newattrs);
        mutex_unlock(&inode->i_mutex);
-out:
+
        return error;
 }