diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-31 11:29:02 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2017-05-31 11:29:02 -0400 |
| commit | d602fb6844940b23afb64d4bf70bb963c15571ee (patch) | |
| tree | 16f19ec73e55f2c53cb56c81a658655f49c6dc1d | |
| parent | f511c0b17b081562dca8ac5061dfa86db4c66cc2 (diff) | |
| parent | a082c6f680da298cf075886ff032f32ccb7c5e1a (diff) | |
Merge branch 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs fixes from Miklos Szeredi:
"Fix regressions:
- missing CONFIG_EXPORTFS dependency
- failure if upper fs doesn't support xattr
- bad error cleanup
This also adds the concept of "impure" directories complementing the
"origin" marking introduced in -rc1. Together they enable getting
consistent st_ino and d_ino for directory listings.
And there's a bug fix and a cleanup as well"
* 'overlayfs-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
ovl: filter trusted xattr for non-admin
ovl: mark upper merge dir with type origin entries "impure"
ovl: mark upper dir with type origin entries "impure"
ovl: remove unused arg from ovl_lookup_temp()
ovl: handle rename when upper doesn't support xattr
ovl: don't fail copy-up if upper doesn't support xattr
ovl: check on mount time if upper fs supports setting xattr
ovl: fix creds leak in copy up error path
ovl: select EXPORTFS
| -rw-r--r-- | fs/overlayfs/Kconfig | 1 | ||||
| -rw-r--r-- | fs/overlayfs/copy_up.c | 24 | ||||
| -rw-r--r-- | fs/overlayfs/dir.c | 61 | ||||
| -rw-r--r-- | fs/overlayfs/inode.c | 12 | ||||
| -rw-r--r-- | fs/overlayfs/namei.c | 16 | ||||
| -rw-r--r-- | fs/overlayfs/overlayfs.h | 16 | ||||
| -rw-r--r-- | fs/overlayfs/ovl_entry.h | 2 | ||||
| -rw-r--r-- | fs/overlayfs/super.c | 18 | ||||
| -rw-r--r-- | fs/overlayfs/util.c | 72 |
9 files changed, 178 insertions, 44 deletions
diff --git a/fs/overlayfs/Kconfig b/fs/overlayfs/Kconfig index 0daac5112f7a..c0c9683934b7 100644 --- a/fs/overlayfs/Kconfig +++ b/fs/overlayfs/Kconfig | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | config OVERLAY_FS | 1 | config OVERLAY_FS |
| 2 | tristate "Overlay filesystem support" | 2 | tristate "Overlay filesystem support" |
| 3 | select EXPORTFS | ||
| 3 | help | 4 | help |
| 4 | An overlay filesystem combines two filesystems - an 'upper' filesystem | 5 | An overlay filesystem combines two filesystems - an 'upper' filesystem |
| 5 | and a 'lower' filesystem. When a name exists in both filesystems, the | 6 | and a 'lower' filesystem. When a name exists in both filesystems, the |
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 9008ab9fbd2e..7a44533f4bbf 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
| @@ -300,7 +300,11 @@ static int ovl_set_origin(struct dentry *dentry, struct dentry *lower, | |||
| 300 | return PTR_ERR(fh); | 300 | return PTR_ERR(fh); |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | err = ovl_do_setxattr(upper, OVL_XATTR_ORIGIN, fh, fh ? fh->len : 0, 0); | 303 | /* |
| 304 | * Do not fail when upper doesn't support xattrs. | ||
| 305 | */ | ||
| 306 | err = ovl_check_setxattr(dentry, upper, OVL_XATTR_ORIGIN, fh, | ||
| 307 | fh ? fh->len : 0, 0); | ||
| 304 | kfree(fh); | 308 | kfree(fh); |
| 305 | 309 | ||
| 306 | return err; | 310 | return err; |
| @@ -342,13 +346,14 @@ static int ovl_copy_up_locked(struct dentry *workdir, struct dentry *upperdir, | |||
| 342 | if (tmpfile) | 346 | if (tmpfile) |
| 343 | temp = ovl_do_tmpfile(upperdir, stat->mode); | 347 | temp = ovl_do_tmpfile(upperdir, stat->mode); |
| 344 | else | 348 | else |
| 345 | temp = ovl_lookup_temp(workdir, dentry); | 349 | temp = ovl_lookup_temp(workdir); |
| 346 | err = PTR_ERR(temp); | ||
| 347 | if (IS_ERR(temp)) | ||
| 348 | goto out1; | ||
| 349 | |||
| 350 | err = 0; | 350 | err = 0; |
| 351 | if (!tmpfile) | 351 | if (IS_ERR(temp)) { |
| 352 | err = PTR_ERR(temp); | ||
| 353 | temp = NULL; | ||
| 354 | } | ||
| 355 | |||
| 356 | if (!err && !tmpfile) | ||
| 352 | err = ovl_create_real(wdir, temp, &cattr, NULL, true); | 357 | err = ovl_create_real(wdir, temp, &cattr, NULL, true); |
| 353 | 358 | ||
| 354 | if (new_creds) { | 359 | if (new_creds) { |
| @@ -454,6 +459,11 @@ static int ovl_copy_up_one(struct dentry *parent, struct dentry *dentry, | |||
| 454 | ovl_path_upper(parent, &parentpath); | 459 | ovl_path_upper(parent, &parentpath); |
| 455 | upperdir = parentpath.dentry; | 460 | upperdir = parentpath.dentry; |
| 456 | 461 | ||
| 462 | /* Mark parent "impure" because it may now contain non-pure upper */ | ||
| 463 | err = ovl_set_impure(parent, upperdir); | ||
| 464 | if (err) | ||
| 465 | return err; | ||
| 466 | |||
| 457 | err = vfs_getattr(&parentpath, &pstat, | 467 | err = vfs_getattr(&parentpath, &pstat, |
| 458 | STATX_ATIME | STATX_MTIME, AT_STATX_SYNC_AS_STAT); | 468 | STATX_ATIME | STATX_MTIME, AT_STATX_SYNC_AS_STAT); |
| 459 | if (err) | 469 | if (err) |
diff --git a/fs/overlayfs/dir.c b/fs/overlayfs/dir.c index 723b98b90698..a63a71656e9b 100644 --- a/fs/overlayfs/dir.c +++ b/fs/overlayfs/dir.c | |||
| @@ -41,7 +41,7 @@ void ovl_cleanup(struct inode *wdir, struct dentry *wdentry) | |||
| 41 | } | 41 | } |
| 42 | } | 42 | } |
| 43 | 43 | ||
| 44 | struct dentry *ovl_lookup_temp(struct dentry *workdir, struct dentry *dentry) | 44 | struct dentry *ovl_lookup_temp(struct dentry *workdir) |
| 45 | { | 45 | { |
| 46 | struct dentry *temp; | 46 | struct dentry *temp; |
| 47 | char name[20]; | 47 | char name[20]; |
| @@ -68,7 +68,7 @@ static struct dentry *ovl_whiteout(struct dentry *workdir, | |||
| 68 | struct dentry *whiteout; | 68 | struct dentry *whiteout; |
| 69 | struct inode *wdir = workdir->d_inode; | 69 | struct inode *wdir = workdir->d_inode; |
| 70 | 70 | ||
| 71 | whiteout = ovl_lookup_temp(workdir, dentry); | 71 | whiteout = ovl_lookup_temp(workdir); |
| 72 | if (IS_ERR(whiteout)) | 72 | if (IS_ERR(whiteout)) |
| 73 | return whiteout; | 73 | return whiteout; |
| 74 | 74 | ||
| @@ -127,17 +127,28 @@ int ovl_create_real(struct inode *dir, struct dentry *newdentry, | |||
| 127 | return err; | 127 | return err; |
| 128 | } | 128 | } |
| 129 | 129 | ||
| 130 | static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) | 130 | static int ovl_set_opaque_xerr(struct dentry *dentry, struct dentry *upper, |
| 131 | int xerr) | ||
| 131 | { | 132 | { |
| 132 | int err; | 133 | int err; |
| 133 | 134 | ||
| 134 | err = ovl_do_setxattr(upperdentry, OVL_XATTR_OPAQUE, "y", 1, 0); | 135 | err = ovl_check_setxattr(dentry, upper, OVL_XATTR_OPAQUE, "y", 1, xerr); |
| 135 | if (!err) | 136 | if (!err) |
| 136 | ovl_dentry_set_opaque(dentry); | 137 | ovl_dentry_set_opaque(dentry); |
| 137 | 138 | ||
| 138 | return err; | 139 | return err; |
| 139 | } | 140 | } |
| 140 | 141 | ||
| 142 | static int ovl_set_opaque(struct dentry *dentry, struct dentry *upperdentry) | ||
| 143 | { | ||
| 144 | /* | ||
| 145 | * Fail with -EIO when trying to create opaque dir and upper doesn't | ||
| 146 | * support xattrs. ovl_rename() calls ovl_set_opaque_xerr(-EXDEV) to | ||
| 147 | * return a specific error for noxattr case. | ||
| 148 | */ | ||
| 149 | return ovl_set_opaque_xerr(dentry, upperdentry, -EIO); | ||
| 150 | } | ||
| 151 | |||
| 141 | /* Common operations required to be done after creation of file on upper */ | 152 | /* Common operations required to be done after creation of file on upper */ |
| 142 | static void ovl_instantiate(struct dentry *dentry, struct inode *inode, | 153 | static void ovl_instantiate(struct dentry *dentry, struct inode *inode, |
| 143 | struct dentry *newdentry, bool hardlink) | 154 | struct dentry *newdentry, bool hardlink) |
| @@ -162,6 +173,11 @@ static bool ovl_type_merge(struct dentry *dentry) | |||
| 162 | return OVL_TYPE_MERGE(ovl_path_type(dentry)); | 173 | return OVL_TYPE_MERGE(ovl_path_type(dentry)); |
| 163 | } | 174 | } |
| 164 | 175 | ||
| 176 | static bool ovl_type_origin(struct dentry *dentry) | ||
| 177 | { | ||
| 178 | return OVL_TYPE_ORIGIN(ovl_path_type(dentry)); | ||
| 179 | } | ||
| 180 | |||
| 165 | static int ovl_create_upper(struct dentry *dentry, struct inode *inode, | 181 | static int ovl_create_upper(struct dentry *dentry, struct inode *inode, |
| 166 | struct cattr *attr, struct dentry *hardlink) | 182 | struct cattr *attr, struct dentry *hardlink) |
| 167 | { | 183 | { |
| @@ -250,7 +266,7 @@ static struct dentry *ovl_clear_empty(struct dentry *dentry, | |||
| 250 | if (upper->d_parent->d_inode != udir) | 266 | if (upper->d_parent->d_inode != udir) |
| 251 | goto out_unlock; | 267 | goto out_unlock; |
| 252 | 268 | ||
| 253 | opaquedir = ovl_lookup_temp(workdir, dentry); | 269 | opaquedir = ovl_lookup_temp(workdir); |
| 254 | err = PTR_ERR(opaquedir); | 270 | err = PTR_ERR(opaquedir); |
| 255 | if (IS_ERR(opaquedir)) | 271 | if (IS_ERR(opaquedir)) |
| 256 | goto out_unlock; | 272 | goto out_unlock; |
| @@ -382,7 +398,7 @@ static int ovl_create_over_whiteout(struct dentry *dentry, struct inode *inode, | |||
| 382 | if (err) | 398 | if (err) |
| 383 | goto out; | 399 | goto out; |
| 384 | 400 | ||
| 385 | newdentry = ovl_lookup_temp(workdir, dentry); | 401 | newdentry = ovl_lookup_temp(workdir); |
| 386 | err = PTR_ERR(newdentry); | 402 | err = PTR_ERR(newdentry); |
| 387 | if (IS_ERR(newdentry)) | 403 | if (IS_ERR(newdentry)) |
| 388 | goto out_unlock; | 404 | goto out_unlock; |
| @@ -846,18 +862,16 @@ static int ovl_set_redirect(struct dentry *dentry, bool samedir) | |||
| 846 | if (IS_ERR(redirect)) | 862 | if (IS_ERR(redirect)) |
| 847 | return PTR_ERR(redirect); | 863 | return PTR_ERR(redirect); |
| 848 | 864 | ||
| 849 | err = ovl_do_setxattr(ovl_dentry_upper(dentry), OVL_XATTR_REDIRECT, | 865 | err = ovl_check_setxattr(dentry, ovl_dentry_upper(dentry), |
| 850 | redirect, strlen(redirect), 0); | 866 | OVL_XATTR_REDIRECT, |
| 867 | redirect, strlen(redirect), -EXDEV); | ||
| 851 | if (!err) { | 868 | if (!err) { |
| 852 | spin_lock(&dentry->d_lock); | 869 | spin_lock(&dentry->d_lock); |
| 853 | ovl_dentry_set_redirect(dentry, redirect); | 870 | ovl_dentry_set_redirect(dentry, redirect); |
| 854 | spin_unlock(&dentry->d_lock); | 871 | spin_unlock(&dentry->d_lock); |
| 855 | } else { | 872 | } else { |
| 856 | kfree(redirect); | 873 | kfree(redirect); |
| 857 | if (err == -EOPNOTSUPP) | 874 | pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err); |
| 858 | ovl_clear_redirect_dir(dentry->d_sb); | ||
| 859 | else | ||
| 860 | pr_warn_ratelimited("overlay: failed to set redirect (%i)\n", err); | ||
| 861 | /* Fall back to userspace copy-up */ | 875 | /* Fall back to userspace copy-up */ |
| 862 | err = -EXDEV; | 876 | err = -EXDEV; |
| 863 | } | 877 | } |
| @@ -943,6 +957,25 @@ static int ovl_rename(struct inode *olddir, struct dentry *old, | |||
| 943 | old_upperdir = ovl_dentry_upper(old->d_parent); | 957 | old_upperdir = ovl_dentry_upper(old->d_parent); |
| 944 | new_upperdir = ovl_dentry_upper(new->d_parent); | 958 | new_upperdir = ovl_dentry_upper(new->d_parent); |
