CVE-2023-3153: Allocation of Resources Without Limits or Throttling (CWE-770)
value: A flaw was found in Open Virtual Network where the service monitor MAC does not properly rate limit. This issue could allow an attacker to cause a denial of service, including on deployments with CoPP enabled and properly configured.
CWE description: The product allocates a reusable resource or group of resources on behalf of an actor without imposing any restrictions on the size or number of resources that can be allocated, in violation of the intended security policy for that actor.
CVSS v3 base score: 5.3
Published: 2023-10-04T12:15Z
Repository: https://github.com/ovn-org/ovn
Language: C
Files changed: lib/copp.c, lib/copp.h, northd/northd.c, ovn-nb.xml, tests/ovn-northd.at, tests/system-ovn.at
Commit date: 2023-08-29 11:13:57 -0400
Commit message: northd, controller: Add CoPP for SVC monitor

The SVC monitor was exposed without any limitation.
Add CoPP for the SVC monitor flow, which adds a way
for CMSs to limit the traffic that this flow accepts.

Signed-off-by: Ales Musil <amusil@redhat.com>

Diff: diff --git a/lib/copp.c b/lib/copp.c
index 603e3f5bf..11dd9029d 100644
--- a/lib/copp.c
+++ b/lib/copp.c
@@ -36,10 +36,11 @@ static char *copp_proto_names[COPP_PROTO_MAX] = {
     [COPP_ND_NS]         = "nd-ns",
     [COPP_ND_NS_RESOLVE] = "nd-ns-resolve",
     [COPP_ND_RA_OPTS]    = "nd-ra-opts",
     [COPP_TCP_RESET]     = "tcp-reset",
     [COPP_REJECT]        = "reject",
+    [COPP_SVC_MONITOR]   = "svc-monitor",
     [COPP_BFD]           = "bfd",
 };
 
 static const char *
 copp_proto_get_name(enum copp_proto proto)
diff --git a/lib/copp.h b/lib/copp.h
index f03004aa6..b99737220 100644
--- a/lib/copp.h
+++ b/lib/copp.h
@@ -35,10 +35,11 @@ enum copp_proto {
     COPP_ND_NS_RESOLVE,
     COPP_ND_RA_OPTS,
     COPP_TCP_RESET,
     COPP_BFD,
     COPP_REJECT,
+    COPP_SVC_MONITOR,
     COPP_PROTO_MAX,
     COPP_PROTO_INVALID = COPP_PROTO_MAX,
 };
 
 struct nbrec_copp;
diff --git a/northd/northd.c b/northd/northd.c
index 7b91a94cb..1254d9322 100644
--- a/northd/northd.c
+++ b/northd/northd.c
@@ -8921,13 +8921,15 @@ build_lswitch_destination_lookup_bmcast(struct ovn_datapath *od,
                                         struct ds *actions,
                                         const struct shash *meter_groups)
 {
     if (od->nbs) {
 
-        ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 110,
-                      "eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)",
-                      "handle_svc_check(inport);");
+        ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 110, "eth.dst == "
+                          "$svc_monitor_mac && (tcp || icmp || icmp6)",
+                          "handle_svc_check(inport);",
+                          copp_meter_get(COPP_SVC_MONITOR, od->nbs->copp,
+                                         meter_groups));
 
         struct mcast_switch_info *mcast_sw_info = &od->mcast_info.sw;
 
         if (mcast_sw_info->enabled) {
             ds_clear(actions);
diff --git a/ovn-nb.xml b/ovn-nb.xml
index 35acda107..59ac42dbd 100644
--- a/ovn-nb.xml
+++ b/ovn-nb.xml
@@ -464,10 +464,14 @@
       Rate limiting meter for BFD packets.
     </column>
     <column name="meters" key="reject">
       Rate limiting meter for packets that trigger a reject action
     </column>
+    <column name="meters" key="svc-monitor">
+      Rate limiting meter for packets that are arriving to service
+      monitor MAC address.
+    </column>
     <column name="external_ids">
       See <em>External IDs</em> at the beginning of this document.
     </column>
   </table>
 
diff --git a/tests/ovn-northd.at b/tests/ovn-northd.at
index b8376991b..70350a781 100644
--- a/tests/ovn-northd.at
+++ b/tests/ovn-northd.at
@@ -3542,11 +3542,11 @@ AT_CHECK([ovn-nbctl copp-list copp0], [0], [dnl
 
 AT_CHECK([ovn-sbctl list logical_flow | grep trigger_event -A 2 | grep -q meter0],[1])
 
 # let's try to add an usupported protocol "dhcp"
 AT_CHECK([ovn-nbctl --wait=hv copp-add copp5 dhcp meter1],[1],[],[dnl
-ovn-nbctl: Invalid control protocol. Allowed values: arp, arp-resolve, dhcpv4-opts, dhcpv6-opts, dns, event-elb, icmp4-error, icmp6-error, igmp, nd-na, nd-ns, nd-ns-resolve, nd-ra-opts, tcp-reset, bfd, reject.
+ovn-nbctl: Invalid control protocol. Allowed values: arp, arp-resolve, dhcpv4-opts, dhcpv6-opts, dns, event-elb, icmp4-error, icmp6-error, igmp, nd-na, nd-ns, nd-ns-resolve, nd-ra-opts, tcp-reset, bfd, reject, svc-monitor.
 ])
 
 #Let's try to add a valid protocol to an unknown datapath
 check ovn-nbctl --wait=hv copp-add copp6 arp meter1
 AT_CHECK([ovn-nbctl --wait=hv ls-copp-add copp6 sw10],[1],[],[dnl
diff --git a/tests/system-ovn.at b/tests/system-ovn.at
index f8131b90e..7c009e157 100644
--- a/tests/system-ovn.at
+++ b/tests/system-ovn.at
@@ -7280,10 +7280,27 @@ OVS_WAIT_UNTIL([
     n_bfd=$(grep 3784 bfd.pcap | wc -l)
     test "${n_bfd}" = "1"
 ])
 kill $(pidof tcpdump)
 
+check ovn-nbctl set nb_global . options:svc_monitor_mac="33:33:33:33:33:33"
+check ovn-nbctl meter-add svc-meter drop 1 pktps 0
+check ovn-nbctl --wait=hv copp-add copp4 svc-monitor svc-meter
+check ovn-nbctl --wait=hv ls-copp-add copp4 sw0
+check ovn-appctl -t ovn-controller vlog/set vconn:dbg
+AT_CHECK([ovn-nbctl copp-list copp4], [0], [dnl
+svc-monitor: svc-meter
+])
+
+ip netns exec sw01 scapy -H <<-EOF
+p = Ether(dst="33:33:33:33:33:33", src="f0:00:00:01:02:03") /\
+    IP(dst="192.168.1.100", src="192.168.1.2") / TCP(dport=1234, sport=1234)
+sendp(p, iface='sw01', loop=0, verbose=0, count=20)
+EOF
+
+OVS_WAIT_UNTIL([test "1" = "$(grep -c "dl_dst=33:33:33:33:33:33" ovn-controller.log)"])
+
 kill $(pidof ovn-controller)
 
 as ovn-sb
 OVS_APP_EXIT_AND_WAIT([ovsdb-server])
 
@@ -7293,11 +7310,12 @@ OVS_APP_EXIT_AND_WAIT([ovsdb-server])
 as northd
 OVS_APP_EXIT_AND_WAIT([NORTHD_TYPE])
 
 as
 OVS_TRAFFIC_VSWITCHD_STOP(["/.*error receiving.*/d
-/.*terminating with signal 15.*/d"])
+/.*terminating with signal 15.*/d
+/.*Service monitor not found/d"])
 
 AT_CLEANUP
 ])
 
 OVN_FOR_EACH_NORTHD([

Vulnerable code:         ovn_lflow_add(lflows, od, S_SWITCH_IN_L2_LKUP, 110,
                      "eth.dst == $svc_monitor_mac && (tcp || icmp || icmp6)",
                      "handle_svc_check(inport);");
ovn-nbctl: Invalid control protocol. Allowed values: arp, arp-resolve, dhcpv4-opts, dhcpv6-opts, dns, event-elb, icmp4-error, icmp6-error, igmp, nd-na, nd-ns, nd-ns-resolve, nd-ra-opts, tcp-reset, bfd, reject.
/.*terminating with signal 15.*/d"])
Fixed code:     [COPP_SVC_MONITOR]   = "svc-monitor",
    COPP_SVC_MONITOR,
        ovn_lflow_metered(lflows, od, S_SWITCH_IN_L2_LKUP, 110, "eth.dst == "
                          "$svc_monitor_mac && (tcp || icmp || icmp6)",
                          "handle_svc_check(inport);",
                          copp_meter_get(COPP_SVC_MONITOR, od->nbs->copp,
                                         meter_groups));
    <column name="meters" key="svc-monitor">
      Rate limiting meter for packets that are arriving to service
      monitor MAC address.
    </column>
ovn-nbctl: Invalid control protocol. Allowed values: arp, arp-resolve, dhcpv4-opts, dhcpv6-opts, dns, event-elb, icmp4-error, icmp6-error, igmp, nd-na, nd-ns, nd-ns-resolve, nd-ra-opts, tcp-reset, bfd, reject, svc-monitor.
check ovn-nbctl set nb_global . options:svc_monitor_mac="33:33:33:33:33:33"
check ovn-nbctl meter-add svc-meter drop 1 pktps 0
check ovn-nbctl --wait=hv copp-add copp4 svc-monitor svc-meter
check ovn-nbctl --wait=hv ls-copp-add copp4 sw0
check ovn-appctl -t ovn-controller vlog/set vconn:dbg
AT_CHECK([ovn-nbctl copp-list copp4], [0], [dnl
svc-monitor: svc-meter
])

ip netns exec sw01 scapy -H <<-EOF
p = Ether(dst="33:33:33:33:33:33", src="f0:00:00:01:02:03") /\
    IP(dst="192.168.1.100", src="192.168.1.2") / TCP(dport=1234, sport=1234)
sendp(p, iface='sw01', loop=0, verbose=0, count=20)
EOF

OVS_WAIT_UNTIL([test "1" = "$(grep -c "dl_dst=33:33:33:33:33:33" ovn-controller.log)"])

/.*terminating with signal 15.*/d
/.*Service monitor not found/d"])