From 4e973e8ec6cd2d467e3b269aa006f500d9b3e942 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 1288686a10..c032b21221 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -1717,11 +1717,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 a5f422ed68a1705b2e02be8add60d9e92ea8ca85 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 c032b21221..72e9dc8424 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -1739,9 +1739,14 @@ 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");
 
-	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));
+	}
 
 	return TLV_SIZE(tlvh);
 }
@@ -1754,14 +1759,28 @@ static uint16_t show_vty_ext_link_adj_sid(struct vty *vty,
 
 	check_tlv_size(EXT_SUBTLV_ADJ_SID_SIZE, "Adjacency SID");
 
-	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));
+	/* 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));
+	}
 
 	return TLV_SIZE(tlvh);
 }
@@ -1775,15 +1794,30 @@ static uint16_t show_vty_ext_link_lan_adj_sid(struct vty *vty,
 
 	check_tlv_size(EXT_SUBTLV_LAN_ADJ_SID_SIZE, "Lan-Adjacency SID");
 
-	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));
+	/* 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));
+	}
 
 	return TLV_SIZE(tlvh);
 }
@@ -1792,13 +1826,22 @@ static uint16_t show_vty_unknown_tlv(struct vty *vty, struct tlv_header *tlvh,
 				     size_t buf_size)
 {
 	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;
 	}
 
-	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));
+	}
 
 	return TLV_SIZE(tlvh);
 }
@@ -1814,18 +1857,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;
 	}
 
-	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);
+	}
 
 	/* Skip Extended TLV and parse sub-TLVs */
 	length -= EXT_TLV_LINK_SIZE;
@@ -1887,15 +1943,28 @@ static uint16_t show_vty_ext_pref_pref_sid(struct vty *vty,
 
 	check_tlv_size(EXT_SUBTLV_PREFIX_SID_SIZE, "Prefix SID");
 
-	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));
+	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));
+	}
 
 	return TLV_SIZE(tlvh);
 }
@@ -1911,17 +1980,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;
 	}
 
-	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);
+	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);
+	}
 
 	/* Skip Extended Prefix TLV and parse sub-TLVs */
 	length -= EXT_TLV_PREFIX_SIZE;
-- 
2.51.0


From 10f1a2cef06eba00e0cb43ea5556d0f19c05a9e6 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 72e9dc8424..b596b542cf 100644
--- a/ospfd/ospf_ext.c
+++ b/ospfd/ospf_ext.c
@@ -1722,11 +1722,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 e227a3151f..292d4daaf1 100644
--- a/ospfd/ospf_ri.c
+++ b/ospfd/ospf_ri.c
@@ -1230,12 +1230,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 ffea80ca0f..21d2218e3f 100644
--- a/ospfd/ospf_te.c
+++ b/ospfd/ospf_te.c
@@ -3217,12 +3217,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

