diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:48:52 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2019-03-12 17:48:52 -0400 |
commit | f88c5942cfaf7d55e46d395136cccaca65b2e3bf (patch) | |
tree | 33640d03b5d3652c41bb09b49d85af2b3659b820 | |
parent | dfee9c257b102d7c0407629eef2ed32e152de0d2 (diff) | |
parent | 993a0b2aec52754f0897b1dab4c453be8217cae5 (diff) |
Merge tag 'ovl-update-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs
Pull overlayfs updates from Miklos Szeredi:
"Fix copy up of security related xattrs"
* tag 'ovl-update-5.1' of git://git.kernel.org/pub/scm/linux/kernel/git/mszeredi/vfs:
ovl: Do not lose security.capability xattr over metadata file copy-up
ovl: During copy up, first copy up data and then xattrs
-rw-r--r-- | fs/overlayfs/copy_up.c | 59 | ||||
-rw-r--r-- | fs/overlayfs/overlayfs.h | 2 | ||||
-rw-r--r-- | fs/overlayfs/util.c | 55 |
3 files changed, 81 insertions, 35 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 9e62dcf06fc4..68b3303e4b46 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
@@ -443,6 +443,24 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) | |||
443 | { | 443 | { |
444 | int err; | 444 | int err; |
445 | 445 | ||
446 | /* | ||
447 | * Copy up data first and then xattrs. Writing data after | ||
448 | * xattrs will remove security.capability xattr automatically. | ||
449 | */ | ||
450 | if (S_ISREG(c->stat.mode) && !c->metacopy) { | ||
451 | struct path upperpath, datapath; | ||
452 | |||
453 | ovl_path_upper(c->dentry, &upperpath); | ||
454 | if (WARN_ON(upperpath.dentry != NULL)) | ||
455 | return -EIO; | ||
456 | upperpath.dentry = temp; | ||
457 | |||
458 | ovl_path_lowerdata(c->dentry, &datapath); | ||
459 | err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size); | ||
460 | if (err) | ||
461 | return err; | ||
462 | } | ||
463 | |||
446 | err = ovl_copy_xattr(c->lowerpath.dentry, temp); | 464 | err = ovl_copy_xattr(c->lowerpath.dentry, temp); |
447 | if (err) | 465 | if (err) |
448 | return err; | 466 | return err; |
@@ -460,19 +478,6 @@ static int ovl_copy_up_inode(struct ovl_copy_up_ctx *c, struct dentry *temp) | |||
460 | return err; | 478 | return err; |
461 | } | 479 | } |
462 | 480 | ||
463 | if (S_ISREG(c->stat.mode) && !c->metacopy) { | ||
464 | struct path upperpath, datapath; | ||
465 | |||
466 | ovl_path_upper(c->dentry, &upperpath); | ||
467 | BUG_ON(upperpath.dentry != NULL); | ||
468 | upperpath.dentry = temp; | ||
469 | |||
470 | ovl_path_lowerdata(c->dentry, &datapath); | ||
471 | err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size); | ||
472 | if (err) | ||
473 | return err; | ||
474 | } | ||
475 | |||
476 | if (c->metacopy) { | 481 | if (c->metacopy) { |
477 | err = ovl_check_setxattr(c->dentry, temp, OVL_XATTR_METACOPY, | 482 | err = ovl_check_setxattr(c->dentry, temp, OVL_XATTR_METACOPY, |
478 | NULL, 0, -EOPNOTSUPP); | 483 | NULL, 0, -EOPNOTSUPP); |
@@ -737,6 +742,8 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) | |||
737 | { | 742 | { |
738 | struct path upperpath, datapath; | 743 | struct path upperpath, datapath; |
739 | int err; | 744 | int err; |
745 | char *capability = NULL; | ||
746 | ssize_t uninitialized_var(cap_size); | ||
740 | 747 | ||
741 | ovl_path_upper(c->dentry, &upperpath); | 748 | ovl_path_upper(c->dentry, &upperpath); |
742 | if (WARN_ON(upperpath.dentry == NULL)) | 749 | if (WARN_ON(upperpath.dentry == NULL)) |
@@ -746,15 +753,37 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) | |||
746 | if (WARN_ON(datapath.dentry == NULL)) | 753 | if (WARN_ON(datapath.dentry == NULL)) |
747 | return -EIO; | 754 | return -EIO; |
748 | 755 | ||
756 | if (c->stat.size) { | ||
757 | err = cap_size = ovl_getxattr(upperpath.dentry, XATTR_NAME_CAPS, | ||
758 | &capability, 0); | ||
759 | if (err < 0 && err != -ENODATA) | ||
760 | goto out; | ||
761 | } | ||
762 | |||
749 | err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size); | 763 | err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size); |
750 | if (err) | 764 | if (err) |
751 | return err; | 765 | goto out_free; |
766 | |||
767 | /* | ||
768 | * Writing to upper file will clear security.capability xattr. We | ||
769 | * don't want that to happen for normal copy-up operation. | ||
770 | */ | ||
771 | if (capability) { | ||
772 | err = ovl_do_setxattr(upperpath.dentry, XATTR_NAME_CAPS, | ||
773 | capability, cap_size, 0); | ||
774 | if (err) | ||
775 | goto out_free; | ||
776 | } | ||
777 | |||
752 | 778 | ||
753 | err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY); | 779 | err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY); |
754 | if (err) | 780 | if (err) |
755 | return err; | 781 | goto out_free; |
756 | 782 | ||
757 | ovl_set_upperdata(d_inode(c->dentry)); | 783 | ovl_set_upperdata(d_inode(c->dentry)); |
784 | out_free: | ||
785 | kfree(capability); | ||
786 | out: | ||
758 | return err; | 787 | return err; |
759 | } | 788 | } |
760 | 789 | ||
diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 5e45cb3630a0..9c6018287d57 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h | |||
@@ -277,6 +277,8 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); | |||
277 | int ovl_check_metacopy_xattr(struct dentry *dentry); | 277 | int ovl_check_metacopy_xattr(struct dentry *dentry); |
278 | bool ovl_is_metacopy_dentry(struct dentry *dentry); | 278 | bool ovl_is_metacopy_dentry(struct dentry *dentry); |
279 | char *ovl_get_redirect_xattr(struct dentry *dentry, int padding); | 279 | char *ovl_get_redirect_xattr(struct dentry *dentry, int padding); |
280 | ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value, | ||
281 | size_t padding); | ||
280 | 282 | ||
281 | static inline bool ovl_is_impuredir(struct dentry *dentry) | 283 | static inline bool ovl_is_impuredir(struct dentry *dentry) |
282 | { | 284 | { |
diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 7c01327b1852..4035e640f402 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c | |||
@@ -863,28 +863,49 @@ bool ovl_is_metacopy_dentry(struct dentry *dentry) | |||
863 | return (oe->numlower > 1); | 863 | return (oe->numlower > 1); |
864 | } | 864 | } |
865 | 865 | ||
866 | char *ovl_get_redirect_xattr(struct dentry *dentry, int padding) | 866 | ssize_t ovl_getxattr(struct dentry *dentry, char *name, char **value, |
867 | size_t padding) | ||
867 | { | 868 | { |
868 | int res; | 869 | ssize_t res; |
869 | char *s, *next, *buf = NULL; | 870 | char *buf = NULL; |
870 | 871 | ||
871 | res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0); | 872 | res = vfs_getxattr(dentry, name, NULL, 0); |
872 | if (res < 0) { | 873 | if (res < 0) { |
873 | if (res == -ENODATA || res == -EOPNOTSUPP) | 874 | if (res == -ENODATA || res == -EOPNOTSUPP) |
874 | return NULL; | 875 | return -ENODATA; |
875 | goto fail; | 876 | goto fail; |
876 | } | 877 | } |
877 | 878 | ||
878 | buf = kzalloc(res + padding + 1, GFP_KERNEL); | 879 | if (res != 0) { |
879 | if (!buf) | 880 | buf = kzalloc(res + padding, GFP_KERNEL); |
880 | return ERR_PTR(-ENOMEM); | 881 | if (!buf) |
882 | return -ENOMEM; | ||
881 | 883 | ||
882 | if (res == 0) | 884 | res = vfs_getxattr(dentry, name, buf, res); |
883 | goto invalid; | 885 | if (res < 0) |
886 | goto fail; | ||
887 | } | ||
888 | *value = buf; | ||
889 | |||
890 | return res; | ||
891 | |||
892 | fail: | ||
893 | pr_warn_ratelimited("overlayfs: failed to get xattr %s: err=%zi)\n", | ||
894 | name, res); | ||
895 | kfree(buf); | ||
896 | return res; | ||
897 | } | ||
884 | 898 | ||
885 | res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, buf, res); | 899 | char *ovl_get_redirect_xattr(struct dentry *dentry, int padding) |
900 | { | ||
901 | int res; | ||
902 | char *s, *next, *buf = NULL; | ||
903 | |||
904 | res = ovl_getxattr(dentry, OVL_XATTR_REDIRECT, &buf, padding + 1); | ||
905 | if (res == -ENODATA) | ||
906 | return NULL; | ||
886 | if (res < 0) | 907 | if (res < 0) |
887 | goto fail; | 908 | return ERR_PTR(res); |
888 | if (res == 0) | 909 | if (res == 0) |
889 | goto invalid; | 910 | goto invalid; |
890 | 911 | ||
@@ -900,15 +921,9 @@ char *ovl_get_redirect_xattr(struct dentry *dentry, int padding) | |||
900 | } | 921 | } |
901 | 922 | ||
902 | return buf; | 923 | return buf; |
903 | |||
904 | err_free: | ||
905 | kfree(buf); | ||
906 | return ERR_PTR(res); | ||
907 | fail: | ||
908 | pr_warn_ratelimited("overlayfs: failed to get redirect (%i)\n", res); | ||
909 | goto err_free; | ||
910 | invalid: | 924 | invalid: |
911 | pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf); | 925 | pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf); |
912 | res = -EINVAL; | 926 | res = -EINVAL; |
913 | goto err_free; | 927 | kfree(buf); |
928 | return ERR_PTR(res); | ||
914 | } | 929 | } |