Bugfix/secure apdu handler unconfirmed (#645)

* Secured APDU handler by avoiding read ahead.
This commit is contained in:
Steve Karg
2024-05-20 09:00:18 -05:00
committed by GitHub
parent cbd9b3f04f
commit 7baf912acd
+40 -29
View File
@@ -554,10 +554,12 @@ static bool apdu_unconfirmed_dcc_disabled(uint8_t service_choice)
* @param apdu [in] The apdu portion of the request, to be processed. * @param apdu [in] The apdu portion of the request, to be processed.
* @param apdu_len [in] The total (remaining) length of the apdu. * @param apdu_len [in] The total (remaining) length of the apdu.
*/ */
void apdu_handler(BACNET_ADDRESS *src, void apdu_handler(
BACNET_ADDRESS *src,
uint8_t *apdu, /* APDU data */ uint8_t *apdu, /* APDU data */
uint16_t apdu_len) uint16_t apdu_len)
{ {
BACNET_PDU_TYPE pdu_type;
BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 }; BACNET_CONFIRMED_SERVICE_DATA service_data = { 0 };
uint8_t service_choice = 0; uint8_t service_choice = 0;
uint8_t *service_request = NULL; uint8_t *service_request = NULL;
@@ -572,13 +574,18 @@ void apdu_handler(BACNET_ADDRESS *src,
bool server = false; bool server = false;
#endif #endif
if (apdu) { if (!apdu) {
/* PDU Type */ return;
switch (apdu[0] & 0xF0) { }
if (apdu_len == 0) {
return;
}
pdu_type = apdu[0] & 0xF0;
switch (pdu_type) {
case PDU_TYPE_CONFIRMED_SERVICE_REQUEST: case PDU_TYPE_CONFIRMED_SERVICE_REQUEST:
len = apdu_decode_confirmed_service_request(&apdu[0], apdu_len, len = apdu_decode_confirmed_service_request(
&service_data, &service_choice, &service_request, apdu, apdu_len, &service_data, &service_choice,
&service_request_len); &service_request, &service_request_len);
if (len == 0) { if (len == 0) {
/* service data unable to be decoded - simply drop */ /* service data unable to be decoded - simply drop */
break; break;
@@ -592,11 +599,11 @@ void apdu_handler(BACNET_ADDRESS *src,
} }
if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) && if ((service_choice < MAX_BACNET_CONFIRMED_SERVICE) &&
(Confirmed_Function[service_choice])) { (Confirmed_Function[service_choice])) {
Confirmed_Function[service_choice](service_request, Confirmed_Function[service_choice](
service_request_len, src, &service_data); service_request, service_request_len, src, &service_data);
} else if (Unrecognized_Service_Handler) { } else if (Unrecognized_Service_Handler) {
Unrecognized_Service_Handler(service_request, Unrecognized_Service_Handler(
service_request_len, src, &service_data); service_request, service_request_len, src, &service_data);
} }
break; break;
case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST: case PDU_TYPE_UNCONFIRMED_SERVICE_REQUEST:
@@ -604,8 +611,9 @@ void apdu_handler(BACNET_ADDRESS *src,
break; break;
} }
service_choice = apdu[1]; service_choice = apdu[1];
service_request = &apdu[2]; /* prepare the service request buffer and length */
service_request_len = apdu_len - 2; service_request_len = apdu_len - 2;
service_request = &apdu[2];
if (apdu_unconfirmed_dcc_disabled(service_choice)) { if (apdu_unconfirmed_dcc_disabled(service_choice)) {
/* When network communications are disabled, /* When network communications are disabled,
only DeviceCommunicationControl and only DeviceCommunicationControl and
@@ -630,8 +638,7 @@ void apdu_handler(BACNET_ADDRESS *src,
invoke_id = apdu[1]; invoke_id = apdu[1];
service_choice = apdu[2]; service_choice = apdu[2];
if (apdu_confirmed_simple_ack_service(service_choice)) { if (apdu_confirmed_simple_ack_service(service_choice)) {
if (Confirmed_ACK_Function[service_choice].simple != if (Confirmed_ACK_Function[service_choice].simple != NULL) {
NULL) {
Confirmed_ACK_Function[service_choice].simple( Confirmed_ACK_Function[service_choice].simple(
src, invoke_id); src, invoke_id);
} }
@@ -644,21 +651,24 @@ void apdu_handler(BACNET_ADDRESS *src,
} }
service_ack_data.segmented_message = service_ack_data.segmented_message =
(apdu[0] & BIT(3)) ? true : false; (apdu[0] & BIT(3)) ? true : false;
service_ack_data.more_follows = service_ack_data.more_follows = (apdu[0] & BIT(2)) ? true : false;
(apdu[0] & BIT(2)) ? true : false;
invoke_id = service_ack_data.invoke_id = apdu[1]; invoke_id = service_ack_data.invoke_id = apdu[1];
len = 2; len = 2;
if (service_ack_data.segmented_message) { if (service_ack_data.segmented_message) {
if (apdu_len < 5) {
break;
}
service_ack_data.sequence_number = apdu[len++]; service_ack_data.sequence_number = apdu[len++];
service_ack_data.proposed_window_number = apdu[len++]; service_ack_data.proposed_window_number = apdu[len++];
} }
service_choice = apdu[len++]; service_choice = apdu[len++];
service_request = &apdu[len]; /* prepare the service request buffer and length */
service_request_len = apdu_len - (uint16_t)len; service_request_len = apdu_len - (uint16_t)len;
service_request = &apdu[len];
if (!apdu_confirmed_simple_ack_service(service_choice)) { if (!apdu_confirmed_simple_ack_service(service_choice)) {
if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) { if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) {
if (Confirmed_ACK_Function[service_choice] if (Confirmed_ACK_Function[service_choice].complex !=
.complex != NULL) { NULL) {
Confirmed_ACK_Function[service_choice].complex( Confirmed_ACK_Function[service_choice].complex(
service_request, service_request_len, src, service_request, service_request_len, src,
&service_ack_data); &service_ack_data);
@@ -678,19 +688,22 @@ void apdu_handler(BACNET_ADDRESS *src,
} }
invoke_id = apdu[1]; invoke_id = apdu[1];
service_choice = apdu[2]; service_choice = apdu[2];
/* prepare the service request buffer and length */
service_request_len = apdu_len - 3;
service_request = &apdu[3];
if (apdu_complex_error(service_choice)) { if (apdu_complex_error(service_choice)) {
if (Error_Function[service_choice].complex) { if (Error_Function[service_choice].complex) {
Error_Function[service_choice].complex(src, Error_Function[service_choice].complex(
invoke_id, service_choice, &apdu[3], src, invoke_id, service_choice, service_request,
apdu_len - 3); service_request_len);
} }
} else if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) { } else if (service_choice < MAX_BACNET_CONFIRMED_SERVICE) {
len = bacerror_decode_error_class_and_code( len = bacerror_decode_error_class_and_code(
&apdu[3], apdu_len - 3, &error_class, &error_code); service_request, service_request_len, &error_class,
if ((len != 0) && &error_code);
(Error_Function[service_choice].error)) { if ((len != 0) && (Error_Function[service_choice].error)) {
Error_Function[service_choice].error(src, invoke_id, Error_Function[service_choice].error(
(BACNET_ERROR_CLASS)error_class, src, invoke_id, (BACNET_ERROR_CLASS)error_class,
(BACNET_ERROR_CODE)error_code); (BACNET_ERROR_CODE)error_code);
} }
} }
@@ -724,5 +737,3 @@ void apdu_handler(BACNET_ADDRESS *src,
break; break;
} }
} }
return;
}