diff options
Diffstat (limited to 'fs/fat/file.c')
| -rw-r--r-- | fs/fat/file.c | 50 |
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 | } |
| 258 | EXPORT_SYMBOL_GPL(fat_getattr); | 255 | EXPORT_SYMBOL_GPL(fat_getattr); |
| 259 | 256 | ||
| 260 | 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, |
| 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); | ||
| 358 | out: | 363 | out: |
| 359 | unlock_kernel(); | ||
| 360 | return error; | 364 | return error; |
| 361 | } | 365 | } |
| 362 | EXPORT_SYMBOL_GPL(fat_setattr); | 366 | EXPORT_SYMBOL_GPL(fat_setattr); |
