aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--fs/fat/file.c47
1 files changed, 44 insertions, 3 deletions
diff --git a/fs/fat/file.c b/fs/fat/file.c
index 69a83b59dce8..c614175876e0 100644
--- a/fs/fat/file.c
+++ b/fs/fat/file.c
@@ -155,6 +155,42 @@ out:
155 return err; 155 return err;
156} 156}
157 157
158static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
159{
160 mode_t req = mode & ~S_IFMT;
161
162 /*
163 * Of the r and x bits, all (subject to umask) must be present. Of the
164 * w bits, either all (subject to umask) or none must be present.
165 */
166
167 if (S_ISREG(mode)) {
168 req &= ~sbi->options.fs_fmask;
169
170 if ((req & (S_IRUGO | S_IXUGO)) !=
171 ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
172 return -EPERM;
173
174 if ((req & S_IWUGO) != 0 &&
175 (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
176 return -EPERM;
177 } else if (S_ISDIR(mode)) {
178 req &= ~sbi->options.fs_dmask;
179
180 if ((req & (S_IRUGO | S_IXUGO)) !=
181 ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
182 return -EPERM;
183
184 if ((req & S_IWUGO) != 0 &&
185 (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
186 return -EPERM;
187 } else {
188 return -EPERM;
189 }
190
191 return 0;
192}
193
158int fat_notify_change(struct dentry *dentry, struct iattr *attr) 194int fat_notify_change(struct dentry *dentry, struct iattr *attr)
159{ 195{
160 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb); 196 struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
@@ -186,9 +222,7 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
186 if (((attr->ia_valid & ATTR_UID) && 222 if (((attr->ia_valid & ATTR_UID) &&
187 (attr->ia_uid != sbi->options.fs_uid)) || 223 (attr->ia_uid != sbi->options.fs_uid)) ||
188 ((attr->ia_valid & ATTR_GID) && 224 ((attr->ia_valid & ATTR_GID) &&
189 (attr->ia_gid != sbi->options.fs_gid)) || 225 (attr->ia_gid != sbi->options.fs_gid)))
190 ((attr->ia_valid & ATTR_MODE) &&
191 (attr->ia_mode & ~MSDOS_VALID_MODE)))
192 error = -EPERM; 226 error = -EPERM;
193 227
194 if (error) { 228 if (error) {
@@ -196,6 +230,13 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
196 error = 0; 230 error = 0;
197 goto out; 231 goto out;
198 } 232 }
233
234 if (attr->ia_valid & ATTR_MODE) {
235 error = check_mode(sbi, attr->ia_mode);
236 if (error != 0 && !sbi->options.quiet)
237 goto out;
238 }
239
199 error = inode_setattr(inode, attr); 240 error = inode_setattr(inode, attr);
200 if (error) 241 if (error)
201 goto out; 242 goto out;