libceph: fail sparse-read if the data length doesn't match
authorXiubo Li <xiubli@redhat.com>
Fri, 13 Oct 2023 05:55:44 +0000 (13:55 +0800)
committerIlya Dryomov <idryomov@gmail.com>
Wed, 7 Feb 2024 13:43:29 +0000 (14:43 +0100)
Once this happens that means there have bugs.

Signed-off-by: Xiubo Li <xiubli@redhat.com>
Reviewed-by: Jeff Layton <jlayton@kernel.org>
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
include/linux/ceph/osd_client.h
net/ceph/osd_client.c

index fa018d5864e7422c522194c16ff45a8dd0db1376..f66f6aac74f6f108ffba40b62159e047a184b732 100644 (file)
@@ -45,6 +45,7 @@ enum ceph_sparse_read_state {
        CEPH_SPARSE_READ_HDR    = 0,
        CEPH_SPARSE_READ_EXTENTS,
        CEPH_SPARSE_READ_DATA_LEN,
+       CEPH_SPARSE_READ_DATA_PRE,
        CEPH_SPARSE_READ_DATA,
 };
 
@@ -64,7 +65,7 @@ struct ceph_sparse_read {
        u64                             sr_req_len;  /* orig request length */
        u64                             sr_pos;      /* current pos in buffer */
        int                             sr_index;    /* current extent index */
-       __le32                          sr_datalen;  /* length of actual data */
+       u32                             sr_datalen;  /* length of actual data */
        u32                             sr_count;    /* extent count in reply */
        int                             sr_ext_len;  /* length of extent array */
        struct ceph_sparse_extent       *sr_extent;  /* extent array */
index 625622016f5761e36bccc3f7a239e265039ce95d..2cea35e4ff8ef1e0e8f8fa4637212053d1b27084 100644 (file)
@@ -5857,8 +5857,8 @@ static int osd_sparse_read(struct ceph_connection *con,
        struct ceph_osd *o = con->private;
        struct ceph_sparse_read *sr = &o->o_sparse_read;
        u32 count = sr->sr_count;
-       u64 eoff, elen;
-       int ret;
+       u64 eoff, elen, len = 0;
+       int i, ret;
 
        switch (sr->sr_state) {
        case CEPH_SPARSE_READ_HDR:
@@ -5903,8 +5903,20 @@ next_op:
                convert_extent_map(sr);
                ret = sizeof(sr->sr_datalen);
                *pbuf = (char *)&sr->sr_datalen;
-               sr->sr_state = CEPH_SPARSE_READ_DATA;
+               sr->sr_state = CEPH_SPARSE_READ_DATA_PRE;
                break;
+       case CEPH_SPARSE_READ_DATA_PRE:
+               /* Convert sr_datalen to host-endian */
+               sr->sr_datalen = le32_to_cpu((__force __le32)sr->sr_datalen);
+               for (i = 0; i < count; i++)
+                       len += sr->sr_extent[i].len;
+               if (sr->sr_datalen != len) {
+                       pr_warn_ratelimited("data len %u != extent len %llu\n",
+                                           sr->sr_datalen, len);
+                       return -EREMOTEIO;
+               }
+               sr->sr_state = CEPH_SPARSE_READ_DATA;
+               fallthrough;
        case CEPH_SPARSE_READ_DATA:
                if (sr->sr_index >= count) {
                        sr->sr_state = CEPH_SPARSE_READ_HDR;