aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fat
diff options
context:
space:
mode:
Diffstat (limited to 'fs/fat')
-rw-r--r--fs/fat/file.c44
1 files changed, 27 insertions, 17 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c
index bdf91e97397d..c672df4036e9 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -254,26 +254,34 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat)
254} 254}
255EXPORT_SYMBOL_GPL(fat_getattr); 255EXPORT_SYMBOL_GPL(fat_getattr);
256 256
257static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, 257static int fat_sanitize_mode(const struct msdos_sb_info *sbi,
258 mode_t mode) 258 struct inode *inode, umode_t *mode_ptr)
259{ 259{
260 mode_t mask, req = mode & ~S_IFMT; 260 mode_t mask, perm;
261 261
262 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))
263 mask = sbi->options.fs_fmask; 268 mask = sbi->options.fs_fmask;
264 else 269 else
265 mask = sbi->options.fs_dmask; 270 mask = sbi->options.fs_dmask;
266 271
272 perm = *mode_ptr & ~(S_IFMT | mask);
273
267 /* 274 /*
268 * 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
269 * 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.
270 */ 277 */
271 req &= ~mask; 278 if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
272 if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))
273 return -EPERM; 279 return -EPERM;
274 if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) 280 if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask)))
275 return -EPERM; 281 return -EPERM;
276 282
283 *mode_ptr &= S_IFMT | perm;
284
277 return 0; 285 return 0;
278} 286}
279 287
@@ -296,7 +304,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
296{ 304{
297 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); 305 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
298 struct inode *inode = dentry->d_inode; 306 struct inode *inode = dentry->d_inode;
299 int mask, error = 0; 307 int error = 0;
300 unsigned int ia_valid; 308 unsigned int ia_valid;
301 309
302 /* 310 /*
@@ -327,12 +335,13 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
327 error = 0; 335 error = 0;
328 goto out; 336 goto out;
329 } 337 }
338
330 if (((attr->ia_valid & ATTR_UID) && 339 if (((attr->ia_valid & ATTR_UID) &&
331 (attr->ia_uid != sbi->options.fs_uid)) || 340 (attr->ia_uid != sbi->options.fs_uid)) ||
332 ((attr->ia_valid & ATTR_GID) && 341 ((attr->ia_valid & ATTR_GID) &&
333 (attr->ia_gid != sbi->options.fs_gid)) || 342 (attr->ia_gid != sbi->options.fs_gid)) ||
334 ((attr->ia_valid & ATTR_MODE) && 343 ((attr->ia_valid & ATTR_MODE) &&
335 fat_check_mode(sbi, inode, attr->ia_mode) < 0)) 344 (attr->ia_mode & ~MSDOS_VALID_MODE)))
336 error = -EPERM; 345 error = -EPERM;
337 346
338 if (error) { 347 if (error) {
@@ -341,15 +350,16 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)
341 goto out; 350 goto out;
342 } 351 }
343 352
344 error = inode_setattr(inode, attr); 353 /*
345 if (error) 354 * We don't return -EPERM here. Yes, strange, but this is too
346 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 }
347 361
348 if (S_ISDIR(inode->i_mode)) 362 error = inode_setattr(inode, attr);
349 mask = sbi->options.fs_dmask;
350 else
351 mask = sbi->options.fs_fmask;
352 inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask);
353out: 363out:
354 return error; 364 return error;
355} 365}