diff options
| -rw-r--r-- | fs/overlayfs/copy_up.c | 28 | ||||
| -rw-r--r-- | fs/overlayfs/overlayfs.h | 2 | ||||
| -rw-r--r-- | fs/overlayfs/util.c | 55 |
3 files changed, 63 insertions, 22 deletions
diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 48119b23375b..68b3303e4b46 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c | |||
| @@ -742,6 +742,8 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) | |||
| 742 | { | 742 | { |
| 743 | struct path upperpath, datapath; | 743 | struct path upperpath, datapath; |
| 744 | int err; | 744 | int err; |
| 745 | char *capability = NULL; | ||
| 746 | ssize_t uninitialized_var(cap_size); | ||
| 745 | 747 | ||
| 746 | ovl_path_upper(c->dentry, &upperpath); | 748 | ovl_path_upper(c->dentry, &upperpath); |
| 747 | if (WARN_ON(upperpath.dentry == NULL)) | 749 | if (WARN_ON(upperpath.dentry == NULL)) |
| @@ -751,15 +753,37 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) | |||
| 751 | if (WARN_ON(datapath.dentry == NULL)) | 753 | if (WARN_ON(datapath.dentry == NULL)) |
| 752 | return -EIO; | 754 | return -EIO; |
| 753 | 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 | |||
| 754 | err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size); | 763 | err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size); |
| 755 | if (err) | 764 | if (err) |
| 756 | 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 | |||
| 757 | 778 | ||
| 758 | err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY); | 779 | err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY); |
| 759 | if (err) | 780 | if (err) |
| 760 | return err; | 781 | goto out_free; |
| 761 | 782 | ||
| 762 | ovl_set_upperdata(d_inode(c->dentry)); | 783 | ovl_set_upperdata(d_inode(c->dentry)); |
| 784 | out_free: | ||
| 785 | kfree(capability); | ||
| 786 | out: | ||
| 763 | return err; | 787 | return err; |
| 764 | } | 788 | } |
| 765 | 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 | } |
