Skip to content

Commit

Permalink
ovl: get exclusive ownership on upper/work dirs
Browse files Browse the repository at this point in the history
Bad things can happen if several concurrent overlay mounts try to
use the same upperdir/workdir path.

Try to get the 'inuse' advisory lock on upperdir and workdir.
Fail mount if another overlay mount instance or another user
holds the 'inuse' lock on these directories.

Note that this provides no protection for concurrent overlay
mount that use overlapping (i.e. descendant) upper/work dirs.

Signed-off-by: Amir Goldstein <amir73il@gmail.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Amir Goldstein authored and Miklos Szeredi committed Jul 4, 2017
1 parent ad0af71 commit 2cac0c0
Show file tree
Hide file tree
Showing 2 changed files with 29 additions and 3 deletions.
3 changes: 3 additions & 0 deletions fs/overlayfs/ovl_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ struct ovl_fs {
struct vfsmount *upper_mnt;
unsigned numlower;
struct vfsmount **lower_mnt;
/* workbasedir is the path at workdir= mount option */
struct dentry *workbasedir;
/* workdir is the 'work' directory under workbasedir */
struct dentry *workdir;
long namelen;
/* pathnames of lower and upper dirs, for show_options */
Expand Down
29 changes: 26 additions & 3 deletions fs/overlayfs/super.c
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ static void ovl_put_super(struct super_block *sb)
unsigned i;

dput(ufs->workdir);
ovl_inuse_unlock(ufs->workbasedir);
dput(ufs->workbasedir);
if (ufs->upper_mnt)
ovl_inuse_unlock(ufs->upper_mnt->mnt_root);
mntput(ufs->upper_mnt);
for (i = 0; i < ufs->numlower; i++)
mntput(ufs->lower_mnt[i]);
Expand Down Expand Up @@ -821,9 +825,15 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
if (err)
goto out_put_upperpath;

err = -EBUSY;
if (!ovl_inuse_trylock(upperpath.dentry)) {
pr_err("overlayfs: upperdir is in-use by another mount\n");
goto out_put_upperpath;
}

err = ovl_mount_dir(ufs->config.workdir, &workpath);
if (err)
goto out_put_upperpath;
goto out_unlock_upperdentry;

err = -EINVAL;
if (upperpath.mnt != workpath.mnt) {
Expand All @@ -834,12 +844,20 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
pr_err("overlayfs: workdir and upperdir must be separate subtrees\n");
goto out_put_workpath;
}

err = -EBUSY;
if (!ovl_inuse_trylock(workpath.dentry)) {
pr_err("overlayfs: workdir is in-use by another mount\n");
goto out_put_workpath;
}

ufs->workbasedir = workpath.dentry;
sb->s_stack_depth = upperpath.mnt->mnt_sb->s_stack_depth;
}
err = -ENOMEM;
lowertmp = kstrdup(ufs->config.lowerdir, GFP_KERNEL);
if (!lowertmp)
goto out_put_workpath;
goto out_unlock_workdentry;

err = -EINVAL;
stacklen = ovl_split_lowerdirs(lowertmp);
Expand Down Expand Up @@ -882,6 +900,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
pr_err("overlayfs: failed to clone upperpath\n");
goto out_put_lowerpath;
}

/* Don't inherit atime flags */
ufs->upper_mnt->mnt_flags &= ~(MNT_NOATIME | MNT_NODIRATIME | MNT_RELATIME);

Expand Down Expand Up @@ -1004,7 +1023,7 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
mntput(upperpath.mnt);
for (i = 0; i < numlower; i++)
mntput(stack[i].mnt);
path_put(&workpath);
mntput(workpath.mnt);
kfree(lowertmp);

if (upperpath.dentry) {
Expand Down Expand Up @@ -1043,8 +1062,12 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
kfree(stack);
out_free_lowertmp:
kfree(lowertmp);
out_unlock_workdentry:
ovl_inuse_unlock(workpath.dentry);
out_put_workpath:
path_put(&workpath);
out_unlock_upperdentry:
ovl_inuse_unlock(upperpath.dentry);
out_put_upperpath:
path_put(&upperpath);
out_free_config:
Expand Down

0 comments on commit 2cac0c0

Please sign in to comment.