diff --git a/net.c b/net.c index 2117b6c5..a0bf7906 100644 --- a/net.c +++ b/net.c @@ -610,6 +610,20 @@ _order_transaction_id( coap_queue_t *lhs, coap_queue_t *rhs ) { : 1; } +/** + * Checks if @p opt fits into the message that ends with @p maxpos. + * This function returns @c 1 on success, or @c 0 if the option @p opt + * would exceed @p maxpos. + */ +static inline int +check_opt_size(coap_opt_t *opt, unsigned char *maxpos) { + if (opt && opt < maxpos) { + if (((*opt & 0x0f) < 0x0f) || (opt + 1 < maxpos)) + return opt + COAP_OPT_SIZE(opt) < maxpos; + } + return 0; +} + int coap_read( coap_context_t *ctx ) { #ifndef WITH_CONTIKI @@ -707,6 +721,12 @@ coap_read( coap_context_t *ctx ) { } else { --cnt; } + + if (cnt && + !check_opt_size(opt, (unsigned char *)node->pdu->hdr + node->pdu->max_size)) { + debug("drop\n"); + goto error; + } opt = options_next(opt); } diff --git a/option.c b/option.c index e2e306aa..7600d8ca 100644 --- a/option.c +++ b/option.c @@ -40,7 +40,7 @@ coap_option_iterator_init(coap_pdu_t *pdu, coap_opt_iterator_t *oi, } #define IS_EMPTY_NOOP(Type,Option) \ - ((Type) % COAP_OPTION_NOOP == 0 && COAP_OPT_LENGTH(Option) == 0) + (((Type) % COAP_OPTION_NOOP == 0) && (COAP_OPT_LENGTH(Option) == 0)) #define opt_finished(oi) ((oi)->optcnt == COAP_OPT_LONG \ ? ((oi)->option && *((oi)->option) == COAP_OPT_END) \ @@ -56,24 +56,25 @@ coap_option_next(coap_opt_iterator_t *oi) { /* proceed to next option */ if (oi->n++) { oi->option = options_next(oi->option); + if (opt_finished(oi)) + return NULL; oi->type += COAP_OPT_DELTA(oi->option); } /* Skip subsequent options if it is an empty no-op (used for * fence-posting) or the filter bit is not set. */ - while (!opt_finished(oi) && - (IS_EMPTY_NOOP(oi->type, oi->option) - || coap_option_getb(oi->filter, oi->type) == 0)) { + while (oi->option && (IS_EMPTY_NOOP(oi->type, oi->option) + || coap_option_getb(oi->filter, oi->type) == 0)) { oi->n++; oi->option = options_next(oi->option); - if (opt_finished(oi)) - break; + if (!oi->option || opt_finished(oi)) + return NULL; oi->type += COAP_OPT_DELTA(oi->option); } - return opt_finished(oi) ? NULL : oi->option; + return oi->option; } coap_opt_t *