Skip to content

Commit a105d68

Browse files
author
Miklos Szeredi
committed
ovl: fix remove/copy-up race
ovl_remove_and_whiteout() needs to check if upper dentry exists or not after having locked upper parent directory. Previously we used a "type" value computed before locking the upper parent directory, which is susceptible to racing with copy-up. There's a similar check in ovl_check_empty_and_clear(). This one is not actually racy, since copy-up doesn't change the "emptyness" property of a directory. Add a comment to this effect, and check the existence of upper dentry locally to make the code cleaner. Signed-off-by: Miklos Szeredi <[email protected]>
1 parent ef94b18 commit a105d68

File tree

1 file changed

+19
-12
lines changed

1 file changed

+19
-12
lines changed

fs/overlayfs/dir.c

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry,
284284
return ERR_PTR(err);
285285
}
286286

287-
static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry,
288-
enum ovl_path_type type)
287+
static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry)
289288
{
290289
int err;
291290
struct dentry *ret = NULL;
@@ -294,8 +293,17 @@ static struct dentry *ovl_check_empty_and_clear(struct dentry *dentry,
294293
err = ovl_check_empty_dir(dentry, &list);
295294
if (err)
296295
ret = ERR_PTR(err);
297-
else if (type == OVL_PATH_MERGE)
298-
ret = ovl_clear_empty(dentry, &list);
296+
else {
297+
/*
298+
* If no upperdentry then skip clearing whiteouts.
299+
*
300+
* Can race with copy-up, since we don't hold the upperdir
301+
* mutex. Doesn't matter, since copy-up can't create a
302+
* non-empty directory from an empty one.
303+
*/
304+
if (ovl_dentry_upper(dentry))
305+
ret = ovl_clear_empty(dentry, &list);
306+
}
299307

300308
ovl_cache_free(&list);
301309

@@ -487,8 +495,7 @@ static int ovl_link(struct dentry *old, struct inode *newdir,
487495
return err;
488496
}
489497

490-
static int ovl_remove_and_whiteout(struct dentry *dentry,
491-
enum ovl_path_type type, bool is_dir)
498+
static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
492499
{
493500
struct dentry *workdir = ovl_workdir(dentry);
494501
struct inode *wdir = workdir->d_inode;
@@ -500,7 +507,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
500507
int err;
501508

502509
if (is_dir) {
503-
opaquedir = ovl_check_empty_and_clear(dentry, type);
510+
opaquedir = ovl_check_empty_and_clear(dentry);
504511
err = PTR_ERR(opaquedir);
505512
if (IS_ERR(opaquedir))
506513
goto out;
@@ -515,9 +522,10 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
515522
if (IS_ERR(whiteout))
516523
goto out_unlock;
517524

518-
if (type == OVL_PATH_LOWER) {
525+
upper = ovl_dentry_upper(dentry);
526+
if (!upper) {
519527
upper = lookup_one_len(dentry->d_name.name, upperdir,
520-
dentry->d_name.len);
528+
dentry->d_name.len);
521529
err = PTR_ERR(upper);
522530
if (IS_ERR(upper))
523531
goto kill_whiteout;
@@ -529,7 +537,6 @@ static int ovl_remove_and_whiteout(struct dentry *dentry,
529537
} else {
530538
int flags = 0;
531539

532-
upper = ovl_dentry_upper(dentry);
533540
if (opaquedir)
534541
upper = opaquedir;
535542
err = -ESTALE;
@@ -648,7 +655,7 @@ static int ovl_do_remove(struct dentry *dentry, bool is_dir)
648655
cap_raise(override_cred->cap_effective, CAP_CHOWN);
649656
old_cred = override_creds(override_cred);
650657

651-
err = ovl_remove_and_whiteout(dentry, type, is_dir);
658+
err = ovl_remove_and_whiteout(dentry, is_dir);
652659

653660
revert_creds(old_cred);
654661
put_cred(override_cred);
@@ -781,7 +788,7 @@ static int ovl_rename2(struct inode *olddir, struct dentry *old,
781788
}
782789

783790
if (overwrite && (new_type == OVL_PATH_LOWER || new_type == OVL_PATH_MERGE) && new_is_dir) {
784-
opaquedir = ovl_check_empty_and_clear(new, new_type);
791+
opaquedir = ovl_check_empty_and_clear(new);
785792
err = PTR_ERR(opaquedir);
786793
if (IS_ERR(opaquedir)) {
787794
opaquedir = NULL;

0 commit comments

Comments
 (0)