Skip to content

Commit

Permalink
fs: port vfs_*() helpers to struct mnt_idmap
Browse files Browse the repository at this point in the history
Convert to struct mnt_idmap.

Last cycle we merged the necessary infrastructure in
256c8ae ("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: Dave Chinner <[email protected]>
Reviewed-by: Christoph Hellwig <[email protected]>
Signed-off-by: Christian Brauner (Microsoft) <[email protected]>
  • Loading branch information
brauner committed Jan 18, 2023
1 parent 64b4cdf commit abf0857
Show file tree
Hide file tree
Showing 25 changed files with 255 additions and 221 deletions.
12 changes: 6 additions & 6 deletions drivers/base/devtmpfs.c
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,7 @@ static int dev_mkdir(const char *name, umode_t mode)
if (IS_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)
/* mark as kernel-created inode */
d_inode(dentry)->i_private = &thread;
Expand Down Expand Up @@ -223,7 +223,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
if (IS_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);
if (!err) {
struct iattr newattrs;
Expand All @@ -233,7 +233,7 @@ static int handle_create(const char *nodename, umode_t mode, kuid_t uid,
newattrs.ia_gid = gid;
newattrs.ia_valid = ATTR_MODE|ATTR_UID|ATTR_GID;
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));

/* mark as kernel-created inode */
Expand All @@ -254,7 +254,7 @@ static int dev_rmdir(const char *name)
return PTR_ERR(dentry);
if (d_really_is_positive(dentry)) {
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);
else
err = -EPERM;
Expand Down Expand Up @@ -341,9 +341,9 @@ static int handle_remove(const char *nodename, struct device *dev)
newattrs.ia_valid =
ATTR_UID|ATTR_GID|ATTR_MODE;
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));
err = vfs_unlink(&init_user_ns, d_inode(parent.dentry),
err = vfs_unlink(&nop_mnt_idmap, d_inode(parent.dentry),
dentry, NULL);
if (!err || err == -ENOENT)
deleted = 1;
Expand Down
13 changes: 7 additions & 6 deletions fs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -352,7 +352,7 @@ EXPORT_SYMBOL(may_setattr);

/**
* 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
* @attr: new attributes
* @delegated_inode: returns inode, if the inode is delegated
Expand All @@ -371,15 +371,16 @@ EXPORT_SYMBOL(may_setattr);
* 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
* If the inode has been found through an idmapped mount the idmap of
* the vfsmount must be passed through @idmap. This function will then
* take care to map the inode according to @idmap before checking
* 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 user_namespace *mnt_userns = mnt_idmap_owner(idmap);
struct inode *inode = dentry->d_inode;
umode_t mode = inode->i_mode;
int error;
Expand Down
4 changes: 2 additions & 2 deletions fs/cachefiles/interface.c
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ static int cachefiles_adjust_size(struct cachefiles_object *object)
newattrs.ia_size = oi_size & PAGE_MASK;
ret = cachefiles_inject_remove_error();
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);
if (ret < 0)
goto truncate_failed;
Expand All @@ -148,7 +148,7 @@ static int cachefiles_adjust_size(struct cachefiles_object *object)
newattrs.ia_size = ni_size;
ret = cachefiles_inject_write_error();
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);

truncate_failed:
Expand Down
12 changes: 6 additions & 6 deletions fs/cachefiles/namei.c
Original file line number Diff line number Diff line change
Expand Up @@ -130,7 +130,7 @@ struct dentry *cachefiles_get_directory(struct cachefiles_cache *cache,
goto mkdir_error;
ret = cachefiles_inject_write_error();
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) {
trace_cachefiles_vfs_error(NULL, d_inode(dir), ret,
cachefiles_trace_mkdir_error);
Expand Down Expand Up @@ -245,7 +245,7 @@ static int cachefiles_unlink(struct cachefiles_cache *cache,

ret = cachefiles_inject_remove_error();
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)
cachefiles_io_error(cache, "Unlink failed");
}
Expand Down Expand Up @@ -382,10 +382,10 @@ int cachefiles_bury_object(struct cachefiles_cache *cache,
cachefiles_io_error(cache, "Rename security error %d", ret);
} else {
struct renamedata rd = {
.old_mnt_userns = &init_user_ns,
.old_mnt_idmap = &nop_mnt_idmap,
.old_dir = d_inode(dir),
.old_dentry = rep,
.new_mnt_userns = &init_user_ns,
.new_mnt_idmap = &nop_mnt_idmap,
.new_dir = d_inode(cache->graveyard),
.new_dentry = grave,
};
Expand Down Expand Up @@ -451,7 +451,7 @@ struct file *cachefiles_create_tmpfile(struct cachefiles_object *object)

ret = cachefiles_inject_write_error();
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,
cache->cache_cred);
ret = PTR_ERR_OR_ZERO(file);
Expand Down Expand Up @@ -714,7 +714,7 @@ bool cachefiles_commit_tmpfile(struct cachefiles_cache *cache,

ret = cachefiles_inject_read_error();
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);
if (ret < 0) {
trace_cachefiles_vfs_error(object, d_inode(fan), ret,
Expand Down
6 changes: 4 additions & 2 deletions fs/coredump.c
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
goto close_fail;
}
} else {
struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
struct inode *inode;
int open_flags = O_CREAT | O_RDWR | O_NOFOLLOW |
Expand Down Expand Up @@ -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
* 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),
current_fsuid())) {
pr_info_ratelimited("Core dump to %s aborted: cannot preserve file owner\n",
Expand All @@ -736,7 +738,7 @@ void do_coredump(const kernel_siginfo_t *siginfo)
}
if (!(cprm.file->f_mode & FMODE_CAN_WRITE))
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))
goto close_fail;
}
Expand Down
24 changes: 12 additions & 12 deletions fs/ecryptfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ static int ecryptfs_do_unlink(struct inode *dir, struct dentry *dentry,
if (d_unhashed(lower_dentry))
rc = -EINVAL;
else
rc = vfs_unlink(&init_user_ns, lower_dir, lower_dentry,
rc = vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry,
NULL);
}
if (rc) {
Expand Down Expand Up @@ -180,7 +180,7 @@ ecryptfs_do_create(struct inode *directory_inode,

rc = lock_parent(ecryptfs_dentry, &lower_dentry, &lower_dir);
if (!rc)
rc = vfs_create(&init_user_ns, lower_dir,
rc = vfs_create(&nop_mnt_idmap, lower_dir,
lower_dentry, mode, true);
if (rc) {
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
Expand All @@ -191,7 +191,7 @@ ecryptfs_do_create(struct inode *directory_inode,
inode = __ecryptfs_get_inode(d_inode(lower_dentry),
directory_inode->i_sb);
if (IS_ERR(inode)) {
vfs_unlink(&init_user_ns, lower_dir, lower_dentry, NULL);
vfs_unlink(&nop_mnt_idmap, lower_dir, lower_dentry, NULL);
goto out_lock;
}
fsstack_copy_attr_times(directory_inode, lower_dir);
Expand Down Expand Up @@ -434,7 +434,7 @@ static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,
lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);
rc = lock_parent(new_dentry, &lower_new_dentry, &lower_dir);
if (!rc)
rc = vfs_link(lower_old_dentry, &init_user_ns, lower_dir,
rc = vfs_link(lower_old_dentry, &nop_mnt_idmap, lower_dir,
lower_new_dentry, NULL);
if (rc || d_really_is_negative(lower_new_dentry))
goto out_lock;
Expand Down Expand Up @@ -478,7 +478,7 @@ static int ecryptfs_symlink(struct user_namespace *mnt_userns,
strlen(symname));
if (rc)
goto out_lock;
rc = vfs_symlink(&init_user_ns, lower_dir, lower_dentry,
rc = vfs_symlink(&nop_mnt_idmap, lower_dir, lower_dentry,
encoded_symname);
kfree(encoded_symname);
if (rc || d_really_is_negative(lower_dentry))
Expand All @@ -504,7 +504,7 @@ static int ecryptfs_mkdir(struct user_namespace *mnt_userns, struct inode *dir,

rc = lock_parent(dentry, &lower_dentry, &lower_dir);
if (!rc)
rc = vfs_mkdir(&init_user_ns, lower_dir,
rc = vfs_mkdir(&nop_mnt_idmap, lower_dir,
lower_dentry, mode);
if (rc || d_really_is_negative(lower_dentry))
goto out;
Expand Down Expand Up @@ -533,7 +533,7 @@ static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)
if (d_unhashed(lower_dentry))
rc = -EINVAL;
else
rc = vfs_rmdir(&init_user_ns, lower_dir, lower_dentry);
rc = vfs_rmdir(&nop_mnt_idmap, lower_dir, lower_dentry);
}
if (!rc) {
clear_nlink(d_inode(dentry));
Expand All @@ -557,7 +557,7 @@ ecryptfs_mknod(struct user_namespace *mnt_userns, struct inode *dir,

rc = lock_parent(dentry, &lower_dentry, &lower_dir);
if (!rc)
rc = vfs_mknod(&init_user_ns, lower_dir,
rc = vfs_mknod(&nop_mnt_idmap, lower_dir,
lower_dentry, mode, dev);
if (rc || d_really_is_negative(lower_dentry))
goto out;
Expand Down Expand Up @@ -616,10 +616,10 @@ ecryptfs_rename(struct user_namespace *mnt_userns, struct inode *old_dir,
goto out_lock;
}

rd.old_mnt_userns = &init_user_ns;
rd.old_mnt_idmap = &nop_mnt_idmap;
rd.old_dir = d_inode(lower_old_dir_dentry);
rd.old_dentry = lower_old_dentry;
rd.new_mnt_userns = &init_user_ns;
rd.new_mnt_idmap = &nop_mnt_idmap;
rd.new_dir = d_inode(lower_new_dir_dentry);
rd.new_dentry = lower_new_dentry;
rc = vfs_rename(&rd);
Expand Down Expand Up @@ -856,7 +856,7 @@ int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)
struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);

inode_lock(d_inode(lower_dentry));
rc = notify_change(&init_user_ns, lower_dentry,
rc = notify_change(&nop_mnt_idmap, lower_dentry,
&lower_ia, NULL);
inode_unlock(d_inode(lower_dentry));
}
Expand Down Expand Up @@ -965,7 +965,7 @@ static int ecryptfs_setattr(struct user_namespace *mnt_userns,
lower_ia.ia_valid &= ~ATTR_MODE;

inode_lock(d_inode(lower_dentry));
rc = notify_change(&init_user_ns, lower_dentry, &lower_ia, NULL);
rc = notify_change(&nop_mnt_idmap, lower_dentry, &lower_ia, NULL);
inode_unlock(d_inode(lower_dentry));
out:
fsstack_copy_attr_all(inode, lower_inode);
Expand Down
12 changes: 7 additions & 5 deletions fs/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -157,7 +157,7 @@ int __init init_mknod(const char *filename, umode_t mode, unsigned int dev)
mode &= ~current_umask();
error = security_path_mknod(&path, dentry, mode, dev);
if (!error)
error = vfs_mknod(mnt_user_ns(path.mnt), path.dentry->d_inode,
error = vfs_mknod(mnt_idmap(path.mnt), path.dentry->d_inode,
dentry, mode, new_decode_dev(dev));
done_path_create(&path, dentry);
return error;
Expand All @@ -167,6 +167,7 @@ int __init init_link(const char *oldname, const char *newname)
{
struct dentry *new_dentry;
struct path old_path, new_path;
struct mnt_idmap *idmap;
struct user_namespace *mnt_userns;
int error;

Expand All @@ -182,14 +183,15 @@ int __init init_link(const char *oldname, const char *newname)
error = -EXDEV;
if (old_path.mnt != new_path.mnt)
goto out_dput;
mnt_userns = mnt_user_ns(new_path.mnt);
idmap = mnt_idmap(new_path.mnt);
mnt_userns = mnt_idmap_owner(idmap);
error = may_linkat(mnt_userns, &old_path);
if (unlikely(error))
goto out_dput;
error = security_path_link(old_path.dentry, &new_path, new_dentry);
if (error)
goto out_dput;
error = vfs_link(old_path.dentry, mnt_userns, new_path.dentry->d_inode,
error = vfs_link(old_path.dentry, idmap, new_path.dentry->d_inode,
new_dentry, NULL);
out_dput:
done_path_create(&new_path, new_dentry);
Expand All @@ -209,7 +211,7 @@ int __init init_symlink(const char *oldname, const char *newname)
return PTR_ERR(dentry);
error = security_path_symlink(&path, dentry, oldname);
if (!error)
error = vfs_symlink(mnt_user_ns(path.mnt), path.dentry->d_inode,
error = vfs_symlink(mnt_idmap(path.mnt), path.dentry->d_inode,
dentry, oldname);
done_path_create(&path, dentry);
return error;
Expand All @@ -233,7 +235,7 @@ int __init init_mkdir(const char *pathname, umode_t mode)
mode &= ~current_umask();
error = security_path_mkdir(&path, dentry, mode);
if (!error)
error = vfs_mkdir(mnt_user_ns(path.mnt), path.dentry->d_inode,
error = vfs_mkdir(mnt_idmap(path.mnt), path.dentry->d_inode,
dentry, mode);
done_path_create(&path, dentry);
return error;
Expand Down
6 changes: 3 additions & 3 deletions fs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1972,7 +1972,7 @@ int dentry_needs_remove_privs(struct user_namespace *mnt_userns,
return mask;
}

static int __remove_privs(struct user_namespace *mnt_userns,
static int __remove_privs(struct mnt_idmap *idmap,
struct dentry *dentry, int kill)
{
struct iattr newattrs;
Expand All @@ -1982,7 +1982,7 @@ static int __remove_privs(struct user_namespace *mnt_userns,
* Note we call this on write, so notify_change will not
* encounter any conflicting delegations:
*/
return notify_change(mnt_userns, dentry, &newattrs, NULL);
return notify_change(idmap, dentry, &newattrs, NULL);
}

static int __file_remove_privs(struct file *file, unsigned int flags)
Expand All @@ -2003,7 +2003,7 @@ static int __file_remove_privs(struct file *file, unsigned int flags)
if (flags & IOCB_NOWAIT)
return -EAGAIN;

error = __remove_privs(file_mnt_user_ns(file), dentry, kill);
error = __remove_privs(file_mnt_idmap(file), dentry, kill);
}

if (!error)
Expand Down
6 changes: 4 additions & 2 deletions fs/ksmbd/smb2pdu.c
Original file line number Diff line number Diff line change
Expand Up @@ -5615,6 +5615,7 @@ static int set_file_basic_info(struct ksmbd_file *fp,
struct iattr attrs;
struct file *filp;
struct inode *inode;
struct mnt_idmap *idmap;
struct user_namespace *user_ns;
int rc = 0;

Expand All @@ -5624,7 +5625,8 @@ static int set_file_basic_info(struct ksmbd_file *fp,
attrs.ia_valid = 0;
filp = fp->filp;
inode = file_inode(filp);
user_ns = file_mnt_user_ns(filp);
idmap = file_mnt_idmap(filp);
user_ns = mnt_idmap_owner(idmap);

if (file_info->CreationTime)
fp->create_time = le64_to_cpu(file_info->CreationTime);
Expand Down Expand Up @@ -5686,7 +5688,7 @@ static int set_file_basic_info(struct ksmbd_file *fp,
inode_lock(inode);
inode->i_ctime = attrs.ia_ctime;
attrs.ia_valid &= ~ATTR_CTIME;
rc = notify_change(user_ns, dentry, &attrs, NULL);
rc = notify_change(idmap, dentry, &attrs, NULL);
inode_unlock(inode);
}
return rc;
Expand Down
Loading

0 comments on commit abf0857

Please sign in to comment.