vboxsf: don't allow to change the inode type

vboxsf_init_inode() is used both for initial setup of inode and for metadata
updates.  Tell it whether we are updating a live inode or setting up a new
instance and have it refuse to change type in the former case.

[fixed the braino caught by Hans de Goede <hdegoede@redhat.com>]

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
This commit is contained in:
Al Viro 2021-02-14 00:12:23 -05:00
parent 6e1eb04a87
commit e98f93e7ca
4 changed files with 49 additions and 31 deletions

View File

@ -225,7 +225,7 @@ static struct dentry *vboxsf_dir_lookup(struct inode *parent,
} else { } else {
inode = vboxsf_new_inode(parent->i_sb); inode = vboxsf_new_inode(parent->i_sb);
if (!IS_ERR(inode)) if (!IS_ERR(inode))
vboxsf_init_inode(sbi, inode, &fsinfo); vboxsf_init_inode(sbi, inode, &fsinfo, false);
} }
return d_splice_alias(inode, dentry); return d_splice_alias(inode, dentry);
@ -245,7 +245,7 @@ static int vboxsf_dir_instantiate(struct inode *parent, struct dentry *dentry,
sf_i = VBOXSF_I(inode); sf_i = VBOXSF_I(inode);
/* The host may have given us different attr then requested */ /* The host may have given us different attr then requested */
sf_i->force_restat = 1; sf_i->force_restat = 1;
vboxsf_init_inode(sbi, inode, info); vboxsf_init_inode(sbi, inode, info, false);
d_instantiate(dentry, inode); d_instantiate(dentry, inode);

View File

@ -207,7 +207,7 @@ static int vboxsf_fill_super(struct super_block *sb, struct fs_context *fc)
err = -ENOMEM; err = -ENOMEM;
goto fail_unmap; goto fail_unmap;
} }
vboxsf_init_inode(sbi, iroot, &sbi->root_info); vboxsf_init_inode(sbi, iroot, &sbi->root_info, false);
unlock_new_inode(iroot); unlock_new_inode(iroot);
droot = d_make_root(iroot); droot = d_make_root(iroot);
@ -418,7 +418,7 @@ static int vboxsf_reconfigure(struct fs_context *fc)
/* Apply changed options to the root inode */ /* Apply changed options to the root inode */
sbi->o = ctx->o; sbi->o = ctx->o;
vboxsf_init_inode(sbi, iroot, &sbi->root_info); vboxsf_init_inode(sbi, iroot, &sbi->root_info, true);
return 0; return 0;
} }

View File

@ -45,12 +45,12 @@ struct inode *vboxsf_new_inode(struct super_block *sb)
} }
/* set [inode] attributes based on [info], uid/gid based on [sbi] */ /* set [inode] attributes based on [info], uid/gid based on [sbi] */
void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
const struct shfl_fsobjinfo *info) const struct shfl_fsobjinfo *info, bool reinit)
{ {
const struct shfl_fsobjattr *attr; const struct shfl_fsobjattr *attr;
s64 allocated; s64 allocated;
int mode; umode_t mode;
attr = &info->attr; attr = &info->attr;
@ -75,29 +75,44 @@ void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
inode->i_mapping->a_ops = &vboxsf_reg_aops; inode->i_mapping->a_ops = &vboxsf_reg_aops;
if (SHFL_IS_DIRECTORY(attr->mode)) { if (SHFL_IS_DIRECTORY(attr->mode)) {
inode->i_mode = sbi->o.dmode_set ? sbi->o.dmode : mode; if (sbi->o.dmode_set)
inode->i_mode &= ~sbi->o.dmask; mode = sbi->o.dmode;
inode->i_mode |= S_IFDIR; mode &= ~sbi->o.dmask;
inode->i_op = &vboxsf_dir_iops; mode |= S_IFDIR;
inode->i_fop = &vboxsf_dir_fops; if (!reinit) {
/* inode->i_op = &vboxsf_dir_iops;
* XXX: this probably should be set to the number of entries inode->i_fop = &vboxsf_dir_fops;
* in the directory plus two (. ..) /*
*/ * XXX: this probably should be set to the number of entries
set_nlink(inode, 1); * in the directory plus two (. ..)
*/
set_nlink(inode, 1);
} else if (!S_ISDIR(inode->i_mode))
return -ESTALE;
inode->i_mode = mode;
} else if (SHFL_IS_SYMLINK(attr->mode)) { } else if (SHFL_IS_SYMLINK(attr->mode)) {
inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; if (sbi->o.fmode_set)
inode->i_mode &= ~sbi->o.fmask; mode = sbi->o.fmode;
inode->i_mode |= S_IFLNK; mode &= ~sbi->o.fmask;
inode->i_op = &vboxsf_lnk_iops; mode |= S_IFLNK;
set_nlink(inode, 1); if (!reinit) {
inode->i_op = &vboxsf_lnk_iops;
set_nlink(inode, 1);
} else if (!S_ISLNK(inode->i_mode))
return -ESTALE;
inode->i_mode = mode;
} else { } else {
inode->i_mode = sbi->o.fmode_set ? sbi->o.fmode : mode; if (sbi->o.fmode_set)
inode->i_mode &= ~sbi->o.fmask; mode = sbi->o.fmode;
inode->i_mode |= S_IFREG; mode &= ~sbi->o.fmask;
inode->i_op = &vboxsf_reg_iops; mode |= S_IFREG;
inode->i_fop = &vboxsf_reg_fops; if (!reinit) {
set_nlink(inode, 1); inode->i_op = &vboxsf_reg_iops;
inode->i_fop = &vboxsf_reg_fops;
set_nlink(inode, 1);
} else if (!S_ISREG(inode->i_mode))
return -ESTALE;
inode->i_mode = mode;
} }
inode->i_uid = sbi->o.uid; inode->i_uid = sbi->o.uid;
@ -116,6 +131,7 @@ void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
info->change_time.ns_relative_to_unix_epoch); info->change_time.ns_relative_to_unix_epoch);
inode->i_mtime = ns_to_timespec64( inode->i_mtime = ns_to_timespec64(
info->modification_time.ns_relative_to_unix_epoch); info->modification_time.ns_relative_to_unix_epoch);
return 0;
} }
int vboxsf_create_at_dentry(struct dentry *dentry, int vboxsf_create_at_dentry(struct dentry *dentry,
@ -199,7 +215,9 @@ int vboxsf_inode_revalidate(struct dentry *dentry)
dentry->d_time = jiffies; dentry->d_time = jiffies;
sf_i->force_restat = 0; sf_i->force_restat = 0;
vboxsf_init_inode(sbi, inode, &info); err = vboxsf_init_inode(sbi, inode, &info, true);
if (err)
return err;
/* /*
* If the file was changed on the host side we need to invalidate the * If the file was changed on the host side we need to invalidate the

View File

@ -82,8 +82,8 @@ extern const struct dentry_operations vboxsf_dentry_ops;
/* from utils.c */ /* from utils.c */
struct inode *vboxsf_new_inode(struct super_block *sb); struct inode *vboxsf_new_inode(struct super_block *sb);
void vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode, int vboxsf_init_inode(struct vboxsf_sbi *sbi, struct inode *inode,
const struct shfl_fsobjinfo *info); const struct shfl_fsobjinfo *info, bool reinit);
int vboxsf_create_at_dentry(struct dentry *dentry, int vboxsf_create_at_dentry(struct dentry *dentry,
struct shfl_createparms *params); struct shfl_createparms *params);
int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path, int vboxsf_stat(struct vboxsf_sbi *sbi, struct shfl_string *path,