ovl: skip copy up of empty security.capability

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: 8db6c34f1d ("Introduce v3 namespaced file capabilities")
Cc: stable@vger.kernel.org
Signed-off-by: Josef Bacik <josef@toxicpanda.com>
[amir: treat -EINVAL as no capability too, and do the same in
 ovl_copy_up_meta_inode_data()]
Signed-off-by: Amir Goldstein <amir73il@gmail.com>
This commit is contained in:
Amir Goldstein 2026-10-18 11:52:52 +02:00
parent 2001cd7ca5
commit 50912a1715

View File

@ -75,6 +75,15 @@ static int ovl_copy_acl(struct ovl_fs *ofs, const struct path *path,
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 *sb, const struct path *oldpath, struct de
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;
}
@ -1099,9 +1112,9 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)
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;
}