--- bluez-libs-3.28/src/sdp.c.cve-2008-2374 2008-03-05 15:15:11.000000000 -0500 +++ bluez-libs-3.28/src/sdp.c 2008-07-14 15:51:24.000000000 -0400 @@ -904,15 +904,76 @@ void sdp_data_free(sdp_data_t *d) free(d); } -static sdp_data_t *extract_int(const void *p, int *len) +int sdp_uuid_extract_safe(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned) { - sdp_data_t *d = malloc(sizeof(sdp_data_t)); + uint8_t type; + + if (bufsize < 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); + return -1; + } + p += sizeof(uint8_t); + *scanned += sizeof(uint8_t); + bufsize -= sizeof(uint8_t); + if (type == SDP_UUID16) { + if (bufsize < sizeof(uint16_t)) { + SDPERR("Not enough room for 16-bit UUID"); + return -1; + } + sdp_uuid16_create(uuid, ntohs(bt_get_unaligned((uint16_t *) p))); + *scanned += sizeof(uint16_t); + p += sizeof(uint16_t); + } else if (type == SDP_UUID32) { + if (bufsize < sizeof(uint32_t)) { + SDPERR("Not enough room for 32-bit UUID"); + return -1; + } + sdp_uuid32_create(uuid, ntohl(bt_get_unaligned((uint32_t *) p))); + *scanned += sizeof(uint32_t); + p += sizeof(uint32_t); + } else { + if (bufsize < sizeof(uint128_t)) { + SDPERR("Not enough room for 128-bit UUID"); + return -1; + } + sdp_uuid128_create(uuid, p); + *scanned += sizeof(uint128_t); + p += sizeof(uint128_t); + } + return 0; +} + +int sdp_uuid_extract(const uint8_t *p, uuid_t *uuid, int *scanned) +{ + /* Assume p points to a buffer of size at least SDP_MAX_ATTR_LEN, + because we don't have any better information */ + return sdp_uuid_extract_safe(p, SDP_MAX_ATTR_LEN, uuid, scanned); +} + +static sdp_data_t *extract_int(const void *p, int bufsize, int *len) +{ + sdp_data_t *d; + + if (bufsize < sizeof(uint8_t)) { + SDPERR("Unexpected end of packet"); + return NULL; + } + + d = malloc(sizeof(sdp_data_t)); SDPDBG("Extracting integer\n"); memset(d, 0, sizeof(sdp_data_t)); d->dtd = *(uint8_t *) p; p += sizeof(uint8_t); *len += sizeof(uint8_t); + bufsize -= sizeof(uint8_t); switch (d->dtd) { case SDP_DATA_NIL: @@ -920,26 +981,51 @@ static sdp_data_t *extract_int(const voi case SDP_BOOL: case SDP_INT8: case SDP_UINT8: + if (bufsize < sizeof(uint8_t)) { + SDPERR("Unexpected end of packet"); + free(d); + return NULL; + } *len += sizeof(uint8_t); d->val.uint8 = *(uint8_t *) p; break; case SDP_INT16: case SDP_UINT16: + if (bufsize < sizeof(uint16_t)) { + SDPERR("Unexpected end of packet"); + free(d); + return NULL; + } *len += sizeof(uint16_t); d->val.uint16 = ntohs(bt_get_unaligned((uint16_t *) p)); break; case SDP_INT32: case SDP_UINT32: + if (bufsize < sizeof(uint32_t)) { + SDPERR("Unexpected end of packet"); + free(d); + return NULL; + } *len += sizeof(uint32_t); d->val.uint32 = ntohl(bt_get_unaligned((uint32_t *) p)); break; case SDP_INT64: case SDP_UINT64: + if (bufsize < sizeof(uint64_t)) { + SDPERR("Unexpected end of packet"); + free(d); + return NULL; + } *len += sizeof(uint64_t); d->val.uint64 = ntoh64(bt_get_unaligned((uint64_t *) p)); break; case SDP_INT128: case SDP_UINT128: + if (bufsize < sizeof(uint128_t)) { + SDPERR("Unexpected end of packet"); + free(d); + return NULL; + } *len += sizeof(uint128_t); ntoh128((uint128_t *) p, &d->val.uint128); break; @@ -950,13 +1036,13 @@ static sdp_data_t *extract_int(const voi 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 bufsize, int *len, sdp_record_t *rec) { 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_safe(p, bufsize, &d->val.uuid, len) < 0) { free(d); return NULL; } @@ -969,29 +1055,49 @@ static sdp_data_t *extract_uuid(const ui /* * 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 bufsize, int *len) { char *s; int n; - sdp_data_t *d = malloc(sizeof(sdp_data_t)); + sdp_data_t *d; + + if (bufsize < sizeof(uint8_t)) { + SDPERR("Unexpected end of packet"); + return NULL; + } + + d = malloc(sizeof(sdp_data_t)); memset(d, 0, sizeof(sdp_data_t)); d->dtd = *(uint8_t *) p; p += sizeof(uint8_t); *len += sizeof(uint8_t); + bufsize -= sizeof(uint8_t); switch (d->dtd) { case SDP_TEXT_STR8: case SDP_URL_STR8: + if (bufsize < sizeof(uint8_t)) { + SDPERR("Unexpected end of packet"); + free(d); + return NULL; + } n = *(uint8_t *) p; p += sizeof(uint8_t); - *len += sizeof(uint8_t) + n; + *len += sizeof(uint8_t); + bufsize -= sizeof(uint8_t); break; case SDP_TEXT_STR16: case SDP_URL_STR16: + if (bufsize < sizeof(uint16_t)) { + SDPERR("Unexpected end of packet"); + free(d); + return NULL; + } n = ntohs(bt_get_unaligned((uint16_t *) p)); p += sizeof(uint16_t); *len += sizeof(uint16_t) + n; + bufsize -= sizeof(uint16_t); break; default: SDPERR("Sizeof text string > UINT16_MAX\n"); @@ -999,10 +1105,23 @@ static sdp_data_t *extract_str(const voi return 0; } + if (bufsize < n) { + SDPERR("String too long to fit in packet"); + free(d); + return NULL; + } + s = malloc(n + 1); + if (!s) { + SDPERR("Not enough memory for incoming string"); + free(d); + return NULL; + } memset(s, 0, n + 1); memcpy(s, p, n); + *len += n; + SDPDBG("Len : %d\n", n); SDPDBG("Str : %s\n", s); @@ -1011,7 +1130,67 @@ static sdp_data_t *extract_str(const voi return d; } -static sdp_data_t *extract_seq(const void *p, int *len, sdp_record_t *rec) +/* + * Extract the sequence type and its length, and return offset into buf + * or 0 on failure. + */ +int sdp_extract_seqtype_safe(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size) +{ + uint8_t dtd; + int scanned = sizeof(uint8_t); + + if (bufsize < sizeof(uint8_t)) { + SDPERR("Unexpected end of packet"); + return 0; + } + + dtd = *(uint8_t *) buf; + buf += sizeof(uint8_t); + bufsize -= sizeof(uint8_t); + *dtdp = dtd; + switch (dtd) { + case SDP_SEQ8: + case SDP_ALT8: + if (bufsize < 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 (bufsize < 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 (bufsize < sizeof(uint32_t)) { + SDPERR("Unexpected end of packet"); + return 0; + } + *size = ntohl(bt_get_unaligned((uint32_t *) buf)); + scanned += sizeof(uint32_t); + break; + default: + SDPERR("Unknown sequence type, aborting\n"); + return 0; + } + return scanned; +} + +int sdp_extract_seqtype(const uint8_t *buf, uint8_t *dtdp, int *size) +{ + /* Assume buf points to a buffer of size at least SDP_MAX_ATTR_LEN, + because we don't have any better information */ + return sdp_extract_seqtype_safe(buf, SDP_MAX_ATTR_LEN, dtdp, size); +} + +static sdp_data_t *extract_seq(const void *p, int bufsize, int *len, sdp_record_t *rec) { int seqlen, n = 0; sdp_data_t *curr, *prev; @@ -1019,17 +1198,24 @@ static sdp_data_t *extract_seq(const voi SDPDBG("Extracting SEQ"); memset(d, 0, sizeof(sdp_data_t)); - *len = sdp_extract_seqtype(p, &d->dtd, &seqlen); + *len = sdp_extract_seqtype_safe(p, bufsize, &d->dtd, &seqlen); SDPDBG("Sequence Type : 0x%x length : 0x%x\n", d->dtd, seqlen); if (*len == 0) return d; + if (*len > bufsize) { + SDPERR("Packet not big enough to hold sequence."); + free(d); + return NULL; + } + p += *len; + bufsize -= *len; curr = prev = NULL; while (n < seqlen) { int attrlen = 0; - curr = sdp_extract_attr(p, &attrlen, rec); + curr = sdp_extract_attr_safe(p, bufsize, &attrlen, rec); if (curr == NULL) break; @@ -1040,6 +1226,7 @@ static sdp_data_t *extract_seq(const voi prev = curr; p += attrlen; n += attrlen; + bufsize -= attrlen; SDPDBG("Extracted: %d SequenceLength: %d", n, seqlen); } @@ -1048,11 +1235,18 @@ static sdp_data_t *extract_seq(const voi return d; } -sdp_data_t *sdp_extract_attr(const uint8_t *p, int *size, sdp_record_t *rec) +sdp_data_t *sdp_extract_attr_safe(const uint8_t *p, int bufsize, int *size, sdp_record_t *rec) { sdp_data_t *elem; int n = 0; - uint8_t dtd = *(const uint8_t *)p; + uint8_t dtd; + + if (bufsize < sizeof(uint8_t)) { + SDPERR("Unexpected end of packet"); + return NULL; + } + + dtd = *(const uint8_t *)p; SDPDBG("extract_attr: dtd=0x%x", dtd); switch (dtd) { @@ -1068,12 +1262,12 @@ sdp_data_t *sdp_extract_attr(const uint8 case SDP_INT32: case SDP_INT64: case SDP_INT128: - elem = extract_int(p, &n); + elem = extract_int(p, bufsize, &n); break; case SDP_UUID16: case SDP_UUID32: case SDP_UUID128: - elem = extract_uuid(p, &n, rec); + elem = extract_uuid(p, bufsize, &n, rec); break; case SDP_TEXT_STR8: case SDP_TEXT_STR16: @@ -1081,7 +1275,7 @@ sdp_data_t *sdp_extract_attr(const uint8 case SDP_URL_STR8: case SDP_URL_STR16: case SDP_URL_STR32: - elem = extract_str(p, &n); + elem = extract_str(p, bufsize, &n); break; case SDP_SEQ8: case SDP_SEQ16: @@ -1089,7 +1283,7 @@ sdp_data_t *sdp_extract_attr(const uint8 case SDP_ALT8: case SDP_ALT16: case SDP_ALT32: - elem = extract_seq(p, &n, rec); + elem = extract_seq(p, bufsize, &n, rec); break; default: SDPERR("Unknown data descriptor : 0x%x terminating\n", dtd); @@ -1099,6 +1293,13 @@ sdp_data_t *sdp_extract_attr(const uint8 return elem; } +sdp_data_t *sdp_extract_attr(const uint8_t *p, int *size, sdp_record_t *rec) +{ + /* Assume p points to a buffer of size at least SDP_MAX_ATTR_LEN, + because we don't have any better information */ + return sdp_extract_attr_safe(p, SDP_MAX_ATTR_LEN, size, rec); +} + #ifdef SDP_DEBUG static void attr_print_func(void *value, void *userData) { @@ -1122,7 +1323,7 @@ void sdp_print_service_attr(sdp_list_t * } #endif -sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int *scanned) +sdp_record_t *sdp_extract_pdu_safe(const uint8_t *buf, int bufsize, int *scanned) { int extracted = 0, seqlen = 0; uint8_t dtd; @@ -1130,21 +1331,30 @@ sdp_record_t *sdp_extract_pdu(const uint sdp_record_t *rec = sdp_record_alloc(); const uint8_t *p = buf; - *scanned = sdp_extract_seqtype(buf, &dtd, &seqlen); + *scanned = sdp_extract_seqtype_safe(buf, bufsize, &dtd, &seqlen); p += *scanned; + bufsize -= *scanned; rec->attrlist = NULL; - while (extracted < seqlen) { + + while (extracted < seqlen && bufsize > 0) { int n = sizeof(uint8_t), attrlen = 0; sdp_data_t *data = NULL; - SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", seqlen, extracted); + SDPDBG("Extract PDU, sequenceLength: %d localExtractedLength: %d", + seqlen, extracted); + + if (bufsize < n + sizeof(uint16_t)) { + SDPERR("Unexpected end of packet"); + break; + } + dtd = *(uint8_t *) p; attr = ntohs(bt_get_unaligned((uint16_t *) (p + n))); n += sizeof(uint16_t); SDPDBG("DTD of attrId : %d Attr id : 0x%x \n", dtd, attr); - data = sdp_extract_attr(p + n, &attrlen, rec); + data = sdp_extract_attr_safe(p + n, bufsize - n, &attrlen, rec); SDPDBG("Attr id : 0x%x attrValueLength : %d\n", attr, attrlen); @@ -1162,9 +1372,11 @@ sdp_record_t *sdp_extract_pdu(const uint extracted += n; p += n; + bufsize -= n; sdp_attr_replace(rec, attr, data); + SDPDBG("Extract PDU, seqLength: %d localExtractedLength: %d", - seqlen, extracted); + seqlen, extracted); } #ifdef SDP_DEBUG SDPDBG("Successful extracting of Svc Rec attributes\n"); @@ -1174,6 +1386,13 @@ sdp_record_t *sdp_extract_pdu(const uint return rec; } +sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int *scanned) +{ + /* Assume buf points to a buffer of size at least SDP_MAX_ATTR_LEN, + because we don't have any better information */ + return sdp_extract_pdu_safe(buf, SDP_MAX_ATTR_LEN, scanned); +} + #ifdef SDP_DEBUG static void print_dataseq(sdp_data_t *p) { @@ -1262,40 +1481,6 @@ sdp_data_t *sdp_data_get(const sdp_recor return NULL; } -/* - * 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) -{ - uint8_t dtd = *(uint8_t *) buf; - int scanned = sizeof(uint8_t); - - buf += sizeof(uint8_t); - *dtdp = dtd; - switch (dtd) { - case SDP_SEQ8: - case SDP_ALT8: - *size = *(uint8_t *) buf; - scanned += sizeof(uint8_t); - break; - case SDP_SEQ16: - case SDP_ALT16: - *size = ntohs(bt_get_unaligned((uint16_t *) buf)); - scanned += sizeof(uint16_t); - break; - case SDP_SEQ32: - case SDP_ALT32: - *size = ntohl(bt_get_unaligned((uint32_t *) buf)); - scanned += sizeof(uint32_t); - break; - default: - SDPERR("Unknown sequence type, aborting\n"); - return 0; - } - return scanned; -} - int sdp_send_req(sdp_session_t *session, uint8_t *buf, uint32_t size) { uint32_t sent = 0; @@ -2328,32 +2513,6 @@ int sdp_uuid_to_proto(uuid_t *uuid) return 0; } -int sdp_uuid_extract(const uint8_t *p, uuid_t *uuid, int *scanned) -{ - uint8_t type = *(const uint8_t *) p; - - if (!SDP_IS_UUID(type)) { - SDPERR("Unknown data type : %d expecting a svc UUID\n", type); - return -1; - } - p += sizeof(uint8_t); - *scanned += sizeof(uint8_t); - if (type == SDP_UUID16) { - sdp_uuid16_create(uuid, ntohs(bt_get_unaligned((uint16_t *) p))); - *scanned += sizeof(uint16_t); - p += sizeof(uint16_t); - } else if (type == SDP_UUID32) { - sdp_uuid32_create(uuid, ntohl(bt_get_unaligned((uint32_t *) p))); - *scanned += sizeof(uint32_t); - p += sizeof(uint32_t); - } else { - sdp_uuid128_create(uuid, p); - *scanned += sizeof(uint128_t); - p += sizeof(uint128_t); - } - return 0; -} - /* * This function appends data to the PDU buffer "dst" from source "src". * The data length is also computed and set. @@ -2483,6 +2642,13 @@ int sdp_device_record_register_binary(sd if (status < 0) goto end; + if (rspsize < sizeof(sdp_pdu_hdr_t)) { + SDPERR("Unexpected end of packet"); + errno = EPROTO; + status = -1; + goto end; + } + rsphdr = (sdp_pdu_hdr_t *) rsp; p = rsp + sizeof(sdp_pdu_hdr_t); @@ -2589,6 +2755,13 @@ int sdp_device_record_unregister_binary( if (status < 0) goto end; + if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint16_t)) { + SDPERR("Unexpected end of packet"); + errno = EPROTO; + status = -1; + goto end; + } + rsphdr = (sdp_pdu_hdr_t *) rspbuf; p = rspbuf + sizeof(sdp_pdu_hdr_t); status = bt_get_unaligned((uint16_t *) p); @@ -2688,6 +2861,13 @@ int sdp_device_record_update(sdp_session if (status < 0) goto end; + if (rspsize < sizeof(sdp_pdu_hdr_t) + sizeof(uint16_t)) { + SDPERR("Unexpected end of packet"); + errno = EPROTO; + status = -1; + goto end; + } + SDPDBG("Send req status : %d\n", status); rsphdr = (sdp_pdu_hdr_t *) rspbuf; @@ -2763,18 +2943,23 @@ void sdp_pattern_add_uuidseq(sdp_record_ * 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, int bufsize, sdp_list_t **seq, int count, int *scanned) { sdp_list_t *pSeq = *seq; uint8_t *pdata = pdu; int n; for (n = 0; n < count; n++) { + if (bufsize < 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); + bufsize -= sizeof(uint32_t); } *seq = pSeq; } @@ -2791,7 +2976,7 @@ static int gen_dataseq_pdu(uint8_t *dst, // Fill up the value and the dtd arrays SDPDBG(""); - + memset(&buf, 0, sizeof(sdp_buf_t)); buf.data = malloc(256); buf.buf_size = 256; @@ -2842,12 +3027,17 @@ typedef struct { 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 (len >= pdata_len) { + SDPERR("Continuation state size exceeds internal buffer"); + len = pdata_len - 1; + } + *pdata++ = len; + memcpy(pdata, cstate->data, len); + return len + 1; } *pdata = 0; return 1; @@ -2889,7 +3079,7 @@ int sdp_service_search_req(sdp_session_t uint32_t reqsize = 0, _reqsize; uint32_t rspsize = 0, rsplen; int seqlen = 0; - int scanned, total_rec_count, rec_count; + int scanned, total_rec_count, rec_count, pdata_len; uint8_t *pdata, *_pdata; uint8_t *reqbuf, *rspbuf; sdp_pdu_hdr_t *reqhdr, *rsphdr; @@ -2927,7 +3117,8 @@ int sdp_service_search_req(sdp_session_t do { // Add continuation state or NULL (first time) - reqsize = _reqsize + copy_cstate(_pdata, cstate); + reqsize = _reqsize + copy_cstate(_pdata, + SDP_REQ_BUFFER_SIZE - _reqsize, cstate); // Set the request header's param length reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); @@ -2941,7 +3132,12 @@ int sdp_service_search_req(sdp_session_t if (status < 0) goto end; - rsplen = 0; + if (rspsize < sizeof(sdp_pdu_hdr_t)) { + SDPERR("Unexpected end of packet"); + status = -1; + goto end; + } + rsphdr = (sdp_pdu_hdr_t *) rspbuf; rsplen = ntohs(rsphdr->plen); @@ -2952,14 +3148,23 @@ int sdp_service_search_req(sdp_session_t } scanned = 0; pdata = rspbuf + sizeof(sdp_pdu_hdr_t); + pdata_len = rspsize - sizeof(sdp_pdu_hdr_t); + + if (pdata_len < 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); + pdata_len -= sizeof(uint16_t); rec_count = ntohs(bt_get_unaligned((uint16_t *) pdata)); pdata += sizeof(uint16_t); scanned += sizeof(uint16_t); + pdata_len -= sizeof(uint16_t); SDPDBG("Total svc count: %d\n", total_rec_count); SDPDBG("Current svc count: %d\n", rec_count); @@ -2969,12 +3174,18 @@ int sdp_service_search_req(sdp_session_t status = -1; goto end; } - extract_record_handle_seq(pdata, rsp, rec_count, &scanned); + extract_record_handle_seq(pdata, pdata_len, rsp, rec_count, &scanned); SDPDBG("BytesScanned : %d\n", scanned); if (rsplen > scanned) { uint8_t cstate_len; + if (rspsize < sizeof(sdp_pdu_hdr_t) + scanned + 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) { @@ -2985,7 +3196,7 @@ int sdp_service_search_req(sdp_session_t } } while (cstate); - end: +end: if (reqbuf) free(reqbuf); if (rspbuf) @@ -3033,7 +3244,7 @@ sdp_record_t *sdp_service_attr_req(sdp_s uint32_t reqsize = 0, _reqsize; uint32_t rspsize = 0, rsp_count; int attr_list_len = 0; - int seqlen = 0; + int seqlen = 0, pdata_len; uint8_t *pdata, *_pdata; uint8_t *reqbuf, *rspbuf; sdp_pdu_hdr_t *reqhdr, *rsphdr; @@ -3089,7 +3300,8 @@ sdp_record_t *sdp_service_attr_req(sdp_s do { // add NULL continuation state - reqsize = _reqsize + copy_cstate(_pdata, cstate); + reqsize = _reqsize + copy_cstate(_pdata, + SDP_REQ_BUFFER_SIZE - _reqsize, cstate); // set the request header's param length reqhdr->tid = htons(sdp_gen_tid(session)); @@ -3098,6 +3310,13 @@ sdp_record_t *sdp_service_attr_req(sdp_s status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize); if (status < 0) goto end; + + if (rspsize < 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) { @@ -3106,11 +3325,25 @@ sdp_record_t *sdp_service_attr_req(sdp_s goto end; } pdata = rspbuf + sizeof(sdp_pdu_hdr_t); + pdata_len = rspsize - sizeof(sdp_pdu_hdr_t); + + if (pdata_len < 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_len -= sizeof(uint16_t); // if continuation state set need to re-issue request before parsing + if (pdata_len < 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); @@ -3137,15 +3370,17 @@ sdp_record_t *sdp_service_attr_req(sdp_s 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); + pdata_len = rsp_concat_buf.data_size; + } + rec = sdp_extract_pdu_safe(pdata, pdata_len, &scanned); if (!rec) status = -1; } - end: +end: if (reqbuf) free(reqbuf); if (rsp_concat_buf.data) @@ -3310,7 +3545,7 @@ int sdp_service_search_async(sdp_session pdata += sizeof(uint16_t); // set the request header's param length - cstate_len = copy_cstate(pdata, NULL); + cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, 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) { @@ -3424,7 +3659,7 @@ int sdp_service_attr_async(sdp_session_t 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, SDP_REQ_BUFFER_SIZE - t->reqsize, 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) { @@ -3543,7 +3778,7 @@ int sdp_service_search_attr_async(sdp_se t->reqsize += seqlen; // set the request header's param length - cstate_len = copy_cstate(pdata, NULL); + cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, 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) { @@ -3756,7 +3991,8 @@ int sdp_process(sdp_session_t *session) 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; @@ -3835,7 +4071,7 @@ int sdp_service_search_attr_req(sdp_sess uint32_t reqsize = 0, _reqsize; uint32_t rspsize = 0; int seqlen = 0, attr_list_len = 0; - int rsp_count = 0, cstate_len = 0; + int rsp_count = 0, cstate_len = 0, pdata_len; uint8_t *pdata, *_pdata; uint8_t *reqbuf, *rspbuf; sdp_pdu_hdr_t *reqhdr, *rsphdr; @@ -3899,12 +4135,19 @@ int sdp_service_search_attr_req(sdp_sess reqhdr->tid = htons(sdp_gen_tid(session)); // add continuation state (can be null) - reqsize = _reqsize + copy_cstate(_pdata, cstate); + reqsize = _reqsize + copy_cstate(_pdata, + SDP_REQ_BUFFER_SIZE - _reqsize, cstate); // set the request header's param length reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t)); rsphdr = (sdp_pdu_hdr_t *) rspbuf; status = sdp_send_req_w4_rsp(session, reqbuf, rspbuf, reqsize, &rspsize); + if (rspsize < sizeof(sdp_pdu_hdr_t)) { + SDPERR("Unexpected end of packet"); + status = -1; + goto end; + } + if (status < 0) { SDPDBG("Status : 0x%x\n", rsphdr->pdu_id); goto end; @@ -3916,9 +4159,25 @@ int sdp_service_search_attr_req(sdp_sess } pdata = rspbuf + sizeof(sdp_pdu_hdr_t); + pdata_len = rspsize - sizeof(sdp_pdu_hdr_t); + + if (pdata_len < 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 + pdata_len -= sizeof(uint16_t); + + if (pdata_len < 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("Attrlist byte count : %d\n", attr_list_len); @@ -3945,24 +4204,27 @@ int sdp_service_search_attr_req(sdp_sess 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; + pdata_len = 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_safe(pdata, pdata_len, &dataType, &seqlen); SDPDBG("Bytes scanned : %d\n", scanned); SDPDBG("Seq length : %d\n", seqlen); if (scanned && seqlen) { pdata += scanned; + pdata_len -= scanned; do { int recsize = 0; - sdp_record_t *rec = sdp_extract_pdu(pdata, &recsize); + sdp_record_t *rec = sdp_extract_pdu_safe(pdata, pdata_len, &recsize); if (rec == NULL) { SDPERR("SVC REC is null\n"); status = -1; @@ -3974,13 +4236,14 @@ int sdp_service_search_attr_req(sdp_sess } scanned += recsize; pdata += recsize; + pdata_len -= recsize; SDPDBG("Loc seq length : %d\n", recsize); SDPDBG("Svc Rec Handle : 0x%x\n", rec->handle); SDPDBG("Bytes scanned : %d\n", scanned); SDPDBG("Attrlist byte count : %d\n", attr_list_len); rec_list = sdp_list_append(rec_list, rec); - } while (scanned < attr_list_len); + } while (scanned < attr_list_len && pdata_len > 0); SDPDBG("Successful scan of service attr lists\n"); *rsp = rec_list; --- bluez-libs-3.28/include/sdp_lib.h.cve-2008-2374 2008-02-01 18:14:55.000000000 -0500 +++ bluez-libs-3.28/include/sdp_lib.h 2008-07-14 15:35:49.000000000 -0400 @@ -479,6 +479,7 @@ void sdp_uuid32_to_uuid128(uuid_t *uuid1 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_safe(const uint8_t *buffer, int bufsize, uuid_t *uuid, int *scanned); void sdp_uuid_print(const uuid_t *uuid); #define MAX_LEN_UUID_STR 37 @@ -585,7 +586,7 @@ static inline int sdp_get_icon_url(const } 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_safe(const uint8_t *pdata, int bufsize, int *scanned); void sdp_data_print(sdp_data_t *data); void sdp_print_service_attr(sdp_list_t *alist); @@ -601,8 +602,10 @@ int sdp_gen_pdu(sdp_buf_t *pdu, sdp_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_safe(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *size); sdp_data_t *sdp_extract_attr(const uint8_t *pdata, int *extractedLength, sdp_record_t *rec); +sdp_data_t *sdp_extract_attr_safe(const uint8_t *pdata, int bufsize, int *extractedLength, sdp_record_t *rec); 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);