Commit 74f9fdfa1f229284ee1ea58fa47f2cdeeb12f6fe

Authored by Dave Hansen
Committed by Al Viro
1 parent cdb70f3f74

[PATCH] r/o bind mounts: elevate write count for do_utimes()

Now includes fix for oops seen by akpm.

"never let a libc developer write your kernel code" - hch

"nor, apparently, a kernel developer" - akpm

Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Cc: Valdis Kletnieks <Valdis.Kletnieks@vt.edu>
Cc: Balbir Singh <balbir@in.ibm.com>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>

Showing 1 changed file with 12 additions and 6 deletions Side-by-side Diff

... ... @@ -2,6 +2,7 @@
2 2 #include <linux/file.h>
3 3 #include <linux/fs.h>
4 4 #include <linux/linkage.h>
  5 +#include <linux/mount.h>
5 6 #include <linux/namei.h>
6 7 #include <linux/sched.h>
7 8 #include <linux/stat.h>
... ... @@ -59,6 +60,7 @@
59 60 struct inode *inode;
60 61 struct iattr newattrs;
61 62 struct file *f = NULL;
  63 + struct vfsmount *mnt;
62 64  
63 65 error = -EINVAL;
64 66 if (times && (!nsec_valid(times[0].tv_nsec) ||
65 67  
66 68  
... ... @@ -79,18 +81,20 @@
79 81 if (!f)
80 82 goto out;
81 83 dentry = f->f_path.dentry;
  84 + mnt = f->f_path.mnt;
82 85 } else {
83 86 error = __user_walk_fd(dfd, filename, (flags & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW, &nd);
84 87 if (error)
85 88 goto out;
86 89  
87 90 dentry = nd.path.dentry;
  91 + mnt = nd.path.mnt;
88 92 }
89 93  
90 94 inode = dentry->d_inode;
91 95  
92   - error = -EROFS;
93   - if (IS_RDONLY(inode))
  96 + error = mnt_want_write(mnt);
  97 + if (error)
94 98 goto dput_and_out;
95 99  
96 100 /* Don't worry, the checks are done in inode_change_ok() */
... ... @@ -98,7 +102,7 @@
98 102 if (times) {
99 103 error = -EPERM;
100 104 if (IS_APPEND(inode) || IS_IMMUTABLE(inode))
101   - goto dput_and_out;
  105 + goto mnt_drop_write_and_out;
102 106  
103 107 if (times[0].tv_nsec == UTIME_OMIT)
104 108 newattrs.ia_valid &= ~ATTR_ATIME;
105 109  
106 110  
107 111  
... ... @@ -118,22 +122,24 @@
118 122 } else {
119 123 error = -EACCES;
120 124 if (IS_IMMUTABLE(inode))
121   - goto dput_and_out;
  125 + goto mnt_drop_write_and_out;
122 126  
123 127 if (!is_owner_or_cap(inode)) {
124 128 if (f) {
125 129 if (!(f->f_mode & FMODE_WRITE))
126   - goto dput_and_out;
  130 + goto mnt_drop_write_and_out;
127 131 } else {
128 132 error = vfs_permission(&nd, MAY_WRITE);
129 133 if (error)
130   - goto dput_and_out;
  134 + goto mnt_drop_write_and_out;
131 135 }
132 136 }
133 137 }
134 138 mutex_lock(&inode->i_mutex);
135 139 error = notify_change(dentry, &newattrs);
136 140 mutex_unlock(&inode->i_mutex);
  141 +mnt_drop_write_and_out:
  142 + mnt_drop_write(mnt);
137 143 dput_and_out:
138 144 if (f)
139 145 fput(f);