|
@@ -155,6 +155,42 @@ out:
|
|
return err;
|
|
return err;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int check_mode(const struct msdos_sb_info *sbi, mode_t mode)
|
|
|
|
+{
|
|
|
|
+ mode_t req = mode & ~S_IFMT;
|
|
|
|
+
|
|
|
|
+ /*
|
|
|
|
+ * 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.
|
|
|
|
+ */
|
|
|
|
+
|
|
|
|
+ if (S_ISREG(mode)) {
|
|
|
|
+ req &= ~sbi->options.fs_fmask;
|
|
|
|
+
|
|
|
|
+ if ((req & (S_IRUGO | S_IXUGO)) !=
|
|
|
|
+ ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_fmask))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ if ((req & S_IWUGO) != 0 &&
|
|
|
|
+ (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_fmask))
|
|
|
|
+ return -EPERM;
|
|
|
|
+ } else if (S_ISDIR(mode)) {
|
|
|
|
+ req &= ~sbi->options.fs_dmask;
|
|
|
|
+
|
|
|
|
+ if ((req & (S_IRUGO | S_IXUGO)) !=
|
|
|
|
+ ((S_IRUGO | S_IXUGO) & ~sbi->options.fs_dmask))
|
|
|
|
+ return -EPERM;
|
|
|
|
+
|
|
|
|
+ if ((req & S_IWUGO) != 0 &&
|
|
|
|
+ (req & S_IWUGO) != (S_IWUGO & ~sbi->options.fs_dmask))
|
|
|
|
+ return -EPERM;
|
|
|
|
+ } else {
|
|
|
|
+ return -EPERM;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return 0;
|
|
|
|
+}
|
|
|
|
+
|
|
int fat_notify_change(struct dentry *dentry, struct iattr *attr)
|
|
int fat_notify_change(struct dentry *dentry, struct iattr *attr)
|
|
{
|
|
{
|
|
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
|
|
struct msdos_sb_info *sbi = MSDOS_SB(dentry->d_sb);
|
|
@@ -186,9 +222,7 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
|
|
if (((attr->ia_valid & ATTR_UID) &&
|
|
if (((attr->ia_valid & ATTR_UID) &&
|
|
(attr->ia_uid != sbi->options.fs_uid)) ||
|
|
(attr->ia_uid != sbi->options.fs_uid)) ||
|
|
((attr->ia_valid & ATTR_GID) &&
|
|
((attr->ia_valid & ATTR_GID) &&
|
|
- (attr->ia_gid != sbi->options.fs_gid)) ||
|
|
|
|
- ((attr->ia_valid & ATTR_MODE) &&
|
|
|
|
- (attr->ia_mode & ~MSDOS_VALID_MODE)))
|
|
|
|
|
|
+ (attr->ia_gid != sbi->options.fs_gid)))
|
|
error = -EPERM;
|
|
error = -EPERM;
|
|
|
|
|
|
if (error) {
|
|
if (error) {
|
|
@@ -196,6 +230,13 @@ int fat_notify_change(struct dentry *dentry, struct iattr *attr)
|
|
error = 0;
|
|
error = 0;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ if (attr->ia_valid & ATTR_MODE) {
|
|
|
|
+ error = check_mode(sbi, attr->ia_mode);
|
|
|
|
+ if (error != 0 && !sbi->options.quiet)
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+
|
|
error = inode_setattr(inode, attr);
|
|
error = inode_setattr(inode, attr);
|
|
if (error)
|
|
if (error)
|
|
goto out;
|
|
goto out;
|