aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-07-23 01:25:02 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2016-07-23 01:25:02 -0400
commit88083e9845612826dfd44a5215647b4f6567317c (patch)
tree3d5df28425c5820a721fb915252aba7b08eaf029
parentb1386cedda177b10fac009ca8d3681034f15b5b3 (diff)
parentcfc9fde0b07c3b44b570057c5f93dda59dca1c94 (diff)
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi: "This contains a fix for a potential crash/corruption issue and another where the suid/sgid bits weren't cleared on write" * 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs: ovl: verify upper dentry in ovl_remove_and_whiteout() ovl: Copy up underlying inode's ->i_mode to overlay inode ovl: handle ATTR_KILL*
-rw-r--r--fs/overlayfs/dir.c54
-rw-r--r--fs/overlayfs/inode.c6
-rw-r--r--fs/overlayfs/overlayfs.h1
3 files changed, 29 insertions, 32 deletions
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c
index c2a6b0894022..5c9d2d80ff70 100644
--- a/fs/overlayfs/dir.c
+++ b/fs/overlayfs/dir.c
@@ -505,6 +505,7 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
505 struct dentry *upper; 505 struct dentry *upper;
506 struct dentry *opaquedir = NULL; 506 struct dentry *opaquedir = NULL;
507 int err; 507 int err;
508 int flags = 0;
508 509
509 if (WARN_ON(!workdir)) 510 if (WARN_ON(!workdir))
510 return -EROFS; 511 return -EROFS;
@@ -534,46 +535,39 @@ static int ovl_remove_and_whiteout(struct dentry *dentry, bool is_dir)
534 if (err) 535 if (err)
535 goto out_dput; 536 goto out_dput;
536 537
537 whiteout = ovl_whiteout(workdir, dentry); 538 upper = lookup_one_len(dentry->d_name.name, upperdir,
538 err = PTR_ERR(whiteout); 539 dentry->d_name.len);
539 if (IS_ERR(whiteout)) 540 err = PTR_ERR(upper);
541 if (IS_ERR(upper))
540 goto out_unlock; 542 goto out_unlock;
541 543
542 upper = ovl_dentry_upper(dentry); 544 err = -ESTALE;
543 if (!upper) { 545 if ((opaquedir && upper != opaquedir) ||
544 upper = lookup_one_len(dentry->d_name.name, upperdir, 546 (!opaquedir && ovl_dentry_upper(dentry) &&
545 dentry->d_name.len); 547 upper != ovl_dentry_upper(dentry))) {
546 err = PTR_ERR(upper); 548 goto out_dput_upper;
547 if (IS_ERR(upper)) 549 }
548 goto kill_whiteout;
549
550 err = ovl_do_rename(wdir, whiteout, udir, upper, 0);
551 dput(upper);
552 if (err)
553 goto kill_whiteout;
554 } else {
555 int flags = 0;
556 550
557 if (opaquedir) 551 whiteout = ovl_whiteout(workdir, dentry);
558 upper = opaquedir; 552 err = PTR_ERR(whiteout);
559 err = -ESTALE; 553 if (IS_ERR(whiteout))
560 if (upper->d_parent != upperdir) 554 goto out_dput_upper;
561 goto kill_whiteout;
562 555
563 if (is_dir) 556 if (d_is_dir(upper))
564 flags |= RENAME_EXCHANGE; 557 flags = RENAME_EXCHANGE;
565 558
566 err = ovl_do_rename(wdir, whiteout, udir, upper, flags); 559 err = ovl_do_rename(wdir, whiteout, udir, upper, flags);
567 if (err) 560 if (err)
568 goto kill_whiteout; 561 goto kill_whiteout;
562 if (flags)
563 ovl_cleanup(wdir, upper);
569 564
570 if (is_dir)
571 ovl_cleanup(wdir, upper);
572 }
573 ovl_dentry_version_inc(dentry->d_parent); 565 ovl_dentry_version_inc(dentry->d_parent);
574out_d_drop: 566out_d_drop:
575 d_drop(dentry); 567 d_drop(dentry);
576 dput(whiteout); 568 dput(whiteout);
569out_dput_upper:
570 dput(upper);
577out_unlock: 571out_unlock:
578 unlock_rename(workdir, upperdir); 572 unlock_rename(workdir, upperdir);
579out_dput: 573out_dput:
diff --git a/fs/overlayfs/inode.c b/fs/overlayfs/inode.c
index c831c2e5f803..d1cdc60dd68f 100644
--- a/fs/overlayfs/inode.c
+++ b/fs/overlayfs/inode.c
@@ -80,6 +80,9 @@ int ovl_setattr(struct dentry *dentry, struct iattr *attr)
80 goto out_drop_write; 80 goto out_drop_write;
81 } 81 }
82 82
83 if (attr->ia_valid & (ATTR_KILL_SUID|ATTR_KILL_SGID))
84 attr->ia_valid &= ~ATTR_MODE;
85
83 inode_lock(upperdentry->d_inode); 86 inode_lock(upperdentry->d_inode);
84 err = notify_change(upperdentry, attr, NULL); 87 err = notify_change(upperdentry, attr, NULL);
85 if (!err) 88 if (!err)
@@ -410,12 +413,11 @@ struct inode *ovl_new_inode(struct super_block *sb, umode_t mode,
410 if (!inode) 413 if (!inode)
411 return NULL; 414 return NULL;
412 415
413 mode &= S_IFMT;
414
415 inode->i_ino = get_next_ino(); 416 inode->i_ino = get_next_ino();
416 inode->i_mode = mode; 417 inode->i_mode = mode;
417 inode->i_flags |= S_NOATIME | S_NOCMTIME; 418 inode->i_flags |= S_NOATIME | S_NOCMTIME;
418 419
420 mode &= S_IFMT;
419 switch (mode) { 421 switch (mode) {
420 case S_IFDIR: 422 case S_IFDIR:
421 inode->i_private = oe; 423 inode->i_private = oe;
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h
index 4bd9b5ba8f42..cfbca53590d0 100644
--- a/fs/overlayfs/overlayfs.h
+++ b/fs/overlayfs/overlayfs.h
@@ -187,6 +187,7 @@ static inline void ovl_copyattr(struct inode *from, struct inode *to)
187{ 187{
188 to->i_uid = from->i_uid; 188 to->i_uid = from->i_uid;
189 to->i_gid = from->i_gid; 189 to->i_gid = from->i_gid;
190 to->i_mode = from->i_mode;
190} 191}
191 192
192/* dir.c */ 193/* dir.c */