| From c4c22b846eceff05b1129b8844a80310e55a7f87 Mon Sep 17 00:00:00 2001 |
| From: Ilya Dryomov <idryomov@gmail.com> |
| Date: Sun, 8 Mar 2026 20:01:27 +0100 |
| Subject: libceph: reject preamble if control segment is empty |
| |
| From: Ilya Dryomov <idryomov@gmail.com> |
| |
| commit c4c22b846eceff05b1129b8844a80310e55a7f87 upstream. |
| |
| 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> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| net/ceph/messenger_v2.c | 17 ++++++++--------- |
| 1 file changed, 8 insertions(+), 9 deletions(-) |
| |
| --- a/net/ceph/messenger_v2.c |
| +++ b/net/ceph/messenger_v2.c |
| @@ -391,7 +391,7 @@ static int head_onwire_len(int ctrl_len, |
| 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; |
| @@ -400,9 +400,7 @@ static int head_onwire_len(int ctrl_len, |
| 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; |
| } |
| @@ -527,11 +525,16 @@ static int decode_preamble(void *p, stru |
| 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]); |
| @@ -548,10 +551,6 @@ static int decode_preamble(void *p, stru |
| 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); |