From cb343b6de673184e4e9327d170017f542133decd Mon Sep 17 00:00:00 2001 From: Michael Zillgith Date: Wed, 30 Jul 2025 07:43:51 +0100 Subject: [PATCH] - fixed BER decoder infinite length handling to avoid inifite loop while decoding (LIB61850-516) --- src/mms/iso_mms/asn1c/constr_CHOICE.c | 52 +++++++----- src/mms/iso_mms/asn1c/constr_SEQUENCE.c | 107 ++++++++++++++---------- src/mms/iso_mms/asn1c/constr_SET_OF.c | 37 ++++---- 3 files changed, 116 insertions(+), 80 deletions(-) diff --git a/src/mms/iso_mms/asn1c/constr_CHOICE.c b/src/mms/iso_mms/asn1c/constr_CHOICE.c index c1db22f3..dd5d241f 100644 --- a/src/mms/iso_mms/asn1c/constr_CHOICE.c +++ b/src/mms/iso_mms/asn1c/constr_CHOICE.c @@ -291,7 +291,8 @@ CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, /* * Read in the "end of data chunks"'s. */ - while(ctx->left < 0) { + while(ctx->left < 0) + { ssize_t tl; tl = ber_fetch_tag(ptr, LEFT, &tlv_tag); @@ -304,25 +305,36 @@ CHOICE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, /* * Expected <0><0>... */ - if(((const uint8_t *)ptr)[0] == 0) { - if(LEFT < 2) { - if(SIZE_VIOLATION) - RETURN(RC_FAIL); - else - RETURN(RC_WMORE); - } else if(((const uint8_t *)ptr)[1] == 0) { - /* - * Correctly finished with <0><0>. - */ - ADVANCE(2); - ctx->left++; - continue; - } - } else { - RETURN(RC_FAIL); - } - - /* UNREACHABLE */ + if (((const uint8_t*)ptr)[0] == 0) + { + if (LEFT < 2) + { + if (SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } + else if (((const uint8_t*)ptr)[1] == 0) + { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + continue; + } + else + { + /* this case should not happen when the message is correctly encoded */ + RETURN(RC_FAIL); + } + } + else + { + RETURN(RC_FAIL); + } + + /* UNREACHABLE */ } NEXT_PHASE(ctx); diff --git a/src/mms/iso_mms/asn1c/constr_SEQUENCE.c b/src/mms/iso_mms/asn1c/constr_SEQUENCE.c index 35aec840..a665e8ac 100644 --- a/src/mms/iso_mms/asn1c/constr_SEQUENCE.c +++ b/src/mms/iso_mms/asn1c/constr_SEQUENCE.c @@ -223,34 +223,41 @@ SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, case -1: RETURN(RC_FAIL); } - if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { - if(LEFT < 2) { - if(SIZE_VIOLATION) - RETURN(RC_FAIL); - else - RETURN(RC_WMORE); - } else if(((const uint8_t *)ptr)[1] == 0) { - - if((edx + elements[edx].optional - == td->elements_count) - || (IN_EXTENSION_GROUP(specs, edx) - && specs->ext_before - > td->elements_count)) { - /* - * Yeah, baby! Found the terminator - * of the indefinite length structure. - */ - /* - * Proceed to the canonical - * finalization function. - * No advancing is necessary. - */ - goto phase3; - } - } - } - - /* + if (ctx->left < 0 && ((const uint8_t*)ptr)[0] == 0) + { + if (LEFT < 2) + { + if (SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } + else if (((const uint8_t*)ptr)[1] == 0) + { + + if ((edx + elements[edx].optional == td->elements_count) || + (IN_EXTENSION_GROUP(specs, edx) && specs->ext_before > td->elements_count)) + { + /* + * Yeah, baby! Found the terminator + * of the indefinite length structure. + */ + /* + * Proceed to the canonical + * finalization function. + * No advancing is necessary. + */ + goto phase3; + } + } + else + { + /* this case should not happen when the message is correctly encoded */ + RETURN(RC_FAIL); + } + } + + /* * Find the next available type with this tag. */ use_bsearch = 0; @@ -421,25 +428,33 @@ SEQUENCE_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, /* * If expected <0><0>... */ - if(ctx->left < 0 - && ((const uint8_t *)ptr)[0] == 0) { - if(LEFT < 2) { - if(SIZE_VIOLATION) - RETURN(RC_FAIL); - else - RETURN(RC_WMORE); - } else if(((const uint8_t *)ptr)[1] == 0) { - /* - * Correctly finished with <0><0>. - */ - ADVANCE(2); - ctx->left++; - ctx->phase = 4; - continue; - } - } + if (ctx->left < 0 && ((const uint8_t*)ptr)[0] == 0) + { + if (LEFT < 2) + { + if (SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } + else if (((const uint8_t*)ptr)[1] == 0) + { + /* + * Correctly finished with <0><0>. + */ + ADVANCE(2); + ctx->left++; + ctx->phase = 4; + continue; + } + else + { + /* this case should not happen when the message is correctly encoded */ + RETURN(RC_FAIL); + } + } - if(!IN_EXTENSION_GROUP(specs, td->elements_count) + if(!IN_EXTENSION_GROUP(specs, td->elements_count) || ctx->phase == 4) { RETURN(RC_FAIL); } diff --git a/src/mms/iso_mms/asn1c/constr_SET_OF.c b/src/mms/iso_mms/asn1c/constr_SET_OF.c index 85f78c97..8e35ac2e 100644 --- a/src/mms/iso_mms/asn1c/constr_SET_OF.c +++ b/src/mms/iso_mms/asn1c/constr_SET_OF.c @@ -158,22 +158,31 @@ SET_OF_decode_ber(asn_codec_ctx_t *opt_codec_ctx, asn_TYPE_descriptor_t *td, case -1: RETURN(RC_FAIL); } - if(ctx->left < 0 && ((const uint8_t *)ptr)[0] == 0) { - if(LEFT < 2) { - if(SIZE_VIOLATION) - RETURN(RC_FAIL); - else - RETURN(RC_WMORE); - } else if(((const uint8_t *)ptr)[1] == 0) { - /* - * Found the terminator of the - * indefinite length structure. - */ - break; + if (ctx->left < 0 && ((const uint8_t*)ptr)[0] == 0) + { + if (LEFT < 2) + { + if (SIZE_VIOLATION) + RETURN(RC_FAIL); + else + RETURN(RC_WMORE); + } + else if (((const uint8_t*)ptr)[1] == 0) + { + /* + * Found the terminator of the + * indefinite length structure. + */ + break; + } + else + { + /* this case should not happen when the message is correctly encoded */ + RETURN(RC_FAIL); } - } + } - /* Outmost tag may be unknown and cannot be fetched/compared */ + /* Outmost tag may be unknown and cannot be fetched/compared */ if(elm->tag != (ber_tlv_tag_t)-1) { if(BER_TAGS_EQUAL(tlv_tag, elm->tag)) { /*