Version in base suite: 2.0.11-1 Base version: mosquitto_2.0.11-1 Target version: mosquitto_2.0.11-1+deb11u1 Base file: /srv/ftp-master.debian.org/ftp/pool/main/m/mosquitto/mosquitto_2.0.11-1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/m/mosquitto/mosquitto_2.0.11-1+deb11u1.dsc changelog | 29 + patches/CVE-2021-34434.patch | 565 ++++++++++++++++++++++++++++++++ patches/CVE-2021-41039.patch | 119 ++++++ patches/CVE-2023-0809.patch | 134 +++++++ patches/CVE-2023-28366-regression.patch | 38 ++ patches/CVE-2023-28366.patch | 396 ++++++++++++++++++++++ patches/CVE-2023-3592.patch | 21 + patches/series | 6 tests/control | 2 9 files changed, 1309 insertions(+), 1 deletion(-) diff -Nru mosquitto-2.0.11/debian/changelog mosquitto-2.0.11/debian/changelog --- mosquitto-2.0.11/debian/changelog 2021-06-09 12:54:36.000000000 +0000 +++ mosquitto-2.0.11/debian/changelog 2023-09-30 14:50:16.000000000 +0000 @@ -1,3 +1,32 @@ +mosquitto (2.0.11-1+deb11u1) bullseye-security; urgency=high + + * Non-maintainer upload. + * Several security vulnerabilities have been discovered in mosquitto, a MQTT + compatible message broker, which may be abused for a denial of service + attack. + * CVE-2021-34434: + In Eclipse Mosquitto when using the dynamic security plugin, if the ability + for a client to make subscriptions on a topic is revoked when a durable + client is offline, then existing subscriptions for that client are not + revoked. + * 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. + * CVE-2023-0809: + Fix excessive memory being allocated based on malicious initial packets + that are not CONNECT packets. + * CVE-2023-3592: + Fix memory leak when clients send v5 CONNECT packets with a will message + that contains invalid property types. + * Fix CVE-2023-28366: + The broker in Eclipse Mosquitto has a memory leak that can be abused + remotely when a client sends many QoS 2 messages with duplicate message + IDs, and fails to respond to PUBREC commands. This occurs because of + mishandling of EAGAIN from the libc send function. + + -- Markus Koschany Sat, 30 Sep 2023 16:50:16 +0200 + mosquitto (2.0.11-1) unstable; urgency=medium * SECURITY UPDATE: In Eclipse Mosquitto 1.6 to 2.0.10, if an authenticated diff -Nru mosquitto-2.0.11/debian/patches/CVE-2021-34434.patch mosquitto-2.0.11/debian/patches/CVE-2021-34434.patch --- mosquitto-2.0.11/debian/patches/CVE-2021-34434.patch 1970-01-01 00:00:00.000000000 +0000 +++ mosquitto-2.0.11/debian/patches/CVE-2021-34434.patch 2023-09-30 14:50:16.000000000 +0000 @@ -0,0 +1,565 @@ +From: Markus Koschany +Date: Fri, 22 Sep 2023 11:40:25 +0200 +Subject: CVE-2021-34434 + +Bug-Debian: https://bugs.debian.org/993400 +Origin: https://github.com/eclipse/mosquitto/commit/32af599c81e63fa38e834b8f1c1f108c49328e95 +--- + lib/mosquitto_internal.h | 4 +- + src/handle_connect.c | 13 +- + src/mosquitto_broker_internal.h | 13 +- + src/plugin_public.c | 30 +++++ + src/subs.c | 174 ++++++++++++------------- + test/broker/02-subpub-recover-subscriptions.py | 81 ++++++++++++ + test/broker/Makefile | 1 + + test/broker/test.py | 1 + + 8 files changed, 212 insertions(+), 105 deletions(-) + create mode 100755 test/broker/02-subpub-recover-subscriptions.py + +diff --git a/lib/mosquitto_internal.h b/lib/mosquitto_internal.h +index 1651c86..64468a3 100644 +--- a/lib/mosquitto_internal.h ++++ b/lib/mosquitto_internal.h +@@ -287,11 +287,9 @@ struct mosquitto { + struct mosquitto__acl_user *acl_list; + struct mosquitto__listener *listener; + struct mosquitto__packet *out_packet_last; +- struct mosquitto__subhier **subs; +- struct mosquitto__subshared_ref **shared_subs; ++ struct mosquitto__client_sub **subs; + char *auth_method; + int sub_count; +- int shared_sub_count; + # ifndef WITH_EPOLL + int pollfd_index; + # endif +diff --git a/src/handle_connect.c b/src/handle_connect.c +index c1a096b..29c0a5c 100644 +--- a/src/handle_connect.c ++++ b/src/handle_connect.c +@@ -102,7 +102,6 @@ static void connection_check_acl(struct mosquitto *context, struct mosquitto_cli + } + } + +- + int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint16_t auth_data_out_len) + { + struct mosquitto *found_context; +@@ -163,13 +162,23 @@ int connect__on_authorised(struct mosquitto *context, void *auth_data_out, uint1 + + for(i=0; isub_count; i++){ + if(context->subs[i]){ +- leaf = context->subs[i]->subs; ++ leaf = context->subs[i]->hier->subs; + while(leaf){ + if(leaf->context == found_context){ + leaf->context = context; + } + leaf = leaf->next; + } ++ ++ if(context->subs[i]->shared){ ++ leaf = context->subs[i]->shared->subs; ++ while(leaf){ ++ if(leaf->context == found_context){ ++ leaf->context = context; ++ } ++ leaf = leaf->next; ++ } ++ } + } + } + } +diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h +index ffc9c9e..657c1ce 100644 +--- a/src/mosquitto_broker_internal.h ++++ b/src/mosquitto_broker_internal.h +@@ -306,6 +306,7 @@ struct mosquitto__config { + struct mosquitto__security_options security_options; + }; + ++ + struct mosquitto__subleaf { + struct mosquitto__subleaf *prev; + struct mosquitto__subleaf *next; +@@ -317,12 +318,6 @@ struct mosquitto__subleaf { + }; + + +-struct mosquitto__subshared_ref { +- struct mosquitto__subhier *hier; +- struct mosquitto__subshared *shared; +-}; +- +- + struct mosquitto__subshared { + UT_hash_handle hh; + char *name; +@@ -339,6 +334,12 @@ struct mosquitto__subhier { + uint16_t topic_len; + }; + ++struct mosquitto__client_sub { ++ struct mosquitto__subhier *hier; ++ struct mosquitto__subshared *shared; ++ char topic_filter[]; ++}; ++ + struct sub__token { + struct sub__token *next; + char *topic; +diff --git a/src/plugin_public.c b/src/plugin_public.c +index 5df56fe..754793b 100644 +--- a/src/plugin_public.c ++++ b/src/plugin_public.c +@@ -263,6 +263,33 @@ int mosquitto_set_username(struct mosquitto *client, const char *username) + } + + ++/* Check to see whether durable clients still have rights to their subscriptions. */ ++static void check_subscription_acls(struct mosquitto *context) ++{ ++ int i; ++ int rc; ++ uint8_t reason; ++ ++ for(i=0; isub_count; i++){ ++ if(context->subs[i] == NULL){ ++ continue; ++ } ++ rc = mosquitto_acl_check(context, ++ context->subs[i]->topic_filter, ++ 0, ++ NULL, ++ 0, /* FIXME */ ++ false, ++ MOSQ_ACL_SUBSCRIBE); ++ ++ if(rc != MOSQ_ERR_SUCCESS){ ++ sub__remove(context, context->subs[i]->topic_filter, db.subs, &reason); ++ } ++ } ++} ++ ++ ++ + static void disconnect_client(struct mosquitto *context, bool with_will) + { + if(context->protocol == mosq_p_mqtt5){ +@@ -271,6 +298,9 @@ static void disconnect_client(struct mosquitto *context, bool with_will) + if(with_will == false){ + mosquitto__set_state(context, mosq_cs_disconnecting); + } ++ if(context->session_expiry_interval > 0){ ++ check_subscription_acls(context); ++ } + do_disconnect(context, MOSQ_ERR_ADMINISTRATIVE_ACTION); + } + +diff --git a/src/subs.c b/src/subs.c +index 5868492..2ccafbc 100644 +--- a/src/subs.c ++++ b/src/subs.c +@@ -199,12 +199,12 @@ static void sub__remove_shared_leaf(struct mosquitto__subhier *subhier, struct m + } + + +-static int sub__add_shared(struct mosquitto *context, uint8_t qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, const char *sharename) ++static int sub__add_shared(struct mosquitto *context, const char *sub, uint8_t qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, const char *sharename) + { + struct mosquitto__subleaf *newleaf; + struct mosquitto__subshared *shared = NULL; +- struct mosquitto__subshared_ref **shared_subs; +- struct mosquitto__subshared_ref *shared_ref; ++ struct mosquitto__client_sub **subs; ++ struct mosquitto__client_sub *csub; + int i; + size_t slen; + int rc; +@@ -237,32 +237,30 @@ static int sub__add_shared(struct mosquitto *context, uint8_t qos, uint32_t iden + } + + if(rc != MOSQ_ERR_SUB_EXISTS){ +- shared_ref = mosquitto__calloc(1, sizeof(struct mosquitto__subshared_ref)); +- if(!shared_ref){ +- sub__remove_shared_leaf(subhier, shared, newleaf); +- return MOSQ_ERR_NOMEM; +- } +- shared_ref->hier = subhier; +- shared_ref->shared = shared; ++ slen = strlen(sub); ++ csub = mosquitto__calloc(1, sizeof(struct mosquitto__client_sub) + slen + 1); ++ if(csub == NULL) return MOSQ_ERR_NOMEM; ++ memcpy(csub->topic_filter, sub, slen); ++ csub->hier = subhier; ++ csub->shared = shared; + +- for(i=0; ishared_sub_count; i++){ +- if(!context->shared_subs[i]){ +- context->shared_subs[i] = shared_ref; +- shared_ref = NULL; ++ for(i=0; isub_count; i++){ ++ if(!context->subs[i]){ ++ context->subs[i] = csub; + break; + } + } +- if(shared_ref){ +- shared_subs = mosquitto__realloc(context->shared_subs, sizeof(struct mosquitto__subshared_ref *)*(size_t)(context->shared_sub_count + 1)); +- if(!shared_subs){ +- mosquitto__free(shared_ref); +- context->shared_subs[context->shared_sub_count-1] = NULL; ++ if(i == context->sub_count){ ++ subs = mosquitto__realloc(context->subs, sizeof(struct mosquitto__client_sub *)*(size_t)(context->sub_count + 1)); ++ if(!subs){ + sub__remove_shared_leaf(subhier, shared, newleaf); ++ mosquitto__free(newleaf); ++ mosquitto__free(csub); + return MOSQ_ERR_NOMEM; + } +- context->shared_subs = shared_subs; +- context->shared_sub_count++; +- context->shared_subs[context->shared_sub_count-1] = shared_ref; ++ context->subs = subs; ++ context->sub_count++; ++ context->subs[context->sub_count-1] = csub; + } + #ifdef WITH_SYS_TREE + db.shared_subscription_count++; +@@ -279,35 +277,45 @@ static int sub__add_shared(struct mosquitto *context, uint8_t qos, uint32_t iden + } + + +-static int sub__add_normal(struct mosquitto *context, uint8_t qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier) ++static int sub__add_normal(struct mosquitto *context, const char *sub, uint8_t qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier) + { + struct mosquitto__subleaf *newleaf = NULL; +- struct mosquitto__subhier **subs; ++ struct mosquitto__client_sub **subs; ++ struct mosquitto__client_sub *csub; + int i; + int rc; ++ size_t slen; + + rc = sub__add_leaf(context, qos, identifier, options, &subhier->subs, &newleaf); + if(rc > 0){ + return rc; + } + ++ slen = strlen(sub); ++ csub = mosquitto__calloc(1, sizeof(struct mosquitto__client_sub) + slen + 1); ++ if(csub == NULL) return MOSQ_ERR_NOMEM; ++ memcpy(csub->topic_filter, sub, slen); ++ csub->hier = subhier; ++ csub->shared = NULL; ++ + if(rc != MOSQ_ERR_SUB_EXISTS){ + for(i=0; isub_count; i++){ + if(!context->subs[i]){ +- context->subs[i] = subhier; ++ context->subs[i] = csub; + break; + } + } + if(i == context->sub_count){ +- subs = mosquitto__realloc(context->subs, sizeof(struct mosquitto__subhier *)*(size_t)(context->sub_count + 1)); ++ subs = mosquitto__realloc(context->subs, sizeof(struct mosquitto__client_sub *)*(size_t)(context->sub_count + 1)); + if(!subs){ + DL_DELETE(subhier->subs, newleaf); + mosquitto__free(newleaf); ++ mosquitto__free(csub); + return MOSQ_ERR_NOMEM; + } + context->subs = subs; + context->sub_count++; +- context->subs[context->sub_count-1] = subhier; ++ context->subs[context->sub_count-1] = csub; + } + #ifdef WITH_SYS_TREE + db.subscription_count++; +@@ -324,7 +332,7 @@ static int sub__add_normal(struct mosquitto *context, uint8_t qos, uint32_t iden + } + + +-static int sub__add_context(struct mosquitto *context, uint8_t qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, char *const *const topics, const char *sharename) ++static int sub__add_context(struct mosquitto *context, const char *topic_filter, uint8_t qos, uint32_t identifier, int options, struct mosquitto__subhier *subhier, char *const *const topics, const char *sharename) + { + struct mosquitto__subhier *branch; + int topic_index = 0; +@@ -349,9 +357,9 @@ static int sub__add_context(struct mosquitto *context, uint8_t qos, uint32_t ide + /* Add add our context */ + if(context && context->id){ + if(sharename){ +- return sub__add_shared(context, qos, identifier, options, subhier, sharename); ++ return sub__add_shared(context, topic_filter, qos, identifier, options, subhier, sharename); + }else{ +- return sub__add_normal(context, qos, identifier, options, subhier); ++ return sub__add_normal(context, topic_filter, qos, identifier, options, subhier); + } + }else{ + return MOSQ_ERR_SUCCESS; +@@ -378,7 +386,8 @@ static int sub__remove_normal(struct mosquitto *context, struct mosquitto__subhi + * but that would involve keeping a copy of the topic string in + * each subleaf. Might be worth considering though. */ + for(i=0; isub_count; i++){ +- if(context->subs[i] == subhier){ ++ if(context->subs[i] && context->subs[i]->hier == subhier){ ++ mosquitto__free(context->subs[i]); + context->subs[i] = NULL; + break; + } +@@ -413,13 +422,13 @@ static int sub__remove_shared(struct mosquitto *context, struct mosquitto__subhi + * It would be nice to be able to use the reference directly, + * but that would involve keeping a copy of the topic string in + * each subleaf. Might be worth considering though. */ +- for(i=0; ishared_sub_count; i++){ +- if(context->shared_subs[i] +- && context->shared_subs[i]->hier == subhier +- && context->shared_subs[i]->shared == shared){ ++ for(i=0; isub_count; i++){ ++ if(context->subs[i] ++ && context->subs[i]->hier == subhier ++ && context->subs[i]->shared == shared){ + +- mosquitto__free(context->shared_subs[i]); +- context->shared_subs[i] = NULL; ++ mosquitto__free(context->subs[i]); ++ context->subs[i] = NULL; + break; + } + } +@@ -599,7 +608,7 @@ int sub__add(struct mosquitto *context, const char *sub, uint8_t qos, uint32_t i + } + + } +- rc = sub__add_context(context, qos, identifier, options, subhier, topics, sharename); ++ rc = sub__add_context(context, sub, qos, identifier, options, subhier, topics, sharename); + + mosquitto__free(local_sub); + mosquitto__free(topics); +@@ -699,47 +708,6 @@ static struct mosquitto__subhier *tmp_remove_subs(struct mosquitto__subhier *sub + } + + +-static int sub__clean_session_shared(struct mosquitto *context) +-{ +- int i; +- struct mosquitto__subleaf *leaf; +- struct mosquitto__subhier *hier; +- +- for(i=0; ishared_sub_count; i++){ +- if(context->shared_subs[i] == NULL){ +- continue; +- } +- leaf = context->shared_subs[i]->shared->subs; +- while(leaf){ +- if(leaf->context==context){ +-#ifdef WITH_SYS_TREE +- db.shared_subscription_count--; +-#endif +- sub__remove_shared_leaf(context->shared_subs[i]->hier, context->shared_subs[i]->shared, leaf); +- break; +- } +- leaf = leaf->next; +- } +- if(context->shared_subs[i]->hier->subs == NULL +- && context->shared_subs[i]->hier->children == NULL +- && context->shared_subs[i]->hier->shared == NULL +- && context->shared_subs[i]->hier->parent){ +- +- hier = context->shared_subs[i]->hier; +- context->shared_subs[i]->hier = NULL; +- do{ +- hier = tmp_remove_subs(hier); +- }while(hier); +- } +- mosquitto__free(context->shared_subs[i]); +- } +- mosquitto__free(context->shared_subs); +- context->shared_subs = NULL; +- context->shared_sub_count = 0; +- +- return MOSQ_ERR_SUCCESS; +-} +- + /* Remove all subscriptions for a client. + */ + int sub__clean_session(struct mosquitto *context) +@@ -752,25 +720,43 @@ int sub__clean_session(struct mosquitto *context) + if(context->subs[i] == NULL){ + continue; + } +- leaf = context->subs[i]->subs; +- while(leaf){ +- if(leaf->context==context){ ++ ++ hier = context->subs[i]->hier; ++ ++ if(context->subs[i]->shared){ ++ leaf = context->subs[i]->shared->subs; ++ while(leaf){ ++ if(leaf->context==context){ + #ifdef WITH_SYS_TREE +- db.subscription_count--; ++ db.shared_subscription_count--; + #endif +- DL_DELETE(context->subs[i]->subs, leaf); +- mosquitto__free(leaf); +- break; ++ sub__remove_shared_leaf(context->subs[i]->hier, context->subs[i]->shared, leaf); ++ break; ++ } ++ leaf = leaf->next; ++ } ++ }else{ ++ leaf = hier->subs; ++ while(leaf){ ++ if(leaf->context==context){ ++#ifdef WITH_SYS_TREE ++ db.subscription_count--; ++#endif ++ DL_DELETE(hier->subs, leaf); ++ mosquitto__free(leaf); ++ break; ++ } ++ leaf = leaf->next; + } +- leaf = leaf->next; + } +- if(context->subs[i]->subs == NULL +- && context->subs[i]->children == NULL +- && context->subs[i]->shared == NULL +- && context->subs[i]->parent){ ++ mosquitto__free(context->subs[i]); ++ context->subs[i] = NULL; ++ ++ if(hier->subs == NULL ++ && hier->children == NULL ++ && hier->shared == NULL ++ && hier->parent){ + +- hier = context->subs[i]; +- context->subs[i] = NULL; + do{ + hier = tmp_remove_subs(hier); + }while(hier); +@@ -780,7 +766,7 @@ int sub__clean_session(struct mosquitto *context) + context->subs = NULL; + context->sub_count = 0; + +- return sub__clean_session_shared(context); ++ return MOSQ_ERR_SUCCESS; + } + + void sub__tree_print(struct mosquitto__subhier *root, int level) +diff --git a/test/broker/02-subpub-recover-subscriptions.py b/test/broker/02-subpub-recover-subscriptions.py +new file mode 100755 +index 0000000..e372299 +--- /dev/null ++++ b/test/broker/02-subpub-recover-subscriptions.py +@@ -0,0 +1,81 @@ ++#!/usr/bin/env python3 ++ ++# Check whether a durable client keeps its subscriptions on reconnecting. ++ ++from mosq_test_helper import * ++ ++def publish_helper(port): ++ connect_packet = mosq_test.gen_connect("subpub-sub-helper") ++ connack_packet = mosq_test.gen_connack(rc=0) ++ publish1_packet = mosq_test.gen_publish("not-shared/sub", qos=0, payload="message1") ++ publish2_packet = mosq_test.gen_publish("shared/sub", qos=0, payload="message2") ++ sock = mosq_test.do_client_connect(connect_packet, connack_packet, timeout=20, port=port) ++ sock.send(publish1_packet) ++ sock.send(publish2_packet) ++ sock.close() ++ ++ ++def do_test(proto_ver): ++ rc = 1 ++ if proto_ver == 5: ++ props = mqtt5_props.gen_uint32_prop(mqtt5_props.PROP_SESSION_EXPIRY_INTERVAL, 60) ++ connect_packet = mosq_test.gen_connect("subpub-sub-test", proto_ver=proto_ver, clean_session=False, properties=props) ++ else: ++ connect_packet = mosq_test.gen_connect("subpub-sub-test", proto_ver=proto_ver, clean_session=False) ++ connack1_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver) ++ connack2_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver, flags=1) ++ ++ mid = 1 ++ subscribe1_packet = mosq_test.gen_subscribe(mid, "not-shared/sub", 0, proto_ver=proto_ver) ++ suback1_packet = mosq_test.gen_suback(mid, 0, proto_ver=proto_ver) ++ ++ mid = 2 ++ subscribe2_packet = mosq_test.gen_subscribe(mid, "$share/name/shared/sub", 0, proto_ver=proto_ver) ++ suback2_packet = mosq_test.gen_suback(mid, 0, proto_ver=proto_ver) ++ ++ publish1_packet = mosq_test.gen_publish("not-shared/sub", qos=0, payload="message1", proto_ver=proto_ver) ++ publish2_packet = mosq_test.gen_publish("shared/sub", qos=0, payload="message2", proto_ver=proto_ver) ++ ++ port = mosq_test.get_port() ++ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) ++ ++ try: ++ sock = mosq_test.do_client_connect(connect_packet, connack1_packet, timeout=2, port=port, connack_error="connack 1") ++ ++ mosq_test.do_send_receive(sock, subscribe1_packet, suback1_packet, "suback1") ++ mosq_test.do_send_receive(sock, subscribe2_packet, suback2_packet, "suback2") ++ ++ publish_helper(port) ++ mosq_test.expect_packet(sock, "publish1", publish1_packet) ++ if proto_ver == 5: ++ mosq_test.expect_packet(sock, "publish2", publish2_packet) ++ sock.close() ++ ++ # Reconnect, but don't resubscribe ++ sock = mosq_test.do_client_connect(connect_packet, connack2_packet, timeout=2, port=port, connack_error="connack 2") ++ ++ publish_helper(port) ++ mosq_test.expect_packet(sock, "publish1", publish1_packet) ++ if proto_ver == 5: ++ mosq_test.expect_packet(sock, "publish2", publish2_packet) ++ sock.close() ++ ++ rc = 0 ++ ++ sock.close() ++ except mosq_test.TestError: ++ pass ++ except Exception as err: ++ print(err) ++ finally: ++ broker.terminate() ++ broker.wait() ++ (stdo, stde) = broker.communicate() ++ if rc: ++ print(stde.decode('utf-8')) ++ exit(rc) ++ ++ ++do_test(proto_ver=4) ++do_test(proto_ver=5) ++exit(0) +diff --git a/test/broker/Makefile b/test/broker/Makefile +index 620e5b6..e9428ae 100644 +--- a/test/broker/Makefile ++++ b/test/broker/Makefile +@@ -70,6 +70,7 @@ test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + ./02-subpub-qos2-receive-maximum-1.py + ./02-subpub-qos2-receive-maximum-2.py + ./02-subpub-qos2.py ++ ./02-subpub-recover-subscriptions.py + ./02-subscribe-dollar-v5.py + ./02-subscribe-invalid-utf8.py + ./02-subscribe-long-topic.py +diff --git a/test/broker/test.py b/test/broker/test.py +index e6fdbe0..1ade932 100755 +--- a/test/broker/test.py ++++ b/test/broker/test.py +@@ -53,6 +53,7 @@ tests = [ + (1, './02-subpub-qos2-receive-maximum-1.py'), + (1, './02-subpub-qos2-receive-maximum-2.py'), + (1, './02-subpub-qos2.py'), ++ (1, './02-subpub-recover-subscriptions.py'), + (1, './02-subscribe-dollar-v5.py'), + (1, './02-subscribe-invalid-utf8.py'), + (1, './02-subscribe-long-topic.py'), diff -Nru mosquitto-2.0.11/debian/patches/CVE-2021-41039.patch mosquitto-2.0.11/debian/patches/CVE-2021-41039.patch --- mosquitto-2.0.11/debian/patches/CVE-2021-41039.patch 1970-01-01 00:00:00.000000000 +0000 +++ mosquitto-2.0.11/debian/patches/CVE-2021-41039.patch 2023-09-30 14:50:16.000000000 +0000 @@ -0,0 +1,119 @@ +From: Markus Koschany +Date: Thu, 21 Sep 2023 12:26:35 +0200 +Subject: CVE-2021-41039 + +Bug-Debian: https://bugs.debian.org/1001028 +Origin: https://github.com/eclipse/mosquitto/commit/9d6a73f9f72005c2f19a262f15d28327eedea91f +--- + 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 100755 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 100755 +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'), diff -Nru mosquitto-2.0.11/debian/patches/CVE-2023-0809.patch mosquitto-2.0.11/debian/patches/CVE-2023-0809.patch --- mosquitto-2.0.11/debian/patches/CVE-2023-0809.patch 1970-01-01 00:00:00.000000000 +0000 +++ mosquitto-2.0.11/debian/patches/CVE-2023-0809.patch 2023-09-30 14:50:16.000000000 +0000 @@ -0,0 +1,134 @@ +From: Markus Koschany +Date: Sat, 30 Sep 2023 13:24:49 +0200 +Subject: CVE-2023-0809 + +Origin: https://github.com/eclipse/mosquitto/commit/a3c680fbb00a0019573fb84c29332e845e6efcad +--- + lib/packet_mosq.c | 2 +- + test/broker/01-bad-initial-packets.py | 78 +++++++++++++++++++++++++++++++++++ + test/broker/Makefile | 1 + + test/broker/test.py | 1 + + 4 files changed, 81 insertions(+), 1 deletion(-) + create mode 100755 test/broker/01-bad-initial-packets.py + +diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c +index 64f96ac..d92c2d8 100644 +--- a/lib/packet_mosq.c ++++ b/lib/packet_mosq.c +@@ -395,7 +395,7 @@ int packet__read(struct mosquitto *mosq) + #ifdef WITH_BROKER + G_BYTES_RECEIVED_INC(1); + /* Clients must send CONNECT as their first command. */ +- if(!(mosq->bridge) && state == mosq_cs_connected && (byte&0xF0) != CMD_CONNECT){ ++ if(!(mosq->bridge) && state == mosq_cs_new && (byte&0xF0) != CMD_CONNECT){ + return MOSQ_ERR_PROTOCOL; + } + #endif +diff --git a/test/broker/01-bad-initial-packets.py b/test/broker/01-bad-initial-packets.py +new file mode 100755 +index 0000000..52f2de9 +--- /dev/null ++++ b/test/broker/01-bad-initial-packets.py +@@ -0,0 +1,78 @@ ++#!/usr/bin/env python3 ++ ++# Test whether non-CONNECT packets as an initial packet can cause excess memory use ++ ++from mosq_test_helper import * ++import psutil ++ ++def write_config(filename, port): ++ with open(filename, 'w') as f: ++ f.write(f"listener {port}\n") ++ f.write("allow_anonymous true\n") ++ f.write("sys_interval 1\n") ++ ++def do_send(port, socks, payload): ++ sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) ++ socks.append(sock) ++ sock.connect(("127.0.0.1", port)) ++ try: ++ sock.send(payload) ++ except ConnectionResetError: ++ pass ++ ++def do_test(port): ++ rc = 1 ++ ++ conf_file = os.path.basename(__file__).replace('.py', '.conf') ++ write_config(conf_file, port) ++ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port, use_conf=True) ++ ++ try: ++ socks = [] ++ ++ do_send(port, socks, b"\x20\x80\x80\x80t" + b"\01"*100000000) # CONNACK ++ do_send(port, socks, b"\x30\x80\x80\x80t" + b"\01"*100000000) # PUBLISH ++ do_send(port, socks, b"\x40\x80\x80\x80t" + b"\01"*100000000) # PUBACK ++ do_send(port, socks, b"\x50\x80\x80\x80t" + b"\01"*100000000) # PUBREC ++ do_send(port, socks, b"\x60\x80\x80\x80t" + b"\01"*100000000) # PUBREL ++ do_send(port, socks, b"\x70\x80\x80\x80t" + b"\01"*100000000) # PUBCOMP ++ do_send(port, socks, b"\x80\x80\x80\x80t" + b"\01"*100000000) # SUBSCRIBE ++ do_send(port, socks, b"\x90\x80\x80\x80t" + b"\01"*100000000) # SUBACK ++ do_send(port, socks, b"\xA0\x80\x80\x80t" + b"\01"*100000000) # UNSUBSCRIBE ++ do_send(port, socks, b"\xB0\x80\x80\x80t" + b"\01"*100000000) # UNSUBACK ++ do_send(port, socks, b"\xC0\x80\x80\x80t" + b"\01"*100000000) # PINGREQ ++ do_send(port, socks, b"\xD0\x80\x80\x80t" + b"\01"*100000000) # PINGRESP ++ do_send(port, socks, b"\xE0\x80\x80\x80t" + b"\01"*100000000) # DISCONNECT ++ do_send(port, socks, b"\xF0\x80\x80\x80t" + b"\01"*100000000) # AUTH ++ ++ mem = psutil.Process(broker.pid).memory_info().vms ++ ++ for s in socks: ++ s.close() ++ ++ limit = 25000000 ++ if mem > limit: ++ raise mosq_test.TestError(f"Process memory {mem} greater than limit of {limit}") ++ ++ rc = 0 ++ except MemoryError: ++ print("Memory error!") ++ except Exception as e: ++ print(e) ++ except mosq_test.TestError: ++ pass ++ finally: ++ os.remove(conf_file) ++ broker.terminate() ++ broker.wait() ++ (stdo, stde) = broker.communicate() ++ if rc: ++ print(stde.decode('utf-8')) ++ exit(rc) ++ ++ ++port = mosq_test.get_port() ++ ++do_test(port) ++ ++exit(0) +diff --git a/test/broker/Makefile b/test/broker/Makefile +index e9428ae..841e148 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-bad-initial-packets.py + ./01-connect-575314.py + ./01-connect-allow-anonymous.py + ./01-connect-bad-packet.py +diff --git a/test/broker/test.py b/test/broker/test.py +index 1ade932..622083b 100755 +--- a/test/broker/test.py ++++ b/test/broker/test.py +@@ -5,6 +5,7 @@ import ptest + + tests = [ + #(ports required, 'path'), ++ (1, './01-bad-initial-packets.py'), + (1, './01-connect-575314.py'), + (1, './01-connect-allow-anonymous.py'), + (1, './01-connect-bad-packet.py'), diff -Nru mosquitto-2.0.11/debian/patches/CVE-2023-28366-regression.patch mosquitto-2.0.11/debian/patches/CVE-2023-28366-regression.patch --- mosquitto-2.0.11/debian/patches/CVE-2023-28366-regression.patch 1970-01-01 00:00:00.000000000 +0000 +++ mosquitto-2.0.11/debian/patches/CVE-2023-28366-regression.patch 2023-09-30 14:50:16.000000000 +0000 @@ -0,0 +1,38 @@ +From: Markus Koschany +Date: Sat, 30 Sep 2023 20:25:18 +0200 +Subject: CVE-2023-28366 regression + +--- + lib/packet_mosq.c | 2 +- + src/context.c | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c +index d92c2d8..beb14e2 100644 +--- a/lib/packet_mosq.c ++++ b/lib/packet_mosq.c +@@ -154,7 +154,7 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet) + pthread_mutex_lock(&mosq->out_packet_mutex); + + #ifdef WITH_BROKER +- if(mosq->out_packet_count >= db.config->max_queued_messages){ ++ if(db.config->max_queued_messages > 0 && mosq->out_packet_count >= db.config->max_queued_messages){ + mosquitto__free(packet); + if(mosq->is_dropping == false){ + mosq->is_dropping = true; +diff --git a/src/context.c b/src/context.c +index ed7c173..bf82cbb 100644 +--- a/src/context.c ++++ b/src/context.c +@@ -83,9 +83,9 @@ struct mosquitto *context__init(mosq_sock_t sock) + } + } + context->bridge = NULL; +- context->msgs_in.inflight_maximum = 1; ++ context->msgs_in.inflight_maximum = db.config->max_inflight_messages; ++ context->msgs_in.inflight_quota = db.config->max_inflight_messages; + context->msgs_out.inflight_maximum = db.config->max_inflight_messages; +- context->msgs_in.inflight_quota = 1; + context->msgs_out.inflight_quota = db.config->max_inflight_messages; + context->max_qos = 2; + #ifdef WITH_TLS diff -Nru mosquitto-2.0.11/debian/patches/CVE-2023-28366.patch mosquitto-2.0.11/debian/patches/CVE-2023-28366.patch --- mosquitto-2.0.11/debian/patches/CVE-2023-28366.patch 1970-01-01 00:00:00.000000000 +0000 +++ mosquitto-2.0.11/debian/patches/CVE-2023-28366.patch 2023-09-30 14:50:16.000000000 +0000 @@ -0,0 +1,396 @@ +From: Markus Koschany +Date: Fri, 22 Sep 2023 11:35:46 +0200 +Subject: CVE-2023-28366 + +Origin: https://github.com/eclipse/mosquitto/commit/6113eac95a9df634fbc858be542c4a0456bfe7b9 +--- + lib/packet_mosq.c | 15 ++++++++++ + src/context.c | 41 ++++++++++++++++----------- + src/database.c | 25 +++++++++------- + src/handle_publish.c | 35 +++++++++++++++-------- + src/mosquitto_broker_internal.h | 4 +-- + test/broker/03-publish-qos2-dup.py | 58 ++++++++++++++++++++++++++++++++++++++ + test/broker/Makefile | 1 + + test/broker/test.py | 1 + + 8 files changed, 141 insertions(+), 39 deletions(-) + create mode 100755 test/broker/03-publish-qos2-dup.py + +diff --git a/lib/packet_mosq.c b/lib/packet_mosq.c +index 43611bc..64f96ac 100644 +--- a/lib/packet_mosq.c ++++ b/lib/packet_mosq.c +@@ -152,6 +152,21 @@ int packet__queue(struct mosquitto *mosq, struct mosquitto__packet *packet) + + packet->next = NULL; + pthread_mutex_lock(&mosq->out_packet_mutex); ++ ++#ifdef WITH_BROKER ++ if(mosq->out_packet_count >= db.config->max_queued_messages){ ++ mosquitto__free(packet); ++ if(mosq->is_dropping == false){ ++ mosq->is_dropping = true; ++ log__printf(NULL, MOSQ_LOG_NOTICE, ++ "Outgoing messages are being dropped for client %s.", ++ mosq->id); ++ } ++ G_MSGS_DROPPED_INC(); ++ return MOSQ_ERR_SUCCESS; ++ } ++#endif ++ + if(mosq->out_packet){ + mosq->out_packet_last->next = packet; + }else{ +diff --git a/src/context.c b/src/context.c +index fc68692..ed7c173 100644 +--- a/src/context.c ++++ b/src/context.c +@@ -83,9 +83,9 @@ struct mosquitto *context__init(mosq_sock_t sock) + } + } + context->bridge = NULL; +- context->msgs_in.inflight_maximum = db.config->max_inflight_messages; ++ context->msgs_in.inflight_maximum = 1; + context->msgs_out.inflight_maximum = db.config->max_inflight_messages; +- context->msgs_in.inflight_quota = db.config->max_inflight_messages; ++ context->msgs_in.inflight_quota = 1; + context->msgs_out.inflight_quota = db.config->max_inflight_messages; + context->max_qos = 2; + #ifdef WITH_TLS +@@ -98,6 +98,27 @@ struct mosquitto *context__init(mosq_sock_t sock) + return context; + } + ++static void context__cleanup_out_packets(struct mosquitto *context) ++{ ++ struct mosquitto__packet *packet; ++ ++ if(!context) return; ++ ++ if(context->current_out_packet){ ++ packet__cleanup(context->current_out_packet); ++ mosquitto__free(context->current_out_packet); ++ context->current_out_packet = NULL; ++ } ++ while(context->out_packet){ ++ packet__cleanup(context->out_packet); ++ packet = context->out_packet; ++ context->out_packet = context->out_packet->next; ++ mosquitto__free(packet); ++ } ++ context->out_packet_count = 0; ++} ++ ++ + /* + * This will result in any outgoing packets going unsent. If we're disconnected + * forcefully then it is usually an error condition and shouldn't be a problem, +@@ -106,8 +127,6 @@ struct mosquitto *context__init(mosq_sock_t sock) + */ + void context__cleanup(struct mosquitto *context, bool force_free) + { +- struct mosquitto__packet *packet; +- + if(!context) return; + + if(force_free){ +@@ -121,6 +140,7 @@ void context__cleanup(struct mosquitto *context, bool force_free) + #endif + + alias__free_all(context); ++ context__cleanup_out_packets(context); + + mosquitto__free(context->auth_method); + context->auth_method = NULL; +@@ -148,18 +168,7 @@ void context__cleanup(struct mosquitto *context, bool force_free) + context->id = NULL; + } + packet__cleanup(&(context->in_packet)); +- if(context->current_out_packet){ +- packet__cleanup(context->current_out_packet); +- mosquitto__free(context->current_out_packet); +- context->current_out_packet = NULL; +- } +- while(context->out_packet){ +- packet__cleanup(context->out_packet); +- packet = context->out_packet; +- context->out_packet = context->out_packet->next; +- mosquitto__free(packet); +- } +- context->out_packet_count = 0; ++ context__cleanup_out_packets(context); + #if defined(WITH_BROKER) && defined(__GLIBC__) && defined(WITH_ADNS) + if(context->adns){ + gai_cancel(context->adns); +diff --git a/src/database.c b/src/database.c +index 94c9e00..b6ea83b 100644 +--- a/src/database.c ++++ b/src/database.c +@@ -499,7 +499,7 @@ int db__message_insert(struct mosquitto *context, uint16_t mid, enum mosquitto_m + } + #endif + +- msg = mosquitto__malloc(sizeof(struct mosquitto_client_msg)); ++ msg = mosquitto__calloc(1, sizeof(struct mosquitto_client_msg)); + if(!msg) return MOSQ_ERR_NOMEM; + msg->prev = NULL; + msg->next = NULL; +@@ -561,6 +561,8 @@ int db__message_insert(struct mosquitto *context, uint16_t mid, enum mosquitto_m + + if(dir == mosq_md_out && msg->qos > 0){ + util__decrement_send_quota(context); ++ }else if(dir == mosq_md_in && msg->qos > 0 && state != mosq_ms_queued){ ++ util__decrement_receive_quota(context); + } + + if(dir == mosq_md_out && update){ +@@ -736,23 +738,24 @@ int db__message_store(const struct mosquitto *source, struct mosquitto_msg_store + return MOSQ_ERR_SUCCESS; + } + +-int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored) ++int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_client_msg **client_msg) + { +- struct mosquitto_client_msg *tail; ++ struct mosquitto_client_msg *cmsg; ++ ++ *client_msg = NULL; + + if(!context) return MOSQ_ERR_INVAL; + +- *stored = NULL; +- DL_FOREACH(context->msgs_in.inflight, tail){ +- if(tail->store->source_mid == mid){ +- *stored = tail->store; ++ DL_FOREACH(context->msgs_in.inflight, cmsg){ ++ if(cmsg->store->source_mid == mid){ ++ *client_msg = cmsg; + return MOSQ_ERR_SUCCESS; + } + } + +- DL_FOREACH(context->msgs_in.queued, tail){ +- if(tail->store->source_mid == mid){ +- *stored = tail->store; ++ DL_FOREACH(context->msgs_in.queued, cmsg){ ++ if(cmsg->store->source_mid == mid){ ++ *client_msg = cmsg; + return MOSQ_ERR_SUCCESS; + } + } +@@ -857,6 +860,7 @@ static int db__message_reconnect_reset_incoming(struct mosquitto *context) + }else{ + /* Message state can be preserved here because it should match + * whatever the client has got. */ ++ msg->dup = 0; + } + } + +@@ -867,6 +871,7 @@ static int db__message_reconnect_reset_incoming(struct mosquitto *context) + * will be sent out of order. + */ + DL_FOREACH_SAFE(context->msgs_in.queued, msg, tmp){ ++ msg->dup = 0; + context->msgs_in.msg_count++; + context->msgs_in.msg_bytes += msg->store->payloadlen; + if(msg->qos > 0){ +diff --git a/src/handle_publish.c b/src/handle_publish.c +index aa3f879..bc21044 100644 +--- a/src/handle_publish.c ++++ b/src/handle_publish.c +@@ -42,6 +42,7 @@ int handle__publish(struct mosquitto *context) + uint8_t header = context->in_packet.command; + int res = 0; + struct mosquitto_msg_store *msg, *stored = NULL; ++ struct mosquitto_client_msg *cmsg_stored = NULL; + size_t len; + uint16_t slen; + char *topic_mount; +@@ -285,24 +286,24 @@ int handle__publish(struct mosquitto *context) + } + + if(msg->qos > 0){ +- db__message_store_find(context, msg->source_mid, &stored); ++ db__message_store_find(context, msg->source_mid, &cmsg_stored); + } + +- if(stored && msg->source_mid != 0 && +- (stored->qos != msg->qos +- || stored->payloadlen != msg->payloadlen +- || strcmp(stored->topic, msg->topic) +- || memcmp(stored->payload, msg->payload, msg->payloadlen) )){ ++ if(cmsg_stored && cmsg_stored->store && msg->source_mid != 0 && ++ (cmsg_stored->store->qos != msg->qos ++ || cmsg_stored->store->payloadlen != msg->payloadlen ++ || strcmp(cmsg_stored->store->topic, msg->topic) ++ || memcmp(cmsg_stored->store->payload, msg->payload, msg->payloadlen) )){ + + log__printf(NULL, MOSQ_LOG_WARNING, "Reused message ID %u from %s detected. Clearing from storage.", msg->source_mid, context->id); + db__message_remove_incoming(context, msg->source_mid); +- stored = NULL; ++ cmsg_stored = NULL; + } + +- if(!stored){ ++ if(!cmsg_stored){ + if(msg->qos == 0 + || db__ready_for_flight(context, mosq_md_in, msg->qos) +- || db__ready_for_queue(context, msg->qos, &context->msgs_in)){ ++ ){ + + dup = 0; + rc = db__message_store(context, msg, message_expiry_interval, 0, mosq_mo_client); +@@ -314,10 +315,13 @@ int handle__publish(struct mosquitto *context) + } + stored = msg; + msg = NULL; ++ dup = 0; + }else{ + db__msg_store_free(msg); + msg = NULL; +- dup = 1; ++ stored = cmsg_stored->store; ++ cmsg_stored->dup++; ++ dup = cmsg_stored->dup; + } + + switch(stored->qos){ +@@ -343,11 +347,17 @@ int handle__publish(struct mosquitto *context) + }else{ + res = 0; + } ++ + /* db__message_insert() returns 2 to indicate dropped message + * due to queue. This isn't an error so don't disconnect them. */ + /* FIXME - this is no longer necessary due to failing early above */ + if(!res){ +- if(send__pubrec(context, stored->source_mid, 0, NULL)) rc = 1; ++ if(dup == 0 || dup == 1){ ++ rc2 = send__pubrec(context, stored->source_mid, 0, NULL); ++ if(rc2) rc = rc2; ++ }else{ ++ return MOSQ_ERR_PROTOCOL; ++ } + }else if(res == 1){ + rc = 1; + } +@@ -372,6 +382,9 @@ process_bad_message: + } + db__msg_store_free(msg); + } ++ if(context->out_packet_count >= db.config->max_queued_messages){ ++ rc = MQTT_RC_QUOTA_EXCEEDED; ++ } + return rc; + } + +diff --git a/src/mosquitto_broker_internal.h b/src/mosquitto_broker_internal.h +index 22fc067..ffc9c9e 100644 +--- a/src/mosquitto_broker_internal.h ++++ b/src/mosquitto_broker_internal.h +@@ -393,7 +393,7 @@ struct mosquitto_client_msg{ + bool retain; + enum mosquitto_msg_direction direction; + enum mosquitto_msg_state state; +- bool dup; ++ uint8_t dup; + }; + + +@@ -650,7 +650,7 @@ void db__message_dequeue_first(struct mosquitto *context, struct mosquitto_msg_d + int db__messages_delete(struct mosquitto *context, bool force_free); + int db__messages_easy_queue(struct mosquitto *context, const char *topic, uint8_t qos, uint32_t payloadlen, const void *payload, int retain, uint32_t message_expiry_interval, mosquitto_property **properties); + int db__message_store(const struct mosquitto *source, struct mosquitto_msg_store *stored, uint32_t message_expiry_interval, dbid_t store_id, enum mosquitto_msg_origin origin); +-int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_msg_store **stored); ++int db__message_store_find(struct mosquitto *context, uint16_t mid, struct mosquitto_client_msg **client_msg); + void db__msg_store_add(struct mosquitto_msg_store *store); + void db__msg_store_remove(struct mosquitto_msg_store *store); + void db__msg_store_ref_inc(struct mosquitto_msg_store *store); +diff --git a/test/broker/03-publish-qos2-dup.py b/test/broker/03-publish-qos2-dup.py +new file mode 100755 +index 0000000..70834fa +--- /dev/null ++++ b/test/broker/03-publish-qos2-dup.py +@@ -0,0 +1,58 @@ ++#!/usr/bin/env python3 ++ ++from mosq_test_helper import * ++ ++def do_test(proto_ver): ++ rc = 1 ++ connect_packet = mosq_test.gen_connect("03-pub-qos2-dup-test", proto_ver=proto_ver) ++ connack_packet = mosq_test.gen_connack(rc=0, proto_ver=proto_ver) ++ ++ mid = 1 ++ publish_packet = mosq_test.gen_publish("topic", qos=2, mid=mid, payload="message", proto_ver=proto_ver, dup=1) ++ pubrec_packet = mosq_test.gen_pubrec(mid, proto_ver=proto_ver) ++ ++ disconnect_packet = mosq_test.gen_disconnect(reason_code=130, proto_ver=proto_ver) ++ ++ port = mosq_test.get_port() ++ broker = mosq_test.start_broker(filename=os.path.basename(__file__), port=port) ++ ++ try: ++ sock = mosq_test.do_client_connect(connect_packet, connack_packet, port=port) ++ mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec 1") ++ mosq_test.do_send_receive(sock, publish_packet, pubrec_packet, "pubrec 2") ++ if proto_ver == 5: ++ mosq_test.do_send_receive(sock, publish_packet, disconnect_packet, "disconnect") ++ rc = 0 ++ else: ++ try: ++ mosq_test.do_send_receive(sock, publish_packet, b"", "disconnect1") ++ rc = 0 ++ except BrokenPipeError: ++ rc = 0 ++ ++ sock.close() ++ except Exception as e: ++ print(e) ++ except mosq_test.TestError: ++ pass ++ finally: ++ broker.terminate() ++ broker.wait() ++ (stdo, stde) = broker.communicate() ++ if rc: ++ print(stde.decode('utf-8')) ++ print("proto_ver=%d" % (proto_ver)) ++ exit(rc) ++ ++ ++def all_tests(): ++ rc = do_test(proto_ver=4) ++ if rc: ++ return rc; ++ rc = do_test(proto_ver=5) ++ if rc: ++ return rc; ++ return 0 ++ ++if __name__ == '__main__': ++ all_tests() +diff --git a/test/broker/Makefile b/test/broker/Makefile +index 1ee2dd2..620e5b6 100644 +--- a/test/broker/Makefile ++++ b/test/broker/Makefile +@@ -100,6 +100,7 @@ test : test-compile 01 02 03 04 05 06 07 08 09 10 11 12 13 14 + ./03-publish-qos1-no-subscribers-v5.py + ./03-publish-qos1-retain-disabled.py + ./03-publish-qos1.py ++ ./03-publish-qos2-dup.py + ./03-publish-qos2-max-inflight.py + ./03-publish-qos2.py + +diff --git a/test/broker/test.py b/test/broker/test.py +index 3dc0058..e6fdbe0 100755 +--- a/test/broker/test.py ++++ b/test/broker/test.py +@@ -83,6 +83,7 @@ tests = [ + (1, './03-publish-qos1-no-subscribers-v5.py'), + (1, './03-publish-qos1-retain-disabled.py'), + (1, './03-publish-qos1.py'), ++ (1, './03-publish-qos2-dup.py'), + (1, './03-publish-qos2-max-inflight.py'), + (1, './03-publish-qos2.py'), + diff -Nru mosquitto-2.0.11/debian/patches/CVE-2023-3592.patch mosquitto-2.0.11/debian/patches/CVE-2023-3592.patch --- mosquitto-2.0.11/debian/patches/CVE-2023-3592.patch 1970-01-01 00:00:00.000000000 +0000 +++ mosquitto-2.0.11/debian/patches/CVE-2023-3592.patch 2023-09-30 14:50:16.000000000 +0000 @@ -0,0 +1,21 @@ +From: Markus Koschany +Date: Fri, 22 Sep 2023 16:00:00 +0200 +Subject: CVE-2023-3592 + +Origin: https://github.com/eclipse/mosquitto/commit/00b24e0eb0686e9a76feb71fdaee650cb7e612fa +--- + src/property_broker.c | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/src/property_broker.c b/src/property_broker.c +index 1a38c20..77894f0 100644 +--- a/src/property_broker.c ++++ b/src/property_broker.c +@@ -103,6 +103,7 @@ int property__process_will(struct mosquitto *context, struct mosquitto_message_a + break; + + default: ++ msg->properties = msg_properties; + return MOSQ_ERR_PROTOCOL; + break; + } diff -Nru mosquitto-2.0.11/debian/patches/series mosquitto-2.0.11/debian/patches/series --- mosquitto-2.0.11/debian/patches/series 2021-06-09 12:54:36.000000000 +0000 +++ mosquitto-2.0.11/debian/patches/series 2023-09-30 14:50:16.000000000 +0000 @@ -2,3 +2,9 @@ 1571.patch deb-test.patch missing-test.patch +CVE-2021-41039.patch +CVE-2023-28366.patch +CVE-2021-34434.patch +CVE-2023-3592.patch +CVE-2023-0809.patch +CVE-2023-28366-regression.patch diff -Nru mosquitto-2.0.11/debian/tests/control mosquitto-2.0.11/debian/tests/control --- mosquitto-2.0.11/debian/tests/control 2021-06-09 12:54:33.000000000 +0000 +++ mosquitto-2.0.11/debian/tests/control 2023-09-30 14:50:16.000000000 +0000 @@ -1,5 +1,5 @@ Tests: broker, library, client -Depends: @, gcc, g++, libc6-dev, python3 +Depends: @, gcc, g++, libc6-dev, python3, python3-psutil # rw-build-tree: tests generate and cleanup config files as they run, plus the # broker saves persistence data and cleans it up. Restrictions: rw-build-tree