bgpd: Fix a couple of issues in BGP-LS NLRI encoding/decoding#21092
bgpd: Fix a couple of issues in BGP-LS NLRI encoding/decoding#21092riw777 merged 8 commits intoFRRouting:masterfrom
Conversation
Greptile SummaryThis PR fixes several correctness and safety issues in the BGP-LS NLRI encoding and decoding pipeline. Changes span attribute encoding ( Key fixes included:
Confidence Score: 5/5
Important Files Changed
Sequence DiagramsequenceDiagram
participant Peer as BGP Peer
participant Parse as bgp_nlri_parse_ls
participant Decode as bgp_ls_decode_nlri
participant Hash as nlri_hash
participant RIB as BGP RIB
Peer->>Parse: packet MP_REACH or UNREACH NLRI
Note over Parse: Guard: peer/bgp/ls_info/packet not NULL
loop for each NLRI in stream
Parse->>Decode: bgp_ls_nlri_alloc() then decode into heap nlri
Decode->>Decode: Parse TLVs with duplicate detection
Decode->>Decode: STREAM_WRITEABLE and STREAM_READABLE checks
Decode-->>Parse: decoded nlri or -1 on error
alt decode failed
Parse->>Parse: bgp_ls_nlri_free(nlri)
Parse-->>Peer: BGP_NLRI_PARSE_ERROR
else decode OK
Parse->>Hash: bgp_ls_nlri_get(nlri)
Note over Hash: deep-copy nlri into hash if new, refcnt incremented
Hash-->>Parse: ls_entry which is hash-owned copy
Parse->>RIB: bgp_update or bgp_withdraw
Parse->>Parse: bgp_ls_nlri_free(nlri) to free temp alloc
end
end
Parse-->>Peer: BGP_NLRI_PARSE_OK
Last reviewed commit: 03dbdfd |
65f6b2d to
f81a315
Compare
|
@greptile review |
f81a315 to
8e3b5fc
Compare
|
@greptile review |
8e3b5fc to
195d66d
Compare
|
@greptile review |
195d66d to
03dbdfd
Compare
|
@greptile review |
|
This pull request has conflicts, please resolve those before we can evaluate the pull request. |
03dbdfd to
04cbca5
Compare
BGP receives BGP Update messages that can contain a BGP-LS NLRI, then processes the TLVs carried in that NLRI. The NLRI may include duplicate TLVs. Today, when a duplicate TLV is received, BGP-LS overwrites the previous value with the new one. RFC 9552 requires duplicate TLVs to be treated as a malformed NLRI. Also, replacing an earlier TLV value with a new one without freeing previously allocated dynamic memory can cause a memory leak. Fix by checking whether the same TLV type appears more than once and returning an error on duplicates. This propagates the parse failure to the caller, which then treats the NLRI as malformed. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
Some encode paths wrote to the stream without first checking that enough space was available. Writing when the stream is full can trigger an assert or crash. Fix by adding `STREAM_WRITEABLE()` checks before writing, and return -1 when space is insufficient. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
parse_ext_admin_group() only verified that the TLV length was a multiple of 4, with no upper bound on the number of 32-bit words to decode. A very large length could trigger excessive growth/work in admin_group_bulk_set(). Define BGP_LS_MAX_EXT_ADMIN_GROUP_WORDS in bgp_ls_nlri.h and reject Extended Admin Group TLVs that exceed this limit during decode. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
`parse_ext_admin_group()` applied `ntohl()` to the value returned by `stream_getl()`. `stream_getl()` already returns the 32-bit value in host byte order, so this caused a second conversion. On little-endian systems, the extra conversion byte-swapped the value again and corrupted decoded Extended Admin Group words. Fix by removing the redundant conversion and passing `stream_getl()` output directly to `admin_group_bulk_set()`. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
In `bgp_nlri_parse_ls()`, `bgp_ls_nlri` was declared on the stack and then filled by `bgp_ls_decode_nlri()` from the input stream. `bgp_ls_decode_nlri()` can allocate dynamic fields inside the NLRI object. Because the parsing loop reused the same stack object on each iteration, those dynamic allocations were leaked across iterations. Fix by moving the NLRI object to heap allocation and using the BGP-LS NLRI helpers for lifecycle management: allocate with `bgp_ls_nlri_alloc()` and free with `bgp_ls_nlri_free()` on both success and error paths. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
bgp_ls_decode_link_descriptor() and bgp_ls_decode_prefix_descriptor() can allocate desc->mt_id when parsing MT-ID TLVs. If a later TLV in the same descriptor fails validation, the functions returned -1 without releasing that allocation, leaking memory on error unwind. Fix by adding centralized error cleanup paths in both descriptor parsers that free desc->mt_id before returning -1. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
bgp_packet_ls_attribute() encoded BGP-LS attributes with a 1-byte length field, which can encode up to 255 bytes of BGP-LS attribute data. BGP-LS attributes often exceed 255 bytes when carrying multiple node/link/prefix TLVs, so a 1-byte length is not sufficient. Fix by setting BGP_ATTR_FLAG_EXTLEN for BGP-LS attributes and encoding the attribute length as 2 bytes. Add a bounds check to ensure the encoded attribute length fits in the extended-length field. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
`bgp_nlri_parse_ls()` dereferenced `peer->bgp->ls_info` without checking that BGP-LS state was initialized. Add defensive checks for peer, peer->bgp, peer->bgp->ls_info, and packet before parsing, and return BGP_NLRI_PARSE_ERROR on invalid state. Signed-off-by: Carmine Scarpitta <cscarpit@cisco.com>
04cbca5 to
2e533d3
Compare
This PR solves a couple of issues in BGP-LS NLRI encoding/decoding.
See individual commits.