Commit 74f9fdfa1f229284ee1ea58fa47f2cdeeb12f6fe
Committed by
Al Viro
1 parent
cdb70f3f74
Exists in
master
and in
7 other branches
[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
fs/utimes.c
... | ... | @@ -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); |