ceph: return -ERANGE if virtual xattr value didn’t fit in buffer [Linux 4.9.188]

This Linux kernel change "ceph: return -ERANGE if virtual xattr value didn’t fit in buffer" is included in the Linux 4.9.188 release. This change is authored by Jeff Layton <jlayton [at] kernel.org> on Thu Jun 13 15:17:00 2019 -0400. The commit for this change in Linux stable tree is 679ff6a (patch) which is from upstream commit 3b42101. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 3b42101.

ceph: return -ERANGE if virtual xattr value didn't fit in buffer

[ Upstream commit 3b421018f48c482bdc9650f894aa1747cf90e51d ]

The getxattr manpage states that we should return ERANGE if the
destination buffer size is too small to hold the value.
ceph_vxattrcb_layout does this internally, but we should be doing
this for all vxattrs.

Fix the only caller of getxattr_cb to check the returned size
against the buffer length and return -ERANGE if it doesn't fit.
Drop the same check in ceph_vxattrcb_layout and just rely on the
caller to handle it.

Signed-off-by: Jeff Layton <jlayton@kernel.org>
Reviewed-by: "Yan, Zheng" <zyan@redhat.com>
Acked-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Signed-off-by: Sasha Levin <sashal@kernel.org>

There are 14 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 fs/ceph/xattr.c | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/fs/ceph/xattr.c b/fs/ceph/xattr.c
index 75267cd..81144a8 100644
--- a/fs/ceph/xattr.c
+++ b/fs/ceph/xattr.c
@@ -74,7 +74,7 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
    const char *ns_field = " pool_namespace=";
    char buf[128];
    size_t len, total_len = 0;
-   int ret;
+   ssize_t ret;

    pool_ns = ceph_try_get_string(ci->i_layout.pool_ns);

@@ -98,11 +98,8 @@ static size_t ceph_vxattrcb_layout(struct ceph_inode_info *ci, char *val,
    if (pool_ns)
        total_len += strlen(ns_field) + pool_ns->len;

-   if (!size) {
-       ret = total_len;
-   } else if (total_len > size) {
-       ret = -ERANGE;
-   } else {
+   ret = total_len;
+   if (size >= total_len) {
        memcpy(val, buf, len);
        ret = len;
        if (pool_name) {
@@ -757,8 +754,11 @@ ssize_t __ceph_getxattr(struct inode *inode, const char *name, void *value,
    vxattr = ceph_match_vxattr(inode, name);
    if (vxattr) {
        err = -ENODATA;
-       if (!(vxattr->exists_cb && !vxattr->exists_cb(ci)))
+       if (!(vxattr->exists_cb && !vxattr->exists_cb(ci))) {
            err = vxattr->getxattr_cb(ci, value, size);
+           if (size && size < err)
+               err = -ERANGE;
+       }
        return err;
    }

Leave a Reply

Your email address will not be published. Required fields are marked *