File: Fix-CONNECT-performance-with-many-user-properties.patch

package info (click to toggle)
mosquitto 2.0.11-1.2%2Bdeb12u2
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 7,196 kB
  • sloc: ansic: 49,309; python: 14,884; xml: 7,055; makefile: 1,761; cpp: 1,542; sh: 267; perl: 70
file content (126 lines) | stat: -rw-r--r-- 4,355 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
From: "Roger A. Light" <roger@atchoo.org>
Date: Tue, 10 Aug 2021 20:48:21 +0100
Subject: Fix CONNECT performance with many user-properties.

Origin: https://github.com/eclipse/mosquitto/commit/9d6a73f9f72005c2f19a262f15d28327eedea91f
Bug: https://bugs.eclipse.org/bugs/show_bug.cgi?id=575314
Bug: https://gitlab.eclipse.org/eclipsefdn/helpdesk/-/issues/637
Bug-Debian: https://bugs.debian.org/1001028
Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2021-41039

An MQTT v5 client connecting with a large number of user-property properties
could cause excessive CPU usage, leading to a loss of performance and
possible denial of service. This has been fixed.
---
 lib/property_mosq.c              | 14 ++++++------
 test/broker/01-connect-575314.py | 49 ++++++++++++++++++++++++++++++++++++++++
 test/broker/Makefile             |  1 +
 test/broker/test.py              |  1 +
 4 files changed, 58 insertions(+), 7 deletions(-)
 create mode 100644 test/broker/01-connect-575314.py

diff --git a/lib/property_mosq.c b/lib/property_mosq.c
index 0cfc9f9..5f0f24c 100644
--- a/lib/property_mosq.c
+++ b/lib/property_mosq.c
@@ -959,14 +959,14 @@ int mosquitto_property_check_all(int command, const mosquitto_property *properti
 		if(rc) return rc;
 
 		/* Check for duplicates */
-		tail = p->next;
-		while(tail){
-			if(p->identifier == tail->identifier
-					&& p->identifier != MQTT_PROP_USER_PROPERTY){
-
-				return MOSQ_ERR_DUPLICATE_PROPERTY;
+		if(p->identifier != MQTT_PROP_USER_PROPERTY){
+			tail = p->next;
+			while(tail){
+				if(p->identifier == tail->identifier){
+					return MOSQ_ERR_DUPLICATE_PROPERTY;
+				}
+				tail = tail->next;
 			}
-			tail = tail->next;
 		}
 
 		p = p->next;
diff --git a/test/broker/01-connect-575314.py b/test/broker/01-connect-575314.py
new file mode 100644
index 0000000..4a8f314
--- /dev/null
+++ b/test/broker/01-connect-575314.py
@@ -0,0 +1,49 @@
+#!/usr/bin/env python3
+
+# Check for performance of processing user-property on CONNECT
+
+from mosq_test_helper import *
+
+def do_test():
+    rc = 1
+    props = mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value")
+    for i in range(0, 20000):
+        props += mqtt5_props.gen_string_pair_prop(mqtt5_props.PROP_USER_PROPERTY, "key", "value")
+    connect_packet_slow = mosq_test.gen_connect("connect-user-property", proto_ver=5, properties=props)
+    connect_packet_fast = mosq_test.gen_connect("a"*65000, proto_ver=5)
+    connack_packet = mosq_test.gen_connack(rc=0, proto_ver=5)
+
+    port = mosq_test.get_port()
+    broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port)
+
+    try:
+        t_start = time.monotonic()
+        sock = mosq_test.do_client_connect(connect_packet_slow, connack_packet, port=port)
+        t_stop = time.monotonic()
+        sock.close()
+
+        t_diff_slow = t_stop - t_start
+
+        t_start = time.monotonic()
+        sock = mosq_test.do_client_connect(connect_packet_fast, connack_packet, port=port)
+        t_stop = time.monotonic()
+        sock.close()
+
+        t_diff_fast = t_stop - t_start
+        # 20 is chosen as a factor that works in plain mode and running under
+        # valgrind. The slow performance manifests as a factor of >100. Fast is <10.
+        if t_diff_slow / t_diff_fast < 20:
+            rc = 0
+    except mosq_test.TestError:
+        pass
+    finally:
+        broker.terminate()
+        broker.wait()
+        (stdo, stde) = broker.communicate()
+        if rc:
+            print(stde.decode('utf-8'))
+            exit(rc)
+
+
+do_test()
+exit(0)
diff --git a/test/broker/Makefile b/test/broker/Makefile
index e1501b4..1ee2dd2 100644
--- a/test/broker/Makefile
+++ b/test/broker/Makefile
@@ -20,6 +20,7 @@ ptest : test-compile
 test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 13 14
 
 01 :
+	./01-connect-575314.py
 	./01-connect-allow-anonymous.py
 	./01-connect-bad-packet.py
 	./01-connect-connack-2163.py
diff --git a/test/broker/test.py b/test/broker/test.py
index 91a4ca4..3dc0058 100755
--- a/test/broker/test.py
+++ b/test/broker/test.py
@@ -5,6 +5,7 @@ import ptest
 
 tests = [
     #(ports required, 'path'),
+    (1, './01-connect-575314.py'),
     (1, './01-connect-allow-anonymous.py'),
     (1, './01-connect-bad-packet.py'),
     (1, './01-connect-connack-2163.py'),