tools headers UAPI: Sync openat2.h with the kernel sources
[linux-2.6-microblaze.git] / fs / attr.c
index b4bbdbd..87ef39d 100644 (file)
--- a/fs/attr.c
+++ b/fs/attr.c
 #include <linux/evm.h>
 #include <linux/ima.h>
 
-static bool chown_ok(const struct inode *inode, kuid_t uid)
+/**
+ * chown_ok - verify permissions to chown inode
+ * @mnt_userns:        user namespace of the mount @inode was found from
+ * @inode:     inode to check permissions on
+ * @uid:       uid to chown @inode to
+ *
+ * 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.
+ */
+static bool chown_ok(struct user_namespace *mnt_userns,
+                    const struct inode *inode,
+                    kuid_t uid)
 {
-       if (uid_eq(current_fsuid(), inode->i_uid) &&
-           uid_eq(uid, inode->i_uid))
+       kuid_t kuid = i_uid_into_mnt(mnt_userns, inode);
+       if (uid_eq(current_fsuid(), kuid) && uid_eq(uid, kuid))
                return true;
-       if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+       if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
                return true;
-       if (uid_eq(inode->i_uid, INVALID_UID) &&
+       if (uid_eq(kuid, INVALID_UID) &&
            ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
                return true;
        return false;
 }
 
-static bool chgrp_ok(const struct inode *inode, kgid_t gid)
+/**
+ * chgrp_ok - verify permissions to chgrp inode
+ * @mnt_userns:        user namespace of the mount @inode was found from
+ * @inode:     inode to check permissions on
+ * @gid:       gid to chown @inode to
+ *
+ * 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.
+ */
+static bool chgrp_ok(struct user_namespace *mnt_userns,
+                    const struct inode *inode, kgid_t gid)
 {
-       if (uid_eq(current_fsuid(), inode->i_uid) &&
-           (in_group_p(gid) || gid_eq(gid, inode->i_gid)))
+       kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
+       if (uid_eq(current_fsuid(), i_uid_into_mnt(mnt_userns, inode)) &&
+           (in_group_p(gid) || gid_eq(gid, kgid)))
                return true;
-       if (capable_wrt_inode_uidgid(inode, CAP_CHOWN))
+       if (capable_wrt_inode_uidgid(mnt_userns, inode, CAP_CHOWN))
                return true;
-       if (gid_eq(inode->i_gid, INVALID_GID) &&
+       if (gid_eq(kgid, INVALID_GID) &&
            ns_capable(inode->i_sb->s_user_ns, CAP_CHOWN))
                return true;
        return false;
@@ -46,6 +74,7 @@ static bool chgrp_ok(const struct inode *inode, kgid_t gid)
 
 /**
  * setattr_prepare - check if attribute changes to a dentry are allowed
+ * @mnt_userns:        user namespace of the mount the inode was found from
  * @dentry:    dentry to check
  * @attr:      attributes to change
  *
@@ -55,10 +84,17 @@ static bool chgrp_ok(const struct inode *inode, kgid_t gid)
  * SGID bit from mode if user is not allowed to set it. Also file capabilities
  * and IMA extended attributes are cleared if ATTR_KILL_PRIV is set.
  *
+ * 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.
+ *
  * Should be called as the first thing in ->setattr implementations,
  * possibly after taking additional locks.
  */
-int setattr_prepare(struct dentry *dentry, struct iattr *attr)
+int setattr_prepare(struct user_namespace *mnt_userns, struct dentry *dentry,
+                   struct iattr *attr)
 {
        struct inode *inode = d_inode(dentry);
        unsigned int ia_valid = attr->ia_valid;
@@ -78,27 +114,27 @@ int setattr_prepare(struct dentry *dentry, struct iattr *attr)
                goto kill_priv;
 
        /* Make sure a caller can chown. */
-       if ((ia_valid & ATTR_UID) && !chown_ok(inode, attr->ia_uid))
+       if ((ia_valid & ATTR_UID) && !chown_ok(mnt_userns, inode, attr->ia_uid))
                return -EPERM;
 
        /* Make sure caller can chgrp. */
-       if ((ia_valid & ATTR_GID) && !chgrp_ok(inode, attr->ia_gid))
+       if ((ia_valid & ATTR_GID) && !chgrp_ok(mnt_userns, inode, attr->ia_gid))
                return -EPERM;
 
        /* Make sure a caller can chmod. */
        if (ia_valid & ATTR_MODE) {
-               if (!inode_owner_or_capable(inode))
+               if (!inode_owner_or_capable(mnt_userns, inode))
                        return -EPERM;
                /* Also check the setgid bit! */
-               if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
-                               inode->i_gid) &&
-                   !capable_wrt_inode_uidgid(inode, CAP_FSETID))
+               if (!in_group_p((ia_valid & ATTR_GID) ? attr->ia_gid :
+                                i_gid_into_mnt(mnt_userns, inode)) &&
+                    !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                        attr->ia_mode &= ~S_ISGID;
        }
 
        /* Check for setting the inode time. */
        if (ia_valid & (ATTR_MTIME_SET | ATTR_ATIME_SET | ATTR_TIMES_SET)) {
-               if (!inode_owner_or_capable(inode))
+               if (!inode_owner_or_capable(mnt_userns, inode))
                        return -EPERM;
        }
 
@@ -107,7 +143,7 @@ kill_priv:
        if (ia_valid & ATTR_KILL_PRIV) {
                int error;
 
-               error = security_inode_killpriv(dentry);
+               error = security_inode_killpriv(mnt_userns, dentry);
                if (error)
                        return error;
        }
@@ -162,20 +198,33 @@ EXPORT_SYMBOL(inode_newsize_ok);
 
 /**
  * setattr_copy - copy simple metadata updates into the generic inode
+ * @mnt_userns:        user namespace of the mount the inode was found from
  * @inode:     the inode to be updated
  * @attr:      the new attributes
  *
  * setattr_copy must be called with i_mutex held.
  *
  * setattr_copy updates the inode's metadata with that specified
- * in attr. Noticeably missing is inode size update, which is more complex
+ * in attr on idmapped mounts. If file ownership is changed setattr_copy
+ * doesn't map ia_uid and ia_gid. It will asssume the caller has already
+ * provided the intended values. Necessary permission checks to determine
+ * whether or not the S_ISGID property needs to be removed are performed with
+ * the correct idmapped mount permission helpers.
+ * Noticeably missing is inode size update, which is more complex
  * as it requires pagecache updates.
  *
+ * 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.
+ *
  * The inode is not marked as dirty after this operation. The rationale is
  * that for "simple" filesystems, the struct inode is the inode storage.
  * The caller is free to mark the inode dirty afterwards if needed.
  */
-void setattr_copy(struct inode *inode, const struct iattr *attr)
+void setattr_copy(struct user_namespace *mnt_userns, struct inode *inode,
+                 const struct iattr *attr)
 {
        unsigned int ia_valid = attr->ia_valid;
 
@@ -191,9 +240,9 @@ void setattr_copy(struct inode *inode, const struct iattr *attr)
                inode->i_ctime = attr->ia_ctime;
        if (ia_valid & ATTR_MODE) {
                umode_t mode = attr->ia_mode;
-
-               if (!in_group_p(inode->i_gid) &&
-                   !capable_wrt_inode_uidgid(inode, CAP_FSETID))
+               kgid_t kgid = i_gid_into_mnt(mnt_userns, inode);
+               if (!in_group_p(kgid) &&
+                   !capable_wrt_inode_uidgid(mnt_userns, inode, CAP_FSETID))
                        mode &= ~S_ISGID;
                inode->i_mode = mode;
        }
@@ -202,6 +251,7 @@ EXPORT_SYMBOL(setattr_copy);
 
 /**
  * notify_change - modify attributes of a filesytem object
+ * @mnt_userns:        user namespace of the mount the inode was found from
  * @dentry:    object affected
  * @attr:      new attributes
  * @delegated_inode: returns inode, if the inode is delegated
@@ -214,13 +264,23 @@ EXPORT_SYMBOL(setattr_copy);
  * retry.  Because breaking a delegation may take a long time, the
  * caller should drop the i_mutex before doing so.
  *
+ * If file ownership is changed notify_change() doesn't map ia_uid and
+ * ia_gid. It will asssume the caller has already provided the intended values.
+ *
  * Alternatively, a caller may pass NULL for delegated_inode.  This may
  * be appropriate for callers that expect the underlying filesystem not
  * to be NFS exported.  Also, passing NULL is fine for callers holding
  * the file open for write, as there can be no conflicting delegation in
  * that case.
+ *
+ * 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.
  */
-int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **delegated_inode)
+int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
+                 struct iattr *attr, struct inode **delegated_inode)
 {
        struct inode *inode = dentry->d_inode;
        umode_t mode = inode->i_mode;
@@ -243,8 +303,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
                if (IS_IMMUTABLE(inode))
                        return -EPERM;
 
-               if (!inode_owner_or_capable(inode)) {
-                       error = inode_permission(inode, MAY_WRITE);
+               if (!inode_owner_or_capable(mnt_userns, inode)) {
+                       error = inode_permission(mnt_userns, inode, MAY_WRITE);
                        if (error)
                                return error;
                }
@@ -320,9 +380,11 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
        /* Don't allow modifications of files with invalid uids or
         * gids unless those uids & gids are being made valid.
         */
-       if (!(ia_valid & ATTR_UID) && !uid_valid(inode->i_uid))
+       if (!(ia_valid & ATTR_UID) &&
+           !uid_valid(i_uid_into_mnt(mnt_userns, inode)))
                return -EOVERFLOW;
-       if (!(ia_valid & ATTR_GID) && !gid_valid(inode->i_gid))
+       if (!(ia_valid & ATTR_GID) &&
+           !gid_valid(i_gid_into_mnt(mnt_userns, inode)))
                return -EOVERFLOW;
 
        error = security_inode_setattr(dentry, attr);
@@ -333,13 +395,13 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
                return error;
 
        if (inode->i_op->setattr)
-               error = inode->i_op->setattr(dentry, attr);
+               error = inode->i_op->setattr(mnt_userns, dentry, attr);
        else
-               error = simple_setattr(dentry, attr);
+               error = simple_setattr(mnt_userns, dentry, attr);
 
        if (!error) {
                fsnotify_change(dentry, ia_valid);
-               ima_inode_post_setattr(dentry);
+               ima_inode_post_setattr(mnt_userns, dentry);
                evm_inode_post_setattr(dentry, ia_valid);
        }