Unverified Commit abf08576 authored by Christian Brauner's avatar Christian Brauner Committed by Christian Brauner (Microsoft)
Browse files

fs: port vfs_*() helpers to struct mnt_idmap



Convert to struct mnt_idmap.

Last cycle we merged the necessary infrastructure in
256c8aed ("fs: introduce dedicated idmap type for mounts").
This is just the conversion to struct mnt_idmap.

Currently we still pass around the plain namespace that was attached to a
mount. This is in general pretty convenient but it makes it easy to
conflate namespaces that are relevant on the filesystem with namespaces
that are relevent on the mount level. Especially for non-vfs developers
without detailed knowledge in this area this can be a potential source for
bugs.

Once the conversion to struct mnt_idmap is done all helpers down to the
really low-level helpers will take a struct mnt_idmap argument instead of
two namespace arguments. This way it becomes impossible to conflate the two
eliminating the possibility of any bugs. All of the vfs and all filesystems
only operate on struct mnt_idmap.

Acked-by: default avatarDave Chinner <dchinner@redhat.com>
Reviewed-by: default avatarChristoph Hellwig <hch@lst.de>
Signed-off-by: default avatarChristian Brauner (Microsoft) <brauner@kernel.org>
parent 64b4cdf2
Loading
Loading
Loading
Loading
+6 −6
Original line number Original line Diff line number Diff line
@@ -173,7 +173,7 @@ static int dev_mkdir(const char *name, umode_t mode)
	if (IS_ERR(dentry))
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);
		return PTR_ERR(dentry);


	err = vfs_mkdir(&init_user_ns, d_inode(path.dentry), dentry, mode);
	err = vfs_mkdir(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode);
	if (!err)
	if (!err)
		/* mark as kernel-created inode */
		/* mark as kernel-created inode */
		d_inode(dentry)->i_private = &thread;
		d_inode(dentry)->i_private = &thread;
@@ -223,7 +223,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
	if (IS_ERR(dentry))
	if (IS_ERR(dentry))
		return PTR_ERR(dentry);
		return PTR_ERR(dentry);


	err = vfs_mknod(&init_user_ns, d_inode(path.dentry), dentry, mode,
	err = vfs_mknod(&nop_mnt_idmap, d_inode(path.dentry), dentry, mode,
			dev->devt);
			dev->devt);
	if (!err) {
	if (!err) {
		struct iattr newattrs;
		struct iattr newattrs;
@@ -233,7 +233,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
		newattrs.ia_gid = gid;
		newattrs.ia_gid = gid;
		newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
		newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
		inode_lock(d_inode(dentry));
		inode_lock(d_inode(dentry));
		notify_change(&init_user_ns, dentry, &newattrs, NULL);
		notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL);
		inode_unlock(d_inode(dentry));
		inode_unlock(d_inode(dentry));


		/* mark as kernel-created inode */
		/* mark as kernel-created inode */
@@ -254,7 +254,7 @@ static int dev_rmdir(const char *name)
		return PTR_ERR(dentry);
		return PTR_ERR(dentry);
	if (d_really_is_positive(dentry)) {
	if (d_really_is_positive(dentry)) {
		if (d_inode(dentry)->i_private == &thread)
		if (d_inode(dentry)->i_private == &thread)
			err = vfs_rmdir(&init_user_ns, d_inode(parent.dentry),
			err = vfs_rmdir(&nop_mnt_idmap, d_inode(parent.dentry),
					dentry);
					dentry);
		else
		else
			err = -EPERM;
			err = -EPERM;
@@ -341,9 +341,9 @@ static int handle_remove(const char *nodename, struct device *dev)
			newattrs.ia_valid =
			newattrs.ia_valid =
				ATTR_UID|ATTR_GID|ATTR_MODE;
				ATTR_UID|ATTR_GID|ATTR_MODE;
			inode_lock(d_inode(dentry));
			inode_lock(d_inode(dentry));
			notify_change(&init_user_ns, dentry, &newattrs, NULL);
			notify_change(&nop_mnt_idmap, dentry, &newattrs, NULL);
			inode_unlock(d_inode(dentry));
			inode_unlock(d_inode(dentry));
			err = vfs_unlink(&init_user_ns, d_inode(parent.dentry),
			err = vfs_unlink(&nop_mnt_idmap, d_inode(parent.dentry),
					 dentry, NULL);
					 dentry, NULL);
			if (!err || err == -ENOENT)
			if (!err || err == -ENOENT)
				deleted = 1;
				deleted = 1;
+7 −6
Original line number Original line Diff line number Diff line
@@ -352,7 +352,7 @@ EXPORT_SYMBOL(may_setattr);


/**
/**
 * notify_change - modify attributes of a filesytem object
 * notify_change - modify attributes of a filesytem object
 * @mnt_userns:	user namespace of the mount the inode was found from
 * @idmap:	idmap of the mount the inode was found from
 * @dentry:	object affected
 * @dentry:	object affected
 * @attr:	new attributes
 * @attr:	new attributes
 * @delegated_inode: returns inode, if the inode is delegated
 * @delegated_inode: returns inode, if the inode is delegated
@@ -371,15 +371,16 @@ EXPORT_SYMBOL(may_setattr);
 * the file open for write, as there can be no conflicting delegation in
 * the file open for write, as there can be no conflicting delegation in
 * that case.
 * that case.
 *
 *
 * If the inode has been found through an idmapped mount the user namespace of
 * If the inode has been found through an idmapped mount the idmap of
 * the vfsmount must be passed through @mnt_userns. This function will then
 * the vfsmount must be passed through @idmap. This function will then
 * take care to map the inode according to @mnt_userns before checking
 * take care to map the inode according to @idmap before checking
 * permissions. On non-idmapped mounts or if permission checking is to be
 * permissions. On non-idmapped mounts or if permission checking is to be
 * performed on the raw inode simply passs init_user_ns.
 * performed on the raw inode simply pass @nop_mnt_idmap.
 */
 */
int notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
		  struct iattr *attr, struct inode **delegated_inode)
		  struct iattr *attr, struct inode **delegated_inode)
{
{
	struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
	struct inode *inode = dentry->d_inode;
	struct inode *inode = dentry->d_inode;
	umode_t mode = inode->i_mode;
	umode_t mode = inode->i_mode;
	int error;
	int error;
+2 −2
Original line number Original line Diff line number Diff line
@@ -138,7 +138,7 @@ static int cachefiles_adjust_size(struct cachefiles_object *object)
		newattrs.ia_size = oi_size & PAGE_MASK;
		newattrs.ia_size = oi_size & PAGE_MASK;
		ret = cachefiles_inject_remove_error();
		ret = cachefiles_inject_remove_error();
		if (ret == 0)
		if (ret == 0)
			ret = notify_change(&init_user_ns, file->f_path.dentry,
			ret = notify_change(&nop_mnt_idmap, file->f_path.dentry,
					    &newattrs, NULL);
					    &newattrs, NULL);
		if (ret < 0)
		if (ret < 0)
			goto truncate_failed;
			goto truncate_failed;
@@ -148,7 +148,7 @@ static int cachefiles_adjust_size(struct cachefiles_object *object)
	newattrs.ia_size = ni_size;
	newattrs.ia_size = ni_size;
	ret = cachefiles_inject_write_error();
	ret = cachefiles_inject_write_error();
	if (ret == 0)
	if (ret == 0)
		ret = notify_change(&init_user_ns, file->f_path.dentry,
		ret = notify_change(&nop_mnt_idmap, file->f_path.dentry,
				    &newattrs, NULL);
				    &newattrs, NULL);


truncate_failed:
truncate_failed:
+6 −6
Original line number Original line Diff line number Diff line
@@ -130,7 +130,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
			goto mkdir_error;
			goto mkdir_error;
		ret = cachefiles_inject_write_error();
		ret = cachefiles_inject_write_error();
		if (ret == 0)
		if (ret == 0)
			ret = vfs_mkdir(&init_user_ns, d_inode(dir), subdir, 0700);
			ret = vfs_mkdir(&nop_mnt_idmap, d_inode(dir), subdir, 0700);
		if (ret < 0) {
		if (ret < 0) {
			trace_cachefiles_vfs_error(NULL, d_inode(dir), ret,
			trace_cachefiles_vfs_error(NULL, d_inode(dir), ret,
						   cachefiles_trace_mkdir_error);
						   cachefiles_trace_mkdir_error);
@@ -245,7 +245,7 @@ static int cachefiles_unlink(struct cachefiles_cache *cache,


	ret = cachefiles_inject_remove_error();
	ret = cachefiles_inject_remove_error();
	if (ret == 0) {
	if (ret == 0) {
		ret = vfs_unlink(&init_user_ns, d_backing_inode(dir), dentry, NULL);
		ret = vfs_unlink(&nop_mnt_idmap, d_backing_inode(dir), dentry, NULL);
		if (ret == -EIO)
		if (ret == -EIO)
			cachefiles_io_error(cache, "Unlink failed");
			cachefiles_io_error(cache, "Unlink failed");
	}
	}
@@ -382,10 +382,10 @@ int cachefiles_bury_object(struct cachefiles_cache *cache,
		cachefiles_io_error(cache, "Rename security error %d", ret);
		cachefiles_io_error(cache, "Rename security error %d", ret);
	} else {
	} else {
		struct renamedata rd = {
		struct renamedata rd = {
			.old_mnt_userns	= &init_user_ns,
			.old_mnt_idmap	= &nop_mnt_idmap,
			.old_dir	= d_inode(dir),
			.old_dir	= d_inode(dir),
			.old_dentry	= rep,
			.old_dentry	= rep,
			.new_mnt_userns	= &init_user_ns,
			.new_mnt_idmap	= &nop_mnt_idmap,
			.new_dir	= d_inode(cache->graveyard),
			.new_dir	= d_inode(cache->graveyard),
			.new_dentry	= grave,
			.new_dentry	= grave,
		};
		};
@@ -451,7 +451,7 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)


	ret = cachefiles_inject_write_error();
	ret = cachefiles_inject_write_error();
	if (ret == 0) {
	if (ret == 0) {
		file = vfs_tmpfile_open(&init_user_ns, &parentpath, S_IFREG,
		file = vfs_tmpfile_open(&nop_mnt_idmap, &parentpath, S_IFREG,
					O_RDWR | O_LARGEFILE | O_DIRECT,
					O_RDWR | O_LARGEFILE | O_DIRECT,
					cache->cache_cred);
					cache->cache_cred);
		ret = PTR_ERR_OR_ZERO(file);
		ret = PTR_ERR_OR_ZERO(file);
@@ -714,7 +714,7 @@ bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache,


	ret = cachefiles_inject_read_error();
	ret = cachefiles_inject_read_error();
	if (ret == 0)
	if (ret == 0)
		ret = vfs_link(object->file->f_path.dentry, &init_user_ns,
		ret = vfs_link(object->file->f_path.dentry, &nop_mnt_idmap,
			       d_inode(fan), dentry, NULL);
			       d_inode(fan), dentry, NULL);
	if (ret < 0) {
	if (ret < 0) {
		trace_cachefiles_vfs_error(object, d_inode(fan), ret,
		trace_cachefiles_vfs_error(object, d_inode(fan), ret,
+4 −2
Original line number Original line Diff line number Diff line
@@ -644,6 +644,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
			goto close_fail;
			goto close_fail;
		}
		}
	} else {
	} else {
		struct mnt_idmap *idmap;
		struct user_namespace *mnt_userns;
		struct user_namespace *mnt_userns;
		struct inode *inode;
		struct inode *inode;
		int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
		int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
@@ -722,7 +723,8 @@ void do_coredump(const kernel_siginfo_t *siginfo)
		 * a process dumps core while its cwd is e.g. on a vfat
		 * a process dumps core while its cwd is e.g. on a vfat
		 * filesystem.
		 * filesystem.
		 */
		 */
		mnt_userns = file_mnt_user_ns(cprm.file);
		idmap = file_mnt_idmap(cprm.file);
		mnt_userns = mnt_idmap_owner(idmap);
		if (!vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode),
		if (!vfsuid_eq_kuid(i_uid_into_vfsuid(mnt_userns, inode),
				    current_fsuid())) {
				    current_fsuid())) {
			pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
			pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
@@ -736,7 +738,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
		}
		}
		if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
		if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
			goto close_fail;
			goto close_fail;
		if (do_truncate(mnt_userns, cprm.file->f_path.dentry,
		if (do_truncate(idmap, cprm.file->f_path.dentry,
				0, 0, cprm.file))
				0, 0, cprm.file))
			goto close_fail;
			goto close_fail;
	}
	}
Loading