mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-07-09 11:24:42 +00:00
bgpd: fix mishandled attribute length
A crafted BGP UPDATE with a malformed path attribute length field causes bgpd to dump up to 65535 bytes of application memory and send it as the data field in a BGP NOTIFY message, which is truncated to 4075 bytes after accounting for protocol headers. After reading a malformed length field, a NOTIFY is generated that is supposed to contain the problematic data, but the malformed length field is inadvertently used to compute how much data we send. CVE-2017-15865 Signed-off-by: Quentin Young <qlyoung@cumulusnetworks.com>
This commit is contained in:
parent
11567ce5a0
commit
dacffad461
@ -2281,10 +2281,46 @@ bgp_attr_parse_ret_t 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",
|
"%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,
|
peer->host, type, length, size, attr_endp,
|
||||||
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[BGP_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_forward_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(
|
bgp_notify_send_with_data(
|
||||||
peer, BGP_NOTIFY_UPDATE_ERR,
|
peer, BGP_NOTIFY_UPDATE_ERR,
|
||||||
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, startp,
|
BGP_NOTIFY_UPDATE_ATTR_LENG_ERR, ndata,
|
||||||
attr_endp - startp);
|
ndl + lfl + 1);
|
||||||
|
|
||||||
return BGP_ATTR_PARSE_ERROR;
|
return BGP_ATTR_PARSE_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user