Description
Three heap-buffer-overflow bugs exist in ospfd's opaque LSA TLV parsers (ospf_te_parse_te, ospf_te_parse_r, ospf_te_parse_ext_link in ospfd/ospf_te.c). All three fire when an opaque LSA with a body length not divisible by 4 is installed into the LSDB via the OSPF API (--apiserver).
Important: The network receive path is NOT vulnerable. ospf_packet_examin() at ospf_packet.c:2760 enforces 4-byte alignment on all incoming LSAs and drops malformed packets before processing. The vulnerability is only reachable via the OSPF API origination path, which bypasses this check.
Root cause: ospf_apiserver_opaque_lsa_new() (ospf_apiserver.c:1530) creates LSAs from the API message body without enforcing 4-byte alignment. The resulting LSA is installed via ospf_lsa_install() which dispatches to TE/SR parsers that assume 4-byte-aligned bodies.
Three confirmed OOB reads (ASAN stack traces attached):
Bug A — ospf_te_parse_ext_link (ospf_te.c:2805), opaque type 8, READ 4 bytes past 21-byte allocation
Bug B — ospf_te_parse_ri (ospf_te.c:2487), opaque type 4, READ 2 bytes past 21-byte allocation
Bug C — ospf_te_parse_te (ospf_te.c:2136), opaque type 1, READ 1 byte past 21-byte allocation
All three share the same call chain:
ospf_apiserver_originate1 (ospf_apiserver.c:1829)
→ ospf_lsa_install (ospf_lsa.c:3163)
→ hook_call(ospf_lsa_update)
→ ospf_opaque_lsa_update_hook
→ new_lsa_callback
→ ospf_mpls_te_lsa_update (ospf_te.c:3091)
→ ospf_te_parse_opaque_lsa
→ ospf_te_parse_te / ospf_te_parse_ri / ospf_te_parse_ext_link ← OOB READ
Additional finding — SR hooks (code-confirmed): When mpls-te is disabled but SR is enabled, ospf_sr_ext_link_lsa_update (ospf_sr.c:1607) and ospf_sr_ri_lsa_update (ospf_sr.c:1426) have the same OOB pattern. These don't abort immediately — the OOB value feeds into TLV_SIZE arithmetic causing potential loop underflow and silent SR state corruption.
jopaque NULL (ospf_opaque.c:1284-1306): When a non-4-byte-aligned LSA is in the LSDB, show ip ospf database opaque-* json
passes a NULL jopaque to show functions. Daemon survives but JSON output is silently incomplete.
BUG_REPORT.md
FRR-bug-report.zip
Version
FRR Version / Commit: 10.7.0-dev (built from source, main branch)
Configure line:
./configure --enable-address-sanitizer --enable-ospfapi --enable-multipath=64 \
--prefix=/usr/local --sysconfdir=/etc/frr --localstatedir=/var/run/frr \
CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib -Wl,-rpath,/usr/local/lib"
Daemons: zebra, ospfd, mgmtd, staticd
Platform: Ubuntu 22.04 (aarch64, Lima VM on Apple M4 Pro)
How to reproduce
Network Setup:
Two-router topotest topology (r1 = API originator, r2 = peer):
r1 (10.0.0.1) ---- r2 (10.0.0.2)
r1/ospfd.conf:
router ospf
ospf router-id 1.0.0.1
capability opaque
mpls-te on
mpls-te router-address 1.0.0.1
router-info area
segment-routing on
segment-routing global-block 16000 23999
segment-routing node-msd 8
segment-routing prefix 1.0.0.1/32 index 1
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Reproduction:
Minimal reproducer (requires ospfd with --apiserver, mpls-te on):
from ospfclient import OspfOpaqueClient, LSA_TYPE_OPAQUE_AREA
import asyncio, ipaddress
async def inject():
c = OspfOpaqueClient("localhost")
await c.connect()
asyncio.ensure_future(c._handle_msg_loop())
await c.register_opaque_data_wait(LSA_TYPE_OPAQUE_AREA, 1)
# 1-byte body → LSA length = 21 (not 4-byte aligned)
# Note: ospfclient CLI pads to 4 bytes — must call add_opaque_data directly
await c.add_opaque_data(ipaddress.ip_address("0.0.0.0"),
LSA_TYPE_OPAQUE_AREA, 1, 1, b"\xde")
await asyncio.sleep(2)
asyncio.run(inject())
inject_otype1.py
inject_otype4.py
inject_otype8.py
raw_lsa_inject.py
Expected behavior
ospfd should reject the malformed LSA at the API ingestion point with a warning log, consistent with how ospf_packet_examin() handles the same condition on the wire receive path. No LSA with a body length not divisible by 4 should reach ospf_lsa_install().
Actual behavior
ospfd installs the malformed LSA without validation, dispatches it to the TE/SR hook callbacks, and crashes with a heap-buffer-overflow in ASAN builds. On production
builds the daemon survives but reads garbage from adjacent heap memory into TLV size arithmetic.
Backtrace (Bug C, most reproducible):
ERROR: AddressSanitizer: heap-buffer-overflow on address 0xffffa1589f34
READ of size 2 at 0xffffa1589f34 thread T0
#0 ospf_te_parse_te ospfd/ospf_te.c:2136
#1 ospf_te_parse_opaque_lsa ospfd/ospf_te.c:2996
#2 ospf_mpls_te_lsa_update ospfd/ospf_te.c:3082
#3 new_lsa_callback ospfd/ospf_opaque.c:1047
#4 ospf_opaque_lsa_update_hook ospfd/ospf_opaque.c:1344
#5 ospf_lsa_install ospfd/ospf_lsa.c:3163
#6 ospf_apiserver_originate1 ospfd/ospf_apiserver.c:1829
#7 ospf_apiserver_handle_originate_request ospfd/ospf_apiserver.c:1723
#8 ospf_apiserver_read ospfd/ospf_apiserver.c:414
0xffffa1589f35 is located 0 bytes to the right of 21-byte region
[0xffffa1589f20,0xffffa1589f35)
allocated by thread T0 here:
#0 __interceptor_calloc
#1 qcalloc lib/memory.c:111
#2 ospf_lsa_data_new ospfd/ospf_lsa.c:305
#3 ospf_apiserver_opaque_lsa_new ospfd/ospf_apiserver.c:1586
Full ASAN log with shadow map attached frr-asan-ospfd-r1.log. Individual test logs for all three bugs attached (frr-bug-a.txt
frr-bug-b.txt
frr-bug-c.txt
).
Additional context
Suggested Fix:
Root fix in ospf_apiserver_opaque_lsa_new():
if (ntohs(data->length) % sizeof(uint32_t) != 0) {
zlog_warn("%s: rejecting opaque LSA with non-4-byte-aligned length %u",
__func__, ntohs(data->length));
return NULL;
}
Defensive fix in each parser (e.g. ospf_te_parse_te):
if (len < TLV_HDR_SIZE) {
zlog_warn("%s: LSA body too short (%u bytes) for TLV header", __func__, len);
return -1;
}
FRR-bug-report.zip
Checklist
Description
Three heap-buffer-overflow bugs exist in ospfd's opaque LSA TLV parsers (
ospf_te_parse_te,ospf_te_parse_r,ospf_te_parse_ext_linkinospfd/ospf_te.c). All three fire when an opaque LSA with a body length not divisible by 4 is installed into the LSDB via the OSPF API (--apiserver).Important: The network receive path is NOT vulnerable.
ospf_packet_examin()atospf_packet.c:2760enforces 4-byte alignment on all incoming LSAs and drops malformed packets before processing. The vulnerability is only reachable via the OSPF API origination path, which bypasses this check.Root cause:
ospf_apiserver_opaque_lsa_new()(ospf_apiserver.c:1530) creates LSAs from the API message body without enforcing 4-byte alignment. The resulting LSA is installed viaospf_lsa_install()which dispatches to TE/SR parsers that assume 4-byte-aligned bodies.Three confirmed OOB reads (ASAN stack traces attached):
Bug A —
ospf_te_parse_ext_link(ospf_te.c:2805), opaque type 8, READ 4 bytes past 21-byte allocationBug B —
ospf_te_parse_ri(ospf_te.c:2487), opaque type 4, READ 2 bytes past 21-byte allocationBug C —
ospf_te_parse_te(ospf_te.c:2136), opaque type 1, READ 1 byte past 21-byte allocationAll three share the same call chain:
Additional finding — SR hooks (code-confirmed): When
mpls-teis disabled but SR is enabled,ospf_sr_ext_link_lsa_update(ospf_sr.c:1607) andospf_sr_ri_lsa_update(ospf_sr.c:1426) have the same OOB pattern. These don't abort immediately — the OOB value feeds intoTLV_SIZEarithmetic causing potential loop underflow and silent SR state corruption.jopaque NULL (ospf_opaque.c:1284-1306): When a non-4-byte-aligned LSA is in the LSDB,
show ip ospf database opaque-* jsonpasses a NULL
jopaqueto show functions. Daemon survives but JSON output is silently incomplete.BUG_REPORT.md
FRR-bug-report.zip
Version
How to reproduce
Network Setup:
Two-router topotest topology (r1 = API originator, r2 = peer):
r1 (10.0.0.1) ---- r2 (10.0.0.2)r1/ospfd.conf:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
Reproduction:
Minimal reproducer (requires ospfd with --apiserver, mpls-te on):
inject_otype1.py
inject_otype4.py
inject_otype8.py
raw_lsa_inject.py
Expected behavior
ospfd should reject the malformed LSA at the API ingestion point with a warning log, consistent with how ospf_packet_examin() handles the same condition on the wire receive path. No LSA with a body length not divisible by 4 should reach ospf_lsa_install().
Actual behavior
ospfd installs the malformed LSA without validation, dispatches it to the TE/SR hook callbacks, and crashes with a heap-buffer-overflow in ASAN builds. On production
builds the daemon survives but reads garbage from adjacent heap memory into TLV size arithmetic.
Backtrace (Bug C, most reproducible):
Full ASAN log with shadow map attached frr-asan-ospfd-r1.log. Individual test logs for all three bugs attached (frr-bug-a.txt
frr-bug-b.txt
frr-bug-c.txt
).
Additional context
Suggested Fix:
Root fix in ospf_apiserver_opaque_lsa_new():
Defensive fix in each parser (e.g. ospf_te_parse_te):
FRR-bug-report.zip
Checklist