diff options
Diffstat (limited to 'fs/fat/file.c')
| -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 27cc1164ec36..771326b8047e 100644 --- a/fs/fat/file.c +++ b/fs/fat/file.c | |||
| @@ -257,26 +257,34 @@ int fat_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat) | |||
| 257 | } | 257 | } |
| 258 | EXPORT_SYMBOL_GPL(fat_getattr); | 258 | EXPORT_SYMBOL_GPL(fat_getattr); |
| 259 | 259 | ||
| 260 | static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, | 260 | static int fat_sanitize_mode(const struct msdos_sb_info *sbi, |
| 261 | mode_t mode) | 261 | struct inode *inode, umode_t *mode_ptr) |
| 262 | { | 262 | { |
| 263 | mode_t mask, req = mode & ~S_IFMT; | 263 | mode_t mask, perm; |
| 264 | 264 | ||
| 265 | if (S_ISREG(mode)) | 265 | /* |
| 266 | * Note, the basic check is already done by a caller of | ||
| 267 | * (attr->ia_mode & ~MSDOS_VALID_MODE) | ||
| 268 | */ | ||
| 269 | |||
| 270 | if (S_ISREG(inode->i_mode)) | ||
| 266 | mask = sbi->options.fs_fmask; | 271 | mask = sbi->options.fs_fmask; |
| 267 | else | 272 | else |
| 268 | mask = sbi->options.fs_dmask; | 273 | mask = sbi->options.fs_dmask; |
| 269 | 274 | ||
| 275 | perm = *mode_ptr & ~(S_IFMT | mask); | ||
| 276 | |||
| 270 | /* | 277 | /* |
| 271 | * Of the r and x bits, all (subject to umask) must be present. Of the | 278 | * 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. | 279 | * w bits, either all (subject to umask) or none must be present. |
| 273 | */ | 280 | */ |
| 274 | req &= ~mask; | 281 | 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; | 282 | return -EPERM; |
| 277 | if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) | 283 | if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask))) |
| 278 | return -EPERM; | 284 | return -EPERM; |
| 279 | 285 | ||
| 286 | *mode_ptr &= S_IFMT | perm; | ||
| 287 | |||
| 280 | return 0; | 288 | return 0; |
| 281 | } | 289 | } |
| 282 | 290 | ||
| @@ -299,7 +307,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 299 | { | 307 | { |
| 300 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); | 308 | struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); |
| 301 | struct inode *inode = dentry->d_inode; | 309 | struct inode *inode = dentry->d_inode; |
| 302 | int mask, error = 0; | 310 | int error = 0; |
| 303 | unsigned int ia_valid; | 311 | unsigned int ia_valid; |
| 304 | 312 | ||
| 305 | lock_kernel(); | 313 | lock_kernel(); |
| @@ -332,12 +340,13 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 332 | error = 0; | 340 | error = 0; |
| 333 | goto out; | 341 | goto out; |
| 334 | } | 342 | } |
| 343 | |||
| 335 | if (((attr->ia_valid & ATTR_UID) && | 344 | if (((attr->ia_valid & ATTR_UID) && |
| 336 | (attr->ia_uid != sbi->options.fs_uid)) || | 345 | (attr->ia_uid != sbi->options.fs_uid)) || |
| 337 | ((attr->ia_valid & ATTR_GID) && | 346 | ((attr->ia_valid & ATTR_GID) && |
| 338 | (attr->ia_gid != sbi->options.fs_gid)) || | 347 | (attr->ia_gid != sbi->options.fs_gid)) || |
| 339 | ((attr->ia_valid & ATTR_MODE) && | 348 | ((attr->ia_valid & ATTR_MODE) && |
| 340 | fat_check_mode(sbi, inode, attr->ia_mode) < 0)) | 349 | (attr->ia_mode & ~MSDOS_VALID_MODE))) |
| 341 | error = -EPERM; | 350 | error = -EPERM; |
| 342 | 351 | ||
| 343 | if (error) { | 352 | if (error) { |
| @@ -346,15 +355,16 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr) | |||
| 346 | goto out; | 355 | goto out; |
| 347 | } | 356 | } |
| 348 | 357 | ||
| 349 | error = inode_setattr(inode, attr); | 358 | /* |
| 350 | if (error) | 359 | * We don't return -EPERM here. Yes, strange, but this is too |
| 351 | goto out; | 360 | * old behavior. |
| 361 | */ | ||
| 362 | if (attr->ia_valid & ATTR_MODE) { | ||
| 363 | if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) | ||
| 364 | attr->ia_valid &= ~ATTR_MODE; | ||
| 365 | } | ||
| 352 | 366 | ||
| 353 | if (S_ISDIR(inode->i_mode)) | 367 | 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); | ||
| 358 | out: | 368 | out: |
| 359 | unlock_kernel(); | 369 | unlock_kernel(); |
| 360 | return error; | 370 | return error; |
