7.3-stable review patch. If anyone has any objections, please let me know. ------------------ From: Amir Goldstein commit 50912a1715b8a7c614b654011a0db750e372b43e upstream. ovl_copy_xattr() gives up if it can't read an attribute that listxattr() has named. An empty security.capability, which anybody has been able to store on any file for a long time, is such a case: it is listed, and getxattr() has nothing to return for it. A file in a lower layer that carries one can't be copied up: it can't be written to, renamed or have its mode changed. There is nothing to copy if there are no data. Go on with the next one. Fixes: 8db6c34f1dbc ("Introduce v3 namespaced file capabilities") Cc: stable@vger.kernel.org Signed-off-by: Josef Bacik [amir: treat -EINVAL as no capability too, and do the same in ovl_copy_up_meta_inode_data()] Signed-off-by: Amir Goldstein Signed-off-by: Greg Kroah-Hartman --- fs/overlayfs/copy_up.c | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -75,6 +75,15 @@ static int ovl_copy_acl(struct ovl_fs *o static ssize_t ovl_getxattr_value(const struct path *path, char *name, char **value, ssize_t *value_size); +/* + * Any user can store an empty security.capability, which fails to read with + * -EINVAL. It grants no capability, so treat it as none, like no xattr. + */ +static bool ovl_no_fscap(ssize_t err) +{ + return err == -ENODATA || err == -EOPNOTSUPP || err == -EINVAL; +} + int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct dentry *new) { struct dentry *old = oldpath->dentry; @@ -134,6 +143,10 @@ int ovl_copy_xattr(struct super_block *s size = ovl_getxattr_value(oldpath, name, &value, &value_size); if (size < 0) { + if (!strcmp(name, XATTR_NAME_CAPS) && ovl_no_fscap(size)) { + error = 0; + continue; + } error = size; break; } @@ -1103,9 +1116,9 @@ static int ovl_copy_up_meta_inode_data(s if (c->stat.size) { err = cap_size = ovl_getxattr_value(&upperpath, XATTR_NAME_CAPS, &capability, &cap_size); - if (cap_size == -ENODATA || cap_size == -EOPNOTSUPP) + if (ovl_no_fscap(cap_size)) cap_size = 0; - if (cap_size < 0) + else if (cap_size < 0) goto out; }