Skip to content
/ linux Public
forked from torvalds/linux

Commit

Permalink
fs: port ->setattr() to pass 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 19, 2023
1 parent abf0857 commit c1632a0
Show file tree
Hide file tree
Showing 101 changed files with 257 additions and 245 deletions.
2 changes: 1 addition & 1 deletion Documentation/filesystems/locking.rst
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ prototypes::
void (*truncate) (struct inode *);
int (*permission) (struct inode *, int, unsigned int);
struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
int (*setattr) (struct dentry *, struct iattr *);
int (*setattr) (struct mnt_idmap *, struct dentry *, struct iattr *);
int (*getattr) (const struct path *, struct kstat *, u32, unsigned int);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
int (*fiemap)(struct inode *, struct fiemap_extent_info *, u64 start, u64 len);
Expand Down
2 changes: 1 addition & 1 deletion Documentation/filesystems/vfs.rst
Original file line number Diff line number Diff line change
Expand Up @@ -436,7 +436,7 @@ As of kernel 2.6.22, the following members are defined:
struct delayed_call *);
int (*permission) (struct user_namespace *, struct inode *, int);
struct posix_acl * (*get_inode_acl)(struct inode *, int, bool);
int (*setattr) (struct user_namespace *, struct dentry *, struct iattr *);
int (*setattr) (struct mnt_idmap *, struct dentry *, struct iattr *);
int (*getattr) (struct user_namespace *, const struct path *, struct kstat *, u32, unsigned int);
ssize_t (*listxattr) (struct dentry *, char *, size_t);
void (*update_time)(struct inode *, struct timespec *, int);
Expand Down
4 changes: 2 additions & 2 deletions arch/powerpc/platforms/cell/spufs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,15 +92,15 @@ spufs_new_inode(struct super_block *sb, umode_t mode)
}

static int
spufs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
spufs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
struct inode *inode = d_inode(dentry);

if ((attr->ia_valid & ATTR_SIZE) &&
(attr->ia_size != inode->i_size))
return -EINVAL;
setattr_copy(&init_user_ns, inode, attr);
setattr_copy(&nop_mnt_idmap, inode, attr);
mark_inode_dirty(inode);
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion fs/9p/acl.c
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,7 @@ int v9fs_iop_set_acl(struct user_namespace *mnt_userns, struct dentry *dentry,
* FIXME should we update ctime ?
* What is the following setxattr update the mode ?
*/
v9fs_vfs_setattr_dotl(&init_user_ns, dentry, &iattr);
v9fs_vfs_setattr_dotl(&nop_mnt_idmap, dentry, &iattr);
}
break;
case ACL_TYPE_DEFAULT:
Expand Down
2 changes: 1 addition & 1 deletion fs/9p/v9fs_vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void v9fs_inode2stat(struct inode *inode, struct p9_wstat *stat);
int v9fs_uflags2omode(int uflags, int extended);

void v9fs_blank_wstat(struct p9_wstat *wstat);
int v9fs_vfs_setattr_dotl(struct user_namespace *mnt_userns,
int v9fs_vfs_setattr_dotl(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *iattr);
int v9fs_file_fsync_dotl(struct file *filp, loff_t start, loff_t end,
int datasync);
Expand Down
8 changes: 4 additions & 4 deletions fs/9p/vfs_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -1060,13 +1060,13 @@ v9fs_vfs_getattr(struct user_namespace *mnt_userns, const struct path *path,

/**
* v9fs_vfs_setattr - set file metadata
* @mnt_userns: The user namespace of the mount
* @idmap: idmap of the mount
* @dentry: file whose metadata to set
* @iattr: metadata assignment structure
*
*/

static int v9fs_vfs_setattr(struct user_namespace *mnt_userns,
static int v9fs_vfs_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *iattr)
{
int retval, use_dentry = 0;
Expand All @@ -1077,7 +1077,7 @@ static int v9fs_vfs_setattr(struct user_namespace *mnt_userns,
struct p9_wstat wstat;

p9_debug(P9_DEBUG_VFS, "\n");
retval = setattr_prepare(&init_user_ns, dentry, iattr);
retval = setattr_prepare(&nop_mnt_idmap, dentry, iattr);
if (retval)
return retval;

Expand Down Expand Up @@ -1135,7 +1135,7 @@ static int v9fs_vfs_setattr(struct user_namespace *mnt_userns,

v9fs_invalidate_inode_attr(inode);

setattr_copy(&init_user_ns, inode, iattr);
setattr_copy(&nop_mnt_idmap, inode, iattr);
mark_inode_dirty(inode);
return 0;
}
Expand Down
8 changes: 4 additions & 4 deletions fs/9p/vfs_inode_dotl.c
Original file line number Diff line number Diff line change
Expand Up @@ -529,13 +529,13 @@ static int v9fs_mapped_iattr_valid(int iattr_valid)

/**
* v9fs_vfs_setattr_dotl - set file metadata
* @mnt_userns: The user namespace of the mount
* @idmap: idmap of the mount
* @dentry: file whose metadata to set
* @iattr: metadata assignment structure
*
*/

int v9fs_vfs_setattr_dotl(struct user_namespace *mnt_userns,
int v9fs_vfs_setattr_dotl(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *iattr)
{
int retval, use_dentry = 0;
Expand All @@ -548,7 +548,7 @@ int v9fs_vfs_setattr_dotl(struct user_namespace *mnt_userns,

p9_debug(P9_DEBUG_VFS, "\n");

retval = setattr_prepare(&init_user_ns, dentry, iattr);
retval = setattr_prepare(&nop_mnt_idmap, dentry, iattr);
if (retval)
return retval;

Expand Down Expand Up @@ -597,7 +597,7 @@ int v9fs_vfs_setattr_dotl(struct user_namespace *mnt_userns,
truncate_setsize(inode, iattr->ia_size);

v9fs_invalidate_inode_attr(inode);
setattr_copy(&init_user_ns, inode, iattr);
setattr_copy(&nop_mnt_idmap, inode, iattr);
mark_inode_dirty(inode);
if (iattr->ia_valid & ATTR_MODE) {
/* We also want to update ACL when we update mode bits */
Expand Down
2 changes: 1 addition & 1 deletion fs/adfs/adfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ struct adfs_discmap {
/* Inode stuff */
struct inode *adfs_iget(struct super_block *sb, struct object_info *obj);
int adfs_write_inode(struct inode *inode, struct writeback_control *wbc);
int adfs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
int adfs_notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr);

/* map.c */
Expand Down
4 changes: 2 additions & 2 deletions fs/adfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -294,15 +294,15 @@ adfs_iget(struct super_block *sb, struct object_info *obj)
* later.
*/
int
adfs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
adfs_notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
struct inode *inode = d_inode(dentry);
struct super_block *sb = inode->i_sb;
unsigned int ia_valid = attr->ia_valid;
int error;

error = setattr_prepare(&init_user_ns, dentry, attr);
error = setattr_prepare(&nop_mnt_idmap, dentry, attr);

/*
* we can't change the UID or GID of any file -
Expand Down
2 changes: 1 addition & 1 deletion fs/affs/affs.h
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ extern int affs_rename2(struct user_namespace *mnt_userns,
/* inode.c */

extern struct inode *affs_new_inode(struct inode *dir);
extern int affs_notify_change(struct user_namespace *mnt_userns,
extern int affs_notify_change(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr);
extern void affs_evict_inode(struct inode *inode);
extern struct inode *affs_iget(struct super_block *sb,
Expand Down
6 changes: 3 additions & 3 deletions fs/affs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -216,15 +216,15 @@ affs_write_inode(struct inode *inode, struct writeback_control *wbc)
}

int
affs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
affs_notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
struct inode *inode = d_inode(dentry);
int error;

pr_debug("notify_change(%lu,0x%x)\n", inode->i_ino, attr->ia_valid);

error = setattr_prepare(&init_user_ns, dentry, attr);
error = setattr_prepare(&nop_mnt_idmap, dentry, attr);
if (error)
goto out;

Expand All @@ -250,7 +250,7 @@ affs_notify_change(struct user_namespace *mnt_userns, struct dentry *dentry,
affs_truncate(inode);
}

setattr_copy(&init_user_ns, inode, attr);
setattr_copy(&nop_mnt_idmap, inode, attr);
mark_inode_dirty(inode);

if (attr->ia_valid & ATTR_MODE)
Expand Down
2 changes: 1 addition & 1 deletion fs/afs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -870,7 +870,7 @@ static const struct afs_operation_ops afs_setattr_operation = {
/*
* set the attributes of an inode
*/
int afs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
int afs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
const unsigned int supported =
Expand Down
2 changes: 1 addition & 1 deletion fs/afs/internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -1172,7 +1172,7 @@ extern bool afs_check_validity(struct afs_vnode *);
extern int afs_validate(struct afs_vnode *, struct key *);
extern int afs_getattr(struct user_namespace *mnt_userns, const struct path *,
struct kstat *, u32, unsigned int);
extern int afs_setattr(struct user_namespace *mnt_userns, struct dentry *, struct iattr *);
extern int afs_setattr(struct mnt_idmap *idmap, struct dentry *, struct iattr *);
extern void afs_evict_inode(struct inode *);
extern int afs_drop_inode(struct inode *);

Expand Down
32 changes: 17 additions & 15 deletions fs/attr.c
Original file line number Diff line number Diff line change
Expand Up @@ -142,7 +142,7 @@ static bool chgrp_ok(struct user_namespace *mnt_userns,

/**
* setattr_prepare - check if attribute changes to a dentry are allowed
* @mnt_userns: user namespace of the mount the inode was found from
* @idmap: idmap of the mount the inode was found from
* @dentry: dentry to check
* @attr: attributes to change
*
Expand All @@ -152,18 +152,19 @@ static bool chgrp_ok(struct user_namespace *mnt_userns,
* 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
* 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 passs @nop_mnt_idmap.
*
* Should be called as the first thing in ->setattr implementations,
* possibly after taking additional locks.
*/
int setattr_prepare(struct user_namespace *mnt_userns, struct dentry *dentry,
int setattr_prepare(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
struct inode *inode = d_inode(dentry);
unsigned int ia_valid = attr->ia_valid;

Expand Down Expand Up @@ -276,7 +277,7 @@ 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
* @idmap: idmap of the mount the inode was found from
* @inode: the inode to be updated
* @attr: the new attributes
*
Expand All @@ -289,19 +290,20 @@ EXPORT_SYMBOL(inode_newsize_ok);
* 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
* 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.
*
* 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 user_namespace *mnt_userns, struct inode *inode,
void setattr_copy(struct mnt_idmap *idmap, struct inode *inode,
const struct iattr *attr)
{
struct user_namespace *mnt_userns = mnt_idmap_owner(idmap);
unsigned int ia_valid = attr->ia_valid;

i_uid_update(mnt_userns, attr, inode);
Expand Down Expand Up @@ -472,17 +474,17 @@ int notify_change(struct mnt_idmap *idmap, struct dentry *dentry,
!vfsgid_valid(i_gid_into_vfsgid(mnt_userns, inode)))
return -EOVERFLOW;

error = security_inode_setattr(mnt_userns, dentry, attr);
error = security_inode_setattr(idmap, dentry, attr);
if (error)
return error;
error = try_break_deleg(inode, delegated_inode);
if (error)
return error;

if (inode->i_op->setattr)
error = inode->i_op->setattr(mnt_userns, dentry, attr);
error = inode->i_op->setattr(idmap, dentry, attr);
else
error = simple_setattr(mnt_userns, dentry, attr);
error = simple_setattr(idmap, dentry, attr);

if (!error) {
fsnotify_change(dentry, ia_valid);
Expand Down
2 changes: 1 addition & 1 deletion fs/bad_inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ static int bad_inode_getattr(struct user_namespace *mnt_userns,
return -EIO;
}

static int bad_inode_setattr(struct user_namespace *mnt_userns,
static int bad_inode_setattr(struct mnt_idmap *idmap,
struct dentry *direntry, struct iattr *attrs)
{
return -EIO;
Expand Down
9 changes: 5 additions & 4 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -5281,7 +5281,7 @@ static int btrfs_setsize(struct inode *inode, struct iattr *attr)
return ret;
}

static int btrfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
static int btrfs_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
struct inode *inode = d_inode(dentry);
Expand All @@ -5291,7 +5291,7 @@ static int btrfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentr
if (btrfs_root_readonly(root))
return -EROFS;

err = setattr_prepare(mnt_userns, dentry, attr);
err = setattr_prepare(idmap, dentry, attr);
if (err)
return err;

Expand All @@ -5302,12 +5302,13 @@ static int btrfs_setattr(struct user_namespace *mnt_userns, struct dentry *dentr
}

if (attr->ia_valid) {
setattr_copy(mnt_userns, inode, attr);
setattr_copy(idmap, inode, attr);
inode_inc_iversion(inode);
err = btrfs_dirty_inode(BTRFS_I(inode));

if (!err && attr->ia_valid & ATTR_MODE)
err = posix_acl_chmod(mnt_userns, dentry, inode->i_mode);
err = posix_acl_chmod(mnt_idmap_owner(idmap), dentry,
inode->i_mode);
}

return err;
Expand Down
4 changes: 2 additions & 2 deletions fs/ceph/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2227,7 +2227,7 @@ int __ceph_setattr(struct inode *inode, struct iattr *attr)
/*
* setattr
*/
int ceph_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
int ceph_setattr(struct mnt_idmap *idmap, struct dentry *dentry,
struct iattr *attr)
{
struct inode *inode = d_inode(dentry);
Expand All @@ -2240,7 +2240,7 @@ int ceph_setattr(struct user_namespace *mnt_userns, struct dentry *dentry,
if (ceph_inode_is_shutdown(inode))
return -ESTALE;

err = setattr_prepare(&init_user_ns, dentry, attr);
err = setattr_prepare(&nop_mnt_idmap, dentry, attr);
if (err != 0)
return err;

Expand Down
2 changes: 1 addition & 1 deletion fs/ceph/super.h
Original file line number Diff line number Diff line change
Expand Up @@ -1043,7 +1043,7 @@ static inline int ceph_do_getattr(struct inode *inode, int mask, bool force)
extern int ceph_permission(struct user_namespace *mnt_userns,
struct inode *inode, int mask);
extern int __ceph_setattr(struct inode *inode, struct iattr *attr);
extern int ceph_setattr(struct user_namespace *mnt_userns,
extern int ceph_setattr(struct mnt_idmap *idmap,
struct dentry *dentry, struct iattr *attr);
extern int ceph_getattr(struct user_namespace *mnt_userns,
const struct path *path, struct kstat *stat,
Expand Down
2 changes: 1 addition & 1 deletion fs/cifs/cifsfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ extern int cifs_revalidate_mapping(struct inode *inode);
extern int cifs_zap_mapping(struct inode *inode);
extern int cifs_getattr(struct user_namespace *, const struct path *,
struct kstat *, u32, unsigned int);
extern int cifs_setattr(struct user_namespace *, struct dentry *,
extern int cifs_setattr(struct mnt_idmap *, struct dentry *,
struct iattr *);
extern int cifs_fiemap(struct inode *, struct fiemap_extent_info *, u64 start,
u64 len);
Expand Down
Loading

0 comments on commit c1632a0

Please sign in to comment.