aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat/file.c
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat/file.c')
-rw-r--r--fs/fat/file.c50
1 files changed, 27 insertions, 23 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 27cc1164ec36..c672df4036e9 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -11,7 +11,6 @@
11#include <linux/mount.h> 11#include <linux/mount.h>
12#include <linux/time.h> 12#include <linux/time.h>
13#include <linux/msdos_fs.h> 13#include <linux/msdos_fs.h>
14#include <linux/smp_lock.h>
15#include <linux/buffer_head.h> 14#include <linux/buffer_head.h>
16#include <linux/writeback.h> 15#include <linux/writeback.h>
17#include <linux/backing-dev.h> 16#include <linux/backing-dev.h>
@@ -242,9 +241,7 @@ void fat_truncate(struct inode *inode)
242 241
243 nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits; 242 nr_clusters = (inode->i_size + (cluster_size - 1)) >> sbi->cluster_bits;
244 243
245 lock_kernel();
246 fat_free(inode, nr_clusters); 244 fat_free(inode, nr_clusters);
247 unlock_kernel();
248 fat_flush_inodes(inode->i_sb, inode, NULL); 245 fat_flush_inodes(inode->i_sb, inode, NULL);
249} 246}
250 247
@@ -257,26 +254,34 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
257} 254}
258EXPORT_SYMBOL_GPL(fat_getattr); 255EXPORT_SYMBOL_GPL(fat_getattr);
259 256
260static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, 257static int fat_sanitize_mode(const struct msdos_sb_info *sbi,
261 mode_t mode) 258 struct inode *inode, umode_t *mode_ptr)
262{ 259{
263 mode_t mask, req = mode & ~S_IFMT; 260 mode_t mask, perm;
264 261
265 if (S_ISREG(mode)) 262 /*
263 * Note, the basic check is already done by a caller of
264 * (attr->ia_mode & ~MSDOS_VALID_MODE)
265 */
266
267 if (S_ISREG(inode->i_mode))
266 mask = sbi->options.fs_fmask; 268 mask = sbi->options.fs_fmask;
267 else 269 else
268 mask = sbi->options.fs_dmask; 270 mask = sbi->options.fs_dmask;
269 271
272 perm = *mode_ptr & ~(S_IFMT | mask);
273
270 /* 274 /*
271 * Of the r and x bits, all (subject to umask) must be present. Of the 275 * Of the r and x bits, all (subject to umask) must be present. Of the
272 * w bits, either all (subject to umask) or none must be present. 276 * w bits, either all (subject to umask) or none must be present.
273 */ 277 */
274 req &= ~mask; 278 if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
275 if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
276 return -EPERM; 279 return -EPERM;
277 if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) 280 if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask)))
278 return -EPERM; 281 return -EPERM;
279 282
283 *mode_ptr &= S_IFMT | perm;
284
280 return 0; 285 return 0;
281} 286}
282 287
@@ -299,11 +304,9 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
299{ 304{
300 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); 305 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
301 struct inode *inode = dentry->d_inode; 306 struct inode *inode = dentry->d_inode;
302 int mask, error = 0; 307 int error = 0;
303 unsigned int ia_valid; 308 unsigned int ia_valid;
304 309
305 lock_kernel();
306
307 /* 310 /*
308 * Expand the file. Since inode_setattr() updates ->i_size 311 * Expand the file. Since inode_setattr() updates ->i_size
309 * before calling the ->truncate(), but FAT needs to fill the 312 * before calling the ->truncate(), but FAT needs to fill the
@@ -332,12 +335,13 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
332 error = 0; 335 error = 0;
333 goto out; 336 goto out;
334 } 337 }
338
335 if (((attr->ia_valid & ATTR_UID) && 339 if (((attr->ia_valid & ATTR_UID) &&
336 (attr->ia_uid != sbi->options.fs_uid)) || 340 (attr->ia_uid != sbi->options.fs_uid)) ||
337 ((attr->ia_valid & ATTR_GID) && 341 ((attr->ia_valid & ATTR_GID) &&
338 (attr->ia_gid != sbi->options.fs_gid)) || 342 (attr->ia_gid != sbi->options.fs_gid)) ||
339 ((attr->ia_valid & ATTR_MODE) && 343 ((attr->ia_valid & ATTR_MODE) &&
340 fat_check_mode(sbi, inode, attr->ia_mode) < 0)) 344 (attr->ia_mode & ~MSDOS_VALID_MODE)))
341 error = -EPERM; 345 error = -EPERM;
342 346
343 if (error) { 347 if (error) {
@@ -346,17 +350,17 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
346 goto out; 350 goto out;
347 } 351 }
348 352
349 error = inode_setattr(inode, attr); 353 /*
350 if (error) 354 * We don't return -EPERM here. Yes, strange, but this is too
351 goto out; 355 * old behavior.
356 */
357 if (attr->ia_valid & ATTR_MODE) {
358 if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0)
359 attr->ia_valid &= ~ATTR_MODE;
360 }
352 361
353 if (S_ISDIR(inode->i_mode)) 362 error = inode_setattr(inode, attr);
354 mask = sbi->options.fs_dmask;
355 else
356 mask = sbi->options.fs_fmask;
357 inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
358out: 363out:
359 unlock_kernel();
360 return error; 364 return error;
361} 365}
362EXPORT_SYMBOL_GPL(fat_setattr); 366EXPORT_SYMBOL_GPL(fat_setattr);