[linux-cifs-client] [PATCH 3/5] [CIFS] disable most mode changes on non-unix/non-cifsacl mounts

Jeff Layton jlayton at redhat.com
Mon May 12 14:49:48 GMT 2008


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: Jeff Layton <jlayton at redhat.com>
---

 fs/cifs/inode.c |   30 ++++++++++++++++++++----------
 1 files changed, 20 insertions(+), 10 deletions(-)
-------------- next part --------------
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index f160128..6c51fc4 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -1552,17 +1552,16 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 #ifdef CONFIG_CIFS_EXPERIMENTAL
 		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_CIFS_ACL)
 			rc = mode_to_acl(inode, full_path, mode);
-		else if ((mode & S_IWUGO) == 0) {
-#else
-		if ((mode & S_IWUGO) == 0) {
+		else
 #endif
-			/* not writeable */
-			if ((cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
-				set_dosattr = true;
-				time_buf.Attributes =
-					cpu_to_le32(cifsInode->cifsAttrs |
-						    ATTR_READONLY);
-			}
+		if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+			goto time_change;
+		else if (((mode & S_IWUGO) == 0) &&
+		    (cifsInode->cifsAttrs & ATTR_READONLY) == 0) {
+			set_dosattr = true;
+			time_buf.Attributes = cpu_to_le32(cifsInode->cifsAttrs |
+							  ATTR_READONLY);
+			attrs->ia_mode = inode->i_mode & ~S_IWUGO;
 		} else if (cifsInode->cifsAttrs & ATTR_READONLY) {
 			/* If file is readonly on server, we would
 			not be able to write to it - so if any write
@@ -1574,9 +1573,20 @@ int cifs_setattr(struct dentry *direntry, struct iattr *attrs)
 			/* Windows ignores set to zero */
 			if (time_buf.Attributes == 0)
 				time_buf.Attributes |= cpu_to_le32(ATTR_NORMAL);
+
+			/* reset local inode permissions to normal */
+			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 {
+			/* ignore mode change - ATTR_READONLY hasn't changed */
+			attrs->ia_valid &= ~ATTR_MODE;
 		}
 	}
 
+time_change:
 	if (attrs->ia_valid & ATTR_ATIME) {
 		set_time = true;
 		time_buf.LastAccessTime =


More information about the linux-cifs-client mailing list