diff mbox series

[ovs-dev,1/6] lldp: validate a bit more received LLDP frames

Message ID 20201026205745.56604-2-fdangelo@redhat.com
State Changes Requested
Headers show
Series Incorporate fixes from lldpd upstream | expand

Commit Message

Fabrizio D'Angelo Oct. 26, 2020, 8:57 p.m. UTC
From: Aaron Conole <aconole@redhat.com>

From: Vincent Bernat <vincent@bernat.ch>

Upstream commit:
    commit 3aeae72b97716fddac290634fad02b952d981f17
    Author: Vincent Bernat <vincent@bernat.ch>
    Date:   Tue, 1 Oct 2019 21:42:42 +0200

    lldp: validate a bit more received LLDP frames

    Notably, we ensure the order and unicity of Chassis ID, Port ID and
    TTL TLV. For Chassis ID and Port ID, we also ensure the maximum size
    does not exceed 256.

    Fix https://github.com/vincentbernat/lldpd/issues/351

Signed-off-by: Aaron Conole <aconole@redhat.com>
Co-authored-by: Aaron Conole <aconole@redhat.com>
Signed-off-by: Vincent Bernat <vincent@bernat.ch>
---
 lib/lldp/lldp.c | 53 +++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 51 insertions(+), 2 deletions(-)
diff mbox series

Patch

diff --git a/lib/lldp/lldp.c b/lib/lldp/lldp.c
index 74f747fcdc..e61ce67746 100644
--- a/lib/lldp/lldp.c
+++ b/lib/lldp/lldp.c
@@ -341,6 +341,12 @@  lldp_send(struct lldpd *global OVS_UNUSED,
 
     return dp_packet_size(p);
 }
+#define CHECK_TLV_MAX_SIZE(x, name)                                 \
+    do { if (tlv_size > (x)) {                                      \
+            VLOG_WARN(name " TLV too large received on %s",         \
+                      hardware->h_ifname);                          \
+            goto malformed;                                         \
+        } } while (0)
 
 int
 lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
@@ -359,7 +365,7 @@  lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
     int length, af;
     bool gotend = false;
     bool ttl_received = false;
-    int tlv_size, tlv_type, tlv_subtype;
+    int tlv_size, tlv_type, tlv_subtype, tlv_count = 0;
     u_int8_t *pos, *tlv;
     void *b;
     struct lldpd_aa_isid_vlan_maps_tlv *isid_vlan_map = NULL;
@@ -411,6 +417,31 @@  lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
                       hardware->h_ifname);
             goto malformed;
         }
+        /* Check order for mandatory TLVs */
+        tlv_count++;
+        switch (tlv_type) {
+        case LLDP_TLV_CHASSIS_ID:
+            if (tlv_count != 1) {
+                VLOG_WARN("first TLV should be a chassis ID on %s, not %d",
+                          hardware->h_ifname, tlv_type);
+                goto malformed;
+            }
+            break;
+        case LLDP_TLV_PORT_ID:
+            if (tlv_count != 2) {
+                VLOG_WARN("second TLV should be a port ID on %s, not %d",
+                          hardware->h_ifname, tlv_type);
+                goto malformed;
+            }
+            break;
+        case LLDP_TLV_TTL:
+            if (tlv_count != 3) {
+                VLOG_WARN("third TLV should be a TTL on %s, not %d",
+                          hardware->h_ifname, tlv_type);
+                goto malformed;
+            }
+            break;
+        }
 
         switch (tlv_type) {
         case LLDP_TLV_END:
@@ -428,7 +459,8 @@  lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
 
         case LLDP_TLV_CHASSIS_ID:
         case LLDP_TLV_PORT_ID:
-            CHECK_TLV_SIZE(2, "Port Id");
+            CHECK_TLV_SIZE(2, "Port/Chassis Id");
+            CHECK_TLV_MAX_SIZE(256, "Port/Chassis Id");
             tlv_subtype = PEEK_UINT8;
             if (tlv_subtype == 0 || tlv_subtype > 7) {
                 VLOG_WARN("unknown subtype for tlv id received on %s",
@@ -438,10 +470,22 @@  lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
             b = xzalloc(tlv_size - 1);
             PEEK_BYTES(b, tlv_size - 1);
             if (tlv_type == LLDP_TLV_PORT_ID) {
+                if (port->p_id != NULL) {
+                    VLOG_WARN("Port ID TLV received twice on %s",
+                              hardware->h_ifname);
+                    free(b);
+                    goto malformed;
+                }
                 port->p_id_subtype = tlv_subtype;
                 port->p_id = b;
                 port->p_id_len = tlv_size - 1;
             } else {
+                if (chassis->c_id != NULL) {
+                    VLOG_WARN("Chassis ID TLV received twice on %s",
+                              hardware->h_ifname);
+                    free(b);
+                    goto malformed;
+                }
                 chassis->c_id_subtype = tlv_subtype;
                 chassis->c_id = b;
                 chassis->c_id_len = tlv_size - 1;
@@ -449,6 +493,11 @@  lldp_decode(struct lldpd *cfg OVS_UNUSED, char *frame, int s,
             break;
 
         case LLDP_TLV_TTL:
+            if (ttl_received) {
+                VLOG_WARN("TTL TLV received twice on %s",
+                          hardware->h_ifname);
+                goto malformed;
+            }
             CHECK_TLV_SIZE(2, "TTL");
             chassis->c_ttl = PEEK_UINT16;
             ttl_received = true;