File 0003-ospfd-NULL-Pointer-Dereference-fixes.patch of Package frr
From 4924c5b54a65894eb175330ad91a4e109ab4e47d Mon Sep 17 00:00:00 2001
From: s1awwhy <seawwhy@163.com>
Date: Sun, 24 Aug 2025 21:17:55 +0800
Subject: [PATCH 1/3] ospfd: Add null check for vty_out in check_tlv_size
Upstream: yes
References: CVE-2025-61099,CVE-2025-61100,CVE-2025-61101,CVE-2025-61102,CVE-2025-61103,CVE-2025-61104,CVE-2025-61105,CVE-2025-61106,CVE-2025-61107,bsc#1252838,bsc#1252829,bsc#1252833,bsc#1252835,bsc#1252810,bsc#1252811,bsc#1252761,bsc#1252812,bsc#1252813
Add security check for vty_out. Specifically, Check NULL for vty. If vty is not available, dump info via zlog.
Signed-off-by: s1awwhy <seawwhy@163.com>
diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c
index df0b3b9081..8ca0df3200 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -1705,11 +1705,15 @@ static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op)
* ------------------------------------
*/
+/* Check NULL for vty. If vty is not available, dump info via zlog */
#define check_tlv_size(size, msg) \
do { \
if (ntohs(tlvh->length) != size) { \
- vty_out(vty, " Wrong %s TLV size: %d(%d). Abort!\n", \
- msg, ntohs(tlvh->length), size); \
+ if (vty != NULL) \
+ vty_out(vty, " Wrong %s TLV size: %d(%d). Abort!\n", \
+ msg, ntohs(tlvh->length), size); \
+ else \
+ zlog_debug(" Wrong %s TLV size: %d(%d). Abort!", msg, ntohs(tlvh->length), size); \
return size + TLV_HDR_SIZE; \
} \
} while (0)
--
2.51.0
From 4950cc9eea2699c74ae1799d2500c41c12e2001d Mon Sep 17 00:00:00 2001
From: s1awwhy <seawwhy@163.com>
Date: Sun, 24 Aug 2025 21:21:23 +0800
Subject: [PATCH 2/3] ospfd: Fix NULL Pointer Deference when dumping link info
Upstream: yes
References: CVE-2025-61099,CVE-2025-61100,CVE-2025-61101,CVE-2025-61102,CVE-2025-61103,CVE-2025-61104,CVE-2025-61105,CVE-2025-61106,CVE-2025-61107,bsc#1252838,bsc#1252829,bsc#1252833,bsc#1252835,bsc#1252810,bsc#1252811,bsc#1252761,bsc#1252812,bsc#1252813
When the command debug ospf packet all send/recv detail is enabled in the OSPF
configuration, ospfd will dump detailed information of any received or sent
OSPF packets, either via VTY or through the zlog. However, the original Opaque
LSA handling code failed to check whether the VTY context and show_opaque_info
were available, resulting in NULL pointer dereference and crashes in ospfd.
The patch fixes the Null Pointer Deference Vulnerability in
show_vty_ext_link_rmt_itf_addr, show_vty_ext_link_adj_sid,
show_vty_ext_link_lan_adj_sid, show_vty_unknown_tlv,
show_vty_link_info, show_vty_ext_pref_pref_sid, show_vtY_pref_info.
Specifically, add NULL check for vty. If vty is not available, dump details
via zlog.
Signed-off-by: s1awwhy <seawwhy@163.com>
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c
index 8ca0df3200..89eea3f116 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -1729,9 +1729,15 @@ static uint16_t show_vty_ext_link_rmt_itf_addr(struct vty *vty,
check_tlv_size(EXT_SUBTLV_RMT_ITF_ADDR_SIZE, "Remote Itf. Address");
if (!json)
- vty_out(vty,
- " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n",
- ntohs(top->header.length), &top->value);
+ if (vty != NULL) {
+ vty_out(vty,
+ " Remote Interface Address Sub-TLV: Length %u\n Address: %pI4\n",
+ ntohs(top->header.length), &top->value);
+ } else {
+ zlog_debug(" Remote Interface Address Sub-TLV: Length %u",
+ ntohs(top->header.length));
+ zlog_debug(" Address: %pI4", &top->value);
+ }
else
json_object_string_addf(json, "remoteInterfaceAddress", "%pI4",
&top->value);
@@ -1752,18 +1758,30 @@ static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
: SID_INDEX_SIZE(EXT_SUBTLV_ADJ_SID_SIZE);
check_tlv_size(tlv_size, "Adjacency SID");
- if (!json)
- vty_out(vty,
- " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
- ntohs(top->header.length), top->flags, top->mtid,
- top->weight,
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
- ? "Label"
- : "Index",
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
- ? GET_LABEL(ntohl(top->value))
- : ntohl(top->value));
- else {
+ if (!json) {
+ /* Add security check for vty_out. If vty is not available, dump info via zlog.*/
+ if (vty != NULL)
+ vty_out(vty,
+ " Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\t%s: %u\n",
+ ntohs(top->header.length), top->flags, top->mtid, top->weight,
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ else {
+ zlog_debug(" Adj-SID Sub-TLV: Length %u", ntohs(top->header.length));
+ zlog_debug(" Flags: 0x%x", top->flags);
+ zlog_debug(" MT-ID:0x%x", top->mtid);
+ zlog_debug(" Weight: 0x%x", top->weight);
+ zlog_debug(" %s: %u",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ }
+ } else {
json_object_string_addf(json, "flags", "0x%x", top->flags);
json_object_string_addf(json, "mtID", "0x%x", top->mtid);
json_object_string_addf(json, "weight", "0x%x", top->weight);
@@ -1791,18 +1809,32 @@ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
: SID_INDEX_SIZE(EXT_SUBTLV_LAN_ADJ_SID_SIZE);
check_tlv_size(tlv_size, "LAN-Adjacency SID");
- if (!json)
- vty_out(vty,
- " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n",
- ntohs(top->header.length), top->flags, top->mtid,
- top->weight, &top->neighbor_id,
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
- ? "Label"
- : "Index",
- CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
- ? GET_LABEL(ntohl(top->value))
- : ntohl(top->value));
- else {
+ if (!json) {
+ /* Add security check for vty_out. If vty is not available, dump info via zlog. */
+ if (vty != NULL) {
+ vty_out(vty,
+ " LAN-Adj-SID Sub-TLV: Length %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\tWeight: 0x%x\n\tNeighbor ID: %pI4\n\t%s: %u\n",
+ ntohs(top->header.length), top->flags, top->mtid, top->weight,
+ &top->neighbor_id,
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ } else {
+ zlog_debug(" LAN-Adj-SID Sub-TLV: Length %u", ntohs(top->header.length));
+ zlog_debug(" Flags: 0x%x", top->flags);
+ zlog_debug(" MT-ID:0x%x", top->mtid);
+ zlog_debug(" Weight: 0x%x", top->weight);
+ zlog_debug(" Neighbor ID: %pI4", &top->neighbor_id);
+ zlog_debug(" %s: %u",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG) ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_LINK_ADJ_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ }
+ } else {
json_object_string_addf(json, "flags", "0x%x", top->flags);
json_object_string_addf(json, "mtID", "0x%x", top->mtid);
json_object_string_addf(json, "weight", "0x%x", top->weight);
@@ -1823,14 +1855,23 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
{
json_object *obj;
+ /* Add security check for vty_out. If vty is not available, dump info via zlog. */
if (TLV_SIZE(tlvh) > buf_size) {
- vty_out(vty, " TLV size %d exceeds buffer size. Abort!",
- TLV_SIZE(tlvh));
+ if (vty != NULL)
+ vty_out(vty, " TLV size %d exceeds buffer size. Abort!", TLV_SIZE(tlvh));
+ else
+ zlog_debug(" TLV size %d exceeds buffer size. Abort!", TLV_SIZE(tlvh));
+
return buf_size;
}
if (!json)
- vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
- ntohs(tlvh->type), ntohs(tlvh->length));
+ if (vty != NULL) {
+ vty_out(vty, " Unknown TLV: [type(0x%x), length(0x%x)]\n",
+ ntohs(tlvh->type), ntohs(tlvh->length));
+ } else {
+ zlog_debug(" Unknown TLV: [type(0x%x), length(0x%x)]",
+ ntohs(tlvh->type), ntohs(tlvh->length));
+ }
else {
obj = json_object_new_object();
json_object_string_addf(obj, "type", "0x%x",
@@ -1855,19 +1896,31 @@ static uint16_t show_vty_link_info(struct vty *vty, struct tlv_header *ext,
/* Verify that TLV length is valid against remaining buffer size */
if (length > buf_size) {
- vty_out(vty,
- " Extended Link TLV size %d exceeds buffer size. Abort!\n",
- length);
+ /* Add security check for vty_out. If vty is not available, dump info via zlog. */
+ if (vty != NULL) {
+ vty_out(vty, " Extended Link TLV size %d exceeds buffer size. Abort!\n",
+ length);
+ } else {
+ zlog_debug(" Extended Link TLV size %d exceeds buffer size. Abort!",
+ length);
+ }
return buf_size;
}
if (!json) {
- vty_out(vty,
- " Extended Link TLV: Length %u\n Link Type: 0x%x\n"
- " Link ID: %pI4\n",
- ntohs(top->header.length), top->link_type,
- &top->link_id);
- vty_out(vty, " Link data: %pI4\n", &top->link_data);
+ /* Add security check for vty_out. If vty is not available, dump info via zlog. */
+ if (vty != NULL) {
+ vty_out(vty,
+ " Extended Link TLV: Length %u\n Link Type: 0x%x\n"
+ " Link ID: %pI4\n",
+ ntohs(top->header.length), top->link_type, &top->link_id);
+ vty_out(vty, " Link data: %pI4\n", &top->link_data);
+ } else {
+ zlog_debug(" Extended Link TLV: Length %u", ntohs(top->header.length));
+ zlog_debug(" Link Type: 0x%x", top->link_type);
+ zlog_debug(" Link ID: %pI4", &top->link_id);
+ zlog_debug(" Link data: %pI4", &top->link_data);
+ }
} else {
json_object_string_addf(json, "linkType", "0x%x",
top->link_type);
@@ -1959,18 +2012,29 @@ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
: SID_INDEX_SIZE(EXT_SUBTLV_PREFIX_SID_SIZE);
check_tlv_size(tlv_size, "Prefix SID");
- if (!json)
- vty_out(vty,
- " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
- ntohs(top->header.length), top->algorithm, top->flags,
- top->mtid,
- CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
- ? "Label"
- : "Index",
- CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
- ? GET_LABEL(ntohl(top->value))
- : ntohl(top->value));
- else {
+ if (!json) {
+ if (vty != NULL) {
+ vty_out(vty,
+ " Prefix SID Sub-TLV: Length %u\n\tAlgorithm: %u\n\tFlags: 0x%x\n\tMT-ID:0x%x\n\t%s: %u\n",
+ ntohs(top->header.length), top->algorithm, top->flags, top->mtid,
+ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ } else {
+ zlog_debug(" Prefix SID Sub-TLV: Length %u", ntohs(top->header.length));
+ zlog_debug(" Algorithm: %u", top->algorithm);
+ zlog_debug(" Flags: 0x%x", top->flags);
+ zlog_debug(" MT-ID:0x%x", top->mtid);
+ zlog_debug(" %s: %u",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG) ? "Label"
+ : "Index",
+ CHECK_FLAG(top->flags, EXT_SUBTLV_PREFIX_SID_VFLG)
+ ? GET_LABEL(ntohl(top->value))
+ : ntohl(top->value));
+ }
+ } else {
json_object_int_add(json, "algorithm", top->algorithm);
json_object_string_addf(json, "flags", "0x%x", top->flags);
json_object_string_addf(json, "mtID", "0x%x", top->mtid);
@@ -1995,19 +2059,31 @@ static uint16_t show_vty_pref_info(struct vty *vty, struct tlv_header *ext,
/* Verify that TLV length is valid against remaining buffer size */
if (length > buf_size) {
- vty_out(vty,
- " Extended Link TLV size %d exceeds buffer size. Abort!\n",
- length);
+ if (vty != NULL) {
+ vty_out(vty, " Extended Link TLV size %d exceeds buffer size. Abort!\n",
+ length);
+ } else {
+ zlog_debug(" Extended Link TLV size %d exceeds buffer size. Abort!",
+ length);
+ }
return buf_size;
}
- if (!json)
- vty_out(vty,
- " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
- "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n",
- ntohs(top->header.length), top->route_type, top->af,
- top->flags, &top->address, top->pref_length);
- else {
+ if (!json) {
+ if (vty != NULL) {
+ vty_out(vty,
+ " Extended Prefix TLV: Length %u\n\tRoute Type: %u\n"
+ "\tAddress Family: 0x%x\n\tFlags: 0x%x\n\tAddress: %pI4/%u\n",
+ ntohs(top->header.length), top->route_type, top->af, top->flags,
+ &top->address, top->pref_length);
+ } else {
+ zlog_debug(" Extended Prefix TLV: Length %u", ntohs(top->header.length));
+ zlog_debug(" Route Type: %u", top->route_type);
+ zlog_debug(" Address Family: 0x%x", top->af);
+ zlog_debug(" Flags: 0x%x", top->flags);
+ zlog_debug(" Address: %pI4/%u", &top->address, top->pref_length);
+ }
+ } else {
json_object_int_add(json, "routeType", top->route_type);
json_object_string_addf(json, "addressFamily", "0x%x", top->af);
json_object_string_addf(json, "flags", "0x%x", top->flags);
--
2.51.0
From 4b5712f5d995d1628a21e79c39a5feda4d5ac5c0 Mon Sep 17 00:00:00 2001
From: Louis Scalbert <louis.scalbert@6wind.com>
Date: Tue, 6 Jan 2026 15:32:32 +0100
Subject: [PATCH 3/3] ospfd: skip subsequent tlvs after invalid length
Upstream: yes
References: CVE-2025-61099,CVE-2025-61100,CVE-2025-61101,CVE-2025-61102,CVE-2025-61103,CVE-2025-61104,CVE-2025-61105,CVE-2025-61106,CVE-2025-61107,bsc#1252838,bsc#1252829,bsc#1252833,bsc#1252835,bsc#1252810,bsc#1252811,bsc#1252761,bsc#1252812,bsc#1252813
Do not attempt to read subsequent TLVs after an TLV invalid length is
detected.
Signed-off-by: Louis Scalbert <louis.scalbert@6wind.com>
diff --git a/ospfd/ospf_ext.c b/ospfd/ospf_ext.c
index 89eea3f116..c1fcd632e0 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -1710,11 +1710,11 @@ static void ospf_ext_lsa_schedule(struct ext_itf *exti, enum lsa_opcode op)
do { \
if (ntohs(tlvh->length) != size) { \
if (vty != NULL) \
- vty_out(vty, " Wrong %s TLV size: %d(%d). Abort!\n", \
+ vty_out(vty, " Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!\n", \
msg, ntohs(tlvh->length), size); \
else \
- zlog_debug(" Wrong %s TLV size: %d(%d). Abort!", msg, ntohs(tlvh->length), size); \
- return size + TLV_HDR_SIZE; \
+ zlog_debug(" Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!", msg, ntohs(tlvh->length), size); \
+ return OSPF_MAX_LSA_SIZE + 1; \
} \
} while (0)
diff --git a/ospfd/ospf_ri.c b/ospfd/ospf_ri.c
index 76e6efeb83..7934b25451 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -1208,12 +1208,12 @@ static int ospf_router_info_lsa_update(struct ospf_lsa *lsa)
do { \
if (ntohs(tlvh->length) > size) { \
if (vty != NULL) \
- vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \
+ vty_out(vty, " Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!\n", \
msg, ntohs(tlvh->length), size); \
else \
- zlog_debug(" Wrong %s TLV size: %d(%d)", \
+ zlog_debug(" Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!", \
msg, ntohs(tlvh->length), size); \
- return size + TLV_HDR_SIZE; \
+ return OSPF_MAX_LSA_SIZE + 1; \
} \
} while (0)
diff --git a/ospfd/ospf_te.c b/ospfd/ospf_te.c
index d57990e1a1..7a68905dc7 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -3190,12 +3190,12 @@ static void ospf_te_init_ted(struct ls_ted *ted, struct ospf *ospf)
do { \
if (ntohs(tlvh->length) > size) { \
if (vty != NULL) \
- vty_out(vty, " Wrong %s TLV size: %d(%d)\n", \
+ vty_out(vty, " Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!\n", \
msg, ntohs(tlvh->length), size); \
else \
- zlog_debug(" Wrong %s TLV size: %d(%d)", \
+ zlog_debug(" Wrong %s TLV size: %d(expected %d). Skip subsequent TLVs!", \
msg, ntohs(tlvh->length), size); \
- return size + TLV_HDR_SIZE; \
+ return OSPF_MAX_LSA_SIZE + 1; \
} \
} while (0)
--
2.51.0