diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-23 01:25:02 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2016-07-23 01:25:02 -0400 |
commit | 88083e9845612826dfd44a5215647b4f6567317c (patch) | |
tree | 3d5df28425c5820a721fb915252aba7b08eaf029 | |
parent | b1386cedda177b10fac009ca8d3681034f15b5b3 (diff) | |
parent | cfc9fde0b07c3b44b570057c5f93dda59dca1c94 (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.c | 54 | ||||
-rw-r--r-- | fs/overlayfs/inode.c | 6 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 1 |
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); |
574 | out_d_drop: | 566 | out_d_drop: |
575 | d_drop(dentry); | 567 | d_drop(dentry); |
576 | dput(whiteout); | 568 | dput(whiteout); |
569 | out_dput_upper: | ||
570 | dput(upper); | ||
577 | out_unlock: | 571 | out_unlock: |
578 | unlock_rename(workdir, upperdir); | 572 | unlock_rename(workdir, upperdir); |
579 | out_dput: | 573 | out_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 */ |