FAILED: patch "[PATCH] ovl: fortify ovl_copy_xattr() against underlying layer" failed to apply to 5.15-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.15-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
To reproduce the conflict and resubmit, you may use the following commands:
git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-5.15.y
git checkout FETCH_HEAD
git cherry-pick -x e6b9117076fb4c0ff4a670efa9c876d9a50d79ab
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026110401-avatar-tapioca-21c6@gregkh' --subject-prefix 'PATCH 5.15.y' 'HEAD^..'
Possible dependencies:
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From e6b9117076fb4c0ff4a670efa9c876d9a50d79ab Mon Sep 17 00:00:00 2001
From: Amir Goldstein <[email protected]>
Date: Fri, 16 Oct 2026 09:33:58 +0200
Subject: [PATCH] ovl: fortify ovl_copy_xattr() against underlying layer
modifications
Adapt ovl_getxattr_value() to be used from ovl_copy_xattr(), by allowing to pass it a pre-allocated buffer, which can be resized and by handling the ENODATA/EOPNOTSUPP return codes in the caller.
This replaces the retry loop in ovl_copy_xattr() with a single retry after resizing the buffer. If the value changed again by then, the underlying layer was modified, so return -EIO instead of retrying.
As a side effect, ovl_copy_up_meta_inode_data() now returns -EIO instead of -ERANGE in this case of underlying xattr size changes.
fs/overlayfs/copy_up.c +32 -36
@@ -72,6 +72,9 @@ static int ovl_copy_acl(struct ovl_fs *ofs, const struct path *path,return err; } +static ssize_t ovl_getxattr_value (const struct path *path,char *name, +char **value,ssize_t *value_size); +int ovl_copy_xattr (struct super_block *sb,const struct path *oldpath,struct dentry *new) {struct dentry *old = oldpath->dentry;
@@ -129,34 +132,12 @@ int ovl_copy_xattr(struct super_block *sb, const struct path *oldpath, struct debreak ; } -retry: - size =ovl_do_getxattr (oldpath, name, value, value_size); -if (size == -ERANGE ) { - size =ovl_do_getxattr (oldpath, name,NULL ,0 ); -/* Nothing was read into value, so it must not be used */ -if (size >=0 && size <= value_size) - size = -EIO ; - } - + size =ovl_getxattr_value (oldpath, name, &value, &value_size);if (size <0 ) { error = size;break ; } -if (size > value_size) { -void *new; - - new =kvmalloc (size,GFP_KERNEL ); -if (!new) { - error = -ENOMEM ; -break ; - } -kvfree (value); - value = new; - value_size = size; - goto retry; - } - error =ovl_do_setxattr (OVL_FS (sb), new, name, value, size,0 );if (error) {if (error != -EOPNOTSUPP ||ovl_must_copy_xattr (name))
@@ -1059,26 +1040,39 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode,return true; } -static ssize_t ovl_getxattr_value (const struct path *path,char *name,char **value) +static ssize_t ovl_getxattr_value (const struct path *path,char *name, +char **value,ssize_t *value_size) {ssize_t res;char *buf; - res =ovl_do_getxattr (path, name,NULL ,0 ); -if (res == -ENODATA || res == -EOPNOTSUPP ) - res =0 ; + res =ovl_do_getxattr (path, name, *value, *value_size); +if (res == -ERANGE ) { + res =ovl_do_getxattr (path, name,NULL ,0 ); +/* Xattr changed underneath us? */ +if (res >=0 && res <= *value_size) +return -EIO ; + } -if (res >0 ) { - buf =kzalloc (res,GFP_KERNEL ); +if (res > *value_size) { + buf =kvmalloc (res,GFP_KERNEL );if (!buf)return -ENOMEM ; res =ovl_do_getxattr (path, name, buf, res); -if (res <0 ) -kfree (buf); -else - *value = buf; +if (res <0 ) { +kvfree (buf); +/* Xattr changed underneath us? */ +if (res == -ERANGE ) +return -EIO ; +return res; + } + +kvfree (*value); + *value = buf; + *value_size = res; } +return res; }
@@ -1089,7 +1083,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)struct path upperpath;int err;char *capability =NULL ; -ssize_t cap_size; +ssize_t cap_size =0 ;ovl_path_upper (c->dentry, &upperpath);if (WARN_ON (upperpath.dentry ==NULL ))
@@ -1097,7 +1091,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); + &capability, &cap_size); +if (cap_size == -ENODATA || cap_size == -EOPNOTSUPP ) + cap_size =0 ;if (cap_size <0 ) goto out; }
@@ -1127,7 +1123,7 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c)ovl_clear_flag (OVL_VERIFIED_DIGEST ,d_inode (c->dentry));ovl_set_upperdata (d_inode (c->dentry)); out_free: -kfree (capability); +kvfree (capability); out:return err; }