diff --git a/mongoose.c b/mongoose.c index 2a56ad68..480c3274 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4113,47 +4113,59 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, size_t new_pos = ofs, len; prop->id = i[0]; - if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size) + if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size || (i + 1) >= end) return 0; i++, new_pos++; switch (mqtt_prop_type_by_id(prop->id)) { case MQTT_PROP_TYPE_STRING_PAIR: + if (i + 2 >= end) return 0; prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->key.buf = (char *) i + 2; i += 2 + prop->key.len; + if (i + 2 >= end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; + if (i + 2 + prop->val.len > end) return 0; new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len; break; case MQTT_PROP_TYPE_BYTE: + if (i + 1 > end) return 0; prop->iv = (uint8_t) i[0]; new_pos++; break; case MQTT_PROP_TYPE_SHORT: + if (i + 2 > end) return 0; prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); new_pos += sizeof(uint16_t); break; case MQTT_PROP_TYPE_INT: + if (i + 4 > end) return 0; prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | ((uint32_t) i[2] << 8) | i[3]; new_pos += sizeof(uint32_t); break; case MQTT_PROP_TYPE_STRING: + if (i + 2 >= end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; + if (i + 2 + prop->val.len > end) return 0; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_BINARY_DATA: + if (i + 2 > end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_VARIABLE_INT: len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv); - new_pos = (!len) ? 0 : new_pos + len; + if (i + len > end) return 0; + new_pos = (len == 0) ? 0 : new_pos + len; + break; + default: + new_pos = 0; break; - default: new_pos = 0; } return new_pos; diff --git a/src/mqtt.c b/src/mqtt.c index 3235f238..0e44e8a0 100644 --- a/src/mqtt.c +++ b/src/mqtt.c @@ -208,47 +208,59 @@ size_t mg_mqtt_next_prop(struct mg_mqtt_message *msg, struct mg_mqtt_prop *prop, size_t new_pos = ofs, len; prop->id = i[0]; - if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size) + if (ofs >= msg->dgram.len || ofs >= msg->props_start + msg->props_size || (i + 1) >= end) return 0; i++, new_pos++; switch (mqtt_prop_type_by_id(prop->id)) { case MQTT_PROP_TYPE_STRING_PAIR: + if (i + 2 >= end) return 0; prop->key.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->key.buf = (char *) i + 2; i += 2 + prop->key.len; + if (i + 2 >= end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; + if (i + 2 + prop->val.len > end) return 0; new_pos += 2 * sizeof(uint16_t) + prop->val.len + prop->key.len; break; case MQTT_PROP_TYPE_BYTE: + if (i + 1 > end) return 0; prop->iv = (uint8_t) i[0]; new_pos++; break; case MQTT_PROP_TYPE_SHORT: + if (i + 2 > end) return 0; prop->iv = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); new_pos += sizeof(uint16_t); break; case MQTT_PROP_TYPE_INT: + if (i + 4 > end) return 0; prop->iv = ((uint32_t) i[0] << 24) | ((uint32_t) i[1] << 16) | ((uint32_t) i[2] << 8) | i[3]; new_pos += sizeof(uint32_t); break; case MQTT_PROP_TYPE_STRING: + if (i + 2 >= end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; + if (i + 2 + prop->val.len > end) return 0; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_BINARY_DATA: + if (i + 2 > end) return 0; prop->val.len = (uint16_t) ((((uint16_t) i[0]) << 8) | i[1]); prop->val.buf = (char *) i + 2; new_pos += 2 + prop->val.len; break; case MQTT_PROP_TYPE_VARIABLE_INT: len = decode_varint(i, (size_t) (end - i), (size_t *) &prop->iv); - new_pos = (!len) ? 0 : new_pos + len; + if (i + len > end) return 0; + new_pos = (len == 0) ? 0 : new_pos + len; + break; + default: + new_pos = 0; break; - default: new_pos = 0; } return new_pos; diff --git a/test/fuzz.c b/test/fuzz.c index 5576427f..9e3876fa 100644 --- a/test/fuzz.c +++ b/test/fuzz.c @@ -62,6 +62,14 @@ int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) { mg_crc32(0, mm.topic.buf, mm.topic.len); mg_crc32(0, mm.data.buf, mm.data.len); mg_crc32(0, mm.dgram.buf, mm.dgram.len); + { + struct mg_mqtt_prop prop; + size_t ofs = 0; + while ((ofs = mg_mqtt_next_prop(&mm, &prop, ofs)) > 0) { + mg_crc32(0, prop.key.buf, prop.key.len); + mg_crc32(0, prop.val.buf, prop.val.len); + } + } } mg_mqtt_parse(NULL, 0, 5, &mm);