Unverified Commit 47291baa authored by Christian Brauner's avatar Christian Brauner
Browse files

namei: make permission helpers idmapped mount aware

The two helpers inode_permission() and generic_permission() are used by
the vfs to perform basic permission checking by verifying that the
caller is privileged over an inode. In order to handle idmapped mounts
we extend the two helpers with an additional user namespace argument.
On idmapped mounts the two helpers will make sure to map the inode
according to the mount's user namespace and then peform identical
permission checks to inode_permission() and generic_permission(). If the
initial user namespace is passed nothing changes so non-idmapped mounts
will see identical behavior as before.

Link: https://lore.kernel.org/r/20210121131959.646623-6-christian.brauner@ubuntu.com


Cc: Christoph Hellwig <hch@lst.de>
Cc: David Howells <dhowells@redhat.com>
Cc: Al Viro <viro@zeniv.linux.org.uk>
Cc: linux-fsdevel@vger.kernel.org
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Reviewed-by: default avatarJames Morris <jamorris@linux.microsoft.com>
Acked-by: default avatarSerge Hallyn <serge@hallyn.com>
Signed-off-by: default avatarChristian Brauner <christian.brauner@ubuntu.com>
parent 0558c1bf
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -244,7 +244,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr, struct inode **de
			return -EPERM;

		if (!inode_owner_or_capable(inode)) {
			error = inode_permission(inode, MAY_WRITE);
			error = inode_permission(&init_user_ns, inode,
						 MAY_WRITE);
			if (error)
				return error;
		}
+1 −1
Original line number Diff line number Diff line
@@ -9889,7 +9889,7 @@ static int btrfs_permission(struct inode *inode, int mask)
		if (BTRFS_I(inode)->flags & BTRFS_INODE_READONLY)
			return -EACCES;
	}
	return generic_permission(inode, mask);
	return generic_permission(&init_user_ns, inode, mask);
}

static int btrfs_tmpfile(struct inode *dir, struct dentry *dentry, umode_t mode)
+7 −5
Original line number Diff line number Diff line
@@ -922,7 +922,7 @@ static int btrfs_may_delete(struct inode *dir, struct dentry *victim, int isdir)
	BUG_ON(d_inode(victim->d_parent) != dir);
	audit_inode_child(dir, victim, AUDIT_TYPE_CHILD_DELETE);

	error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
	error = inode_permission(&init_user_ns, dir, MAY_WRITE | MAY_EXEC);
	if (error)
		return error;
	if (IS_APPEND(dir))
@@ -951,7 +951,7 @@ static inline int btrfs_may_create(struct inode *dir, struct dentry *child)
		return -EEXIST;
	if (IS_DEADDIR(dir))
		return -ENOENT;
	return inode_permission(dir, MAY_WRITE | MAY_EXEC);
	return inode_permission(&init_user_ns, dir, MAY_WRITE | MAY_EXEC);
}

/*
@@ -2538,7 +2538,8 @@ static int btrfs_search_path_in_tree_user(struct inode *inode,
				ret = PTR_ERR(temp_inode);
				goto out_put;
			}
			ret = inode_permission(temp_inode, MAY_READ | MAY_EXEC);
			ret = inode_permission(&init_user_ns, temp_inode,
					       MAY_READ | MAY_EXEC);
			iput(temp_inode);
			if (ret) {
				ret = -EACCES;
@@ -3068,7 +3069,8 @@ static noinline int btrfs_ioctl_snap_destroy(struct file *file,
		if (root == dest)
			goto out_dput;

		err = inode_permission(inode, MAY_WRITE | MAY_EXEC);
		err = inode_permission(&init_user_ns, inode,
				       MAY_WRITE | MAY_EXEC);
		if (err)
			goto out_dput;
	}
@@ -3139,7 +3141,7 @@ static int btrfs_ioctl_defrag(struct file *file, void __user *argp)
		 * running and allows defrag on files open in read-only mode.
		 */
		if (!capable(CAP_SYS_ADMIN) &&
		    inode_permission(inode, MAY_WRITE)) {
		    inode_permission(&init_user_ns, inode, MAY_WRITE)) {
			ret = -EPERM;
			goto out;
		}
+1 −1
Original line number Diff line number Diff line
@@ -2331,7 +2331,7 @@ int ceph_permission(struct inode *inode, int mask)
	err = ceph_do_getattr(inode, CEPH_CAP_AUTH_SHARED, false);

	if (!err)
		err = generic_permission(inode, mask);
		err = generic_permission(&init_user_ns, inode, mask);
	return err;
}

+1 −1
Original line number Diff line number Diff line
@@ -320,7 +320,7 @@ static int cifs_permission(struct inode *inode, int mask)
		on the client (above and beyond ACL on servers) for
		servers which do not support setting and viewing mode bits,
		so allowing client to check permissions is useful */
		return generic_permission(inode, mask);
		return generic_permission(&init_user_ns, inode, mask);
}

static struct kmem_cache *cifs_inode_cachep;
Loading