diff options
author | Samanvitha B Bhargav <bsamanvitha@vmware.com> | 2023-08-08 14:09:16 +0200 |
---|---|---|
committer | Samanvitha B Bhargav <bsamanvitha@vmware.com> | 2023-08-12 13:07:21 +0200 |
commit | e9e304e810927d32e17e7e930d1f141b5d199803 (patch) | |
tree | 66305615c0511399511c62f82a573deabd79676e /bgpd/bgp_attr.c | |
parent | Merge pull request #14171 from mjstapp/fix_bgp_lblpool_indent (diff) | |
download | frr-e9e304e810927d32e17e7e930d1f141b5d199803.tar.xz frr-e9e304e810927d32e17e7e930d1f141b5d199803.zip |
bgpd: Fix update message error handling for total attribute length
As per RFC7606 section 4,
when the total attribute length value is in conflict with the
enclosed attribute length, treat-as-withdraw approach must be followed.
However, notification is being sent out for this case currently,
that leads to session reset.
Fix:
The handling has been updated to conform to treat-as-withdraw
approach only for EBGP case. For IBGP, since we are not following
treat-as-withdraw approach for any of the error handling cases,
the existing behavior is retained for the IBGP.
Signed-off-by: Samanvitha B Bhargav <bsamanvitha@vmware.com>
Diffstat (limited to 'bgpd/bgp_attr.c')
-rw-r--r-- | bgpd/bgp_attr.c | 100 |
1 files changed, 59 insertions, 41 deletions
diff --git a/bgpd/bgp_attr.c b/bgpd/bgp_attr.c index d31e266c9..2e6059d62 100644 --- a/bgpd/bgp_attr.c +++ b/bgpd/bgp_attr.c @@ -3537,48 +3537,66 @@ enum bgp_attr_parse_ret bgp_attr_parse(struct peer *peer, struct attr *attr, "%s: BGP type %d length %d is too large, attribute total length is %d. attr_endp is %p. endp is %p", peer->host, type, length, size, attr_endp, endp); - /* - * RFC 4271 6.3 - * If any recognized attribute has an Attribute - * Length that conflicts with the expected length - * (based on the attribute type code), then the - * Error Subcode MUST be set to Attribute Length - * Error. The Data field MUST contain the erroneous - * attribute (type, length, and value). - * ---------- - * We do not currently have a good way to determine the - * length of the attribute independent of the length - * received in the message. Instead we send the - * minimum between the amount of data we have and the - * amount specified by the attribute length field. - * - * Instead of directly passing in the packet buffer and - * offset we use the stream_get* functions to read into - * a stack buffer, since they perform bounds checking - * and we are working with untrusted data. - */ - unsigned char ndata[peer->max_packet_size]; - memset(ndata, 0x00, sizeof(ndata)); - size_t lfl = - CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1; - /* Rewind to end of flag field */ - stream_rewind_getp(BGP_INPUT(peer), (1 + lfl)); - /* Type */ - stream_get(&ndata[0], BGP_INPUT(peer), 1); - /* Length */ - stream_get(&ndata[1], BGP_INPUT(peer), lfl); - /* Value */ - size_t atl = attr_endp - startp; - size_t ndl = MIN(atl, STREAM_READABLE(BGP_INPUT(peer))); - stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl); - bgp_notify_send_with_data( - peer, BGP_NOTIFY_UPDATE_ERR, - BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata, - ndl + lfl + 1); - - ret = BGP_ATTR_PARSE_ERROR; - goto done; + /* Only relax error handling for eBGP peers */ + if (peer->sort != BGP_PEER_EBGP) { + /* + * RFC 4271 6.3 + * If any recognized attribute has an Attribute + * Length that conflicts with the expected length + * (based on the attribute type code), then the + * Error Subcode MUST be set to Attribute Length + * Error. The Data field MUST contain the erroneous + * attribute (type, length, and value). + * ---------- + * We do not currently have a good way to determine the + * length of the attribute independent of the length + * received in the message. Instead we send the + * minimum between the amount of data we have and the + * amount specified by the attribute length field. + * + * Instead of directly passing in the packet buffer and + * offset we use the stream_get* functions to read into + * a stack buffer, since they perform bounds checking + * and we are working with untrusted data. + */ + unsigned char ndata[peer->max_packet_size]; + + memset(ndata, 0x00, sizeof(ndata)); + size_t lfl = + CHECK_FLAG(flag, BGP_ATTR_FLAG_EXTLEN) ? 2 : 1; + /* Rewind to end of flag field */ + stream_rewind_getp(BGP_INPUT(peer), (1 + lfl)); + /* Type */ + stream_get(&ndata[0], BGP_INPUT(peer), 1); + /* Length */ + stream_get(&ndata[1], BGP_INPUT(peer), lfl); + /* Value */ + size_t atl = attr_endp - startp; + size_t ndl = MIN(atl, STREAM_READABLE(BGP_INPUT(peer))); + + stream_get(&ndata[lfl + 1], BGP_INPUT(peer), ndl); + + bgp_notify_send_with_data( + peer, BGP_NOTIFY_UPDATE_ERR, + BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata, + ndl + lfl + 1); + + ret = BGP_ATTR_PARSE_ERROR; + goto done; + } else { + /* Handling as per RFC7606 section 4, treat-as-withdraw approach + * must be followed when the total attribute length is in conflict + * with the enclosed path attribute length. + */ + flog_warn( + EC_BGP_ATTRIBUTE_PARSE_WITHDRAW, + "%s: Attribute %s, parse error - treating as withdrawal", + peer->host, lookup_msg(attr_str, type, NULL)); + ret = BGP_ATTR_PARSE_WITHDRAW; + stream_forward_getp(BGP_INPUT(peer), endp - BGP_INPUT_PNT(peer)); + goto done; + } } struct bgp_attr_parser_args attr_args = { |