[Bluetooth] Add packet size checks for CAPI messages
With malformed packets it might be possible to overwrite internal CMTP and CAPI data structures. This patch adds additional length checks to prevent these kinds of remote attacks. Signed-off-by: Marcel Holtmann <marcel@holtmann.org>
This commit is contained in:
parent
d2e7543c41
commit
f477756920
|
@ -196,6 +196,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
|
|||
|
||||
switch (CAPIMSG_SUBCOMMAND(skb->data)) {
|
||||
case CAPI_CONF:
|
||||
if (skb->len < CAPI_MSG_BASELEN + 10)
|
||||
break;
|
||||
|
||||
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
|
||||
info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8);
|
||||
|
||||
|
@ -226,6 +229,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
|
|||
break;
|
||||
|
||||
case CAPI_FUNCTION_GET_PROFILE:
|
||||
if (skb->len < CAPI_MSG_BASELEN + 11 + sizeof(capi_profile))
|
||||
break;
|
||||
|
||||
controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
|
||||
msgnum = CAPIMSG_MSGID(skb->data);
|
||||
|
||||
|
@ -246,17 +252,26 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
|
|||
break;
|
||||
|
||||
case CAPI_FUNCTION_GET_MANUFACTURER:
|
||||
if (skb->len < CAPI_MSG_BASELEN + 15)
|
||||
break;
|
||||
|
||||
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
|
||||
|
||||
if (!info && ctrl) {
|
||||
int len = min_t(uint, CAPI_MANUFACTURER_LEN,
|
||||
skb->data[CAPI_MSG_BASELEN + 14]);
|
||||
|
||||
memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
|
||||
strncpy(ctrl->manu,
|
||||
skb->data + CAPI_MSG_BASELEN + 15,
|
||||
skb->data[CAPI_MSG_BASELEN + 14]);
|
||||
skb->data + CAPI_MSG_BASELEN + 15, len);
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case CAPI_FUNCTION_GET_VERSION:
|
||||
if (skb->len < CAPI_MSG_BASELEN + 32)
|
||||
break;
|
||||
|
||||
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
|
||||
|
||||
if (!info && ctrl) {
|
||||
|
@ -269,13 +284,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
|
|||
break;
|
||||
|
||||
case CAPI_FUNCTION_GET_SERIAL_NUMBER:
|
||||
if (skb->len < CAPI_MSG_BASELEN + 17)
|
||||
break;
|
||||
|
||||
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
|
||||
|
||||
if (!info && ctrl) {
|
||||
int len = min_t(uint, CAPI_SERIAL_LEN,
|
||||
skb->data[CAPI_MSG_BASELEN + 16]);
|
||||
|
||||
memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
|
||||
strncpy(ctrl->serial,
|
||||
skb->data + CAPI_MSG_BASELEN + 17,
|
||||
skb->data[CAPI_MSG_BASELEN + 16]);
|
||||
skb->data + CAPI_MSG_BASELEN + 17, len);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -284,14 +304,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
|
|||
break;
|
||||
|
||||
case CAPI_IND:
|
||||
if (skb->len < CAPI_MSG_BASELEN + 6)
|
||||
break;
|
||||
|
||||
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
|
||||
|
||||
if (func == CAPI_FUNCTION_LOOPBACK) {
|
||||
int len = min_t(uint, skb->len - CAPI_MSG_BASELEN - 6,
|
||||
skb->data[CAPI_MSG_BASELEN + 5]);
|
||||
appl = CAPIMSG_APPID(skb->data);
|
||||
msgnum = CAPIMSG_MSGID(skb->data);
|
||||
cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
|
||||
skb->data + CAPI_MSG_BASELEN + 6,
|
||||
skb->data[CAPI_MSG_BASELEN + 5]);
|
||||
skb->data + CAPI_MSG_BASELEN + 6, len);
|
||||
}
|
||||
|
||||
break;
|
||||
|
@ -309,6 +333,9 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb)
|
|||
|
||||
BT_DBG("session %p skb %p len %d", session, skb, skb->len);
|
||||
|
||||
if (skb->len < CAPI_MSG_BASELEN)
|
||||
return;
|
||||
|
||||
if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
|
||||
cmtp_recv_interopmsg(session, skb);
|
||||
return;
|
||||
|
|
Loading…
Reference in New Issue