curl · Report #3484319
MQTT Protocol Violation & Integer Overflow in libcurl
How it was found
Executive Summary
Vulnerability Type: CWE-190
Component: lib/mqtt.c
Function: mqtt_decode_len
Affected Architectures:
- All architectures: Protocol non-compliance leading to stream desynchronization
- 32-bit architectures: Deterministic integer overflow in length decoding
libcurl does not correctly enforce the MQTT v3.1.1 specification limit for the “Remaining Length” field when decoding incoming packets. This allows malformed MQTT packets to be parsed incorrectly, leading to protocol desynchronization and potential denial of service. On 32-bit systems, the decoding logic additionally allows a deterministic integer overflow.
Root Cause: Inconsistent Length Handling
The issue is caused by an inconsistency within lib/mqtt.c.
The encoder correctly enforces the MQTT specification limit, while the decoder does not.
Correct Behavior (Encoding)
In mqtt_encode_len, the implementation explicitly limits the Remaining Length field to four bytes, as required by the specification:
for(i = 0; (len > 0) && (i < 4); i++) {
unsigned char encoded;
encoded = len % 0x80;
/* ... */
}
This ensures protocol compliance.
Incorrect Behavior (Decoding)
In contrast, mqtt_decode_len does not enforce the same limit:
for(i = 0; (i < buflen) && (encoded & 128); i++) {
encoded = buf[i];
len += (encoded & 127) * mult;
mult *= 128;
}
The loop continues as long as the continuation bit is set and input is available, allowing more than four bytes to be consumed as part of the Remaining Length field.
Specification Violation
According to the MQTT v3.1.1 specification, Section 2.2.3 (Remaining Length):
“The number of bytes in the Remaining Length field MUST NOT exceed four bytes.”
By accepting and processing length fields longer than four bytes, libcurl violates the MQTT specification and enters an undefined protocol state.
Integer Overflow on 32-bit Systems
On 32-bit architectures, size_t is a 32-bit unsigned integer.
The variable mult is repeatedly multiplied by 128 during decoding.
Example progression on a 32-bit system:
| Iteration | mult value | Operation | Result |
|---|---|---|---|
| 0 | 1 | 1 × 128 | 128 |
| 1 | 128 | 128 × 128 | 16,384 |
| 2 | 16,384 | × 128 | 2,097,152 |
| 3 | 2,097,152 | × 128 | 268,435,456 |
| 4 | 268,435,456 | × 128 | Overflow → 0 |
After the overflow, mult becomes zero, and any further bytes consumed contribute nothing to the decoded length. This allows a large or malformed Remaining Length field to be partially “hidden” while still advancing the input pointer.
Impact
Impact
Protocol Desynchronization (All Architectures)
By consuming more than four bytes for the Remaining Length field, libcurl can become desynchronized from the MQTT stream. Bytes intended to be part of the payload or subsequent packets may instead be interpreted as length data, causing incorrect parsing of later packets.
Denial of Service
This desynchronization can result in malformed packet handling, unexpected connection termination, or repeated protocol errors such as CURLE_WEIRD_SERVER_REPLY.
No memory corruption or code execution is claimed.
Recommended Fix
The decoding logic should explicitly enforce the four-byte limit defined by the MQTT specification.
Example fix:
for(i = 0; (i < buflen) && (encoded & 128); i++) {
if(i >= 4) {
/* Malformed Remaining Length */
return 0; /* or propagate an error to the caller */
}
encoded = buf[i];
len += (encoded & 127) * mult;
mult *= 128;
}
Optionally, the decoded length can also be checked against the implementation limit:
if(len > MAX_MQTT_MESSAGE_SIZE)
return 0;
Verification Notes
The issue was verified through code inspection and logic simulation, confirming that mqtt_decode_len accepts more than four bytes for the Remaining Length field and allows arithmetic overflow on 32-bit systems. Runtime exploitation was not required to demonstrate the protocol violation.
Conclusion
This is a protocol parsing bug caused by missing enforcement of a mandatory MQTT specification limit. While it does not directly result in memory corruption, it allows malformed MQTT packets to desynchronize the client’s protocol state and cause denial of service. Aligning the decoder with the existing encoder logic resolves the issue cleanly.