diff options
-rw-r--r-- | fs/fat/file.c | 47 |
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 | ||
158 | static 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 | |||
158 | int fat_notify_change(struct dentry *dentry, struct iattr *attr) | 194 | int 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; |