From: "Glenn Durfee" <gdurfee@google.com>
To: "BlueZ development" <bluez-devel@lists.sourceforge.net>
Subject: Re: [Bluez-devel] SDP payload processing vulnerability
Date: Mon, 16 Jun 2008 13:49:18 -0700 [thread overview]
Message-ID: <b32d44000806161349x20323e9eg84072c277b6bd2e8@mail.gmail.com> (raw)
In-Reply-To: <b32d44000806161327u680c290au54fd21f2fef1d58e@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 3054 bytes --]
Oops, sent the wrong version, meant to send this one instead.
On Mon, Jun 16, 2008 at 1:27 PM, Glenn Durfee <gdurfee@google.com> wrote:
> Hi all,
>
> The SDP parsing code blindly trusts string length fields in incoming
> SDP packets, exposing reliant applications to over-the-wireless memory
> manipulation attacks. An attacker need only send a malformed
> response to an SDP query to take advantage of this.
>
> This is most apparent in file bluez-libs-3.30/src/sdp.c, lines 988,
> 994, 1002 (see below). Also elsewhere in the code where input
> pointers are advanced without checking bytes remaining to be parsed.
> The root of the problem is that in bluez-libs-3.30/src/sdp.c:1125, the
> function sdp_extract_pdu() takes a buffer to parse (in) and a pointer
> to a length field (out), but it does not take an incoming length field
> (in).
>
> Attached is a patch to fix this issue. Basically I added a
> "bytesleft" argument to all of the SDP payload processing routines;
> length fields are checked
> against the number of remaining bytes to ensure the parser doesn't run
> past the end of the packet, or do crazy things like malloc two gigs of
> memory. This touches a lot of places, and changes the external API
> for SDP payload processing, but I don't see any other way to do this
> -- the parser MUST be aware of the incoming packet size in order for
> this to be secure.
>
> Glenn
>
> bluez-libs-3.30/src/sdp.c:
>
> 972 static sdp_data_t *extract_str(const void *p, int *len)
> 973 {
> 974 char *s;
> 975 int n;
> 976 sdp_data_t *d = malloc(sizeof(sdp_data_t));
> 977
> 978 memset(d, 0, sizeof(sdp_data_t));
> 979 d->dtd = *(uint8_t *) p;
> 980 p += sizeof(uint8_t);
> 981 *len += sizeof(uint8_t);
> 982
> 983 switch (d->dtd) {
> 984 case SDP_TEXT_STR8:
> 985 case SDP_URL_STR8:
> 986 n = *(uint8_t *) p; // <-- from the incoming packet
> 987 p += sizeof(uint8_t);
> 988 *len += sizeof(uint8_t) + n; // <-- blindly
> trusted here, may advance parser past end of packet
> 989 break;
> 990 case SDP_TEXT_STR16:
> 991 case SDP_URL_STR16:
> 992 n = ntohs(bt_get_unaligned((uint16_t *) p)); //
> <-- from the incoming packet
> 993 p += sizeof(uint16_t);
> 994 *len += sizeof(uint16_t) + n; // <-- blindly
> trusted here, may advance parser past end of packet
> 995 break;
> 996 default:
> 997 SDPERR("Sizeof text string > UINT16_MAX\n");
> 998 free(d);
> 999 return 0;
> 1000 }
> 1001
> 1002 s = malloc(n + 1); // <-- really blindly trusted here,
> also no NULL checking
> 1003 memset(s, 0, n + 1);
> 1004 memcpy(s, p, n);
> 1005
> 1006 SDPDBG("Len : %d\n", n);
> 1007 SDPDBG("Str : %s\n", s);
> 1008
> 1009 d->val.str = s;
> 1010 d->unitSize = n + sizeof(uint8_t); // <-- more blind trust
> 1011 return d;
> 1012 }
>
[-- Attachment #2: bluetooth.patch.2 --]
[-- Type: application/octet-stream, Size: 40385 bytes --]
diff -ur bluetooth.orig/bluez-libs-3.30/include/bluetooth/sdp_lib.h bluetooth/bluez-libs-3.30/include/bluetooth/sdp_lib.h
--- bluetooth.orig/bluez-libs-3.30/include/bluetooth/sdp_lib.h 2008-06-13 13:36:13.913274000 -0700
+++ bluetooth/bluez-libs-3.30/include/bluetooth/sdp_lib.h 2008-06-13 12:06:26.929565000 -0700
@@ -478,7 +478,7 @@
void sdp_uuid32_to_uuid128(uuid_t *uuid128, uuid_t *uuid32);
int sdp_uuid128_to_uuid(uuid_t *uuid);
int sdp_uuid_to_proto(uuid_t *uuid);
-int sdp_uuid_extract(const uint8_t *buffer, uuid_t *uuid, int *scanned);
+int sdp_uuid_extract(const uint8_t *buffer, uuid_t *uuid, int *scanned, int bytesleft);
void sdp_uuid_print(const uuid_t *uuid);
#define MAX_LEN_UUID_STR 37
@@ -584,8 +584,7 @@
return sdp_get_string_attr(rec, SDP_ATTR_ICON_URL, str, len);
}
-sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int *scanned);
-sdp_data_t *sdp_extract_string(uint8_t *, int *);
+sdp_record_t *sdp_extract_pdu(const uint8_t *pdata, int *scanned, int packet_size);
void sdp_data_print(sdp_data_t *data);
void sdp_print_service_attr(sdp_list_t *alist);
@@ -600,9 +599,9 @@
int sdp_gen_pdu(sdp_buf_t *pdu, sdp_data_t *data);
int sdp_gen_record_pdu(const sdp_record_t *rec, sdp_buf_t *pdu);
-int sdp_extract_seqtype(const uint8_t *buf, uint8_t *dtdp, int *seqlen);
+int sdp_extract_seqtype(const uint8_t *buf, uint8_t *dtdp, int *seqlen, int bytesleft);
-sdp_data_t *sdp_extract_attr(const uint8_t *pdata, int *extractedLength, sdp_record_t *rec);
+sdp_data_t *sdp_extract_attr(const uint8_t *pdata, int *extractedLength, sdp_record_t *rec, int bytesleft);
void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid);
void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq);
diff -ur bluetooth.orig/bluez-libs-3.30/src/sdp.c bluetooth/bluez-libs-3.30/src/sdp.c
--- bluetooth.orig/bluez-libs-3.30/src/sdp.c 2008-06-13 13:36:13.990281000 -0700
+++ bluetooth/bluez-libs-3.30/src/sdp.c 2008-06-13 12:34:14.999932000 -0700
@@ -904,43 +904,81 @@
free(d);
}
-static sdp_data_t *extract_int(const void *p, int *len)
+static sdp_data_t *extract_int(const void *p, int *len, int bytesleft)
{
sdp_data_t *d = malloc(sizeof(sdp_data_t));
SDPDBG("Extracting integer\n");
memset(d, 0, sizeof(sdp_data_t));
+
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
+
d->dtd = *(uint8_t *) p;
p += sizeof(uint8_t);
*len += sizeof(uint8_t);
-
+ bytesleft -= sizeof(uint8_t);
+
switch (d->dtd) {
case SDP_DATA_NIL:
break;
case SDP_BOOL:
case SDP_INT8:
case SDP_UINT8:
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
*len += sizeof(uint8_t);
+ bytesleft -= sizeof(uint8_t);
d->val.uint8 = *(uint8_t *) p;
break;
case SDP_INT16:
case SDP_UINT16:
+ if (bytesleft < sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
*len += sizeof(uint16_t);
+ bytesleft -= sizeof(uint16_t);
d->val.uint16 = ntohs(bt_get_unaligned((uint16_t *) p));
break;
case SDP_INT32:
case SDP_UINT32:
+ if (bytesleft < sizeof(uint32_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
*len += sizeof(uint32_t);
+ bytesleft -= sizeof(uint32_t);
d->val.uint32 = ntohl(bt_get_unaligned((uint32_t *) p));
break;
case SDP_INT64:
case SDP_UINT64:
+ if (bytesleft < sizeof(uint64_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
*len += sizeof(uint64_t);
+ bytesleft -= sizeof(uint64_t);
d->val.uint64 = ntoh64(bt_get_unaligned((uint64_t *) p));
break;
case SDP_INT128:
case SDP_UINT128:
+ if (bytesleft < sizeof(uint128_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
*len += sizeof(uint128_t);
+ bytesleft -= sizeof(uint128_t);
ntoh128((uint128_t *) p, &d->val.uint128);
break;
default:
@@ -950,16 +988,21 @@
return d;
}
-static sdp_data_t *extract_uuid(const uint8_t *p, int *len, sdp_record_t *rec)
+static sdp_data_t *extract_uuid(const uint8_t *p, int *len, sdp_record_t *rec, int bytesleft)
{
sdp_data_t *d = malloc(sizeof(sdp_data_t));
SDPDBG("Extracting UUID");
memset(d, 0, sizeof(sdp_data_t));
- if (sdp_uuid_extract(p, &d->val.uuid, len) < 0) {
+ if (sdp_uuid_extract(p, &d->val.uuid, len, bytesleft) < 0) {
free(d);
return NULL;
}
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
d->dtd = *(uint8_t *) p;
if (rec)
sdp_pattern_add_uuid(rec, &d->val.uuid);
@@ -969,29 +1012,63 @@
/*
* Extract strings from the PDU (could be service description and similar info)
*/
-static sdp_data_t *extract_str(const void *p, int *len)
+static sdp_data_t *extract_str(const void *p, int *len, int bytesleft)
{
char *s;
int n;
sdp_data_t *d = malloc(sizeof(sdp_data_t));
memset(d, 0, sizeof(sdp_data_t));
+
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
+
d->dtd = *(uint8_t *) p;
p += sizeof(uint8_t);
*len += sizeof(uint8_t);
+ bytesleft -= sizeof(uint8_t);
switch (d->dtd) {
case SDP_TEXT_STR8:
case SDP_URL_STR8:
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
n = *(uint8_t *) p;
p += sizeof(uint8_t);
- *len += sizeof(uint8_t) + n;
+ *len += sizeof(uint8_t);
+ bytesleft -= sizeof(uint8_t);
+ if (n <= 0 || n > bytesleft) {
+ SDPERR("Invalid length of text string");
+ free(d);
+ return 0;
+ }
+ *len += n;
+ bytesleft -= n;
break;
case SDP_TEXT_STR16:
case SDP_URL_STR16:
+ if (bytesleft < sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
n = ntohs(bt_get_unaligned((uint16_t *) p));
p += sizeof(uint16_t);
- *len += sizeof(uint16_t) + n;
+ *len += sizeof(uint16_t);
+ bytesleft -= sizeof(uint16_t);
+ if (n <= 0 || n > bytesleft) {
+ SDPERR("Invalid length of text string");
+ free(d);
+ return 0;
+ }
+ *len += n;
+ bytesleft -= n;
break;
default:
SDPERR("Sizeof text string > UINT16_MAX\n");
@@ -1000,6 +1077,12 @@
}
s = malloc(n + 1);
+ if (NULL == s) {
+ SDPERR("Cannot allocate memory for string");
+ free(d);
+ return 0;
+ }
+
memset(s, 0, n + 1);
memcpy(s, p, n);
@@ -1011,7 +1094,7 @@
return d;
}
-static sdp_data_t *extract_seq(const void *p, int *len, sdp_record_t *rec)
+static sdp_data_t *extract_seq(const void *p, int *len, sdp_record_t *rec, int bytesleft)
{
int seqlen, n = 0;
sdp_data_t *curr, *prev;
@@ -1019,17 +1102,24 @@
SDPDBG("Extracting SEQ");
memset(d, 0, sizeof(sdp_data_t));
- *len = sdp_extract_seqtype(p, &d->dtd, &seqlen);
+ *len = sdp_extract_seqtype(p, &d->dtd, &seqlen, bytesleft);
SDPDBG("Sequence Type : 0x%x length : 0x%x\n", d->dtd, seqlen);
if (*len == 0)
return d;
+ if (bytesleft < *len) {
+ SDPERR("Unexpected end of packet");
+ free(d);
+ return 0;
+ }
+
p += *len;
+ bytesleft -= *len;
curr = prev = NULL;
while (n < seqlen) {
int attrlen = 0;
- curr = sdp_extract_attr(p, &attrlen, rec);
+ curr = sdp_extract_attr(p, &attrlen, rec, bytesleft);
if (curr == NULL)
break;
@@ -1040,6 +1130,7 @@
prev = curr;
p += attrlen;
n += attrlen;
+ bytesleft -= attrlen;
SDPDBG("Extracted: %d SequenceLength: %d", n, seqlen);
}
@@ -1048,10 +1139,16 @@
return d;
}
-sdp_data_t *sdp_extract_attr(const uint8_t *p, int *size, sdp_record_t *rec)
+sdp_data_t *sdp_extract_attr(const uint8_t *p, int *size, sdp_record_t *rec, int bytesleft)
{
sdp_data_t *elem;
int n = 0;
+
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ return 0;
+ }
+
uint8_t dtd = *(const uint8_t *)p;
SDPDBG("extract_attr: dtd=0x%x", dtd);
@@ -1068,12 +1165,12 @@
case SDP_INT32:
case SDP_INT64:
case SDP_INT128:
- elem = extract_int(p, &n);
+ elem = extract_int(p, &n, bytesleft);
break;
case SDP_UUID16:
case SDP_UUID32:
case SDP_UUID128:
- elem = extract_uuid(p, &n, rec);
+ elem = extract_uuid(p, &n, rec, bytesleft);
break;
case SDP_TEXT_STR8:
case SDP_TEXT_STR16:
@@ -1081,7 +1178,7 @@
case SDP_URL_STR8:
case SDP_URL_STR16:
case SDP_URL_STR32:
- elem = extract_str(p, &n);
+ elem = extract_str(p, &n, bytesleft);
break;
case SDP_SEQ8:
case SDP_SEQ16:
@@ -1089,13 +1186,14 @@
case SDP_ALT8:
case SDP_ALT16:
case SDP_ALT32:
- elem = extract_seq(p, &n, rec);
+ elem = extract_seq(p, &n, rec, bytesleft);
break;
default:
SDPERR("Unknown data descriptor : 0x%x terminating\n", dtd);
return NULL;
}
*size += n;
+ bytesleft -= n;
return elem;
}
@@ -1122,21 +1220,37 @@
}
#endif
-sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int *scanned)
+sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int *scanned, int packet_size)
{
int extracted = 0, seqlen = 0;
uint8_t dtd;
uint16_t attr;
sdp_record_t *rec = sdp_record_alloc();
const uint8_t *p = buf;
+ int bytesleft = packet_size;
- *scanned = sdp_extract_seqtype(buf, &dtd, &seqlen);
+ *scanned = sdp_extract_seqtype(buf, &dtd, &seqlen, bytesleft);
+ if (*scanned == 0) {
+ SDPERR("Sequence length 0 of incoming SDP PDU");
+ return rec;
+ }
p += *scanned;
+ bytesleft -= *scanned;
+ if (bytesleft < seqlen) {
+ SDPERR("Insufficient data in packet to contain sequence");
+ return rec;
+ }
+
rec->attrlist = NULL;
while (extracted < seqlen) {
int n = sizeof(uint8_t), attrlen = 0;
sdp_data_t *data = NULL;
+ if (bytesleft < sizeof(uint8_t)+sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ break;
+ }
+
SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", seqlen, extracted);
dtd = *(uint8_t *) p;
attr = ntohs(bt_get_unaligned((uint16_t *) (p + n)));
@@ -1144,7 +1258,8 @@
SDPDBG("DTD of attrId : %d Attr id : 0x%x \n", dtd, attr);
- data = sdp_extract_attr(p + n, &attrlen, rec);
+ bytesleft -= sizeof(uint8_t)+sizeof(uint16_t);
+ data = sdp_extract_attr(p + n, &attrlen, rec, bytesleft);
SDPDBG("Attr id : 0x%x attrValueLength : %d\n", attr, attrlen);
@@ -1162,6 +1277,7 @@
extracted += n;
p += n;
+ bytesleft -= n;
sdp_attr_replace(rec, attr, data);
SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d",
seqlen, extracted);
@@ -1266,26 +1382,43 @@
* Extract the sequence type and its length, and return offset into buf
* or 0 on failure.
*/
-int sdp_extract_seqtype(const uint8_t *buf, uint8_t *dtdp, int *size)
+int sdp_extract_seqtype(const uint8_t *buf, uint8_t *dtdp, int *size, int bytesleft)
{
uint8_t dtd = *(uint8_t *) buf;
int scanned = sizeof(uint8_t);
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ return 0;
+ }
buf += sizeof(uint8_t);
+ bytesleft -= sizeof(uint8_t);
*dtdp = dtd;
switch (dtd) {
case SDP_SEQ8:
case SDP_ALT8:
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ return 0;
+ }
*size = *(uint8_t *) buf;
scanned += sizeof(uint8_t);
break;
case SDP_SEQ16:
case SDP_ALT16:
+ if (bytesleft < sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ return 0;
+ }
*size = ntohs(bt_get_unaligned((uint16_t *) buf));
scanned += sizeof(uint16_t);
break;
case SDP_SEQ32:
case SDP_ALT32:
+ if (bytesleft < sizeof(uint32_t)) {
+ SDPERR("Unexpected end of packet");
+ return 0;
+ }
*size = ntohl(bt_get_unaligned((uint32_t *) buf));
scanned += sizeof(uint32_t);
break;
@@ -2329,9 +2462,16 @@
return 0;
}
-int sdp_uuid_extract(const uint8_t *p, uuid_t *uuid, int *scanned)
+int sdp_uuid_extract(const uint8_t *p, uuid_t *uuid, int *scanned, int bytesleft)
{
- uint8_t type = *(const uint8_t *) p;
+ uint8_t type;
+
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet");
+ return -1;
+ }
+
+ type = *(const uint8_t *) p;
if (!SDP_IS_UUID(type)) {
SDPERR("Unknown data type : %d expecting a svc UUID\n", type);
@@ -2339,17 +2479,34 @@
}
p += sizeof(uint8_t);
*scanned += sizeof(uint8_t);
+ bytesleft -= sizeof(uint8_t);
+
if (type == SDP_UUID16) {
+ if (bytesleft < sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ return -1;
+ }
sdp_uuid16_create(uuid, ntohs(bt_get_unaligned((uint16_t *) p)));
*scanned += sizeof(uint16_t);
+ bytesleft -= sizeof(uint16_t);
p += sizeof(uint16_t);
} else if (type == SDP_UUID32) {
+ if (bytesleft < sizeof(uint32_t)) {
+ SDPERR("Unexpected end of packet");
+ return -1;
+ }
sdp_uuid32_create(uuid, ntohl(bt_get_unaligned((uint32_t *) p)));
*scanned += sizeof(uint32_t);
+ bytesleft -= sizeof(uint32_t);
p += sizeof(uint32_t);
} else {
+ if (bytesleft < sizeof(uint128_t)) {
+ SDPERR("Unexpected end of packet");
+ return -1;
+ }
sdp_uuid128_create(uuid, p);
*scanned += sizeof(uint128_t);
+ bytesleft -= sizeof(uint128_t);
p += sizeof(uint128_t);
}
return 0;
@@ -2447,6 +2604,7 @@
uint32_t reqsize, rspsize;
sdp_pdu_hdr_t *reqhdr, *rsphdr;
int status;
+ int bytesleft;
SDPDBG("");
@@ -2483,9 +2641,19 @@
status = sdp_send_req_w4_rsp(session, req, rsp, reqsize, &rspsize);
if (status < 0)
goto end;
+
+ bytesleft = rspsize;
+ if (bytesleft < sizeof(sdp_pdu_hdr_t)) {
+ SDPERR("Unexpected end of packet");
+ errno = EINVAL;
+ status = -1;
+ goto end;
+ }
+
rsphdr = (sdp_pdu_hdr_t *) rsp;
p = rsp + sizeof(sdp_pdu_hdr_t);
+ bytesleft -= sizeof(sdp_pdu_hdr_t);
if (rsphdr->pdu_id == SDP_ERROR_RSP) {
/* Invalid service record */
@@ -2495,7 +2663,13 @@
errno = EPROTO;
status = -1;
} else {
- if (handle)
+ if (bytesleft < sizeof(uint32_t)) {
+ SDPERR("Unexpected end of packet");
+ errno = EINVAL;
+ status = -1;
+ goto end;
+ }
+ if (handle)
*handle = ntohl(bt_get_unaligned((uint32_t *) p));
}
@@ -2556,6 +2730,7 @@
uint32_t reqsize = 0, rspsize = 0;
sdp_pdu_hdr_t *reqhdr, *rsphdr;
int status;
+ int bytesleft;
SDPDBG("");
@@ -2590,9 +2765,19 @@
if (status < 0)
goto end;
- rsphdr = (sdp_pdu_hdr_t *) rspbuf;
+ bytesleft = rspsize;
+ if (bytesleft < sizeof(sdp_pdu_hdr_t)+sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ errno = EINVAL;
+ status = -1;
+ goto end;
+ }
+
+ rsphdr = (sdp_pdu_hdr_t *) rspbuf;
p = rspbuf + sizeof(sdp_pdu_hdr_t);
+ bytesleft -= sizeof(sdp_pdu_hdr_t);
status = bt_get_unaligned((uint16_t *) p);
+ bytesleft -= sizeof(uint16_t);
if (rsphdr->pdu_id == SDP_ERROR_RSP) {
/* For this case the status always is invalid record handle */
@@ -2644,6 +2829,7 @@
uint32_t handle;
sdp_buf_t pdu;
int status;
+ int bytesleft;
SDPDBG("");
@@ -2688,12 +2874,23 @@
status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);
if (status < 0)
goto end;
+
+ bytesleft = rspsize;
SDPDBG("Send req status : %d\n", status);
- rsphdr = (sdp_pdu_hdr_t *) rspbuf;
+ if (bytesleft < sizeof(sdp_pdu_hdr_t)+sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ errno = EINVAL;
+ status = -1;
+ goto end;
+ }
+
+ rsphdr = (sdp_pdu_hdr_t *) rspbuf;
p = rspbuf + sizeof(sdp_pdu_hdr_t);
+ bytesleft -= sizeof(sdp_pdu_hdr_t);
status = bt_get_unaligned((uint16_t *) p);
+ bytesleft -= sizeof(uint16_t);
if (rsphdr->pdu_id == SDP_ERROR_RSP) {
/* The status can be invalid sintax or invalid record handle */
@@ -2764,18 +2961,23 @@
* handles are not in "data element sequence" form, but just like
* an array of service handles
*/
-static void extract_record_handle_seq(uint8_t *pdu, sdp_list_t **seq, int count, int *scanned)
+static void extract_record_handle_seq(uint8_t *pdu, sdp_list_t **seq, int count, int *scanned, int bytesleft)
{
sdp_list_t *pSeq = *seq;
uint8_t *pdata = pdu;
int n;
for (n = 0; n < count; n++) {
+ if (bytesleft < sizeof(uint32_t)) {
+ SDPERR("Unexpected end of packet");
+ break;
+ }
uint32_t *pSvcRec = malloc(sizeof(uint32_t));
*pSvcRec = ntohl(bt_get_unaligned((uint32_t *) pdata));
pSeq = sdp_list_append(pSeq, pSvcRec);
pdata += sizeof(uint32_t);
*scanned += sizeof(uint32_t);
+ bytesleft -= sizeof(uint32_t);
}
*seq = pSeq;
}
@@ -2843,12 +3045,17 @@
unsigned char data[16];
} __attribute__ ((packed)) sdp_cstate_t;
-static int copy_cstate(uint8_t *pdata, const sdp_cstate_t *cstate)
+static int copy_cstate(uint8_t *pdata, int pdata_len, const sdp_cstate_t *cstate)
{
if (cstate) {
- *pdata++ = cstate->length;
- memcpy(pdata, cstate->data, cstate->length);
- return cstate->length + 1;
+ uint8_t len = cstate->length;
+ if ((int)len > pdata_len) {
+ SDPERR("Continuation state size exceeds internal buffer");
+ } else {
+ *pdata++ = len;
+ memcpy(pdata, cstate->data, len);
+ return len + 1;
+ }
}
*pdata = 0;
return 1;
@@ -2892,9 +3099,11 @@
int seqlen = 0;
int scanned, total_rec_count, rec_count;
uint8_t *pdata, *_pdata;
+ int _pdata_len;
uint8_t *reqbuf, *rspbuf;
sdp_pdu_hdr_t *reqhdr, *rsphdr;
sdp_cstate_t *cstate = NULL;
+ int bytesleft;
reqbuf = malloc(SDP_REQ_BUFFER_SIZE);
rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
@@ -2924,11 +3133,12 @@
_reqsize = reqsize;
_pdata = pdata;
+ _pdata_len = SDP_REQ_BUFFER_SIZE - reqsize;
*rsp = NULL;
do {
// Add continuation state or NULL (first time)
- reqsize = _reqsize + copy_cstate(_pdata, cstate);
+ reqsize = _reqsize + copy_cstate(_pdata, _pdata_len, cstate);
// Set the request header's param length
reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
@@ -2940,8 +3150,16 @@
*/
status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);
if (status < 0)
- goto end;
-
+ goto end;
+
+ bytesleft = rspsize;
+
+ if (bytesleft < sizeof(sdp_pdu_hdr_t)) {
+ SDPERR("Unexpected end of packet");
+ status = -1;
+ goto end;
+ }
+
rsplen = 0;
rsphdr = (sdp_pdu_hdr_t *) rspbuf;
rsplen = ntohs(rsphdr->plen);
@@ -2953,14 +3171,22 @@
}
scanned = 0;
pdata = rspbuf + sizeof(sdp_pdu_hdr_t);
-
+ bytesleft -= sizeof(sdp_pdu_hdr_t);
+ if (bytesleft < sizeof(uint16_t)+sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ status = -1;
+ goto end;
+ }
+
// net service record match count
total_rec_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
pdata += sizeof(uint16_t);
scanned += sizeof(uint16_t);
+ bytesleft -= sizeof(uint16_t);
rec_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
pdata += sizeof(uint16_t);
scanned += sizeof(uint16_t);
+ bytesleft -= sizeof(uint16_t);
SDPDBG("Total svc count: %d\n", total_rec_count);
SDPDBG("Current svc count: %d\n", rec_count);
@@ -2970,12 +3196,19 @@
status = -1;
goto end;
}
- extract_record_handle_seq(pdata, rsp, rec_count, &scanned);
+ extract_record_handle_seq(pdata, rsp, rec_count, &scanned, bytesleft);
SDPDBG("BytesScanned : %d\n", scanned);
+ bytesleft -= scanned;
if (rsplen > scanned) {
uint8_t cstate_len;
+ if (bytesleft < sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet: continuation state data missing");
+ status = -1;
+ goto end;
+ }
+
pdata = rspbuf + sizeof(sdp_pdu_hdr_t) + scanned;
cstate_len = *(uint8_t *) pdata;
if (cstate_len > 0) {
@@ -3036,12 +3269,14 @@
int attr_list_len = 0;
int seqlen = 0;
uint8_t *pdata, *_pdata;
+ int _pdata_len;
uint8_t *reqbuf, *rspbuf;
sdp_pdu_hdr_t *reqhdr, *rsphdr;
sdp_cstate_t *cstate = NULL;
uint8_t cstate_len = 0;
sdp_buf_t rsp_concat_buf;
sdp_record_t *rec = 0;
+ int bytesleft;
if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) {
errno = EINVAL;
@@ -3087,10 +3322,11 @@
// save before Continuation State
_pdata = pdata;
_reqsize = reqsize;
+ _pdata_len = SDP_REQ_BUFFER_SIZE - reqsize;
do {
// add NULL continuation state
- reqsize = _reqsize + copy_cstate(_pdata, cstate);
+ reqsize = _reqsize + copy_cstate(_pdata, _pdata_len, cstate);
// set the request header's param length
reqhdr->tid = htons(sdp_gen_tid(session));
@@ -3099,6 +3335,14 @@
status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize);
if (status < 0)
goto end;
+ bytesleft = rspsize;
+
+ if (bytesleft < sizeof(sdp_pdu_hdr_t)) {
+ SDPERR("Unexpected end of packet");
+ status = -1;
+ goto end;
+ }
+
rsp_count = 0;
rsphdr = (sdp_pdu_hdr_t *) rspbuf;
if (rsphdr->pdu_id == SDP_ERROR_RSP) {
@@ -3107,12 +3351,25 @@
goto end;
}
pdata = rspbuf + sizeof(sdp_pdu_hdr_t);
+ bytesleft -= sizeof(sdp_pdu_hdr_t);
+
+ if (bytesleft < sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ status = -1;
+ goto end;
+ }
rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
attr_list_len += rsp_count;
pdata += sizeof(uint16_t);
+ bytesleft -= sizeof(uint16_t);
// if continuation state set need to re-issue request before parsing
- cstate_len = *(uint8_t *) (pdata + rsp_count);
+ if (bytesleft < rsp_count + sizeof(uint8_t)) {
+ SDPERR("Unexpected end of packet: continuation state data missing");
+ status = -1;
+ goto end;
+ }
+ cstate_len = *(uint8_t *) (pdata + rsp_count);
SDPDBG("Response id : %d\n", rsphdr->pdu_id);
SDPDBG("Attrlist byte count : %d\n", rsp_count);
@@ -3138,9 +3395,11 @@
if (attr_list_len > 0) {
int scanned = 0;
- if (rsp_concat_buf.data_size != 0)
+ if (rsp_concat_buf.data_size != 0) {
pdata = rsp_concat_buf.data;
- rec = sdp_extract_pdu(pdata, &scanned);
+ bytesleft = rsp_concat_buf.data_size;
+ }
+ rec = sdp_extract_pdu(pdata, &scanned, bytesleft);
if (!rec)
status = -1;
@@ -3269,6 +3528,7 @@
sdp_pdu_hdr_t *reqhdr;
uint8_t *pdata;
int cstate_len, seqlen = 0;
+ int pdata_len;
if (!session || !session->priv)
return -1;
@@ -3296,6 +3556,7 @@
// generate PDU
pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
t->reqsize = sizeof(sdp_pdu_hdr_t);
+ pdata_len = SDP_REQ_BUFFER_SIZE - t->reqsize;
// add service class IDs for search
seqlen = gen_searchseq_pdu(pdata, search);
@@ -3305,13 +3566,15 @@
// now set the length and increment the pointer
t->reqsize += seqlen;
pdata += seqlen;
+ pdata_len -= seqlen;
bt_put_unaligned(htons(max_rec_num), (uint16_t *) pdata);
t->reqsize += sizeof(uint16_t);
pdata += sizeof(uint16_t);
+ pdata_len -= sizeof(uint16_t);
// set the request header's param length
- cstate_len = copy_cstate(pdata, NULL);
+ cstate_len = copy_cstate(pdata, pdata_len, NULL);
reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
@@ -3373,6 +3636,7 @@
sdp_pdu_hdr_t *reqhdr;
uint8_t *pdata;
int cstate_len, seqlen = 0;
+ int pdata_len;
if (!session || !session->priv)
return -1;
@@ -3400,16 +3664,19 @@
// generate PDU
pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
t->reqsize = sizeof(sdp_pdu_hdr_t);
+ pdata_len = SDP_REQ_BUFFER_SIZE - t->reqsize;
// add the service record handle
bt_put_unaligned(htonl(handle), (uint32_t *) pdata);
t->reqsize += sizeof(uint32_t);
pdata += sizeof(uint32_t);
+ pdata_len -= sizeof(uint32_t);
// specify the response limit
bt_put_unaligned(htons(65535), (uint16_t *) pdata);
t->reqsize += sizeof(uint16_t);
pdata += sizeof(uint16_t);
+ pdata_len -= sizeof(uint16_t);
// get attr seq PDU form
seqlen = gen_attridseq_pdu(pdata, attrid_list,
@@ -3422,10 +3689,11 @@
// now set the length and increment the pointer
t->reqsize += seqlen;
pdata += seqlen;
+ pdata_len -= seqlen;
SDPDBG("Attr list length : %d\n", seqlen);
// set the request header's param length
- cstate_len = copy_cstate(pdata, NULL);
+ cstate_len = copy_cstate(pdata, pdata_len, NULL);
reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
@@ -3488,6 +3756,7 @@
sdp_pdu_hdr_t *reqhdr;
uint8_t *pdata;
int cstate_len, seqlen = 0;
+ int pdata_len;
if (!session || !session->priv)
return -1;
@@ -3515,6 +3784,7 @@
// generate PDU
pdata = t->reqbuf + sizeof(sdp_pdu_hdr_t);
t->reqsize = sizeof(sdp_pdu_hdr_t);
+ pdata_len = SDP_REQ_BUFFER_SIZE - t->reqsize;
// add service class IDs for search
seqlen = gen_searchseq_pdu(pdata, search);
@@ -3524,10 +3794,12 @@
// now set the length and increment the pointer
t->reqsize += seqlen;
pdata += seqlen;
+ pdata_len -= seqlen;
bt_put_unaligned(htons(SDP_MAX_ATTR_LEN), (uint16_t *) pdata);
t->reqsize += sizeof(uint16_t);
pdata += sizeof(uint16_t);
+ pdata_len -= sizeof(uint16_t);
SDPDBG("Max attr byte count : %d\n", SDP_MAX_ATTR_LEN);
@@ -3540,11 +3812,12 @@
}
pdata += seqlen;
+ pdata_len -= seqlen;
SDPDBG("Attr list length : %d\n", seqlen);
t->reqsize += seqlen;
// set the request header's param length
- cstate_len = copy_cstate(pdata, NULL);
+ cstate_len = copy_cstate(pdata, pdata_len, NULL);
reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
@@ -3757,7 +4030,7 @@
reqhdr->tid = htons(sdp_gen_tid(session));
// add continuation state
- cstate_len = copy_cstate(t->reqbuf + t->reqsize, pcstate);
+ cstate_len = copy_cstate(t->reqbuf + t->reqsize, SDP_REQ_BUFFER_SIZE - t->reqsize, pcstate);
reqsize = t->reqsize + cstate_len;
@@ -3838,12 +4111,14 @@
int seqlen = 0, attr_list_len = 0;
int rsp_count = 0, cstate_len = 0;
uint8_t *pdata, *_pdata;
+ int _pdata_len;
uint8_t *reqbuf, *rspbuf;
sdp_pdu_hdr_t *reqhdr, *rsphdr;
uint8_t dataType;
sdp_list_t *rec_list = NULL;
sdp_buf_t rsp_concat_buf;
sdp_cstate_t *cstate = NULL;
+ int bytesleft;
if (reqtype != SDP_ATTR_REQ_INDIVIDUAL && reqtype != SDP_ATTR_REQ_RANGE) {
errno = EINVAL;
@@ -3895,12 +4170,13 @@
// save before Continuation State
_pdata = pdata;
_reqsize = reqsize;
+ _pdata_len = SDP_REQ_BUFFER_SIZE - reqsize;
do {
reqhdr->tid = htons(sdp_gen_tid(session));
// add continuation state (can be null)
- reqsize = _reqsize + copy_cstate(_pdata, cstate);
+ reqsize = _reqsize + copy_cstate(_pdata, _pdata_len, cstate);
// set the request header's param length
reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
@@ -3910,6 +4186,13 @@
SDPDBG("Status : 0x%x\n", rsphdr->pdu_id);
goto end;
}
+
+ bytesleft = rspsize;
+ if (bytesleft < sizeof(sdp_pdu_hdr_t)) {
+ SDPERR("Unexpected end of packet");
+ status = -1;
+ goto end;
+ }
if (rsphdr->pdu_id == SDP_ERROR_RSP) {
status = -1;
@@ -3917,9 +4200,25 @@
}
pdata = rspbuf + sizeof(sdp_pdu_hdr_t);
+ bytesleft -= sizeof(sdp_pdu_hdr_t);
+
+ if (bytesleft < sizeof(uint16_t)) {
+ SDPERR("Unexpected end of packet");
+ status = -1;
+ goto end;
+ }
+
rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
attr_list_len += rsp_count;
pdata += sizeof(uint16_t); // pdata points to attribute list
+ bytesleft -= sizeof(uint16_t);
+
+ if (bytesleft < rsp_count) {
+ SDPERR("Unexpected end of packet: continuation state data missing");
+ status = -1;
+ goto end;
+ }
+
cstate_len = *(uint8_t *) (pdata + rsp_count);
SDPDBG("Attrlist byte count : %d\n", attr_list_len);
@@ -3946,24 +4245,27 @@
if (attr_list_len > 0) {
int scanned = 0;
- if (rsp_concat_buf.data_size != 0)
+ if (rsp_concat_buf.data_size != 0) {
pdata = rsp_concat_buf.data;
+ bytesleft = rsp_concat_buf.data_size;
+ }
/*
* Response is a sequence of sequence(s) for one or
* more data element sequence(s) representing services
* for which attributes are returned
*/
- scanned = sdp_extract_seqtype(pdata, &dataType, &seqlen);
+ scanned = sdp_extract_seqtype(pdata, &dataType, &seqlen, bytesleft);
SDPDBG("Bytes scanned : %d\n", scanned);
SDPDBG("Seq length : %d\n", seqlen);
if (scanned && seqlen) {
pdata += scanned;
+ bytesleft -= scanned;
do {
int recsize = 0;
- sdp_record_t *rec = sdp_extract_pdu(pdata, &recsize);
+ sdp_record_t *rec = sdp_extract_pdu(pdata, &recsize, bytesleft);
if (rec == NULL) {
SDPERR("SVC REC is null\n");
status = -1;
@@ -3975,6 +4277,7 @@
}
scanned += recsize;
pdata += recsize;
+ bytesleft -= recsize;
SDPDBG("Loc seq length : %d\n", recsize);
SDPDBG("Svc Rec Handle : 0x%x\n", rec->handle);
diff -ur bluetooth.orig/bluez-utils-3.30/audio/headset.c bluetooth/bluez-utils-3.30/audio/headset.c
--- bluetooth.orig/bluez-utils-3.30/audio/headset.c 2008-06-13 13:36:14.201284000 -0700
+++ bluetooth/bluez-utils-3.30/audio/headset.c 2008-06-13 12:37:15.957158000 -0700
@@ -848,7 +848,7 @@
goto failed_not_supported;
}
- record = sdp_extract_pdu(array, &record_len);
+ record = sdp_extract_pdu(array, &record_len, array_len);
if (!record) {
error("Unable to extract service record from reply");
goto failed_not_supported;
diff -ur bluetooth.orig/bluez-utils-3.30/audio/manager.c bluetooth/bluez-utils-3.30/audio/manager.c
--- bluetooth.orig/bluez-utils-3.30/audio/manager.c 2008-06-13 13:36:14.204281000 -0700
+++ bluetooth/bluez-utils-3.30/audio/manager.c 2008-06-13 12:37:44.757153000 -0700
@@ -419,7 +419,7 @@
goto failed;
}
- record = sdp_extract_pdu(array, &record_len);
+ record = sdp_extract_pdu(array, &record_len, array_len);
if (!record) {
error("Unable to extract service record from reply");
goto done;
diff -ur bluetooth.orig/bluez-utils-3.30/common/glib-helper.c bluetooth/bluez-utils-3.30/common/glib-helper.c
--- bluetooth.orig/bluez-utils-3.30/common/glib-helper.c 2008-06-13 13:36:14.300310000 -0700
+++ bluetooth/bluez-utils-3.30/common/glib-helper.c 2008-06-13 12:25:08.683864000 -0700
@@ -62,23 +62,25 @@
int scanned, seqlen = 0;
uint8_t dataType;
int err = 0;
+ int bytesleft = size;
if (status || type != SDP_SVC_SEARCH_ATTR_RSP) {
err = -EPROTO;
goto done;
}
- scanned = sdp_extract_seqtype(rsp, &dataType, &seqlen);
+ scanned = sdp_extract_seqtype(rsp, &dataType, &seqlen, bytesleft);
if (!scanned || !seqlen)
goto done;
rsp += scanned;
+ bytesleft -= scanned;
do {
sdp_record_t *rec;
int recsize;
recsize = 0;
- rec = sdp_extract_pdu(rsp, &recsize);
+ rec = sdp_extract_pdu(rsp, &recsize, bytesleft);
if (!rec)
break;
@@ -89,6 +91,7 @@
scanned += recsize;
rsp += recsize;
+ bytesleft -= recsize;
recs = sdp_list_append(recs, rec);
} while (scanned < size);
diff -ur bluetooth.orig/bluez-utils-3.30/hcid/dbus-database.c bluetooth/bluez-utils-3.30/hcid/dbus-database.c
--- bluetooth.orig/bluez-utils-3.30/hcid/dbus-database.c 2008-06-13 13:36:14.708148000 -0700
+++ bluetooth/bluez-utils-3.30/hcid/dbus-database.c 2008-06-13 12:27:57.935715000 -0700
@@ -107,7 +107,7 @@
if (len <= 0)
return error_invalid_arguments(conn, msg, NULL);
- sdp_record = sdp_extract_pdu(record, &scanned);
+ sdp_record = sdp_extract_pdu(record, &scanned, len);
if (!sdp_record) {
error("Parsing of service record failed");
return error_failed_errno(conn, msg, EIO);
@@ -253,7 +253,7 @@
if (!user_record)
return error_not_available(conn, msg);
- sdp_record = sdp_extract_pdu(bin_record, &scanned);
+ sdp_record = sdp_extract_pdu(bin_record, &scanned, size);
if (!sdp_record) {
error("Parsing of service record failed");
return error_invalid_arguments(conn, msg, NULL);
diff -ur bluetooth.orig/bluez-utils-3.30/hcid/dbus-sdp.c bluetooth/bluez-utils-3.30/hcid/dbus-sdp.c
--- bluetooth.orig/bluez-utils-3.30/hcid/dbus-sdp.c 2008-06-13 13:36:14.711144000 -0700
+++ bluetooth/bluez-utils-3.30/hcid/dbus-sdp.c 2008-06-13 13:25:14.830806000 -0700
@@ -494,7 +494,7 @@
dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
DBUS_TYPE_BYTE_AS_STRING, &array_iter);
- rec = sdp_extract_pdu(rsp, &scanned);
+ rec = sdp_extract_pdu(rsp, &scanned, size);
if (rec == NULL || size != scanned) {
error("Invalid service record!");
goto done;
@@ -563,7 +563,7 @@
reply = dbus_message_new_method_return(ctxt->rq);
- rec = sdp_extract_pdu(rsp, &scanned);
+ rec = sdp_extract_pdu(rsp, &scanned, size);
if (rec == NULL || size != scanned) {
error("Invalid service record!");
goto done;
@@ -731,6 +731,7 @@
GSList *l = NULL;
int scanned, extracted = 0, len = 0, recsize = 0;
uint8_t dtd = 0;
+ int bytesleft = (int)size;
if (!ctxt)
return;
@@ -766,16 +767,18 @@
DBUS_TYPE_STRING, &dst,
DBUS_TYPE_INVALID);
- scanned = sdp_extract_seqtype(rsp, &dtd, &len);
+ scanned = sdp_extract_seqtype(rsp, &dtd, &len, bytesleft);
rsp += scanned;
+ bytesleft -= scanned;
for (; extracted < len; rsp += recsize, extracted += recsize) {
sdp_record_t *rec;
sdp_data_t *d;
recsize = 0;
- rec = sdp_extract_pdu(rsp, &recsize);
+ rec = sdp_extract_pdu(rsp, &recsize, bytesleft);
if (!rec)
break;
+ bytesleft -= recsize;
sdp_store_record(src, dst, rec->handle, rsp, recsize);
diff -ur bluetooth.orig/bluez-utils-3.30/input/manager.c bluetooth/bluez-utils-3.30/input/manager.c
--- bluetooth.orig/bluez-utils-3.30/input/manager.c 2008-06-13 13:36:15.400156000 -0700
+++ bluetooth/bluez-utils-3.30/input/manager.c 2008-06-13 12:39:37.109807000 -0700
@@ -536,7 +536,7 @@
goto fail;
}
- pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned);
+ pr->hid_rec = sdp_extract_pdu(rec_bin, &scanned, len);
if (!pr->hid_rec) {
error_not_supported(pr->conn, pr->msg);
goto fail;
@@ -673,7 +673,7 @@
goto fail;
}
- pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned);
+ pr->pnp_rec = sdp_extract_pdu(rec_bin, &scanned, len);
if (get_handles(pr, hid_uuid, hid_handle_reply) < 0) {
error_not_supported(pr->conn, pr->msg);
error("HID service search request failed");
@@ -793,7 +793,7 @@
goto fail;
}
- rec = sdp_extract_pdu(rec_bin, &scanned);
+ rec = sdp_extract_pdu(rec_bin, &scanned, len);
if (!rec) {
error_not_supported(pr->conn, pr->msg);
goto fail;
diff -ur bluetooth.orig/bluez-utils-3.30/network/manager.c bluetooth/bluez-utils-3.30/network/manager.c
--- bluetooth.orig/bluez-utils-3.30/network/manager.c 2008-06-13 13:36:15.503140000 -0700
+++ bluetooth/bluez-utils-3.30/network/manager.c 2008-06-13 12:40:13.287871000 -0700
@@ -253,7 +253,7 @@
goto fail;
}
- rec = sdp_extract_pdu(rec_bin, &scanned);
+ rec = sdp_extract_pdu(rec_bin, &scanned, len);
/* Concat remote name and service name */
memset(name, 0, MAX_NAME_SIZE);
diff -ur bluetooth.orig/bluez-utils-3.30/sdpd/request.c bluetooth/bluez-utils-3.30/sdpd/request.c
--- bluetooth.orig/bluez-utils-3.30/sdpd/request.c 2008-06-13 13:36:15.720000000 -0700
+++ bluetooth/bluez-utils-3.30/sdpd/request.c 2008-06-13 13:30:53.543764000 -0700
@@ -67,8 +67,9 @@
uint8_t dataType;
int status = 0;
const uint8_t *p;
+ int bytesleft = len;
- scanned = sdp_extract_seqtype(buf, &seqType, &data_size);
+ scanned = sdp_extract_seqtype(buf, &seqType, &data_size, bytesleft);
debug("Seq type : %d", seqType);
if (!scanned || (seqType != SDP_SEQ8 && seqType != SDP_SEQ16)) {
@@ -76,12 +77,18 @@
return -1;
}
p = buf + scanned;
+ bytesleft -= scanned;
debug("Data size : %d", data_size);
for (;;) {
char *pElem = NULL;
int localSeqLength = 0;
+
+ if (bytesleft < sizeof(uint8_t)) {
+ debug("->Unexpected end of buffer");
+ return -1;
+ }
dataType = *(uint8_t *)p;
debug("Data type: 0x%02x", dataType);
@@ -100,6 +107,12 @@
case SDP_UINT16:
p += sizeof(uint8_t);
seqlen += sizeof(uint8_t);
+ bytesleft -= sizeof(uint8_t);
+ if (bytesleft < sizeof(uint16_t)) {
+ debug("->Unexpected end of buffer");
+ return -1;
+ }
+
pElem = malloc(sizeof(uint16_t));
bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem);
p += sizeof(uint16_t);
@@ -108,7 +121,13 @@
case SDP_UINT32:
p += sizeof(uint8_t);
seqlen += sizeof(uint8_t);
- pElem = malloc(sizeof(uint32_t));
+ bytesleft -= sizeof(uint8_t);
+ if (bytesleft < sizeof(uint32_t)) {
+ debug("->Unexpected end of buffer");
+ return -1;
+ }
+
+ pElem = malloc(sizeof(uint32_t));
bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem);
p += sizeof(uint32_t);
seqlen += sizeof(uint32_t);
@@ -117,10 +136,11 @@
case SDP_UUID32:
case SDP_UUID128:
pElem = malloc(sizeof(uuid_t));
- status = sdp_uuid_extract(p, (uuid_t *)pElem, &localSeqLength);
+ status = sdp_uuid_extract(p, (uuid_t *)pElem, &localSeqLength, bytesleft);
if (status == 0) {
seqlen += localSeqLength;
p += localSeqLength;
+ bytesleft -= localSeqLength;
}
break;
default:
diff -ur bluetooth.orig/bluez-utils-3.30/sdpd/service.c bluetooth/bluez-utils-3.30/sdpd/service.c
--- bluetooth.orig/bluez-utils-3.30/sdpd/service.c 2008-06-13 13:36:15.716011000 -0700
+++ bluetooth/bluez-utils-3.30/sdpd/service.c 2008-06-13 12:53:10.911126000 -0700
@@ -412,7 +412,7 @@
}
// FIXME: refactor for server-side
-static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p, uint32_t handleExpected, int *scanned)
+static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p, uint32_t handleExpected, int *scanned, int bytesleft)
{
int extractStatus = -1, localExtractedLength = 0;
uint8_t dtd;
@@ -422,8 +422,9 @@
sdp_data_t *pAttr = NULL;
uint32_t handle = 0xffffffff;
- *scanned = sdp_extract_seqtype(p, &dtd, &seqlen);
+ *scanned = sdp_extract_seqtype(p, &dtd, &seqlen, bytesleft);
p += *scanned;
+ bytesleft -= *scanned;
lookAheadAttrId = ntohs(bt_get_unaligned((uint16_t *) (p + sizeof(uint8_t))));
debug("Look ahead attr id : %d", lookAheadAttrId);
@@ -464,7 +465,7 @@
debug("DTD of attrId : %d Attr id : 0x%x", dtd, attrId);
- pAttr = sdp_extract_attr(p + attrSize, &attrValueLength, rec);
+ pAttr = sdp_extract_attr(p + attrSize, &attrValueLength, rec, bytesleft - attrSize);
debug("Attr id : 0x%x attrValueLength : %d", attrId, attrValueLength);
@@ -475,6 +476,7 @@
}
localExtractedLength += attrSize;
p += attrSize;
+ bytesleft -= attrSize;
sdp_attr_replace(rec, attrId, pAttr);
extractStatus = 0;
debug("Extract PDU, seqLength: %d localExtractedLength: %d",
@@ -500,15 +502,17 @@
sdp_data_t *handle;
uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
sdp_record_t *rec;
+ int bytesleft = req->len - sizeof(sdp_pdu_hdr_t);
req->flags = *p++;
if (req->flags & SDP_DEVICE_RECORD) {
bacpy(&req->device, (bdaddr_t *) p);
p += sizeof(bdaddr_t);
+ bytesleft -= sizeof(bdaddr_t);
}
// save image of PDU: we need it when clients request this attribute
- rec = extract_pdu_server(&req->device, p, 0xffffffff, &scanned);
+ rec = extract_pdu_server(&req->device, p, 0xffffffff, &scanned, bytesleft);
if (!rec)
goto invalid;
@@ -578,18 +582,20 @@
sdp_record_t *orec;
int status = 0, scanned = 0;
uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
+ int bytesleft = req->len - sizeof(sdp_pdu_hdr_t);
uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
debug("Svc Rec Handle: 0x%x", handle);
p += sizeof(uint32_t);
+ bytesleft -= sizeof(uint32_t);
orec = sdp_record_find(handle);
debug("SvcRecOld: %p", orec);
if (orec) {
- sdp_record_t *nrec = extract_pdu_server(BDADDR_ANY, p, handle, &scanned);
+ sdp_record_t *nrec = extract_pdu_server(BDADDR_ANY, p, handle, &scanned, bytesleft);
if (nrec && handle == nrec->handle) {
update_db_timestamp();
update_svclass_list();
diff -ur bluetooth.orig/bluez-utils-3.30/serial/manager.c bluetooth/bluez-utils-3.30/serial/manager.c
--- bluetooth.orig/bluez-utils-3.30/serial/manager.c 2008-06-13 13:36:15.779001000 -0700
+++ bluetooth/bluez-utils-3.30/serial/manager.c 2008-06-13 12:40:48.550090000 -0700
@@ -520,7 +520,7 @@
goto fail;
}
- rec = sdp_extract_pdu(rec_bin, &scanned);
+ rec = sdp_extract_pdu(rec_bin, &scanned, len);
if (!rec) {
error("Can't extract SDP record.");
error_not_supported(pc->conn, pc->msg);
[-- Attachment #3: Type: text/plain, Size: 247 bytes --]
-------------------------------------------------------------------------
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
[-- Attachment #4: Type: text/plain, Size: 164 bytes --]
_______________________________________________
Bluez-devel mailing list
Bluez-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/bluez-devel
next prev parent reply other threads:[~2008-06-16 20:49 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-06-16 20:27 [Bluez-devel] SDP payload processing vulnerability Glenn Durfee
2008-06-16 20:49 ` Glenn Durfee [this message]
2008-06-16 20:59 ` Marcel Holtmann
2008-06-16 21:21 ` Glenn Durfee
2008-06-16 21:37 ` Marcel Holtmann
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=b32d44000806161349x20323e9eg84072c277b6bd2e8@mail.gmail.com \
--to=gdurfee@google.com \
--cc=bluez-devel@lists.sourceforge.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox