overlayfs fixes for 5.8-rc6

-----BEGIN PGP SIGNATURE-----
 
 iHUEABYIAB0WIQSQHSd0lITzzeNWNm3h3BK/laaZPAUCXxGF+QAKCRDh3BK/laaZ
 PCHnAQCqNxcxncKMebpJ2hNIEPuSvUPRA4+iOOnc+9HTZ4A09wD/d/8ryybORTZN
 IHq2PpQUtuGgASv6GrptJSmpDvG6RA0=
 =lOD9
 -----END PGP SIGNATURE-----

Merge tag 'ovl-fixes-5.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs into master

Pull overlayfs fixes from Miklos Szeredi:

 - fix a regression introduced in v4.20 in handling a regenerated
   squashfs lower layer

 - two regression fixes for this cycle, one of which is Oops inducing

 - miscellaneous issues

* tag 'ovl-fixes-5.8-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
  ovl: fix lookup of indexed hardlinks with metacopy
  ovl: fix unneeded call to ovl_change_flags()
  ovl: fix mount option checks for nfs_export with no upperdir
  ovl: force read-only sb on failure to create index dir
  ovl: fix regression with re-formatted lower squashfs
  ovl: fix oops in ovl_indexdir_cleanup() with nfs_export=on
  ovl: relax WARN_ON() when decoding lower directory file handle
  ovl: remove not used argument in ovl_check_origin
  ovl: change ovl_copy_up_flags static
  ovl: inode reference leak in ovl_is_inuse true case.
This commit is contained in:
Linus Torvalds 2020-07-17 10:29:19 -07:00
commit 44fea37378
7 changed files with 65 additions and 42 deletions

View File

@ -560,8 +560,8 @@ When the NFS export feature is enabled, all directory index entries are
verified on mount time to check that upper file handles are not stale.
This verification may cause significant overhead in some cases.
Note: the mount options index=off,nfs_export=on are conflicting and will
result in an error.
Note: the mount options index=off,nfs_export=on are conflicting for a
read-write mount and will result in an error.
Testsuite

View File

@ -895,7 +895,7 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry,
return err;
}
int ovl_copy_up_flags(struct dentry *dentry, int flags)
static int ovl_copy_up_flags(struct dentry *dentry, int flags)
{
int err = 0;
const struct cred *old_cred = ovl_override_creds(dentry->d_sb);

View File

@ -476,7 +476,7 @@ static struct dentry *ovl_lookup_real_inode(struct super_block *sb,
if (IS_ERR_OR_NULL(this))
return this;
if (WARN_ON(ovl_dentry_real_at(this, layer->idx) != real)) {
if (ovl_dentry_real_at(this, layer->idx) != real) {
dput(this);
this = ERR_PTR(-EIO);
}

View File

@ -33,13 +33,16 @@ static char ovl_whatisit(struct inode *inode, struct inode *realinode)
return 'm';
}
/* No atime modificaton nor notify on underlying */
#define OVL_OPEN_FLAGS (O_NOATIME | FMODE_NONOTIFY)
static struct file *ovl_open_realfile(const struct file *file,
struct inode *realinode)
{
struct inode *inode = file_inode(file);
struct file *realfile;
const struct cred *old_cred;
int flags = file->f_flags | O_NOATIME | FMODE_NONOTIFY;
int flags = file->f_flags | OVL_OPEN_FLAGS;
int acc_mode = ACC_MODE(flags);
int err;
@ -72,8 +75,7 @@ static int ovl_change_flags(struct file *file, unsigned int flags)
struct inode *inode = file_inode(file);
int err;
/* No atime modificaton on underlying */
flags |= O_NOATIME | FMODE_NONOTIFY;
flags |= OVL_OPEN_FLAGS;
/* If some flag changed that cannot be changed then something's amiss */
if (WARN_ON((file->f_flags ^ flags) & ~OVL_SETFL_MASK))
@ -126,7 +128,7 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real,
}
/* Did the flags change since open? */
if (unlikely((file->f_flags ^ real->file->f_flags) & ~O_NOATIME))
if (unlikely((file->f_flags ^ real->file->f_flags) & ~OVL_OPEN_FLAGS))
return ovl_change_flags(real->file, file->f_flags);
return 0;

View File

@ -389,7 +389,7 @@ invalid:
}
static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,
struct ovl_path **stackp, unsigned int *ctrp)
struct ovl_path **stackp)
{
struct ovl_fh *fh = ovl_get_fh(upperdentry, OVL_XATTR_ORIGIN);
int err;
@ -406,10 +406,6 @@ static int ovl_check_origin(struct ovl_fs *ofs, struct dentry *upperdentry,
return err;
}
if (WARN_ON(*ctrp))
return -EIO;
*ctrp = 1;
return 0;
}
@ -861,8 +857,6 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
goto out;
}
if (upperdentry && !d.is_dir) {
unsigned int origin_ctr = 0;
/*
* Lookup copy up origin by decoding origin file handle.
* We may get a disconnected dentry, which is fine,
@ -873,8 +867,7 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
* number - it's the same as if we held a reference
* to a dentry in lower layer that was moved under us.
*/
err = ovl_check_origin(ofs, upperdentry, &origin_path,
&origin_ctr);
err = ovl_check_origin(ofs, upperdentry, &origin_path);
if (err)
goto out_put_upper;
@ -1073,6 +1066,10 @@ struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry,
upperredirect = NULL;
goto out_free_oe;
}
err = ovl_check_metacopy_xattr(upperdentry);
if (err < 0)
goto out_free_oe;
uppermetacopy = err;
}
if (upperdentry || ctr) {

View File

@ -483,7 +483,6 @@ void ovl_aio_request_cache_destroy(void);
/* copy_up.c */
int ovl_copy_up(struct dentry *dentry);
int ovl_copy_up_with_data(struct dentry *dentry);
int ovl_copy_up_flags(struct dentry *dentry, int flags);
int ovl_maybe_copy_up(struct dentry *dentry, int flags);
int ovl_copy_xattr(struct dentry *old, struct dentry *new);
int ovl_set_attr(struct dentry *upper, struct kstat *stat);

View File

@ -580,12 +580,19 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
}
}
/* Workdir is useless in non-upper mount */
if (!config->upperdir && config->workdir) {
pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
config->workdir);
kfree(config->workdir);
config->workdir = NULL;
/* Workdir/index are useless in non-upper mount */
if (!config->upperdir) {
if (config->workdir) {
pr_info("option \"workdir=%s\" is useless in a non-upper mount, ignore\n",
config->workdir);
kfree(config->workdir);
config->workdir = NULL;
}
if (config->index && index_opt) {
pr_info("option \"index=on\" is useless in a non-upper mount, ignore\n");
index_opt = false;
}
config->index = false;
}
err = ovl_parse_redirect_mode(config, config->redirect_mode);
@ -622,11 +629,13 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config)
/* Resolve nfs_export -> index dependency */
if (config->nfs_export && !config->index) {
if (nfs_export_opt && index_opt) {
if (!config->upperdir && config->redirect_follow) {
pr_info("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n");
config->nfs_export = false;
} else if (nfs_export_opt && index_opt) {
pr_err("conflicting options: nfs_export=on,index=off\n");
return -EINVAL;
}
if (index_opt) {
} else if (index_opt) {
/*
* There was an explicit index=off that resulted
* in this conflict.
@ -1352,8 +1361,15 @@ static int ovl_get_indexdir(struct super_block *sb, struct ovl_fs *ofs,
goto out;
}
/* index dir will act also as workdir */
iput(ofs->workdir_trap);
ofs->workdir_trap = NULL;
dput(ofs->workdir);
ofs->workdir = NULL;
ofs->indexdir = ovl_workdir_create(ofs, OVL_INDEXDIR_NAME, true);
if (ofs->indexdir) {
ofs->workdir = dget(ofs->indexdir);
err = ovl_setup_trap(sb, ofs->indexdir, &ofs->indexdir_trap,
"indexdir");
if (err)
@ -1396,6 +1412,18 @@ static bool ovl_lower_uuid_ok(struct ovl_fs *ofs, const uuid_t *uuid)
if (!ofs->config.nfs_export && !ovl_upper_mnt(ofs))
return true;
/*
* We allow using single lower with null uuid for index and nfs_export
* for example to support those features with single lower squashfs.
* To avoid regressions in setups of overlay with re-formatted lower
* squashfs, do not allow decoding origin with lower null uuid unless
* user opted-in to one of the new features that require following the
* lower inode of non-dir upper.
*/
if (!ofs->config.index && !ofs->config.metacopy && !ofs->config.xino &&
uuid_is_null(uuid))
return false;
for (i = 0; i < ofs->numfs; i++) {
/*
* We use uuid to associate an overlay lower file handle with a
@ -1493,14 +1521,23 @@ static int ovl_get_layers(struct super_block *sb, struct ovl_fs *ofs,
if (err < 0)
goto out;
/*
* Check if lower root conflicts with this overlay layers before
* checking if it is in-use as upperdir/workdir of "another"
* mount, because we do not bother to check in ovl_is_inuse() if
* the upperdir/workdir is in fact in-use by our
* upperdir/workdir.
*/
err = ovl_setup_trap(sb, stack[i].dentry, &trap, "lowerdir");
if (err)
goto out;
if (ovl_is_inuse(stack[i].dentry)) {
err = ovl_report_in_use(ofs, "lowerdir");
if (err)
if (err) {
iput(trap);
goto out;
}
}
mnt = clone_private_mount(&stack[i]);
@ -1575,10 +1612,6 @@ static struct ovl_entry *ovl_get_lowerstack(struct super_block *sb,
if (!ofs->config.upperdir && numlower == 1) {
pr_err("at least 2 lowerdir are needed while upperdir nonexistent\n");
return ERR_PTR(-EINVAL);
} else if (!ofs->config.upperdir && ofs->config.nfs_export &&
ofs->config.redirect_follow) {
pr_warn("NFS export requires \"redirect_dir=nofollow\" on non-upper mount, falling back to nfs_export=off.\n");
ofs->config.nfs_export = false;
}
stack = kcalloc(numlower, sizeof(struct path), GFP_KERNEL);
@ -1842,21 +1875,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (!ovl_upper_mnt(ofs))
sb->s_flags |= SB_RDONLY;
if (!(ovl_force_readonly(ofs)) && ofs->config.index) {
/* index dir will act also as workdir */
dput(ofs->workdir);
ofs->workdir = NULL;
iput(ofs->workdir_trap);
ofs->workdir_trap = NULL;
if (!ovl_force_readonly(ofs) && ofs->config.index) {
err = ovl_get_indexdir(sb, ofs, oe, &upperpath);
if (err)
goto out_free_oe;
/* Force r/o mount with no index dir */
if (ofs->indexdir)
ofs->workdir = dget(ofs->indexdir);
else
if (!ofs->indexdir)
sb->s_flags |= SB_RDONLY;
}