CVE-2021-43612: Out-of-bounds Write (CWE-787)
value: In lldpd before 1.0.13, when decoding SONMP packets in the sonmp_decode function, it's possible to trigger an out-of-bounds heap read via short SONMP packets.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 7.5
Published: 2023-04-15T22:15Z
Repository: https://github.com/lldpd/lldpd
Language: C
Files changed: NEWS, src/daemon/protocols/sonmp.c, src/daemon/protocols/sonmp.h, tests/check_sonmp.c
Commit date: 2021-11-13 13:20:11 +0100
Commit message: sonmp: fix heap overflow when reading SONMP packets

By sending short SONMP packets, an attacker can make the decoder crash
by reading too much data on the heap. SONMP packets are fixed in size,
just ensure we get the enough bytes to contain a SONMP packet.

CVE-2021-43612

Diff: diff --git a/NEWS b/NEWS
index 68925bf..dbb1b80 100644
--- a/NEWS
+++ b/NEWS
@@ -1,10 +1,12 @@
 lldpd (1.0.13)
  * Fix:
    + Add support for 2.5G, 5G, 25G and 50G based Ethernet (#475)
    + Fix link-down detection on OpenBSD (#476)
    + Fix LLDP packets encapsuled in VLAN 0 in some conditions
+   + Fix heap overflow when reading SONMP. CVE-2021-43612.
+     Thanks to Jeremy Galindo for discovering this one.
 
 lldpd (1.0.12)
   * Fix:
     + Use a dedicated file lock to prevent concurrent changes from lldpcli.
     + Require/display powerpairs for Dot3 power even when device type is PD.
diff --git a/src/daemon/protocols/sonmp.c b/src/daemon/protocols/sonmp.c
index 41dcf6a..f8f1246 100644
--- a/src/daemon/protocols/sonmp.c
+++ b/src/daemon/protocols/sonmp.c
@@ -309,11 +309,11 @@ sonmp_decode(struct lldpd *cfg, char *frame, int s,
 	TAILQ_INIT(&port->p_vlans);
 #endif
 
 	length = s;
 	pos = (u_int8_t*)frame;
-	if (length < SONMP_SIZE) {
+	if (length < SONMP_SIZE + 2*ETHER_ADDR_LEN + sizeof(u_int16_t)) {
 		log_warnx("sonmp", "too short SONMP frame received on %s", hardware->h_ifname);
 		goto malformed;
 	}
 	if (PEEK_CMP(mcastaddr, sizeof(mcastaddr)) != 0)
 		/* There is two multicast address. We just handle only one of
diff --git a/src/daemon/protocols/sonmp.h b/src/daemon/protocols/sonmp.h
index 0e60106..ff7a720 100644
--- a/src/daemon/protocols/sonmp.h
+++ b/src/daemon/protocols/sonmp.h
@@ -22,11 +22,11 @@
 	0x01, 0x00, 0x81, 0x00, 0x01, 0x00					\
 }
 #define LLC_ORG_NORTEL { 0x00, 0x00, 0x81 }
 #define LLC_PID_SONMP_HELLO 0x01a2
 #define LLC_PID_SONMP_FLATNET 0x01a1
-#define SONMP_SIZE (2*ETHER_ADDR_LEN + sizeof(u_int16_t) + 8)
+#define SONMP_SIZE 19
 
 struct sonmp_chassis {
 	int type;
 	char *description;
 };
diff --git a/tests/check_sonmp.c b/tests/check_sonmp.c
index 8c7a208..b25f0e2 100644
--- a/tests/check_sonmp.c
+++ b/tests/check_sonmp.c
@@ -31,11 +31,11 @@ START_TEST (test_send_sonmp)
 	int n;
 	/* Packet we should build:
 IEEE 802.3 Ethernet 
     Destination: Bay-Networks-(Synoptics)-autodiscovery (01:00:81:00:01:00)
     Source: 5e:10:8e:e7:84:ad (5e:10:8e:e7:84:ad)
-    Length: 22
+    Length: 19
 Logical-Link Control
     DSAP: SNAP (0xaa)
     IG Bit: Individual
     SSAP: SNAP (0xaa)
     CR Bit: Command
@@ -53,11 +53,11 @@ Nortel Networks / SynOptics Network Management Protocol
     Number of links: 1
 
 IEEE 802.3 Ethernet 
     Destination: Bay-Networks-(Synoptics)-autodiscovery (01:00:81:00:01:01)
     Source: 5e:10:8e:e7:84:ad (5e:10:8e:e7:84:ad)
-    Length: 22
+    Length: 19
 Logical-Link Control
     DSAP: SNAP (0xaa)
     IG Bit: Individual
     SSAP: SNAP (0xaa)
     CR Bit: Command
@@ -74,17 +74,17 @@ Nortel Networks / SynOptics Network Management Protocol
     NMM state: New (3)
     Number of links: 1
 	*/
 	char pkt1[] = {
 		0x01, 0x00, 0x81, 0x00, 0x01, 0x00, 0x5e, 0x10,
-		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x16, 0xaa, 0xaa,
+		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x13, 0xaa, 0xaa,
 		0x03, 0x00, 0x00, 0x81, 0x01, 0xa2, 0xac, 0x11,
 		0x8e, 0x25, 0x00, 0x00, 0x04, 0x01, 0x0c, 0x03,
 		0x01 };
 	char pkt2[] = {
 		0x01, 0x00, 0x81, 0x00, 0x01, 0x01, 0x5e, 0x10,
-		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x16, 0xaa, 0xaa,
+		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x13, 0xaa, 0xaa,
 		0x03, 0x00, 0x00, 0x81, 0x01, 0xa1, 0xac, 0x11,
 		0x8e, 0x25, 0x00, 0x00, 0x04, 0x01, 0x0c, 0x03,
 		0x01 };
 	struct packet *pkt;
 	in_addr_t addr;	
@@ -97,11 +97,11 @@ Nortel Networks / SynOptics Network Management Protocol
 	chassis.c_id_subtype = LLDP_CHASSISID_SUBTYPE_LLADDR;
 	chassis.c_id = macaddress;
 	chassis.c_id_len = ETHER_ADDR_LEN;
 	TAILQ_INIT(&chassis.c_mgmt);
 	addr = inet_addr("172.17.142.37");
-	mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, 
+	mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4,
 				&addr, sizeof(in_addr_t), 0);
 	if (mgmt == NULL)
 		ck_abort();
 	TAILQ_INSERT_TAIL(&chassis.c_mgmt, mgmt, m_entries);
 

Vulnerable code: 	if (length < SONMP_SIZE) {
#define SONMP_SIZE (2*ETHER_ADDR_LEN + sizeof(u_int16_t) + 8)
    Length: 22
    Length: 22
		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x16, 0xaa, 0xaa,
		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x16, 0xaa, 0xaa,
	mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4, 
Fixed code:    + Fix heap overflow when reading SONMP. CVE-2021-43612.
     Thanks to Jeremy Galindo for discovering this one.
	if (length < SONMP_SIZE + 2*ETHER_ADDR_LEN + sizeof(u_int16_t)) {
#define SONMP_SIZE 19
    Length: 19
    Length: 19
		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x13, 0xaa, 0xaa,
		0x8e, 0xe7, 0x84, 0xad, 0x00, 0x13, 0xaa, 0xaa,
	mgmt = lldpd_alloc_mgmt(LLDPD_AF_IPV4,