Skip to content

Commit 2847f9f

Browse files
Adafruit_MQTT::publishPacket: Protect against memory corruption.
Fixes #109 Fixes #122 After spending a long time pulling my hair to understand why I was hitting a panic when attempting to read from my registered subscriptions, I found out that the subscriptions member of the Adafruit_MQTT instance was corrupted. :( Turns out the memory corruption was caused by my publish call, where the payload I was providing was bigger than the allocated space in the buffer for construction of the packet (see buffer[MAXBUFFERSIZE]). To protect myself from ever making this mistake again, I am proposing a simple logic in publishPacket where instead of silently corrupting memory, the code uses as much payload as it can fit in the available space. By seeing the truncated payload, user can decide whether he/she should 1)break it up into different topics, 2) put the payload on a diet, or 3) increase MAXBUFFERSIZE.
1 parent 3693eb8 commit 2847f9f

File tree

2 files changed

+21
-6
lines changed

2 files changed

+21
-6
lines changed

Adafruit_MQTT.cpp

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ bool Adafruit_MQTT::publish(const char *topic, const char *data, uint8_t qos) {
303303

304304
bool Adafruit_MQTT::publish(const char *topic, uint8_t *data, uint16_t bLen, uint8_t qos) {
305305
// Construct and send publish packet.
306-
uint16_t len = publishPacket(buffer, topic, data, bLen, qos);
306+
uint16_t len = publishPacket(buffer, (uint16_t) sizeof(buffer), topic, data, bLen, qos);
307307
if (!sendPacket(buffer, len))
308308
return false;
309309

@@ -639,7 +639,7 @@ uint8_t Adafruit_MQTT::connectPacket(uint8_t *packet) {
639639

640640

641641
// as per http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718040
642-
uint16_t Adafruit_MQTT::publishPacket(uint8_t *packet, const char *topic,
642+
uint16_t Adafruit_MQTT::publishPacket(uint8_t *packet, uint16_t maxPacketLen, const char *topic,
643643
uint8_t *data, uint16_t bLen, uint8_t qos) {
644644
uint8_t *p = packet;
645645
uint16_t len=0;
@@ -650,7 +650,20 @@ uint16_t Adafruit_MQTT::publishPacket(uint8_t *packet, const char *topic,
650650
if(qos > 0) {
651651
len += 2; // qos packet id
652652
}
653-
len += bLen; // payload length
653+
654+
// payload length
655+
if (len + bLen <= maxPacketLen) {
656+
len += bLen;
657+
} else {
658+
// If we make it here, we got a pickle: the payload is not going
659+
// to fit in the packet buffer. Instead of corrupting memory, let's
660+
// do something less damaging by reducing the bLen to what we are
661+
// able to accomodate. Alternatively, consider using a bigger
662+
// maxPacketLen.
663+
const bool extraByteNeeded = maxPacketLen % 128 != 0;
664+
bLen = maxPacketLen - (len + maxPacketLen / 128 + (extraByteNeeded ? 1 : 0));
665+
len = maxPacketLen;
666+
}
654667

655668
// Now you can start generating the packet!
656669
p[0] = MQTT_CTRL_PUBLISH << 4 | qos << 1;
@@ -683,8 +696,9 @@ uint16_t Adafruit_MQTT::publishPacket(uint8_t *packet, const char *topic,
683696

684697
memmove(p, data, bLen);
685698
p+= bLen;
686-
len = p - packet;
687-
DEBUG_PRINTLN(F("MQTT publish packet:"));
699+
len = (p - 1) - packet;
700+
DEBUG_PRINT(F("MQTT publish packet (length: "));
701+
DEBUG_PRINT(len); DEBUG_PRINTLN(F("):"));
688702
DEBUG_PRINTBUFFER(buffer, len);
689703
return len;
690704
}

Adafruit_MQTT.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -243,7 +243,8 @@ class Adafruit_MQTT {
243243
// Functions to generate MQTT packets.
244244
uint8_t connectPacket(uint8_t *packet);
245245
uint8_t disconnectPacket(uint8_t *packet);
246-
uint16_t publishPacket(uint8_t *packet, const char *topic, uint8_t *payload, uint16_t bLen, uint8_t qos);
246+
uint16_t publishPacket(uint8_t *packet, uint16_t maxPacketLen,
247+
const char *topic, uint8_t *payload, uint16_t bLen, uint8_t qos);
247248
uint8_t subscribePacket(uint8_t *packet, const char *topic, uint8_t qos);
248249
uint8_t unsubscribePacket(uint8_t *packet, const char *topic);
249250
uint8_t pingPacket(uint8_t *packet);

0 commit comments

Comments
 (0)