Feature/app data buffer check (#79)

* Added comments and buffer overflow checks

* Removed backslashs from C-code.
This commit is contained in:
Roy Schneider
2020-04-28 15:45:03 +02:00
committed by GitHub
parent 89929ee802
commit 0abcbea971
20 changed files with 1588 additions and 635 deletions
+107 -41
View File
@@ -40,7 +40,15 @@
/** @file rp.c Encode/Decode Read Property and RP ACKs */
#if BACNET_SVC_RP_A
/* encode service */
/** Encode the service
*
* @param apdu Pointer to the buffer for encoding.
* @param invoke_id Invoke ID
* @param rpdata Pointer to the property data to be encoded.
*
* @return Bytes encoded or zero on error.
*/
int rp_encode_apdu(
uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA *rpdata)
{
@@ -60,6 +68,7 @@ int rp_encode_apdu(
rpdata->object_type, rpdata->object_instance);
apdu_len += len;
}
/* The value should be in the range of 0 to 4194303. */
if (rpdata->object_property <= MAX_BACNET_PROPERTY_ID) {
/* check bounds so that we could create malformed
messages for testing */
@@ -79,7 +88,14 @@ int rp_encode_apdu(
}
#endif
/* decode the service request only */
/** Decode the service request only
*
* @param apdu Pointer to the buffer for encoding.
* @param apdu_len Count of valid bytes inthe buffer.
* @param rpdata Pointer to the property data to be encoded.
*
* @return Bytes decoded or zero on error.
*/
int rp_decode_service_request(
uint8_t *apdu, unsigned apdu_len, BACNET_READ_PROPERTY_DATA *rpdata)
{
@@ -143,7 +159,14 @@ int rp_decode_service_request(
return (int)len;
}
/* alternate method to encode the ack without extra buffer */
/** Alternate method to encode the ack without extra buffer.
*
* @param apdu Pointer to the buffer for encoding.
* @param invoke_id Invoke Id
* @param rpdata Pointer to the property data to be encoded.
*
* @return Bytes decoded or zero on error.
*/
int rp_ack_encode_apdu_init(
uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA *rpdata)
{
@@ -176,7 +199,15 @@ int rp_ack_encode_apdu_init(
return apdu_len;
}
/* note: encode the application tagged data yourself */
/** Encode the closing tag for the object property.
* Note: Encode the application tagged data yourself.
*
* @param apdu Pointer to the buffer for encoding.
* @param invoke_id Invoke Id
* @param rpdata Pointer to the property data to be encoded.
*
* @return Bytes encoded or zero on error.
*/
int rp_ack_encode_apdu_object_property_end(uint8_t *apdu)
{
int apdu_len = 0; /* total length of the apdu, return value */
@@ -188,17 +219,31 @@ int rp_ack_encode_apdu_object_property_end(uint8_t *apdu)
return apdu_len;
}
/** Encode the acknowledge.
*
* @param apdu Pointer to the buffer for encoding.
* @param invoke_id Invoke Id
* @param rpdata Pointer to the property data to be encoded.
*
* @return Bytes encoded or zero on error.
*/
int rp_ack_encode_apdu(
uint8_t *apdu, uint8_t invoke_id, BACNET_READ_PROPERTY_DATA *rpdata)
{
int imax = 0;
int len = 0; /* length of each encoding */
int apdu_len = 0; /* total length of the apdu, return value */
if (apdu) {
/* Do the initial encoding */
apdu_len = rp_ack_encode_apdu_init(apdu, invoke_id, rpdata);
/* propertyValue */
for (len = 0; len < rpdata->application_data_len; len++) {
/* propertyValue
* double check maximum possible */
imax = rpdata->application_data_len;
if (imax > (MAX_APDU - apdu_len - 2)) {
imax = (MAX_APDU - apdu_len - 2);
}
for (len = 0; len < imax; len++) {
apdu[apdu_len++] = rpdata->application_data[len];
}
apdu_len += encode_closing_tag(&apdu[apdu_len], 3);
@@ -231,41 +276,62 @@ int rp_ack_decode_service_request(uint8_t *apdu,
uint32_t property = 0; /* for decoding */
BACNET_UNSIGNED_INTEGER unsigned_value = 0; /* for decoding */
/* FIXME: check apdu_len against the len during decode */
/* Tag 0: Object ID */
if (!decode_is_context_tag(&apdu[0], 0)) {
return -1;
}
len = 1;
len += decode_object_id(&apdu[len], &object_type, &rpdata->object_instance);
rpdata->object_type = object_type;
/* Tag 1: Property ID */
len +=
decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
if (tag_number != 1) {
return -1;
}
len += decode_enumerated(&apdu[len], len_value_type, &property);
rpdata->object_property = (BACNET_PROPERTY_ID)property;
/* Tag 2: Optional Array Index */
tag_len =
decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
if (tag_number == 2) {
len += tag_len;
len += decode_unsigned(&apdu[len], len_value_type, &unsigned_value);
rpdata->array_index = (BACNET_ARRAY_INDEX)unsigned_value;
} else {
rpdata->array_index = BACNET_ARRAY_ALL;
}
/* Tag 3: opening context tag */
if (decode_is_opening_tag_number(&apdu[len], 3)) {
/* a tag number of 3 is not extended so only one octet */
len++;
/* don't decode the application tag number or its data here */
rpdata->application_data = &apdu[len];
rpdata->application_data_len = apdu_len - len - 1 /*closing tag */;
/* len includes the data and the closing tag */
len = apdu_len;
/* Check basics. */
if (apdu && (apdu_len >= 8 /*minimum*/)) {
/* Tag 0: Object ID */
if (!decode_is_context_tag(&apdu[0], 0)) {
return -1;
}
len = 1;
len += decode_object_id(&apdu[len], &object_type, &rpdata->object_instance);
rpdata->object_type = object_type;
/* Tag 1: Property ID */
if (len >= apdu_len) {
return -1;
}
len +=
decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
if (tag_number != 1) {
return -1;
}
if (len >= apdu_len) {
return -1;
}
len += decode_enumerated(&apdu[len], len_value_type, &property);
rpdata->object_property = (BACNET_PROPERTY_ID)property;
/* Tag 2: Optional Array Index */
if (len >= apdu_len) {
return -1;
}
tag_len =
decode_tag_number_and_value(&apdu[len], &tag_number, &len_value_type);
if (tag_number == 2) {
len += tag_len;
len += decode_unsigned(&apdu[len], len_value_type, &unsigned_value);
rpdata->array_index = (BACNET_ARRAY_INDEX)unsigned_value;
} else {
rpdata->array_index = BACNET_ARRAY_ALL;
}
/* Tag 3: opening context tag */
if (len >= apdu_len) {
return -1;
}
if (decode_is_opening_tag_number(&apdu[len], 3)) {
/* a tag number of 3 is not extended so only one octet */
len++;
/* don't decode the application tag number or its data here */
rpdata->application_data = &apdu[len];
/* Just to ensure we do not create a wrapped over value here. */
if (len < apdu_len) {
rpdata->application_data_len = apdu_len - len - 1 /*closing tag */;
} else {
rpdata->application_data_len = 0;
}
/* len includes the data and the closing tag */
len = apdu_len;
} else {
return -1;
}
} else {
return -1;
}