Skip to content

Commit 993a0b2

Browse files
rhvgoyalMiklos Szeredi
authored andcommitted
ovl: Do not lose security.capability xattr over metadata file copy-up
If a file has been copied up metadata only, and later data is copied up, upper loses any security.capability xattr it has (underlying filesystem clears it as upon file write). From a user's point of view, this is just a file copy-up and that should not result in losing security.capability xattr. Hence, before data copy up, save security.capability xattr (if any) and restore it on upper after data copy up is complete. Signed-off-by: Vivek Goyal <vgoyal@redhat.com> Reviewed-by: Amir Goldstein <amir73il@gmail.com> Fixes: 0c28887 ("ovl: A new xattr OVL_XATTR_METACOPY for file on upper") Cc: <stable@vger.kernel.org> # v4.19+ Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
1 parent 5f32879 commit 993a0b2

File tree

3 files changed

+63
-22
lines changed

3 files changed

+63
-22
lines changed

fs/overlayfs/copy_up.c

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -742,6 +742,8 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
742742
{
743743
struct path upperpath, datapath;
744744
int err;
745+
char *capability = NULL;
746+
ssize_t uninitialized_var(cap_size);
745747

746748
ovl_path_upper(c->dentry, &upperpath);
747749
if (WARN_ON(upperpath.dentry == NULL))
@@ -751,15 +753,37 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
751753
if (WARN_ON(datapath.dentry == NULL))
752754
return -EIO;
753755

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+
754763
err = ovl_copy_up_data(&datapath, &upperpath, c->stat.size);
755764
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+
757778

758779
err = vfs_removexattr(upperpath.dentry, OVL_XATTR_METACOPY);
759780
if (err)
760-
return err;
781+
goto out_free;
761782

762783
ovl_set_upperdata(d_inode(c->dentry));
784+
out_free:
785+
kfree(capability);
786+
out:
763787
return err;
764788
}
765789

fs/overlayfs/overlayfs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -277,6 +277,8 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir);
277277
int ovl_check_metacopy_xattr(struct dentry *dentry);
278278
bool ovl_is_metacopy_dentry(struct dentry *dentry);
279279
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);
280282

281283
static inline bool ovl_is_impuredir(struct dentry *dentry)
282284
{

fs/overlayfs/util.c

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -863,28 +863,49 @@ bool ovl_is_metacopy_dentry(struct dentry *dentry)
863863
return (oe->numlower > 1);
864864
}
865865

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)
867868
{
868-
int res;
869-
char *s, *next, *buf = NULL;
869+
ssize_t res;
870+
char *buf = NULL;
870871

871-
res = vfs_getxattr(dentry, OVL_XATTR_REDIRECT, NULL, 0);
872+
res = vfs_getxattr(dentry, name, NULL, 0);
872873
if (res < 0) {
873874
if (res == -ENODATA || res == -EOPNOTSUPP)
874-
return NULL;
875+
return -ENODATA;
875876
goto fail;
876877
}
877878

878-
buf = kzalloc(res + padding + 1, GFP_KERNEL);
879-
if (!buf)
880-
return ERR_PTR(-ENOMEM);
879+
if (res != 0) {
880+
buf = kzalloc(res + padding, GFP_KERNEL);
881+
if (!buf)
882+
return -ENOMEM;
881883

882-
if (res == 0)
883-
goto invalid;
884+
res = vfs_getxattr(dentry, name, buf, res);
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+
}
884898

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;
886907
if (res < 0)
887-
goto fail;
908+
return ERR_PTR(res);
888909
if (res == 0)
889910
goto invalid;
890911

@@ -900,15 +921,9 @@ char *ovl_get_redirect_xattr(struct dentry *dentry, int padding)
900921
}
901922

902923
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;
910924
invalid:
911925
pr_warn_ratelimited("overlayfs: invalid redirect (%s)\n", buf);
912926
res = -EINVAL;
913-
goto err_free;
927+
kfree(buf);
928+
return ERR_PTR(res);
914929
}

0 commit comments

Comments
 (0)