--- /dev/null
+From vendor-sec-admin@lst.de Mon Dec 11 06:28:38 2006
+Message-ID: <457D68B0.6060503@redhat.com>
+From: Marcel Holtmann <holtmann@redhat.com>
+CC: Al Viro <viro@zeniv.linux.org.uk>
+Subject: Bluetooth: Add packet size checks for CAPI messages (CVE-2006-6106)
+Date: Mon, 11 Dec 2006 15:18:24 +0100
+
+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>
+Signed-off-by: Chris Wright <chrisw@sous-sol.org>
+---
+
+ net/bluetooth/cmtp/capi.c | 39 +++++++++++++++++++++++++++++++++------
+ 1 file changed, 33 insertions(+), 6 deletions(-)
+
+--- linux-2.6.18.5.orig/net/bluetooth/cmtp/capi.c
++++ linux-2.6.18.5/net/bluetooth/cmtp/capi.c
+@@ -196,6 +196,9 @@ static void cmtp_recv_interopmsg(struct
+
+ 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
+ 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
+ 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
+ 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
+ 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_sessi
+
+ 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;