diff options
author | Dave Hansen <haveblue@us.ibm.com> | 2008-02-15 17:37:46 -0500 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2008-04-19 00:29:24 -0400 |
commit | 42a74f206b914db13ee1f5ae932dcd91a77c8579 (patch) | |
tree | 24e3dbe55edaacc750067ab9e01778255a6bff08 /fs/ext3 | |
parent | 20ddee2c75339cc095f6191c3115f81da8955e96 (diff) |
[PATCH] r/o bind mounts: elevate write count for ioctls()
Some ioctl()s can cause writes to the filesystem. Take these, and make them
use mnt_want/drop_write() instead.
[AV: updated]
Acked-by: Al Viro <viro@ZenIV.linux.org.uk>
Signed-off-by: Christoph Hellwig <hch@lst.de>
Signed-off-by: Dave Hansen <haveblue@us.ibm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'fs/ext3')
-rw-r--r-- | fs/ext3/ioctl.c | 103 |
1 files changed, 68 insertions, 35 deletions
diff --git a/fs/ext3/ioctl.c b/fs/ext3/ioctl.c index 023a070f55f1..0d0c70151642 100644 --- a/fs/ext3/ioctl.c +++ b/fs/ext3/ioctl.c | |||
@@ -12,6 +12,7 @@ | |||
12 | #include <linux/capability.h> | 12 | #include <linux/capability.h> |
13 | #include <linux/ext3_fs.h> | 13 | #include <linux/ext3_fs.h> |
14 | #include <linux/ext3_jbd.h> | 14 | #include <linux/ext3_jbd.h> |
15 | #include <linux/mount.h> | ||
15 | #include <linux/time.h> | 16 | #include <linux/time.h> |
16 | #include <linux/compat.h> | 17 | #include <linux/compat.h> |
17 | #include <linux/smp_lock.h> | 18 | #include <linux/smp_lock.h> |
@@ -38,14 +39,19 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
38 | unsigned int oldflags; | 39 | unsigned int oldflags; |
39 | unsigned int jflag; | 40 | unsigned int jflag; |
40 | 41 | ||
41 | if (IS_RDONLY(inode)) | 42 | err = mnt_want_write(filp->f_path.mnt); |
42 | return -EROFS; | 43 | if (err) |
44 | return err; | ||
43 | 45 | ||
44 | if (!is_owner_or_cap(inode)) | 46 | if (!is_owner_or_cap(inode)) { |
45 | return -EACCES; | 47 | err = -EACCES; |
48 | goto flags_out; | ||
49 | } | ||
46 | 50 | ||
47 | if (get_user(flags, (int __user *) arg)) | 51 | if (get_user(flags, (int __user *) arg)) { |
48 | return -EFAULT; | 52 | err = -EFAULT; |
53 | goto flags_out; | ||
54 | } | ||
49 | 55 | ||
50 | if (!S_ISDIR(inode->i_mode)) | 56 | if (!S_ISDIR(inode->i_mode)) |
51 | flags &= ~EXT3_DIRSYNC_FL; | 57 | flags &= ~EXT3_DIRSYNC_FL; |
@@ -54,7 +60,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
54 | /* Is it quota file? Do not allow user to mess with it */ | 60 | /* Is it quota file? Do not allow user to mess with it */ |
55 | if (IS_NOQUOTA(inode)) { | 61 | if (IS_NOQUOTA(inode)) { |
56 | mutex_unlock(&inode->i_mutex); | 62 | mutex_unlock(&inode->i_mutex); |
57 | return -EPERM; | 63 | err = -EPERM; |
64 | goto flags_out; | ||
58 | } | 65 | } |
59 | oldflags = ei->i_flags; | 66 | oldflags = ei->i_flags; |
60 | 67 | ||
@@ -70,7 +77,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
70 | if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { | 77 | if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { |
71 | if (!capable(CAP_LINUX_IMMUTABLE)) { | 78 | if (!capable(CAP_LINUX_IMMUTABLE)) { |
72 | mutex_unlock(&inode->i_mutex); | 79 | mutex_unlock(&inode->i_mutex); |
73 | return -EPERM; | 80 | err = -EPERM; |
81 | goto flags_out; | ||
74 | } | 82 | } |
75 | } | 83 | } |
76 | 84 | ||
@@ -81,7 +89,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
81 | if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { | 89 | if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) { |
82 | if (!capable(CAP_SYS_RESOURCE)) { | 90 | if (!capable(CAP_SYS_RESOURCE)) { |
83 | mutex_unlock(&inode->i_mutex); | 91 | mutex_unlock(&inode->i_mutex); |
84 | return -EPERM; | 92 | err = -EPERM; |
93 | goto flags_out; | ||
85 | } | 94 | } |
86 | } | 95 | } |
87 | 96 | ||
@@ -89,7 +98,8 @@ int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, | |||
89 | handle = ext3_journal_start(inode, 1); | 98 | handle = ext3_journal_start(inode, 1); |
90 | if (IS_ERR(handle)) { | 99 | if (IS_ERR(handle)) { |
91 | mutex_unlock(&inode->i_mutex); | 100 | mutex_unlock(&inode->i_mutex); |
92 | return PTR_ERR(handle); | 101 | err = PTR_ERR(handle); |
102 | goto flags_out; | ||
93 | } | 103 | } |
94 | if (IS_SYNC(inode)) | 104 | if (IS_SYNC(inode)) |
95 | handle->h_sync = 1; | 105 | handle->h_sync = 1; |
@@ -115,6 +125,8 @@ flags_err: | |||
115 | if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) | 125 | if ((jflag ^ oldflags) & (EXT3_JOURNAL_DATA_FL)) |
116 | err = ext3_change_inode_journal_flag(inode, jflag); | 126 | err = ext3_change_inode_journal_flag(inode, jflag); |
117 | mutex_unlock(&inode->i_mutex); | 127 | mutex_unlock(&inode->i_mutex); |
128 | flags_out: | ||
129 | mnt_drop_write(filp->f_path.mnt); | ||
118 | return err; | 130 | return err; |
119 | } | 131 | } |
120 | case EXT3_IOC_GETVERSION: | 132 | case EXT3_IOC_GETVERSION: |
@@ -129,14 +141,18 @@ flags_err: | |||
129 | 141 | ||
130 | if (!is_owner_or_cap(inode)) | 142 | if (!is_owner_or_cap(inode)) |
131 | return -EPERM; | 143 | return -EPERM; |
132 | if (IS_RDONLY(inode)) | 144 | err = mnt_want_write(filp->f_path.mnt); |
133 | return -EROFS; | 145 | if (err) |
134 | if (get_user(generation, (int __user *) arg)) | 146 | return err; |
135 | return -EFAULT; | 147 | if (get_user(generation, (int __user *) arg)) { |
136 | 148 | err = -EFAULT; | |
149 | goto setversion_out; | ||
150 | } | ||
137 | handle = ext3_journal_start(inode, 1); | 151 | handle = ext3_journal_start(inode, 1); |
138 | if (IS_ERR(handle)) | 152 | if (IS_ERR(handle)) { |
139 | return PTR_ERR(handle); | 153 | err = PTR_ERR(handle); |
154 | goto setversion_out; | ||
155 | } | ||
140 | err = ext3_reserve_inode_write(handle, inode, &iloc); | 156 | err = ext3_reserve_inode_write(handle, inode, &iloc); |
141 | if (err == 0) { | 157 | if (err == 0) { |
142 | inode->i_ctime = CURRENT_TIME_SEC; | 158 | inode->i_ctime = CURRENT_TIME_SEC; |
@@ -144,6 +160,8 @@ flags_err: | |||
144 | err = ext3_mark_iloc_dirty(handle, inode, &iloc); | 160 | err = ext3_mark_iloc_dirty(handle, inode, &iloc); |
145 | } | 161 | } |
146 | ext3_journal_stop(handle); | 162 | ext3_journal_stop(handle); |
163 | setversion_out: | ||
164 | mnt_drop_write(filp->f_path.mnt); | ||
147 | return err; | 165 | return err; |
148 | } | 166 | } |
149 | #ifdef CONFIG_JBD_DEBUG | 167 | #ifdef CONFIG_JBD_DEBUG |
@@ -179,18 +197,24 @@ flags_err: | |||
179 | } | 197 | } |
180 | return -ENOTTY; | 198 | return -ENOTTY; |
181 | case EXT3_IOC_SETRSVSZ: { | 199 | case EXT3_IOC_SETRSVSZ: { |
200 | int err; | ||
182 | 201 | ||
183 | if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) | 202 | if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) |
184 | return -ENOTTY; | 203 | return -ENOTTY; |
185 | 204 | ||
186 | if (IS_RDONLY(inode)) | 205 | err = mnt_want_write(filp->f_path.mnt); |
187 | return -EROFS; | 206 | if (err) |
207 | return err; | ||
188 | 208 | ||
189 | if (!is_owner_or_cap(inode)) | 209 | if (!is_owner_or_cap(inode)) { |
190 | return -EACCES; | 210 | err = -EACCES; |
211 | goto setrsvsz_out; | ||
212 | } | ||
191 | 213 | ||
192 | if (get_user(rsv_window_size, (int __user *)arg)) | 214 | if (get_user(rsv_window_size, (int __user *)arg)) { |
193 | return -EFAULT; | 215 | err = -EFAULT; |
216 | goto setrsvsz_out; | ||
217 | } | ||
194 | 218 | ||
195 | if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) | 219 | if (rsv_window_size > EXT3_MAX_RESERVE_BLOCKS) |
196 | rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; | 220 | rsv_window_size = EXT3_MAX_RESERVE_BLOCKS; |
@@ -208,7 +232,9 @@ flags_err: | |||
208 | rsv->rsv_goal_size = rsv_window_size; | 232 | rsv->rsv_goal_size = rsv_window_size; |
209 | } | 233 | } |
210 | mutex_unlock(&ei->truncate_mutex); | 234 | mutex_unlock(&ei->truncate_mutex); |
211 | return 0; | 235 | setrsvsz_out: |
236 | mnt_drop_write(filp->f_path.mnt); | ||
237 | return err; | ||
212 | } | 238 | } |
213 | case EXT3_IOC_GROUP_EXTEND: { | 239 | case EXT3_IOC_GROUP_EXTEND: { |
214 | ext3_fsblk_t n_blocks_count; | 240 | ext3_fsblk_t n_blocks_count; |
@@ -218,17 +244,20 @@ flags_err: | |||
218 | if (!capable(CAP_SYS_RESOURCE)) | 244 | if (!capable(CAP_SYS_RESOURCE)) |
219 | return -EPERM; | 245 | return -EPERM; |
220 | 246 | ||
221 | if (IS_RDONLY(inode)) | 247 | err = mnt_want_write(filp->f_path.mnt); |
222 | return -EROFS; | 248 | if (err) |
223 | 249 | return err; | |
224 | if (get_user(n_blocks_count, (__u32 __user *)arg)) | ||
225 | return -EFAULT; | ||
226 | 250 | ||
251 | if (get_user(n_blocks_count, (__u32 __user *)arg)) { | ||
252 | err = -EFAULT; | ||
253 | goto group_extend_out; | ||
254 | } | ||
227 | err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); | 255 | err = ext3_group_extend(sb, EXT3_SB(sb)->s_es, n_blocks_count); |
228 | journal_lock_updates(EXT3_SB(sb)->s_journal); | 256 | journal_lock_updates(EXT3_SB(sb)->s_journal); |
229 | journal_flush(EXT3_SB(sb)->s_journal); | 257 | journal_flush(EXT3_SB(sb)->s_journal); |
230 | journal_unlock_updates(EXT3_SB(sb)->s_journal); | 258 | journal_unlock_updates(EXT3_SB(sb)->s_journal); |
231 | 259 | group_extend_out: | |
260 | mnt_drop_write(filp->f_path.mnt); | ||
232 | return err; | 261 | return err; |
233 | } | 262 | } |
234 | case EXT3_IOC_GROUP_ADD: { | 263 | case EXT3_IOC_GROUP_ADD: { |
@@ -239,18 +268,22 @@ flags_err: | |||
239 | if (!capable(CAP_SYS_RESOURCE)) | 268 | if (!capable(CAP_SYS_RESOURCE)) |
240 | return -EPERM; | 269 | return -EPERM; |
241 | 270 | ||
242 | if (IS_RDONLY(inode)) | 271 | err = mnt_want_write(filp->f_path.mnt); |
243 | return -EROFS; | 272 | if (err) |
273 | return err; | ||
244 | 274 | ||
245 | if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, | 275 | if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, |
246 | sizeof(input))) | 276 | sizeof(input))) { |
247 | return -EFAULT; | 277 | err = -EFAULT; |
278 | goto group_add_out; | ||
279 | } | ||
248 | 280 | ||
249 | err = ext3_group_add(sb, &input); | 281 | err = ext3_group_add(sb, &input); |
250 | journal_lock_updates(EXT3_SB(sb)->s_journal); | 282 | journal_lock_updates(EXT3_SB(sb)->s_journal); |
251 | journal_flush(EXT3_SB(sb)->s_journal); | 283 | journal_flush(EXT3_SB(sb)->s_journal); |
252 | journal_unlock_updates(EXT3_SB(sb)->s_journal); | 284 | journal_unlock_updates(EXT3_SB(sb)->s_journal); |
253 | 285 | group_add_out: | |
286 | mnt_drop_write(filp->f_path.mnt); | ||
254 | return err; | 287 | return err; |
255 | } | 288 | } |
256 | 289 | ||