bgpd: harden attribute parsing and packet handling in a few places#21095
bgpd: harden attribute parsing and packet handling in a few places#21095ton31337 wants to merge 4 commits intoFRRouting:masterfrom
Conversation
Greptile SummaryThis PR applies five security fixes across BGP attribute parsing and packet handling to prevent buffer over-reads and incorrect continued processing after error conditions. Key changes:
Confidence Score: 4/5
Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[Receive BGP UPDATE / CAPABILITY / ROUTE-REFRESH] --> B{Message type?}
B -->|ROUTE-REFRESH| C{subtype != 0?}
C -->|Yes| D{msg_length == 4?}
D -->|No| E[bgp_notify_send INVALID_MSG_LEN\n+ return BGP_Stop ✅ FIXED]
D -->|Yes| F{subtype > 2?}
F -->|Yes| G[flog_err + return BGP_PACKET_NOOP ✅ FIXED]
F -->|No| H[Process ORF data]
B -->|CAPABILITY: GRACEFUL_RESTART| I[data = pnt + 3\nend = data + hdr->length ✅ FIXED\nlen = end - data]
I --> J{len < 2?}
J -->|Yes| K[Error: invalid length, return]
J -->|No| L[Parse gr_restart_flag_time\nIterate AFI/SAFI entries]
B -->|UPDATE: AIGP attr| M[bgp_attr_aigp_get_tlv_metric]
M --> N{length >= tlv_length? ✅ FIXED}
N -->|No| O[flog_err + return false]
N -->|Yes| P[Read metric value]
B -->|UPDATE: Tunnel Encap attr| Q{subtype < 128?}
Q -->|Yes| R{length >= 2? ✅ FIXED}
R -->|No| S[bgp_attr_malformed]
R -->|Yes| T[Read 1-byte sublength]
Q -->|No| U{length >= 3? ✅ FIXED}
U -->|No| S
U -->|Yes| V[Read 2-byte sublength]
|
f70941e to
e0c7d40
Compare
bgpd/bgp_packet.c
Outdated
| * it MUST ignore the received ROUTE-REFRESH message. | ||
| */ | ||
| if (subtype > 2) | ||
| if (subtype > 2) { |
There was a problem hiding this comment.
Medium: 62da4d0 still leaves a remotely triggerable session-reset path for unknown Enhanced Route Refresh subtypes. The new early returns stop parsing after bgp_notify_send(), which is good, but the checks are still ordered so that msg_length != 4 is evaluated before subtype > 2. That means an attacker can send subtype 3+ with a non-4-byte payload and still force BGP_Stop, even though the code comment says unknown subtypes "MUST ignore" the message.
| if (BGP_ATTR_ENCAP == type) { | ||
| subtype = stream_getc(BGP_INPUT(connection)); | ||
| if (subtype < 128) { | ||
| if (length < 2) { |
There was a problem hiding this comment.
Low: e0c7d40 fixes the length -= 2/3/4 underflow, but it still reads the sub-TLV subtype before proving there is even 1 byte of attribute payload left. If length == 0 and there are more bytes later in the packet, stream_getc() will still consume one byte from the following attribute before the malformed path runs. bgp_attr_malformed() later restores getp to the declared end of the attribute, so this is probably not exploitable memory corruption, but the commit does not fully eliminate cross-attribute reads on malformed input.
The NOTIFY tears down the session asynchronously, but the function continues parsing attacker-controlled bytes as ORF data before the session actually closes. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
…ability
The GR function computes end 3 bytes too early (pnt vs data), causing
it to stop parsing 3 bytes before the real end. For a carefully
crafted GR capability, the last AFI/SAFI entry (4 bytes) is silently
dropped.
Dynamic capability header is:
+------------------------------+
| Action (1 octet) |
+------------------------------+
| Capability Code (1 octet) |
+------------------------------+
| Capability Length (1 octet) |
+------------------------------+
| Capability Value (variable) |
+------------------------------+
So we set wrongly the end of the packet (too early).
Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
If "length" is 1 before the subtraction, "length -= 2" wraps to 65535 (unsigned). The subsequent "sublength > length" check then passes when it should fail, because length is now enormous. The parser consumes bytes from adjacent attributes, corrupting the overall attribute parse state. The STREAM_READABLE check at line 3184 prevents actual buffer overflows, but attribute boundary violations can cause incorrect route processing. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
e0c7d40 to
5e55e12
Compare
When data + 1 == end (exactly 1 byte remaining, sufficient to read the length byte), the function incorrectly rejects the capability. Same issue at line 3498 for domain name length. Also, hostname len can't be 0 (while domainname - can), so let's fix this too. Signed-off-by: Donatas Abraitis <donatas@opensourcerouting.org>
No description provided.