From 1e59054afa991ad6b793ee203f70207082b30a93 Mon Sep 17 00:00:00 2001 From: Lyle Zhu Date: Fri, 21 Jun 2024 11:59:04 +0800 Subject: [PATCH] Bluetooth: RFCOMM: check the validity of received frame Check whether the received frame is complete by comparing the length of the received data with the frame data. Signed-off-by: Lyle Zhu --- subsys/bluetooth/host/classic/rfcomm.c | 33 ++++++++++++------- .../bluetooth/host/classic/rfcomm_internal.h | 20 +++++++---- 2 files changed, 35 insertions(+), 18 deletions(-) diff --git a/subsys/bluetooth/host/classic/rfcomm.c b/subsys/bluetooth/host/classic/rfcomm.c index 99948995ca1d..af67f2851b91 100644 --- a/subsys/bluetooth/host/classic/rfcomm.c +++ b/subsys/bluetooth/host/classic/rfcomm.c @@ -1494,10 +1494,13 @@ static int rfcomm_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) { struct bt_rfcomm_session *session = RFCOMM_SESSION(chan); struct bt_rfcomm_hdr *hdr = (void *)buf->data; + struct bt_rfcomm_hdr_ext *hdr_ext = (void *)buf->data; uint8_t dlci, frame_type, fcs, fcs_len; + uint16_t msg_len; + uint16_t hdr_len; /* Need to consider FCS also*/ - if (buf->len < (sizeof(*hdr) + 1)) { + if (buf->len < (sizeof(*hdr) + sizeof(fcs))) { LOG_ERR("Too small RFCOMM Frame"); return 0; } @@ -1507,19 +1510,28 @@ static int rfcomm_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) LOG_DBG("session %p dlci %x type %x", session, dlci, frame_type); - fcs_len = (frame_type == BT_RFCOMM_UIH) ? BT_RFCOMM_FCS_LEN_UIH : - BT_RFCOMM_FCS_LEN_NON_UIH; - fcs = *(net_buf_tail(buf) - 1); + if (BT_RFCOMM_LEN_EXTENDED(hdr->length)) { + msg_len = BT_RFCOMM_GET_LEN_EXTENDED(hdr_ext->hdr.length, hdr_ext->second_length); + hdr_len = sizeof(*hdr_ext); + } else { + msg_len = BT_RFCOMM_GET_LEN(hdr->length); + hdr_len = sizeof(*hdr); + } + + if (buf->len < (hdr_len + msg_len + sizeof(fcs))) { + LOG_ERR("Too small RFCOMM information (%d < %d)", buf->len, + hdr_len + msg_len + sizeof(fcs)); + return 0; + } + + fcs_len = (frame_type == BT_RFCOMM_UIH) ? BT_RFCOMM_FCS_LEN_UIH : hdr_len; + fcs = *(net_buf_tail(buf) - sizeof(fcs)); if (!rfcomm_check_fcs(fcs_len, buf->data, fcs)) { LOG_ERR("FCS check failed"); return 0; } - if (BT_RFCOMM_LEN_EXTENDED(hdr->length)) { - net_buf_pull(buf, sizeof(*hdr) + 1); - } else { - net_buf_pull(buf, sizeof(*hdr)); - } + net_buf_pull(buf, hdr_len); switch (frame_type) { case BT_RFCOMM_SABM: @@ -1529,8 +1541,7 @@ static int rfcomm_recv(struct bt_l2cap_chan *chan, struct net_buf *buf) if (!dlci) { rfcomm_handle_msg(session, buf); } else { - rfcomm_handle_data(session, buf, dlci, - BT_RFCOMM_GET_PF(hdr->control)); + rfcomm_handle_data(session, buf, dlci, BT_RFCOMM_GET_PF(hdr->control)); } break; case BT_RFCOMM_DISC: diff --git a/subsys/bluetooth/host/classic/rfcomm_internal.h b/subsys/bluetooth/host/classic/rfcomm_internal.h index ed5edd93b46e..07ff13bd0e9b 100644 --- a/subsys/bluetooth/host/classic/rfcomm_internal.h +++ b/subsys/bluetooth/host/classic/rfcomm_internal.h @@ -49,6 +49,11 @@ struct bt_rfcomm_hdr { uint8_t length; } __packed; +struct bt_rfcomm_hdr_ext { + struct bt_rfcomm_hdr hdr; + uint8_t second_length; +} __packed; + #define BT_RFCOMM_SABM 0x2f #define BT_RFCOMM_UA 0x63 #define BT_RFCOMM_UIH 0xef @@ -137,13 +142,14 @@ struct bt_rfcomm_rpn { sizeof(struct bt_rfcomm_hdr) + 1 + (mtu) + \ BT_RFCOMM_FCS_SIZE) -#define BT_RFCOMM_GET_DLCI(addr) (((addr) & 0xfc) >> 2) -#define BT_RFCOMM_GET_FRAME_TYPE(ctrl) ((ctrl) & 0xef) -#define BT_RFCOMM_GET_MSG_TYPE(type) (((type) & 0xfc) >> 2) -#define BT_RFCOMM_GET_MSG_CR(type) (((type) & 0x02) >> 1) -#define BT_RFCOMM_GET_LEN(len) (((len) & 0xfe) >> 1) -#define BT_RFCOMM_GET_CHANNEL(dlci) ((dlci) >> 1) -#define BT_RFCOMM_GET_PF(ctrl) (((ctrl) & 0x10) >> 4) +#define BT_RFCOMM_GET_DLCI(addr) (((addr) & 0xfc) >> 2) +#define BT_RFCOMM_GET_FRAME_TYPE(ctrl) ((ctrl) & 0xef) +#define BT_RFCOMM_GET_MSG_TYPE(type) (((type) & 0xfc) >> 2) +#define BT_RFCOMM_GET_MSG_CR(type) (((type) & 0x02) >> 1) +#define BT_RFCOMM_GET_LEN(len) (((len) & 0xfe) >> 1) +#define BT_RFCOMM_GET_LEN_EXTENDED(first, second) ((((first) & 0xfe) >> 1) | ((second) << 7)) +#define BT_RFCOMM_GET_CHANNEL(dlci) ((dlci) >> 1) +#define BT_RFCOMM_GET_PF(ctrl) (((ctrl) & 0x10) >> 4) #define BT_RFCOMM_SET_ADDR(dlci, cr) ((((dlci) & 0x3f) << 2) | \ ((cr) << 1) | 0x01)