Bug #61: add strict decoding for AtomicReadFile, AtomicWriteFile, and DeviceCommunicationControl

This commit is contained in:
Steve Karg
2020-01-04 12:06:28 -06:00
parent 20735f0162
commit f721350b3f
7 changed files with 1502 additions and 369 deletions
+86 -57
View File
@@ -243,7 +243,7 @@ int bacapp_decode_data(uint8_t *apdu,
case BACNET_APPLICATION_TAG_OBJECT_ID: {
uint16_t object_type = 0;
uint32_t instance = 0;
len = decode_object_id_safe(
len = bacnet_object_id_decode(
&apdu[0], len_value_type, &object_type, &instance);
value->type.Object_Id.type = object_type;
value->type.Object_Id.instance = instance;
@@ -271,8 +271,17 @@ int bacapp_decode_data(uint8_t *apdu,
return len;
}
/**
* @brief Decode the BACnet Application Data
*
* @param apdu - buffer of data to be decoded
* @param apdu_len_max - number of bytes in the buffer
* @param value - decoded value, if decoded
*
* @return the number of apdu bytes consumed, or #BACNET_STATUS_ERROR
*/
int bacapp_decode_application_data(
uint8_t *apdu, unsigned max_apdu_len, BACNET_APPLICATION_DATA_VALUE *value)
uint8_t *apdu, unsigned apdu_len_max, BACNET_APPLICATION_DATA_VALUE *value)
{
int len = 0;
int tag_len = 0;
@@ -280,19 +289,27 @@ int bacapp_decode_application_data(
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
/* FIXME: use max_apdu_len! */
(void)max_apdu_len;
if (apdu && value && !IS_CONTEXT_SPECIFIC(*apdu)) {
value->context_specific = false;
tag_len =
decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
if (tag_len) {
tag_len = bacnet_tag_number_and_value_decode(
&apdu[0], apdu_len_max, &tag_number, &len_value_type);
if (tag_len > 0) {
len += tag_len;
value->tag = tag_number;
decode_len = bacapp_decode_data(
&apdu[len], tag_number, len_value_type, value);
if (value->tag != MAX_BACNET_APPLICATION_TAG) {
len += decode_len;
if (len <= apdu_len_max) {
decode_len =
bacapp_decode_data_len(NULL, tag_number, len_value_type);
if (decode_len <= (apdu_len_max - len)) {
decode_len = bacapp_decode_data(
&apdu[len], tag_number, len_value_type, value);
if (value->tag != MAX_BACNET_APPLICATION_TAG) {
len += decode_len;
} else {
len = BACNET_STATUS_ERROR;
}
} else {
len = BACNET_STATUS_ERROR;
}
} else {
len = BACNET_STATUS_ERROR;
}
@@ -342,7 +359,7 @@ bool bacapp_decode_application_data_safe(uint8_t *new_apdu,
if (value && apdu_len_remaining > 0 &&
!IS_CONTEXT_SPECIFIC(apdu[apdu_len])) {
value->context_specific = false;
tag_len = decode_tag_number_and_value_safe(
tag_len = bacnet_tag_number_and_value_decode(
&apdu[apdu_len], apdu_len_remaining, &tag_number, &len_value_type);
/* If tag_len is zero, then the tag information is truncated */
if (tag_len) {
@@ -375,34 +392,41 @@ int bacapp_decode_data_len(
{
int len = 0;
if (apdu) {
switch (tag_data_type) {
case BACNET_APPLICATION_TAG_NULL:
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
case BACNET_APPLICATION_TAG_SIGNED_INT:
case BACNET_APPLICATION_TAG_REAL:
case BACNET_APPLICATION_TAG_DOUBLE:
case BACNET_APPLICATION_TAG_OCTET_STRING:
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
case BACNET_APPLICATION_TAG_BIT_STRING:
case BACNET_APPLICATION_TAG_ENUMERATED:
case BACNET_APPLICATION_TAG_DATE:
case BACNET_APPLICATION_TAG_TIME:
case BACNET_APPLICATION_TAG_OBJECT_ID:
len = (int)len_value_type;
break;
default:
break;
}
(void)apdu;
switch (tag_data_type) {
case BACNET_APPLICATION_TAG_NULL:
break;
case BACNET_APPLICATION_TAG_BOOLEAN:
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
case BACNET_APPLICATION_TAG_SIGNED_INT:
case BACNET_APPLICATION_TAG_REAL:
case BACNET_APPLICATION_TAG_DOUBLE:
case BACNET_APPLICATION_TAG_OCTET_STRING:
case BACNET_APPLICATION_TAG_CHARACTER_STRING:
case BACNET_APPLICATION_TAG_BIT_STRING:
case BACNET_APPLICATION_TAG_ENUMERATED:
case BACNET_APPLICATION_TAG_DATE:
case BACNET_APPLICATION_TAG_TIME:
case BACNET_APPLICATION_TAG_OBJECT_ID:
len = (int)len_value_type;
break;
default:
break;
}
return len;
}
int bacapp_decode_application_data_len(uint8_t *apdu, unsigned max_apdu_len)
/**
* @brief Determine the BACnet Application Data number of APDU bytes consumed
*
* @param apdu - buffer of data to be decoded
* @param apdu_len_max - number of bytes in the buffer
*
* @return number of bytes decoded, or zero if errors occur
*/
int bacapp_decode_application_data_len(uint8_t *apdu, unsigned apdu_len_max)
{
int len = 0;
int tag_len = 0;
@@ -410,15 +434,13 @@ int bacapp_decode_application_data_len(uint8_t *apdu, unsigned max_apdu_len)
uint8_t tag_number = 0;
uint32_t len_value_type = 0;
/* FIXME: use max_apdu_len! */
(void)max_apdu_len;
if (apdu && !IS_CONTEXT_SPECIFIC(*apdu)) {
tag_len =
decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
if (tag_len) {
tag_len = bacnet_tag_number_and_value_decode(
&apdu[0], apdu_len_max, &tag_number, &len_value_type);
if (tag_len > 0) {
len += tag_len;
decode_len =
bacapp_decode_data_len(&apdu[len], tag_number, len_value_type);
bacapp_decode_data_len(NULL, tag_number, len_value_type);
len += decode_len;
}
}
@@ -730,8 +752,17 @@ int bacapp_decode_context_data(uint8_t *apdu,
return apdu_len;
}
/**
* @brief Determine the BACnet Context Data number of APDU bytes consumed
*
* @param apdu - buffer of data to be decoded
* @param apdu_len_max - number of bytes in the buffer
* @param property - context property identifier
*
* @return number of bytes decoded, or zero if errors occur
*/
int bacapp_decode_context_data_len(
uint8_t *apdu, unsigned max_apdu_len, BACNET_PROPERTY_ID property)
uint8_t *apdu, unsigned apdu_len_max, BACNET_PROPERTY_ID property)
{
int apdu_len = 0, len = 0;
int tag_len = 0;
@@ -739,17 +770,14 @@ int bacapp_decode_context_data_len(
uint32_t len_value_type = 0;
uint8_t tag = 0;
/* FIXME: use max_apdu_len! */
(void)max_apdu_len;
if (apdu && IS_CONTEXT_SPECIFIC(*apdu)) {
tag_len =
decode_tag_number_and_value(&apdu[0], &tag_number, &len_value_type);
tag_len = bacnet_tag_number_and_value_decode(
&apdu[0], apdu_len_max, &tag_number, &len_value_type);
if (tag_len) {
apdu_len = tag_len;
tag = bacapp_context_tag_type(property, tag_number);
if (tag < MAX_BACNET_APPLICATION_TAG) {
len = bacapp_decode_data_len(
&apdu[apdu_len], tag, len_value_type);
len = bacapp_decode_data_len(NULL, tag, len_value_type);
apdu_len += len;
} else {
apdu_len += len_value_type;
@@ -878,7 +906,7 @@ bool bacapp_copy(BACNET_APPLICATION_DATA_VALUE *dest_value,
Include a value property identifier for context specific data
such as the value received in a WriteProperty request */
int bacapp_data_len(
uint8_t *apdu, unsigned max_apdu_len, BACNET_PROPERTY_ID property)
uint8_t *apdu, unsigned apdu_len_max, BACNET_PROPERTY_ID property)
{
int len = 0;
int total_len = 0;
@@ -889,31 +917,32 @@ int bacapp_data_len(
uint32_t value = 0;
if (IS_OPENING_TAG(apdu[0])) {
len = decode_tag_number_and_value(&apdu[apdu_len], &tag_number, &value);
len = bacnet_tag_number_and_value_decode(
&apdu[apdu_len], apdu_len_max - apdu_len, &tag_number, &value);
apdu_len += len;
opening_tag_number = tag_number;
opening_tag_number_counter = 1;
while (opening_tag_number_counter) {
if (IS_OPENING_TAG(apdu[apdu_len])) {
len = decode_tag_number_and_value(
&apdu[apdu_len], &tag_number, &value);
len = bacnet_tag_number_and_value_decode(&apdu[apdu_len],
apdu_len_max - apdu_len, &tag_number, &value);
if (tag_number == opening_tag_number) {
opening_tag_number_counter++;
}
} else if (IS_CLOSING_TAG(apdu[apdu_len])) {
len = decode_tag_number_and_value(
&apdu[apdu_len], &tag_number, &value);
len = bacnet_tag_number_and_value_decode(&apdu[apdu_len],
apdu_len_max - apdu_len, &tag_number, &value);
if (tag_number == opening_tag_number) {
opening_tag_number_counter--;
}
} else if (IS_CONTEXT_SPECIFIC(apdu[apdu_len])) {
/* context-specific tagged data */
len = bacapp_decode_context_data_len(
&apdu[apdu_len], max_apdu_len - apdu_len, property);
&apdu[apdu_len], apdu_len_max - apdu_len, property);
} else {
/* application tagged data */
len = bacapp_decode_application_data_len(
&apdu[apdu_len], max_apdu_len - apdu_len);
&apdu[apdu_len], apdu_len_max - apdu_len);
}
apdu_len += len;
if (opening_tag_number_counter) {
@@ -925,7 +954,7 @@ int bacapp_data_len(
break;
}
}
if ((unsigned)apdu_len > max_apdu_len) {
if ((unsigned)apdu_len > apdu_len_max) {
/* error: exceeding our buffer limit */
total_len = BACNET_STATUS_ERROR;
break;