]> git.neil.brown.name Git - history.git/commitdiff
[PATCH] open_namei cleanup, nfsctl permission check fix
authorAlexander Viro <viro@math.psu.edu>
Tue, 9 Apr 2002 10:09:44 +0000 (03:09 -0700)
committerLinus Torvalds <torvalds@penguin.transmeta.com>
Tue, 9 Apr 2002 10:09:44 +0000 (03:09 -0700)
a) part of open_namei() done after we'd found vfsmount/dentry of
the object we want to open had been split into a helper - may_open().

b) do_open() in fs/nfsctl.c didn't do any permission checks on
the nfsd file it was opening - sudden idiocy attack on my part (I missed
the fact that dentry_open() doesn't do permission checks - open_namei()
does).  Fixed by adding obvious may_open() calls.

fs/namei.c
fs/nfsctl.c
include/linux/fs.h

index 5813b32b98f7e96b6515f8b341c04a885905a96c..1bd152eb69dd3db4d47bb9ba912a806cd6b636b1 100644 (file)
@@ -988,6 +988,80 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
        return error;
 }
 
+int may_open(struct nameidata *nd, int acc_mode, int flag)
+{
+       struct dentry *dentry = nd->dentry;
+       struct inode *inode = dentry->d_inode;
+       int error;
+
+       if (!inode)
+               return -ENOENT;
+
+       if (S_ISLNK(inode->i_mode))
+               return -ELOOP;
+       
+       if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
+               return -EISDIR;
+
+       error = permission(inode, 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
+        * can write to them even if the filesystem is read-only.
+        */
+       if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
+               flag &= ~O_TRUNC;
+       } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
+               if (nd->mnt->mnt_flags & MNT_NODEV)
+                       return -EACCES;
+
+               flag &= ~O_TRUNC;
+       } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE))
+               return -EROFS;
+       /*
+        * An append-only file must be opened in append mode for writing.
+        */
+       if (IS_APPEND(inode)) {
+               if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))
+                       return -EPERM;
+               if (flag & O_TRUNC)
+                       return -EPERM;
+       }
+
+       /*
+        * Ensure there are no outstanding leases on the file.
+        */
+       error = get_lease(inode, flag);
+       if (error)
+               return error;
+
+       if (flag & O_TRUNC) {
+               error = get_write_access(inode);
+               if (error)
+                       return error;
+
+               /*
+                * Refuse to truncate files with mandatory locks held on them.
+                */
+               error = locks_verify_locked(inode);
+               if (!error) {
+                       DQUOT_INIT(inode);
+                       
+                       error = do_truncate(dentry, 0);
+               }
+               put_write_access(inode);
+               if (error)
+                       return error;
+       } else
+               if (flag & FMODE_WRITE)
+                       DQUOT_INIT(inode);
+
+       return 0;
+}
+
 /*
  *     open_namei()
  *
@@ -1005,7 +1079,6 @@ int vfs_create(struct inode *dir, struct dentry *dentry, int mode)
 int open_namei(const char * pathname, int flag, int mode, struct nameidata *nd)
 {
        int acc_mode, error = 0;
-       struct inode *inode;
        struct dentry *dentry;
        struct dentry *dir;
        int count = 0;
@@ -1092,80 +1165,9 @@ do_last:
        if (dentry->d_inode && S_ISDIR(dentry->d_inode->i_mode))
                goto exit;
 ok:
-       error = -ENOENT;
-       inode = dentry->d_inode;
-       if (!inode)
-               goto exit;
-
-       error = -ELOOP;
-       if (S_ISLNK(inode->i_mode))
-               goto exit;
-       
-       error = -EISDIR;
-       if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE))
-               goto exit;
-
-       error = permission(inode,acc_mode);
+       error = may_open(nd, acc_mode, flag);
        if (error)
                goto exit;
-
-       /*
-        * FIFO's, sockets and device files are special: they don't
-        * actually live on the filesystem itself, and as such you
-        * can write to them even if the filesystem is read-only.
-        */
-       if (S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
-               flag &= ~O_TRUNC;
-       } else if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) {
-               error = -EACCES;
-               if (nd->mnt->mnt_flags & MNT_NODEV)
-                       goto exit;
-
-               flag &= ~O_TRUNC;
-       } else {
-               error = -EROFS;
-               if (IS_RDONLY(inode) && (flag & 2))
-                       goto exit;
-       }
-       /*
-        * An append-only file must be opened in append mode for writing.
-        */
-       error = -EPERM;
-       if (IS_APPEND(inode)) {
-               if  ((flag & FMODE_WRITE) && !(flag & O_APPEND))
-                       goto exit;
-               if (flag & O_TRUNC)
-                       goto exit;
-       }
-
-       /*
-        * Ensure there are no outstanding leases on the file.
-        */
-       error = get_lease(inode, flag);
-       if (error)
-               goto exit;
-
-       if (flag & O_TRUNC) {
-               error = get_write_access(inode);
-               if (error)
-                       goto exit;
-
-               /*
-                * Refuse to truncate files with mandatory locks held on them.
-                */
-               error = locks_verify_locked(inode);
-               if (!error) {
-                       DQUOT_INIT(inode);
-                       
-                       error = do_truncate(dentry, 0);
-               }
-               put_write_access(inode);
-               if (error)
-                       goto exit;
-       } else
-               if (flag & FMODE_WRITE)
-                       DQUOT_INIT(inode);
-
        return 0;
 
 exit_dput:
index 6da2299fd2b7552275cb8da1439785539da2a0c2..99afff5ad4ce25c8a71f2af23a29fd1e4067d42e 100644 (file)
@@ -37,7 +37,16 @@ static struct file *do_open(char *name, int flags)
        if (error)
                return ERR_PTR(error);
 
-       return dentry_open(nd.dentry, nd.mnt, flags);
+       if (flags == O_RDWR)
+               error = may_open(&nd,MAY_READ|MAY_WRITE,FMODE_READ|FMODE_WRITE);
+       else
+               error = may_open(&nd, MAY_WRITE, FMODE_WRITE);
+
+       if (!error)
+               return dentry_open(nd.dentry, nd.mnt, flags);
+
+       path_release(&nd);
+       return ERR_PTR(error);
 }
 
 static struct {
index c27c3bc58cc93e49163c339bb3aec46fb6afb62a..20928d804327dfb207f74c1717a83e90f163039e 100644 (file)
@@ -1233,6 +1233,7 @@ static inline void allow_write_access(struct file *file)
 extern int do_pipe(int *);
 
 extern int open_namei(const char *, int, int, struct nameidata *);
+extern int may_open(struct nameidata *, int, int);
 
 extern int kernel_read(struct file *, unsigned long, char *, unsigned long);
 extern struct file * open_exec(const char *);