Bugfix/bacnet array encoding overflows (#414)

* Add common BACnetARRAY encode function to fix Device object list buffer overflow. Refactor device, analog-output, access-door and binary-output objects to use common BACnetARRAY encoder.

* Fix non-POSIX builds (win32).

* Cleanup some ports/stm32 build warnings
---------

Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
Steve Karg
2023-04-13 20:43:54 -05:00
committed by GitHub
parent 064c6f7f1c
commit e517df0d47
23 changed files with 872 additions and 834 deletions
+51 -9
View File
@@ -254,54 +254,96 @@ static bool dlmstp_compare_data_expecting_reply(uint8_t *request_pdu,
};
struct DER_compare_t request;
struct DER_compare_t reply;
bool request_segmented = false;
bool reply_segmented = false;
/* decode the request data */
request.address.mac[0] = src_address;
request.address.mac_len = 1;
offset = npdu_decode(
&request_pdu[0], NULL, &request.address, &request.npdu_data);
offset = bacnet_npdu_decode(request_pdu, request_pdu_len, NULL,
&request.address, &request.npdu_data);
if (request.npdu_data.network_layer_message) {
return false;
}
if (offset >= request_pdu_len) {
return false;
}
request.pdu_type = request_pdu[offset] & 0xF0;
if (request.pdu_type != PDU_TYPE_CONFIRMED_SERVICE_REQUEST) {
return false;
}
if (request_pdu[offset] & BIT(3)) {
request_segmented = true;
}
if ((offset + 2) >= request_pdu_len) {
return false;
}
request.invoke_id = request_pdu[offset + 2];
/* segmented message? */
if (request_pdu[offset] & BIT(3))
if (request_segmented) {
if ((offset + 5) >= request_pdu_len) {
return false;
}
request.service_choice = request_pdu[offset + 5];
else
} else {
if ((offset + 3) >= request_pdu_len) {
return false;
}
request.service_choice = request_pdu[offset + 3];
}
/* decode the reply data */
reply.address.mac[0] = dest_address;
reply.address.mac_len = 1;
offset = npdu_decode(&reply_pdu[0], &reply.address, NULL, &reply.npdu_data);
offset = bacnet_npdu_decode(
reply_pdu, reply_pdu_len, &reply.address, NULL, &reply.npdu_data);
if (reply.npdu_data.network_layer_message) {
return false;
}
if (offset >= request_pdu_len) {
return false;
}
reply.pdu_type = reply_pdu[offset] & 0xF0;
if (reply_pdu[offset] & BIT(3)) {
reply_segmented = true;
}
/* reply could be a lot of things:
confirmed, simple ack, abort, reject, error */
reply.pdu_type = reply_pdu[offset] & 0xF0;
switch (reply.pdu_type) {
case PDU_TYPE_SIMPLE_ACK:
if ((offset + 2) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
break;
case PDU_TYPE_COMPLEX_ACK:
reply.invoke_id = reply_pdu[offset + 1];
/* segmented message? */
if (reply_pdu[offset] & BIT(3))
if (reply_segmented) {
if ((offset + 4) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 4];
else
} else {
if ((offset + 2) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
}
break;
case PDU_TYPE_ERROR:
if ((offset + 2) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
reply.service_choice = reply_pdu[offset + 2];
break;
case PDU_TYPE_REJECT:
case PDU_TYPE_ABORT:
if ((offset + 1) >= request_pdu_len) {
return false;
}
reply.invoke_id = reply_pdu[offset + 1];
break;
default: