aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2017-06-30 13:22:59 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2017-06-30 13:22:59 -0400
commit86c3e00afd64a507aef954cd581547f28807e51a (patch)
treedf0ad2fcc7749a282683acc5aac473c398b2bbc5
parent4d8a991d460d4fa4829beaffdcba45a217ca0fa7 (diff)
parentfbaf94ee3cd5cfa85fe2d4d04be968820cb00556 (diff)
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi: "Fix two bugs in copy-up code. One introduced in 4.11 and one in 4.12-rc" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: don't set origin on broken lower hardlink ovl: copy-up: don't unlock between lookup and link
-rw-r--r--fs/overlayfs/copy_up.c33
1 files changed, 19 insertions, 14 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c
index 7a44533f4bbf..a2a65120c9d0 100644
--- a/fs/overlayfs/copy_up.c
+++ b/fs/overlayfs/copy_up.c
@@ -330,15 +330,9 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
330 .link = link 330 .link = link
331 }; 331 };
332 332
333 upper = lookup_one_len(dentry->d_name.name, upperdir,
334 dentry->d_name.len);
335 err = PTR_ERR(upper);
336 if (IS_ERR(upper))
337 goto out;
338
339 err = security_inode_copy_up(dentry, &new_creds); 333 err = security_inode_copy_up(dentry, &new_creds);
340 if (err < 0) 334 if (err < 0)
341 goto out1; 335 goto out;
342 336
343 if (new_creds) 337 if (new_creds)
344 old_creds = override_creds(new_creds); 338 old_creds = override_creds(new_creds);
@@ -362,7 +356,7 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
362 } 356 }
363 357
364 if (err) 358 if (err)
365 goto out2; 359 goto out;
366 360
367 if (S_ISREG(stat->mode)) { 361 if (S_ISREG(stat->mode)) {
368 struct path upperpath; 362 struct path upperpath;
@@ -398,10 +392,23 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
398 /* 392 /*
399 * Store identifier of lower inode in upper inode xattr to 393 * Store identifier of lower inode in upper inode xattr to
400 * allow lookup of the copy up origin inode. 394 * allow lookup of the copy up origin inode.
395 *
396 * Don't set origin when we are breaking the association with a lower
397 * hard link.
401 */ 398 */
402 err = ovl_set_origin(dentry, lowerpath->dentry, temp); 399 if (S_ISDIR(stat->mode) || stat->nlink == 1) {
403 if (err) 400 err = ovl_set_origin(dentry, lowerpath->dentry, temp);
401 if (err)
402 goto out_cleanup;
403 }
404
405 upper = lookup_one_len(dentry->d_name.name, upperdir,
406 dentry->d_name.len);
407 if (IS_ERR(upper)) {
408 err = PTR_ERR(upper);
409 upper = NULL;
404 goto out_cleanup; 410 goto out_cleanup;
411 }
405 412
406 if (tmpfile) 413 if (tmpfile)
407 err = ovl_do_link(temp, udir, upper, true); 414 err = ovl_do_link(temp, udir, upper, true);
@@ -416,17 +423,15 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir,
416 423
417 /* Restore timestamps on parent (best effort) */ 424 /* Restore timestamps on parent (best effort) */
418 ovl_set_timestamps(upperdir, pstat); 425 ovl_set_timestamps(upperdir, pstat);
419out2: 426out:
420 dput(temp); 427 dput(temp);
421out1:
422 dput(upper); 428 dput(upper);
423out:
424 return err; 429 return err;
425 430
426out_cleanup: 431out_cleanup:
427 if (!tmpfile) 432 if (!tmpfile)
428 ovl_cleanup(wdir, temp); 433 ovl_cleanup(wdir, temp);
429 goto out2; 434 goto out;
430} 435}
431 436
432/* 437/*