summaryrefslogtreecommitdiffstats
path: root/bgpd/bgp_attr.c
diff options
context:
space:
mode:
authorSamanvitha B Bhargav <bsamanvitha@vmware.com>2023-08-08 14:09:16 +0200
committerSamanvitha B Bhargav <bsamanvitha@vmware.com>2023-08-12 13:07:21 +0200
commite9e304e810927d32e17e7e930d1f141b5d199803 (patch)
tree66305615c0511399511c62f82a573deabd79676e /bgpd/bgp_attr.c
parentMerge pull request #14171 from mjstapp/fix_bgp_lblpool_indent (diff)
downloadfrr-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.c100
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 = {