Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion examples/mqtt/main/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,2 +1,6 @@
idf_component_register(SRCS "app_main.cpp"
idf_component_register(SRCS "app_main.c"
INCLUDE_DIRS ".")

# target_compile_options(${COMPONENT_LIB} PUBLIC -fsanitize=address)
# target_link_options(${COMPONENT_LIB} PUBLIC -fsanitize=address)

210 changes: 210 additions & 0 deletions examples/mqtt/main/app_main.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,210 @@
/*
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Unlicense OR CC0-1.0
*/
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#include <string.h>
#include <stdlib.h>
#include "esp_system.h"
#include "nvs_flash.h"
#include "esp_event.h"
#include "esp_netif.h"
#include "protocol_examples_common.h"
#include "esp_log.h"
#include "mqtt_client.h"
#include "mqtt5_client.h"
#include "sdkconfig.h"

static const char *TAG = "mqtt5_example";


static void log_error_if_nonzero(const char *message, int error_code)
{
if (error_code != 0) {
ESP_LOGE(TAG, "Last error %s: 0x%x", message, error_code);
}
}

/*
* @brief Event handler registered to receive MQTT events
*
* This function is called by the MQTT client event loop.
*
* @param handler_args user data registered to the event.
* @param base Event base for the handler(always MQTT Base in this example).
* @param event_id The id for the received event.
* @param event_data The data for the event, esp_mqtt_event_handle_t.
*/
static esp_mqtt5_user_property_item_t user_property_arr[] = {
{"board", "esp32"},
{"u", "user"},
{"p", "password"}
};

#define USE_PROPERTY_ARR_SIZE sizeof(user_property_arr)/sizeof(esp_mqtt5_user_property_item_t)

static void print_user_property(mqtt5_user_property_handle_t user_property)
{
if (user_property) {
uint8_t count = esp_mqtt5_client_get_user_property_count(user_property);
if (count) {
esp_mqtt5_user_property_item_t *item = malloc(count * sizeof(esp_mqtt5_user_property_item_t));
if (esp_mqtt5_client_get_user_property(user_property, item, &count) == ESP_OK) {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing NULL check after malloc allocation

Medium Severity

The malloc call in print_user_property() doesn't check if the allocation succeeded before using the returned pointer. If malloc returns NULL due to memory exhaustion, passing it to esp_mqtt5_client_get_user_property() will cause undefined behavior or a crash.

Fix in Cursor Fix in Web

for (int i = 0; i < count; i++) {
esp_mqtt5_user_property_item_t *t = &item[i];
ESP_LOGI(TAG, "key is %s, value is %s", t->key, t->value);
free((char *)t->key);
free((char *)t->value);
}
}
free(item);
}
}
}

static void mqtt5_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data)
{
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%" PRIi32, base, event_id);
esp_mqtt_event_handle_t event = event_data;
esp_mqtt_client_handle_t client = event->client;
int msg_id;

ESP_LOGD(TAG, "free heap size is %" PRIu32 ", minimum %" PRIu32, esp_get_free_heap_size(), esp_get_minimum_free_heap_size());
switch ((esp_mqtt_event_id_t)event_id) {
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
esp_mqtt_client_disconnect(client);
// print_user_property(event->property->user_property);
// msg_id = esp_mqtt_client_subscribe(client, "sensor/data", 0);
// ESP_LOGI(TAG, "sent subscribe successful, msg_id=%d", msg_id);
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
print_user_property(event->property->user_property);
break;

case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d, reason code=0x%02x ", event->msg_id, (uint8_t)*event->data);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unsafe dereference of event->data without validation

Medium Severity

The MQTT_EVENT_SUBSCRIBED handler dereferences event->data to read the reason code without first verifying that event->data is non-NULL and event->data_len is greater than zero. If the event lacks data, this causes a null pointer dereference or reads invalid memory.

Fix in Cursor Fix in Web

print_user_property(event->property->user_property);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
print_user_property(event->property->user_property);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
print_user_property(event->property->user_property);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG, "MQTT_EVENT_DATA");
print_user_property(event->property->user_property);
ESP_LOGI(TAG, "payload_format_indicator is %d", event->property->payload_format_indicator);
ESP_LOGI(TAG, "response_topic is %.*s", event->property->response_topic_len, event->property->response_topic);
ESP_LOGI(TAG, "correlation_data is %.*s", event->property->correlation_data_len, event->property->correlation_data);
ESP_LOGI(TAG, "content_type is %.*s", event->property->content_type_len, event->property->content_type);
ESP_LOGI(TAG, "TOPIC=%.*s", event->topic_len, event->topic);
printf("data length: %d\n", event->data_len);
for (int i = 0; i < /*(uint32_t)*/event->data_len; i++) {
printf("%02x ", event->data[i]);
}
printf("\n");
// ESP_LOGI(TAG, "DATA=%.*s", event->data_len, event->data);
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
print_user_property(event->property->user_property);
ESP_LOGI(TAG, "MQTT5 return code is %d", event->error_handle->connect_return_code);
if (event->error_handle->error_type == MQTT_ERROR_TYPE_TCP_TRANSPORT) {
log_error_if_nonzero("reported from esp-tls", event->error_handle->esp_tls_last_esp_err);
log_error_if_nonzero("reported from tls stack", event->error_handle->esp_tls_stack_err);
log_error_if_nonzero("captured as transport's socket errno", event->error_handle->esp_transport_sock_errno);
ESP_LOGI(TAG, "Last errno string (%s)", strerror(event->error_handle->esp_transport_sock_errno));

}
break;
default:
ESP_LOGI(TAG, "Other event id:%d", event->event_id);
break;
}
}

static void mqtt5_app_start(void)
{
esp_mqtt5_connection_property_config_t connect_property = {
.session_expiry_interval = 10,
.maximum_packet_size = 1024,
.receive_maximum = 65535,
.topic_alias_maximum = 2,
.request_resp_info = true,
.request_problem_info = true,
.will_delay_interval = 10,
.payload_format_indicator = true,
.message_expiry_interval = 10,
.response_topic = "/test/response",
.correlation_data = "123456",
.correlation_data_len = 6,
};
const esp_mqtt_client_config_t mqtt5_cfg = {
.broker = {
.address.uri = "mqtt://127.0.0.1:1883",
},
.session = {
.protocol_ver = MQTT_PROTOCOL_V_5,
.last_will = {
.topic = "/topic/will",
.msg = "i will leave",
.msg_len = 12,
.qos = 1,
.retain = true,
},
},
};

esp_mqtt_client_handle_t client = esp_mqtt_client_init(&mqtt5_cfg);

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Missing NULL check after MQTT client initialization

Medium Severity

The return value of esp_mqtt_client_init() is not checked for NULL before being used. If initialization fails (due to memory exhaustion or invalid configuration), the NULL handle is passed to esp_mqtt5_client_set_connect_property(), esp_mqtt_client_register_event(), and esp_mqtt_client_start(), causing crashes or undefined behavior.

Additional Locations (2)

Fix in Cursor Fix in Web


/* Set connection properties and user properties */
esp_mqtt5_client_set_user_property(&connect_property.user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
esp_mqtt5_client_set_user_property(&connect_property.will_user_property, user_property_arr, USE_PROPERTY_ARR_SIZE);
esp_mqtt5_client_set_connect_property(client, &connect_property);

/* If you call esp_mqtt5_client_set_user_property to set user properties, DO NOT forget to delete them.
* esp_mqtt5_client_set_connect_property will malloc buffer to store the user_property and you can delete it after
*/
esp_mqtt5_client_delete_user_property(connect_property.user_property);
esp_mqtt5_client_delete_user_property(connect_property.will_user_property);

/* The last argument may be used to pass data to the event handler, in this example mqtt_event_handler */
esp_mqtt_client_register_event(client, ESP_EVENT_ANY_ID, mqtt5_event_handler, NULL);
esp_mqtt_client_start(client);
}


void app_main(void)
{
ESP_LOGI(TAG, "[APP] Startup..");
ESP_LOGI(TAG, "[APP] Free memory: %" PRIu32 " bytes", esp_get_free_heap_size());
ESP_LOGI(TAG, "[APP] IDF version: %s", esp_get_idf_version());

// esp_log_level_set("*", ESP_LOG_INFO);
// esp_log_level_set("mqtt_client", ESP_LOG_VERBOSE);
// esp_log_level_set("mqtt5_example", ESP_LOG_VERBOSE);
// esp_log_level_set("transport_base", ESP_LOG_VERBOSE);
// esp_log_level_set("esp-tls", ESP_LOG_VERBOSE);
// esp_log_level_set("transport", ESP_LOG_VERBOSE);
// esp_log_level_set("outbox", ESP_LOG_VERBOSE);

ESP_ERROR_CHECK(nvs_flash_init());
ESP_ERROR_CHECK(esp_netif_init());
ESP_ERROR_CHECK(esp_event_loop_create_default());

/* This helper function configures Wi-Fi or Ethernet, as selected in menuconfig.
* Read "Establishing Wi-Fi or Ethernet Connection" section in
* examples/protocols/README.md for more information about this function.
*/
ESP_ERROR_CHECK(example_connect());

mqtt5_app_start();
}
136 changes: 0 additions & 136 deletions examples/mqtt/main/app_main.cpp

This file was deleted.

Loading
Loading