Skip to content

Commit 8d4ef4e

Browse files
committed
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi: "Fix a regression in 4.14 and one in 4.13. The latter is a case when Docker is doing something it really shouldn't and gets away with it. We now print a warning instead of erroring out. There are also fixes to several error paths" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: fix regression caused by exclusive upper/work dir protection ovl: fix missing unlock_rename() in ovl_do_copy_up() ovl: fix dentry leak in ovl_indexdir_cleanup() ovl: fix dput() of ERR_PTR in ovl_cleanup_index() ovl: fix error value printed in ovl_lookup_index() ovl: fix may_write_real() for overlayfs directories
2 parents 1249b57 + 85fdee1 commit 8d4ef4e

File tree

10 files changed

+60
-37
lines changed

10 files changed

+60
-37
lines changed

Documentation/filesystems/overlayfs.txt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -210,8 +210,11 @@ path as another overlay mount and it may use a lower layer path that is
210210
beneath or above the path of another overlay lower layer path.
211211

212212
Using an upper layer path and/or a workdir path that are already used by
213-
another overlay mount is not allowed and will fail with EBUSY. Using
213+
another overlay mount is not allowed and may fail with EBUSY. Using
214214
partially overlapping paths is not allowed but will not fail with EBUSY.
215+
If files are accessed from two overlayfs mounts which share or overlap the
216+
upper layer and/or workdir path the behavior of the overlay is undefined,
217+
though it will not result in a crash or deadlock.
215218

216219
Mounting an overlay using an upper layer path, where the upper layer path
217220
was previously used by another mounted overlay in combination with a

fs/namespace.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,9 @@ static inline int may_write_real(struct file *file)
468468

469469
/* File refers to upper, writable layer? */
470470
upperdentry = d_real(dentry, NULL, 0, D_REAL_UPPER);
471-
if (upperdentry && file_inode(file) == d_inode(upperdentry))
471+
if (upperdentry &&
472+
(file_inode(file) == d_inode(upperdentry) ||
473+
file_inode(file) == d_inode(dentry)))
472474
return 0;
473475

474476
/* Lower layer: can't write to real file, sorry... */

fs/overlayfs/copy_up.c

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -561,10 +561,8 @@ static int ovl_do_copy_up(struct ovl_copy_up_ctx *c)
561561
c->tmpfile = true;
562562
err = ovl_copy_up_locked(c);
563563
} else {
564-
err = -EIO;
565-
if (lock_rename(c->workdir, c->destdir) != NULL) {
566-
pr_err("overlayfs: failed to lock workdir+upperdir\n");
567-
} else {
564+
err = ovl_lock_rename_workdir(c->workdir, c->destdir);
565+
if (!err) {
568566
err = ovl_copy_up_locked(c);
569567
unlock_rename(c->workdir, c->destdir);
570568
}

fs/overlayfs/dir.c

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -216,26 +216,6 @@ static int ovl_create_upper(struct dentry *dentry, struct inode *inode,
216216
return err;
217217
}
218218

219-
static int ovl_lock_rename_workdir(struct dentry *workdir,
220-
struct dentry *upperdir)
221-
{
222-
/* Workdir should not be the same as upperdir */
223-
if (workdir == upperdir)
224-
goto err;
225-
226-
/* Workdir should not be subdir of upperdir and vice versa */
227-
if (lock_rename(workdir, upperdir) != NULL)
228-
goto err_unlock;
229-
230-
return 0;
231-
232-
err_unlock:
233-
unlock_rename(workdir, upperdir);
234-
err:
235-
pr_err("overlayfs: failed to lock workdir+upperdir\n");
236-
return -EIO;
237-
}
238-
239219
static struct dentry *ovl_clear_empty(struct dentry *dentry,
240220
struct list_head *list)
241221
{

fs/overlayfs/namei.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -506,6 +506,7 @@ static struct dentry *ovl_lookup_index(struct dentry *dentry,
506506

507507
index = lookup_one_len_unlocked(name.name, ofs->indexdir, name.len);
508508
if (IS_ERR(index)) {
509+
err = PTR_ERR(index);
509510
pr_warn_ratelimited("overlayfs: failed inode index lookup (ino=%lu, key=%*s, err=%i);\n"
510511
"overlayfs: mount with '-o index=off' to disable inodes index.\n",
511512
d_inode(origin)->i_ino, name.len, name.name,

fs/overlayfs/overlayfs.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,7 @@ bool ovl_inuse_trylock(struct dentry *dentry);
235235
void ovl_inuse_unlock(struct dentry *dentry);
236236
int ovl_nlink_start(struct dentry *dentry, bool *locked);
237237
void ovl_nlink_end(struct dentry *dentry, bool locked);
238+
int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir);
238239

239240
static inline bool ovl_is_impuredir(struct dentry *dentry)
240241
{

fs/overlayfs/ovl_entry.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@ struct ovl_fs {
3737
bool noxattr;
3838
/* sb common to all layers */
3939
struct super_block *same_sb;
40+
/* Did we take the inuse lock? */
41+
bool upperdir_locked;
42+
bool workdir_locked;
4043
};
4144

4245
/* private information held for every overlayfs dentry */

fs/overlayfs/readdir.c

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -988,6 +988,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
988988
struct path *lowerstack, unsigned int numlower)
989989
{
990990
int err;
991+
struct dentry *index = NULL;
991992
struct inode *dir = dentry->d_inode;
992993
struct path path = { .mnt = mnt, .dentry = dentry };
993994
LIST_HEAD(list);
@@ -1007,8 +1008,6 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
10071008

10081009
inode_lock_nested(dir, I_MUTEX_PARENT);
10091010
list_for_each_entry(p, &list, l_node) {
1010-
struct dentry *index;
1011-
10121011
if (p->name[0] == '.') {
10131012
if (p->len == 1)
10141013
continue;
@@ -1018,6 +1017,7 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
10181017
index = lookup_one_len(p->name, dentry, p->len);
10191018
if (IS_ERR(index)) {
10201019
err = PTR_ERR(index);
1020+
index = NULL;
10211021
break;
10221022
}
10231023
err = ovl_verify_index(index, lowerstack, numlower);
@@ -1029,7 +1029,9 @@ int ovl_indexdir_cleanup(struct dentry *dentry, struct vfsmount *mnt,
10291029
break;
10301030
}
10311031
dput(index);
1032+
index = NULL;
10321033
}
1034+
dput(index);
10331035
inode_unlock(dir);
10341036
out:
10351037
ovl_cache_free(&list);

fs/overlayfs/super.c

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -211,9 +211,10 @@ static void ovl_put_super(struct super_block *sb)
211211

212212
dput(ufs->indexdir);
213213
dput(ufs->workdir);
214-
ovl_inuse_unlock(ufs->workbasedir);
214+
if (ufs->workdir_locked)
215+
ovl_inuse_unlock(ufs->workbasedir);
215216
dput(ufs->workbasedir);
216-
if (ufs->upper_mnt)
217+
if (ufs->upper_mnt && ufs->upperdir_locked)
217218
ovl_inuse_unlock(ufs->upper_mnt->mnt_root);
218219
mntput(ufs->upper_mnt);
219220
for (i = 0; i < ufs->numlower; i++)
@@ -881,9 +882,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
881882
goto out_put_upperpath;
882883

883884
err = -EBUSY;
884-
if (!ovl_inuse_trylock(upperpath.dentry)) {
885-
pr_err("overlayfs: upperdir is in-use by another mount\n");
885+
if (ovl_inuse_trylock(upperpath.dentry)) {
886+
ufs->upperdir_locked = true;
887+
} else if (ufs->config.index) {
888+
pr_err("overlayfs: upperdir is in-use by another mount, mount with '-o index=off' to override exclusive upperdir protection.\n");
886889
goto out_put_upperpath;
890+
} else {
891+
pr_warn("overlayfs: upperdir is in-use by another mount, accessing files from both mounts will result in undefined behavior.\n");
887892
}
888893

889894
err = ovl_mount_dir(ufs->config.workdir, &workpath);
@@ -901,9 +906,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
901906
}
902907

903908
err = -EBUSY;
904-
if (!ovl_inuse_trylock(workpath.dentry)) {
905-
pr_err("overlayfs: workdir is in-use by another mount\n");
909+
if (ovl_inuse_trylock(workpath.dentry)) {
910+
ufs->workdir_locked = true;
911+
} else if (ufs->config.index) {
912+
pr_err("overlayfs: workdir is in-use by another mount, mount with '-o index=off' to override exclusive workdir protection.\n");
906913
goto out_put_workpath;
914+
} else {
915+
pr_warn("overlayfs: workdir is in-use by another mount, accessing files from both mounts will result in undefined behavior.\n");
907916
}
908917

909918
ufs->workbasedir = workpath.dentry;
@@ -1156,11 +1165,13 @@ static int ovl_fill_super(struct super_block *sb, void *data, int silent)
11561165
out_free_lowertmp:
11571166
kfree(lowertmp);
11581167
out_unlock_workdentry:
1159-
ovl_inuse_unlock(workpath.dentry);
1168+
if (ufs->workdir_locked)
1169+
ovl_inuse_unlock(workpath.dentry);
11601170
out_put_workpath:
11611171
path_put(&workpath);
11621172
out_unlock_upperdentry:
1163-
ovl_inuse_unlock(upperpath.dentry);
1173+
if (ufs->upperdir_locked)
1174+
ovl_inuse_unlock(upperpath.dentry);
11641175
out_put_upperpath:
11651176
path_put(&upperpath);
11661177
out_free_config:

fs/overlayfs/util.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -430,7 +430,7 @@ void ovl_inuse_unlock(struct dentry *dentry)
430430
}
431431
}
432432

433-
/* Called must hold OVL_I(inode)->oi_lock */
433+
/* Caller must hold OVL_I(inode)->lock */
434434
static void ovl_cleanup_index(struct dentry *dentry)
435435
{
436436
struct inode *dir = ovl_indexdir(dentry->d_sb)->d_inode;
@@ -469,6 +469,9 @@ static void ovl_cleanup_index(struct dentry *dentry)
469469
err = PTR_ERR(index);
470470
if (!IS_ERR(index))
471471
err = ovl_cleanup(dir, index);
472+
else
473+
index = NULL;
474+
472475
inode_unlock(dir);
473476
if (err)
474477
goto fail;
@@ -557,3 +560,22 @@ void ovl_nlink_end(struct dentry *dentry, bool locked)
557560
mutex_unlock(&OVL_I(d_inode(dentry))->lock);
558561
}
559562
}
563+
564+
int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir)
565+
{
566+
/* Workdir should not be the same as upperdir */
567+
if (workdir == upperdir)
568+
goto err;
569+
570+
/* Workdir should not be subdir of upperdir and vice versa */
571+
if (lock_rename(workdir, upperdir) != NULL)
572+
goto err_unlock;
573+
574+
return 0;
575+
576+
err_unlock:
577+
unlock_rename(workdir, upperdir);
578+
err:
579+
pr_err("overlayfs: failed to lock workdir+upperdir\n");
580+
return -EIO;
581+
}

0 commit comments

Comments
 (0)