Commit f4777569 authored by Marcel Holtmann's avatar Marcel Holtmann Committed by David S. Miller

[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: default avatarMarcel Holtmann <marcel@holtmann.org>
parent d2e7543c
...@@ -196,6 +196,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s ...@@ -196,6 +196,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
switch (CAPIMSG_SUBCOMMAND(skb->data)) { switch (CAPIMSG_SUBCOMMAND(skb->data)) {
case CAPI_CONF: case CAPI_CONF:
if (skb->len < CAPI_MSG_BASELEN + 10)
break;
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5); func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 5);
info = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 8); 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 ...@@ -226,6 +229,9 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break; break;
case CAPI_FUNCTION_GET_PROFILE: 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); controller = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 11);
msgnum = CAPIMSG_MSGID(skb->data); msgnum = CAPIMSG_MSGID(skb->data);
...@@ -246,17 +252,26 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s ...@@ -246,17 +252,26 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break; break;
case CAPI_FUNCTION_GET_MANUFACTURER: case CAPI_FUNCTION_GET_MANUFACTURER:
if (skb->len < CAPI_MSG_BASELEN + 15)
break;
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10); controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 10);
if (!info && ctrl) { if (!info && ctrl) {
strncpy(ctrl->manu, int len = min_t(uint, CAPI_MANUFACTURER_LEN,
skb->data + CAPI_MSG_BASELEN + 15,
skb->data[CAPI_MSG_BASELEN + 14]); skb->data[CAPI_MSG_BASELEN + 14]);
memset(ctrl->manu, 0, CAPI_MANUFACTURER_LEN);
strncpy(ctrl->manu,
skb->data + CAPI_MSG_BASELEN + 15, len);
} }
break; break;
case CAPI_FUNCTION_GET_VERSION: case CAPI_FUNCTION_GET_VERSION:
if (skb->len < CAPI_MSG_BASELEN + 32)
break;
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
if (!info && ctrl) { if (!info && ctrl) {
...@@ -269,13 +284,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s ...@@ -269,13 +284,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break; break;
case CAPI_FUNCTION_GET_SERIAL_NUMBER: case CAPI_FUNCTION_GET_SERIAL_NUMBER:
if (skb->len < CAPI_MSG_BASELEN + 17)
break;
controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12); controller = CAPIMSG_U32(skb->data, CAPI_MSG_BASELEN + 12);
if (!info && ctrl) { if (!info && ctrl) {
int len = min_t(uint, CAPI_SERIAL_LEN,
skb->data[CAPI_MSG_BASELEN + 16]);
memset(ctrl->serial, 0, CAPI_SERIAL_LEN); memset(ctrl->serial, 0, CAPI_SERIAL_LEN);
strncpy(ctrl->serial, strncpy(ctrl->serial,
skb->data + CAPI_MSG_BASELEN + 17, skb->data + CAPI_MSG_BASELEN + 17, len);
skb->data[CAPI_MSG_BASELEN + 16]);
} }
break; break;
...@@ -284,14 +304,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s ...@@ -284,14 +304,18 @@ static void cmtp_recv_interopmsg(struct cmtp_session *session, struct sk_buff *s
break; break;
case CAPI_IND: case CAPI_IND:
if (skb->len < CAPI_MSG_BASELEN + 6)
break;
func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3); func = CAPIMSG_U16(skb->data, CAPI_MSG_BASELEN + 3);
if (func == CAPI_FUNCTION_LOOPBACK) { 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); appl = CAPIMSG_APPID(skb->data);
msgnum = CAPIMSG_MSGID(skb->data); msgnum = CAPIMSG_MSGID(skb->data);
cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func, cmtp_send_interopmsg(session, CAPI_RESP, appl, msgnum, func,
skb->data + CAPI_MSG_BASELEN + 6, skb->data + CAPI_MSG_BASELEN + 6, len);
skb->data[CAPI_MSG_BASELEN + 5]);
} }
break; break;
...@@ -309,6 +333,9 @@ void cmtp_recv_capimsg(struct cmtp_session *session, struct sk_buff *skb) ...@@ -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); 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) { if (CAPIMSG_COMMAND(skb->data) == CAPI_INTEROPERABILITY) {
cmtp_recv_interopmsg(session, skb); cmtp_recv_interopmsg(session, skb);
return; return;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment