]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-client.git/commitdiff
libceph: reject preamble if control segment is empty
authorIlya Dryomov <idryomov@gmail.com>
Sun, 8 Mar 2026 19:01:27 +0000 (20:01 +0100)
committerIlya Dryomov <idryomov@gmail.com>
Tue, 10 Mar 2026 11:16:00 +0000 (12:16 +0100)
While head_onwire_len() has a branch to handle ctrl_len == 0 case,
prepare_read_control() always sets up a kvec for the CRC meaning that
a non-empty control segment is effectively assumed.  All frames that
clients deal with meet that assumption, so let's make it official and
treat the preamble with an empty control segment as malformed.

Cc: stable@vger.kernel.org
Signed-off-by: Ilya Dryomov <idryomov@gmail.com>
Reviewed-by: Alex Markuze <amarkuze@redhat.com>
net/ceph/messenger_v2.c

index c4ddf7911f7d72c4073e6bf88ac4478ed2143653..50f65820f623f309533f94e571cafad815c87ea5 100644 (file)
@@ -392,7 +392,7 @@ static int head_onwire_len(int ctrl_len, bool secure)
        int head_len;
        int rem_len;
 
-       BUG_ON(ctrl_len < 0 || ctrl_len > CEPH_MSG_MAX_CONTROL_LEN);
+       BUG_ON(ctrl_len < 1 || ctrl_len > CEPH_MSG_MAX_CONTROL_LEN);
 
        if (secure) {
                head_len = CEPH_PREAMBLE_SECURE_LEN;
@@ -401,9 +401,7 @@ static int head_onwire_len(int ctrl_len, bool secure)
                        head_len += padded_len(rem_len) + CEPH_GCM_TAG_LEN;
                }
        } else {
-               head_len = CEPH_PREAMBLE_PLAIN_LEN;
-               if (ctrl_len)
-                       head_len += ctrl_len + CEPH_CRC_LEN;
+               head_len = CEPH_PREAMBLE_PLAIN_LEN + ctrl_len + CEPH_CRC_LEN;
        }
        return head_len;
 }
@@ -528,11 +526,16 @@ static int decode_preamble(void *p, struct ceph_frame_desc *desc)
                desc->fd_aligns[i] = ceph_decode_16(&p);
        }
 
-       if (desc->fd_lens[0] < 0 ||
+       /*
+        * This would fire for FRAME_TAG_WAIT (it has one empty
+        * segment), but we should never get it as client.
+        */
+       if (desc->fd_lens[0] < 1 ||
            desc->fd_lens[0] > CEPH_MSG_MAX_CONTROL_LEN) {
                pr_err("bad control segment length %d\n", desc->fd_lens[0]);
                return -EINVAL;
        }
+
        if (desc->fd_lens[1] < 0 ||
            desc->fd_lens[1] > CEPH_MSG_MAX_FRONT_LEN) {
                pr_err("bad front segment length %d\n", desc->fd_lens[1]);
@@ -549,10 +552,6 @@ static int decode_preamble(void *p, struct ceph_frame_desc *desc)
                return -EINVAL;
        }
 
-       /*
-        * This would fire for FRAME_TAG_WAIT (it has one empty
-        * segment), but we should never get it as client.
-        */
        if (!desc->fd_lens[desc->fd_seg_cnt - 1]) {
                pr_err("last segment empty, segment count %d\n",
                       desc->fd_seg_cnt);