diff options
| author | Marcel Holtmann <marcel@holtmann.org> | 2008-06-20 03:30:53 +0000 | 
|---|---|---|
| committer | Marcel Holtmann <marcel@holtmann.org> | 2008-06-20 03:30:53 +0000 | 
| commit | a3648e0df0ff53fef74e5437ff089aef96209db2 (patch) | |
| tree | 75f26b20aac5eaeb9d8cf54f4fd90f7dcf4b1c1e /src | |
| parent | 5e4c3e1a8fdab9ac8a45ef0e80cd045421c73621 (diff) | |
Add more safe version of three low-level extraction functions
Diffstat (limited to 'src')
| -rw-r--r-- | src/sdp.c | 299 | 
1 files changed, 220 insertions, 79 deletions
| @@ -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 void *p, int *len)  	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 void *p, int *len)  	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 uint8_t *p, int *len, sdp_record_t *rec)  /*   * 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 void *p, int *len)  		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 void *p, int *len)  	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 void *p, int *len, sdp_record_t *rec)  	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 void *p, int *len, sdp_record_t *rec)  		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 void *p, int *len, sdp_record_t *rec)  	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_t *p, int *size, sdp_record_t *rec)  	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_t *p, int *size, sdp_record_t *rec)  	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_t *p, int *size, sdp_record_t *rec)  	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_t *p, int *size, sdp_record_t *rec)  	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)  { @@ -1262,40 +1463,6 @@ sdp_data_t *sdp_data_get(const sdp_record_t *rec, uint16_t attrId)  	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; @@ -2329,32 +2496,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. @@ -2792,7 +2933,7 @@ static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd)  	// Fill up the value and the dtd arrays  	SDPDBG(""); -	 +  	memset(&buf, 0, sizeof(sdp_buf_t));  	buf.data = malloc(256);  	buf.buf_size = 256; @@ -2986,7 +3127,7 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,  		}  	} while (cstate); -  end: +end:  	if (reqbuf)  		free(reqbuf);  	if (rspbuf) @@ -3146,7 +3287,7 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,  			status = -1;  	} -  end: +end:  	if (reqbuf)  		free(reqbuf);  	if (rsp_concat_buf.data) | 
