Merge branch 'work.misc' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
[platform/kernel/linux-starfive.git] / fs / inode.c
index 6598ea2..a047ab3 100644 (file)
@@ -1494,7 +1494,7 @@ struct inode *find_inode_rcu(struct super_block *sb, unsigned long hashval,
 EXPORT_SYMBOL(find_inode_rcu);
 
 /**
- * find_inode_by_rcu - Find an inode in the inode cache
+ * find_inode_by_ino_rcu - Find an inode in the inode cache
  * @sb:                Super block of file system to search
  * @ino:       The inode number to match
  *
@@ -1744,24 +1744,26 @@ static int relatime_need_update(struct vfsmount *mnt, struct inode *inode,
 
 int generic_update_time(struct inode *inode, struct timespec64 *time, int flags)
 {
-       int iflags = I_DIRTY_TIME;
-       bool dirty = false;
-
-       if (flags & S_ATIME)
-               inode->i_atime = *time;
-       if (flags & S_VERSION)
-               dirty = inode_maybe_inc_iversion(inode, false);
-       if (flags & S_CTIME)
-               inode->i_ctime = *time;
-       if (flags & S_MTIME)
-               inode->i_mtime = *time;
-       if ((flags & (S_ATIME | S_CTIME | S_MTIME)) &&
-           !(inode->i_sb->s_flags & SB_LAZYTIME))
-               dirty = true;
-
-       if (dirty)
-               iflags |= I_DIRTY_SYNC;
-       __mark_inode_dirty(inode, iflags);
+       int dirty_flags = 0;
+
+       if (flags & (S_ATIME | S_CTIME | S_MTIME)) {
+               if (flags & S_ATIME)
+                       inode->i_atime = *time;
+               if (flags & S_CTIME)
+                       inode->i_ctime = *time;
+               if (flags & S_MTIME)
+                       inode->i_mtime = *time;
+
+               if (inode->i_sb->s_flags & SB_LAZYTIME)
+                       dirty_flags |= I_DIRTY_TIME;
+               else
+                       dirty_flags |= I_DIRTY_SYNC;
+       }
+
+       if ((flags & S_VERSION) && inode_maybe_inc_iversion(inode, false))
+               dirty_flags |= I_DIRTY_SYNC;
+
+       __mark_inode_dirty(inode, dirty_flags);
        return 0;
 }
 EXPORT_SYMBOL(generic_update_time);
@@ -1778,7 +1780,7 @@ static int update_time(struct inode *inode, struct timespec64 *time, int flags)
 }
 
 /**
- *     touch_atime     -       update the access time
+ *     atime_needs_update      -       update the access time
  *     @path: the &struct path to update
  *     @inode: inode to update
  *
@@ -1797,7 +1799,7 @@ bool atime_needs_update(const struct path *path, struct inode *inode)
        /* Atime updates will likely cause i_uid and i_gid to be written
         * back improprely if their true value is unknown to the vfs.
         */
-       if (HAS_UNMAPPED_ID(inode))
+       if (HAS_UNMAPPED_ID(mnt_user_ns(mnt), inode))
                return false;
 
        if (IS_NOATIME(inode))
@@ -1904,7 +1906,8 @@ int dentry_needs_remove_privs(struct dentry *dentry)
        return mask;
 }
 
-static int __remove_privs(struct dentry *dentry, int kill)
+static int __remove_privs(struct user_namespace *mnt_userns,
+                         struct dentry *dentry, int kill)
 {
        struct iattr newattrs;
 
@@ -1913,7 +1916,7 @@ static int __remove_privs(struct dentry *dentry, int kill)
         * Note we call this on write, so notify_change will not
         * encounter any conflicting delegations:
         */
-       return notify_change(dentry, &newattrs, NULL);
+       return notify_change(mnt_userns, dentry, &newattrs, NULL);
 }
 
 /*
@@ -1940,7 +1943,7 @@ int file_remove_privs(struct file *file)
        if (kill < 0)
                return kill;
        if (kill)
-               error = __remove_privs(dentry, kill);
+               error = __remove_privs(file_mnt_user_ns(file), dentry, kill);
        if (!error)
                inode_has_no_xattr(inode);
 
@@ -2131,14 +2134,21 @@ EXPORT_SYMBOL(init_special_inode);
 
 /**
  * inode_init_owner - Init uid,gid,mode for new inode according to posix standards
+ * @mnt_userns:        User namespace of the mount the inode was created from
  * @inode: New inode
  * @dir: Directory inode
  * @mode: mode of the new inode
+ *
+ * If the inode has been created through an idmapped mount the user namespace of
+ * the vfsmount must be passed through @mnt_userns. This function will then take
+ * care to map the inode according to @mnt_userns before checking permissions
+ * and initializing i_uid and i_gid. On non-idmapped mounts or if permission
+ * checking is to be performed on the raw inode simply passs init_user_ns.
  */
-void inode_init_owner(struct inode *inode, const struct inode *dir,
-                       umode_t mode)
+void inode_init_owner(struct user_namespace *mnt_userns, struct inode *inode,
+                     const struct inode *dir, umode_t mode)
 {
-       inode->i_uid = current_fsuid();
+       inode->i_uid = fsuid_into_mnt(mnt_userns);
        if (dir && dir->i_mode & S_ISGID) {
                inode->i_gid = dir->i_gid;
 
@@ -2146,31 +2156,41 @@ void inode_init_owner(struct inode *inode, const struct inode *dir,
                if (S_ISDIR(mode))
                        mode |= S_ISGID;
                else if ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP) &&
-                        !in_group_p(inode->i_gid) &&
-                        !capable_wrt_inode_uidgid(dir, CAP_FSETID))
+                        !in_group_p(i_gid_into_mnt(mnt_userns, dir)) &&
+                        !capable_wrt_inode_uidgid(mnt_userns, dir, CAP_FSETID))
                        mode &= ~S_ISGID;
        } else
-               inode->i_gid = current_fsgid();
+               inode->i_gid = fsgid_into_mnt(mnt_userns);
        inode->i_mode = mode;
 }
 EXPORT_SYMBOL(inode_init_owner);
 
 /**
  * inode_owner_or_capable - check current task permissions to inode
+ * @mnt_userns:        user namespace of the mount the inode was found from
  * @inode: inode being checked
  *
  * Return true if current either has CAP_FOWNER in a namespace with the
  * inode owner uid mapped, or owns the file.
+ *
+ * If the inode has been found through an idmapped mount the user namespace of
+ * the vfsmount must be passed through @mnt_userns. This function will then take
+ * care to map the inode according to @mnt_userns before checking permissions.
+ * On non-idmapped mounts or if permission checking is to be performed on the
+ * raw inode simply passs init_user_ns.
  */
-bool inode_owner_or_capable(const struct inode *inode)
+bool inode_owner_or_capable(struct user_namespace *mnt_userns,
+                           const struct inode *inode)
 {
+       kuid_t i_uid;
        struct user_namespace *ns;
 
-       if (uid_eq(current_fsuid(), inode->i_uid))
+       i_uid = i_uid_into_mnt(mnt_userns, inode);
+       if (uid_eq(current_fsuid(), i_uid))
                return true;
 
        ns = current_user_ns();
-       if (kuid_has_mapping(ns, inode->i_uid) && ns_capable(ns, CAP_FOWNER))
+       if (kuid_has_mapping(ns, i_uid) && ns_capable(ns, CAP_FOWNER))
                return true;
        return false;
 }