
Avis public et analyse technique pour CVE-2026-36590, une vulnérabilité de déni de service dans NanoMQ v0.24.9.
Ce dépôt contient l'avis public et l'analyse technique pour CVE-2026-36590, une vulnérabilité de déni de service affectant EMQ NanoMQ v0.24.9.
Ce dépôt est public pour fournir une référence technique accessible pour la révision du CVE. La classification finale de CVE-2026-36590 sera déterminée par l'équipe CVE ou le CNA concerné.
L'équipe NanoMQ a contesté ce problème et le considère comme lié à la configuration. Ce dépôt se concentre sur les preuves techniques, y compris les éléments de reproduction, les résultats ASAN, les journaux d'exécution et l'analyse du code source.
/nanomq/nng/src/supplemental/mqtt/mqtt_qos_db_api.c / nni_qos_db_setLorsque NanoMQ v0.24.9 est compilé sans le support SQLite alors que est configuré sur , le pointeur de la base de données QoS peut rester . Lors du traitement des messages QoS MQTT, peut revenir prématurément sans libérer une référence de message clonée. Des messages PUBLISH MQTT avec QoS > 0 répétés peuvent entraîner une consommation continue de mémoire, menant finalement à un déni de service.
sqlite.enabletrueNULLnni_qos_db_setLe problème dépend d'une configuration d'exécution non standard, mais les faits suivants montrent pourquoi il nécessite encore une révision approfondie :
NanoMQ accepte la configuration d'exécution et continue de fonctionner, au lieu de signaler que le support SQLite n'est pas disponible dans la version actuelle.
Cette incohérence de configuration peut se produire en pratique. Un utilisateur peut compiler NanoMQ avec la commande de construction normale, puis copier ou activer ultérieurement la section de persistance SQLite à partir d'un fichier de configuration d'exemple.
Le chemin de code affecté ne valide pas complètement cet état incohérent. Lorsque la configuration d'exécution considère SQLite comme activé mais que le pointeur de la base de données est NULL, nni_qos_db_set() revient prématurément sans libérer l'objet message passé.
Une fois cette configuration acceptée, le problème peut être déclenché par du trafic MQTT distant. Des messages PUBLISH avec QoS > 0 répétés peuvent entrer dans le chemin affecté et provoquer des fuites de mémoire accumulées.
Les tests ASAN avec 1, 50 et 500 cycles de reproduction montrent que les octets et les allocations fuités augmentent avec le nombre de tentatives de déclenchement. Cela suggère que le problème dépend du nombre d'entrées, plutôt que d'une petite fuite ponctuelle.
Les utilisateurs doivent restreindre l'accès aux instances NanoMQ, éviter d'exposer les services MQTT à des clients non fiables, et éviter d'activer la persistance SQLite dans les versions sans support SQLite. Le fournisseur doit ajouter une validation au démarrage pour la configuration SQLite et libérer la référence du message dans la branche db == NULL de nni_qos_db_set.
Docker/Docker_Reproduction_Guide.mdRésumé Ce dépôt contient la preuve de concept (PoC) et l'analyse détaillée d'une vulnérabilité de fuite de mémoire trouvée dans NanoMQ. Le problème permet à des attaquants distants de provoquer un déni de service (DoS) en épuisant la mémoire système via des messages MQTT QoS spécifiques.
J'ai mené une analyse approfondie d'un phénomène de fuite de mémoire dans NanoMQ. Grâce à une instrumentation dynamique et à une revue de code, j'ai identifié un chemin critique de fuite de ressources déclenché lorsque la configuration d'exécution active SQLite (sqlite.enable=true) mais que le binaire est compilé sans le support SQLite (NNG_SUPP_SQLITE non défini).
Pour rester concis, j'ai résumé les principales conclusions ci-dessous. Pour l'analyse technique complète (y compris les traces ASAN détaillées, les diagrammes de cycle de vie et les journaux d'instrumentation), veuillez vous référer au fichier Analysis_Report.md ci-joint.
À l'aide d'AddressSanitizer, j'ai localisé la source de la mémoire fuitée dans nni_msg_alloc au sein de tcptran_pipe_recv_cb (nng/src/sp/transport/mqtt/broker_tcp.c). La mémoire était allouée mais jamais complètement libérée.
J'ai analysé le mécanisme de comptage de références de nni_msg. Un cycle de vie normal d'un message QoS 1 devrait impliquer :
GDB étant peu pratique pour ce scénario de haute concurrence, j'ai utilisé une instrumentation dynamique pour tracer le cycle de vie d'objets mémoire spécifiques (par exemple, 0x60e00002ffa0).
La découverte : Les journaux ont confirmé une inadéquation du cycle de vie :
nmq_pipe_send_start_v4.Le traçage du flux d'exécution a révélé pourquoi la 3e libération manquait :
-DNNG_SUPP_SQLITE, ce qui a entraîné le retrait de la logique d'initialisation dans nano_sock_setdb. Cependant, nanomq.conf avait sqlite.enable = true. Cela a fait que le pointeur db est resté NULL.nni_qos_db_set pour stockage, la fonction vérifie le pointeur NULL :// Fichier : /nanomq/nng/src/supplemental/mqtt/mqtt_qos_db_api.c
void nni_qos_db_set(..., void *db, ..., nng_msg *msg) {
if (db == NULL) {
// DÉFAUT CRITIQUE :
// Le retour prématuré se déclenche car db est NULL.
// La fonction détient la propriété de 'msg' (Ref++) mais ne la libère pas.
return;
}
// ...
}
La fonction revient silencieusement sans appeler nni_msg_free(msg). Cela entraîne la perte irrémédiable du pointeur msg, abandonnant effectivement le bloc mémoire.
nni_qos_db_set. Elle ne gère pas la propriété du pointeur msg lors d'un retour prématuré dû à un état de base de données invalide.Recommandations :
nano_sock_setdb ou fonction main) pour s'assurer que SQLite fonctionne correctement. Si conf->sqlite.enable == true est détecté mais que la macro NNG_SUPP_SQLITE n'est pas définie ou que SQLite est anormal, le système doit soit quitter avec une erreur, soit forcer la désactivation de enable à false et afficher un avertissement.nni_qos_db_set. Si db == NULL, nni_msg_free(msg) doit être appelé pour équilibrer le compteur de références et éviter les fuites de mémoire.