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)  }  EXPORT_SYMBOL_GPL(fat_getattr); -static int fat_check_mode(const struct msdos_sb_info *sbi, struct inode *inode, -			  mode_t mode) +static int fat_sanitize_mode(const struct msdos_sb_info *sbi, +			     struct inode *inode, umode_t *mode_ptr)  { -	mode_t mask, req = mode & ~S_IFMT; +	mode_t mask, perm; -	if (S_ISREG(mode)) +	/* +	 * Note, the basic check is already done by a caller of +	 * (attr->ia_mode & ~MSDOS_VALID_MODE) +	 */ + +	if (S_ISREG(inode->i_mode))  		mask = sbi->options.fs_fmask;  	else  		mask = sbi->options.fs_dmask; +	perm = *mode_ptr & ~(S_IFMT | mask); +  	/*  	 * Of the r and x bits, all (subject to umask) must be present. Of the  	 * w bits, either all (subject to umask) or none must be present.  	 */ -	req &= ~mask; -	if ((req & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO))) +	if ((perm & (S_IRUGO | S_IXUGO)) != (inode->i_mode & (S_IRUGO|S_IXUGO)))  		return -EPERM; -	if ((req & S_IWUGO) && ((req & S_IWUGO) != (S_IWUGO & ~mask))) +	if ((perm & S_IWUGO) && ((perm & S_IWUGO) != (S_IWUGO & ~mask)))  		return -EPERM; +	*mode_ptr &= S_IFMT | perm; +  	return 0;  } @@ -296,7 +304,7 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)  {  	struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);  	struct inode *inode = dentry->d_inode; -	int mask, error = 0; +	int error = 0;  	unsigned int ia_valid;  	/* @@ -327,12 +335,13 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)  			error = 0;  		goto out;  	} +  	if (((attr->ia_valid & ATTR_UID) &&  	     (attr->ia_uid != sbi->options.fs_uid)) ||  	    ((attr->ia_valid & ATTR_GID) &&  	     (attr->ia_gid != sbi->options.fs_gid)) ||  	    ((attr->ia_valid & ATTR_MODE) && -	     fat_check_mode(sbi, inode, attr->ia_mode) < 0)) +	     (attr->ia_mode & ~MSDOS_VALID_MODE)))  		error = -EPERM;  	if (error) { @@ -341,15 +350,16 @@ int fat_setattr(struct dentry *dentry, struct iattr *attr)  		goto out;  	} -	error = inode_setattr(inode, attr); -	if (error) -		goto out; +	/* +	 * We don't return -EPERM here. Yes, strange, but this is too +	 * old behavior. +	 */ +	if (attr->ia_valid & ATTR_MODE) { +		if (fat_sanitize_mode(sbi, inode, &attr->ia_mode) < 0) +			attr->ia_valid &= ~ATTR_MODE; +	} -	if (S_ISDIR(inode->i_mode)) -		mask = sbi->options.fs_dmask; -	else -		mask = sbi->options.fs_fmask; -	inode->i_mode &= S_IFMT | (S_IRWXUGO & ~mask); +	error = inode_setattr(inode, attr);  out:  	return error;  } |