Commit 5132861a authored by Jeff Layton's avatar Jeff Layton Committed by Steve French

disable most mode changes on non-unix/non-cifsacl mounts

CIFS currently allows you to change the mode of an inode on a share that
doesn't have unix extensions enabled, and isn't using cifsacl. The inode
in this case *only* has its mode changed in memory on the client. This
is problematic since it can change any time the inode is purged from the
cache.

This patch makes cifs_setattr silently ignore most mode changes when
unix extensions and cifsacl support are not enabled, and when the share
is not mounted with the "dynperm" option. The exceptions are:

When a mode change would remove all write access to an inode we turn on
the ATTR_READONLY bit on the server and remove all write bits from the
inode's mode in memory.

When a mode change would add a write bit to an inode that previously had
them all turned off, it turns off the ATTR_READONLY bit on the server,
and resets the mode back to what it would normally be (generally, the
file_mode or dir_mode of the share).
Signed-off-by: default avatarJeff Layton <jlayton@redhat.com>
Signed-off-by: default avatarSteve French <sfrench@us.ibm.com>
parent b7206153
...@@ -1575,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1575,7 +1575,7 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
attrs->ia_valid &= ~ATTR_MODE; attrs->ia_valid &= ~ATTR_MODE;
if (attrs->ia_valid & ATTR_MODE) { if (attrs->ia_valid & ATTR_MODE) {
cFYI(1, ("Mode changed to 0x%x", attrs->ia_mode)); cFYI(1, ("Mode changed to 0%o", attrs->ia_mode));
mode = attrs->ia_mode; mode = attrs->ia_mode;
} }
...@@ -1590,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1590,18 +1590,18 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL) if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
rc = mode_to_acl(inode, full_path, mode); rc = mode_to_acl(inode, full_path, mode);
else if ((mode & S_IWUGO) == 0) { else
#else
if ((mode & S_IWUGO) == 0) {
#endif #endif
/* not writeable */ if (((mode & S_IWUGO) == 0) &&
if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) { (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
set_dosattr = true; set_dosattr = true;
time_buf.Attributes = time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
cpu_to_le32(cifsInode->cifsAttrs | ATTR_READONLY);
ATTR_READONLY); /* fix up mode if we're not using dynperm */
} if ((cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM) == 0)
} else if (cifsInode->cifsAttrs & ATTR_READONLY) { attrs->ia_mode = inode->i_mode & ~S_IWUGO;
} else if ((mode & S_IWUGO) &&
(cifsInode->cifsAttrs & ATTR_READONLY)) {
/* If file is readonly on server, we would /* If file is readonly on server, we would
not be able to write to it - so if any write not be able to write to it - so if any write
bit is enabled for user or group or other we bit is enabled for user or group or other we
...@@ -1612,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs) ...@@ -1612,6 +1612,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
/* Windows ignores set to zero */ /* Windows ignores set to zero */
if (time_buf.Attributes == 0) if (time_buf.Attributes == 0)
time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL); time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
/* reset local inode permissions to normal */
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
attrs->ia_mode &= ~(S_IALLUGO);
if (S_ISDIR(inode->i_mode))
attrs->ia_mode |=
cifs_sb->mnt_dir_mode;
else
attrs->ia_mode |=
cifs_sb->mnt_file_mode;
}
} else if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)) {
/* ignore mode change - ATTR_READONLY hasn't changed */
attrs->ia_valid &= ~ATTR_MODE;
} }
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment