Merge branch 'work.gfs2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
authorLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Sep 2021 19:45:26 +0000 (12:45 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Thu, 9 Sep 2021 19:45:26 +0000 (12:45 -0700)
Pull gfs2 setattr updates from Al Viro:
 "Make it possible for filesystems to use a generic 'may_setattr()' and
  switch gfs2 to using it"

* 'work.gfs2' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs:
  gfs2: Switch to may_setattr in gfs2_setattr
  fs: Move notify_change permission checks into may_setattr

fs/attr.c
fs/gfs2/inode.c
include/linux/fs.h

index 87ef39d..473d21b 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
@@ -249,6 +249,34 @@ void setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
 }
 EXPORT_SYMBOL(setattr_copy);
 
+int may_setattr(struct user_namespace *mnt_userns, struct inode *inode,
+               unsigned int ia_valid)
+{
+       int error;
+
+       if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
+               if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+                       return -EPERM;
+       }
+
+       /*
+        * If utimes(2) and friends are called with times == NULL (or both
+        * times are UTIME_NOW), then we need to check for write permission
+        */
+       if (ia_valid & ATTR_TOUCH) {
+               if (IS_IMMUTABLE(inode))
+                       return -EPERM;
+
+               if (!inode_owner_or_capable(mnt_userns, inode)) {
+                       error = inode_permission(mnt_userns, inode, MAY_WRITE);
+                       if (error)
+                               return error;
+               }
+       }
+       return 0;
+}
+EXPORT_SYMBOL(may_setattr);
+
 /**
  * notify_change - modify attributes of a filesytem object
  * @mnt_userns:        user namespace of the mount the inode was found from
@@ -290,25 +318,9 @@ int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
 
        WARN_ON_ONCE(!inode_is_locked(inode));
 
-       if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
-               if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
-                       return -EPERM;
-       }
-
-       /*
-        * If utimes(2) and friends are called with times == NULL (or both
-        * times are UTIME_NOW), then we need to check for write permission
-        */
-       if (ia_valid & ATTR_TOUCH) {
-               if (IS_IMMUTABLE(inode))
-                       return -EPERM;
-
-               if (!inode_owner_or_capable(mnt_userns, inode)) {
-                       error = inode_permission(mnt_userns, inode, MAY_WRITE);
-                       if (error)
-                               return error;
-               }
-       }
+       error = may_setattr(mnt_userns, inode, ia_valid);
+       if (error)
+               return error;
 
        if ((ia_valid & ATTR_MODE)) {
                umode_t amode = attr->ia_mode;
index 6e15434..3130f85 100644 (file)
@@ -1985,8 +1985,8 @@ static int gfs2_setattr(struct user_namespace *mnt_userns,
        if (error)
                goto out;
 
-       error = -EPERM;
-       if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
+       error = may_setattr(&init_user_ns, inode, attr->ia_valid);
+       if (error)
                goto error;
 
        error = setattr_prepare(&init_user_ns, dentry, attr);
index 29b3550..e7a6333 100644 (file)
@@ -3439,6 +3439,8 @@ extern int buffer_migrate_page_norefs(struct address_space *,
 #define buffer_migrate_page_norefs NULL
 #endif
 
+int may_setattr(struct user_namespace *mnt_userns, struct inode *inode,
+               unsigned int ia_valid);
 int setattr_prepare(struct user_namespace *, struct dentry *, struct iattr *);
 extern int inode_newsize_ok(const struct inode *, loff_t offset);
 void setattr_copy(struct user_namespace *, struct inode *inode,