diff options
Diffstat (limited to 'fs/fat')
-rw-r--r-- | fs/fat/file.c | 44 |
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 | } |
255 | EXPORT_SYMBOL_GPL(fat_getattr); | 255 | EXPORT_SYMBOL_GPL(fat_getattr); |
256 | 256 | ||
257 | static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, | 257 | static 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); | ||
353 | out: | 363 | out: |
354 | return error; | 364 | return error; |
355 | } | 365 | } |