Commit 7e40ddcab1 for frr
commit 7e40ddcab109301e4ba130ce501fd5069439a1af
Author: Mark Stapp <mjs@cisco.com>
Date: Thu Sep 17 11:18:24 2026 -0400
pceplib: fix encode and decode of Path Setup Cap TLV
Fix the encoder and decoder for the Path Setup Capability
TLV. Correct alignment/padding, and fix TLV header values.
Improve validation for the (optional) sub-TLVs in the
Path Setup Capability TLV. Ensure there are enough bytes for
a sub-TLV header, examine the header and validate the
sub-TLV length.
Signed-off-by: Mark Stapp <mjs@cisco.com>
diff --git a/pceplib/pcep_msg_tlvs_encoding.c b/pceplib/pcep_msg_tlvs_encoding.c
index c342b27a7a..4efe03e9e7 100644
--- a/pceplib/pcep_msg_tlvs_encoding.c
+++ b/pceplib/pcep_msg_tlvs_encoding.c
@@ -32,11 +32,8 @@
#include "pcep_utils_logging.h"
#include "pcep_utils_memory.h"
-void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr,
- uint16_t tlv_length, struct pcep_versioning *versioning,
- uint8_t *buf);
-void pcep_decode_tlv_hdr(const uint8_t *tlv_buf,
- struct pcep_object_tlv_header *tlv_hdr);
+void write_tlv_header(struct pcep_object_tlv_header *tlv_hdr, uint16_t tlv_length,
+ struct pcep_versioning *versioning, uint8_t *buf);
/*
* forward declarations for initialize_tlv_encoders()
@@ -620,14 +617,15 @@ uint16_t pcep_encode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv,
return LENGTH_1WORD;
}
-uint16_t
-pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv,
- struct pcep_versioning *versioning,
- uint8_t *tlv_body_buf)
+uint16_t pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv,
+ struct pcep_versioning *vers,
+ uint8_t *tlv_body_buf)
{
- (void)versioning;
+ uint16_t pst_length;
struct pcep_object_tlv_path_setup_type_capability *pst_cap =
(struct pcep_object_tlv_path_setup_type_capability *)tlv;
+ (void)vers;
+
if (pst_cap->pst_list == NULL) {
return 0;
}
@@ -641,27 +639,36 @@ pcep_encode_tlv_path_setup_type_capability(struct pcep_object_tlv_header *tlv,
tlv_body_buf[index++] = *((uint8_t *)node->data);
}
- uint16_t pst_length = normalize_pcep_tlv_length(
- LENGTH_1WORD + pst_cap->pst_list->num_entries);
- if (pst_cap->sub_tlv_list == NULL) {
+ /* If there are no sub-TLVS, any padding needed for the PSTs
+ * should not be included in the tlv header length
+ */
+ pst_length = LENGTH_1WORD + pst_cap->pst_list->num_entries;
+ if (pst_cap->sub_tlv_list == NULL || pst_cap->sub_tlv_list->num_entries == 0) {
return pst_length;
}
- /* Any padding used for the PSTs should not be included in the tlv
- * header length */
- index = normalize_pcep_tlv_length(index);
- uint16_t sub_tlvs_length = 0;
+ /* Pad PST list, then start sub-TLVs */
+ pst_length = normalize_pcep_tlv_length(pst_length);
+
+ index = pst_length;
+ uint16_t sub_tlvs_total = 0;
node = pst_cap->sub_tlv_list->head;
for (; node != NULL; node = node->next_node) {
- struct pcep_object_tlv_header *sub_tlv =
- (struct pcep_object_tlv_header *)node->data;
- uint16_t sub_tlv_length = pcep_encode_tlv(sub_tlv, versioning,
- tlv_body_buf + index);
- index += sub_tlv_length;
- sub_tlvs_length += sub_tlv_length;
+ struct pcep_object_tlv_header *sub_tlv = node->data;
+ uint16_t sub_length = pcep_encode_tlv(sub_tlv, vers, tlv_body_buf + index);
+
+ /* Each sub-TLV is padded - except the last one */
+ if (node->next_node) {
+ sub_length = normalize_pcep_tlv_length(sub_length);
+ index += sub_length;
+ sub_tlvs_total += sub_length;
+ } else {
+ index += sub_length;
+ sub_tlvs_total += sub_length;
+ }
}
- return sub_tlvs_length + pst_length;
+ return sub_tlvs_total + pst_length;
}
uint16_t pcep_encode_tlv_te_path_binding(struct pcep_object_tlv_header *tlv,
@@ -1266,18 +1273,18 @@ pcep_decode_tlv_path_setup_type(struct pcep_object_tlv_header *tlv_hdr,
struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability(
struct pcep_object_tlv_header *tlv_hdr, const uint8_t *tlv_body_buf)
{
- struct pcep_object_tlv_path_setup_type_capability *tlv =
- (struct pcep_object_tlv_path_setup_type_capability *)
- common_tlv_create(
- tlv_hdr,
- sizeof(struct
- pcep_object_tlv_path_setup_type_capability));
+ struct pcep_object_tlv_path_setup_type_capability *tlv = (void *)
+ common_tlv_create(tlv_hdr,
+ sizeof(struct pcep_object_tlv_path_setup_type_capability));
bool error_p = false;
uint16_t len = tlv->header.encoded_tlv_length;
int i;
uint8_t num_psts;
uint16_t buf_index;
uint8_t num_iterations;
+ struct pcep_object_tlv_header sub_hdr;
+ struct pcep_object_tlv_header *sub_tlv;
+ uint16_t norm_len;
/* RFC 8408 Section 3, RFC 8664 Section 4.1.1, 4.1.2 */
@@ -1321,32 +1328,71 @@ struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability(
dll_append(tlv->pst_list, pst);
}
- /* If no sub-tlvs, all done */
- if (tlv->header.encoded_tlv_length == (LENGTH_1WORD + num_psts))
+ /* If no sub-tlvs follow the PSTs, all done
+ * RFC8408, section 3
+ */
+ if (tlv->header.encoded_tlv_length == LENGTH_1WORD + num_psts)
goto done;
- /* Compute padded length for start of subtlvs */
+ /* Compute padded length of types for start of sub-TLVs */
buf_index = normalize_pcep_tlv_length(LENGTH_1WORD + num_psts);
- num_iterations = 0;
- /* If we have sub-TLVs, they must be included in the overall length */
- if (buf_index > tlv->header.encoded_tlv_length) {
+ /* If we have sub-TLVs, they must be included in the overall length; there
+ * must be room for at least one sub-tlv header
+ */
+ if (buf_index > tlv->header.encoded_tlv_length ||
+ tlv->header.encoded_tlv_length - buf_index < TLV_HEADER_LENGTH) {
pcep_log(LOG_INFO, "%s: Path Setup Type Capability length invalid", __func__);
error_p = true;
goto done;
}
- /* Must have one sub-TLV per PST value, no more */
+ /* Must have zero or one sub-TLV per PST value, no more ((RFC8408, section 3)*/
+ num_iterations = 0;
tlv->sub_tlv_list = dll_initialize();
- while ((tlv->header.encoded_tlv_length - buf_index) > TLV_HEADER_LENGTH &&
- num_iterations < num_psts &&
+ while ((tlv->header.encoded_tlv_length - buf_index) >= TLV_HEADER_LENGTH &&
num_iterations++ < MAX_ITERATIONS) {
- struct pcep_object_tlv_header *sub_tlv =
- pcep_decode_tlv(tlv_body_buf + buf_index);
- if (sub_tlv == NULL) {
+ /*
+ * RFC8408, section 3
+ */
+ if (num_iterations > num_psts) {
+ pcep_log(LOG_INFO, "PathSetupType Capability TLV: too many sub-TLVs");
+ error_p = true;
+ goto done;
+ }
+
+ /* Examine the sub-tlv header, validate length
+ * RFC5440, 7.1
+ */
+ pcep_decode_tlv_hdr(tlv_body_buf + buf_index, &sub_hdr);
+
+ /* Check for over-size length value that will wrap uint16_t
+ * when normalized
+ */
+ if (sub_hdr.encoded_tlv_length > 0xFFF8) {
pcep_log(LOG_INFO,
- "%s: Decode PathSetupType Capability sub-TLV decode returned NULL",
+ "%s: PathSetupType Capability sub-TLV length too large",
__func__);
+ error_p = true;
+ goto done;
+ }
+
+ /* Test the full, padded length */
+ norm_len = normalize_pcep_tlv_length(
+ sub_hdr.encoded_tlv_length + TLV_HEADER_LENGTH);
+
+ if (norm_len > tlv->header.encoded_tlv_length - buf_index) {
+ pcep_log(LOG_INFO,
+ "%s: PathSetupType Capability sub-TLV invalid length %d",
+ __func__, sub_hdr.encoded_tlv_length);
+ error_p = true;
+ goto done;
+ }
+
+ sub_tlv = pcep_decode_tlv(tlv_body_buf + buf_index);
+ if (sub_tlv == NULL) {
+ pcep_log(LOG_INFO, "%s: sub-TLV decode returned NULL", __func__);
+ error_p = true;
goto done;
}
@@ -1356,7 +1402,7 @@ struct pcep_object_tlv_header *pcep_decode_tlv_path_setup_type_capability(
* _except_ for the last sub-TLV; the padding bytes are not included
* for the last sub-TLV. What were they thinking?
*/
- buf_index += normalize_pcep_tlv_length(sub_tlv->encoded_tlv_length);
+ buf_index += norm_len;
}
done: