Skip to content

Commit 765dc3a

Browse files
committed
sys/net/gcoap: reduce insanity of hack
gcoap contains a hack where a `coap_pkt_t` is pulled out of thin air, parts of the members are left uninitialized and a function is called on that mostly uninitialized data while crossing fingers hard that the result will be correct. (With the current implementation of the used function this hack does actually work.) Estimated level of insanity: 😱😱😱😱😱 This adds to insane functions to get the length of a token and the length of a header of a CoAP packet while crossing fingers hard that the packet is valid and that the functions do not overread. Estimated level of insanity: 😱😱😱 The newly introduced insane functions are used to replace the old insane hack, resulting in an estimated reduction of insanity of 😱😱. Side note: This actually does fix a bug, as the old code did not take into account the length of the extended TKL field in case of RFC 8974 being used. But that is a bug in the abused API, and not in the caller abusing the API.
1 parent 00e25ad commit 765dc3a

File tree

2 files changed

+67
-24
lines changed

2 files changed

+67
-24
lines changed

sys/include/net/nanocoap.h

Lines changed: 64 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -352,6 +352,10 @@ struct _coap_request_ctx {
352352
#endif
353353
};
354354

355+
/* forward declarations */
356+
static inline uint8_t *coap_hdr_data_ptr(const coap_hdr_t *hdr);
357+
static inline size_t coap_hdr_get_token_len(const coap_hdr_t *hdr);
358+
355359
/**
356360
* @brief Get resource path associated with a CoAP request
357361
*
@@ -548,28 +552,9 @@ static inline unsigned coap_get_id(const coap_pkt_t *pkt)
548552
*/
549553
static inline unsigned coap_get_token_len(const coap_pkt_t *pkt)
550554
{
551-
uint8_t tkl = pkt->hdr->ver_t_tkl & 0xf;
552-
553-
if (!IS_USED(MODULE_NANOCOAP_TOKEN_EXT)) {
554-
return tkl;
555-
}
556-
557-
void *ext = pkt->hdr + 1;
558-
switch (tkl) {
559-
case 13:
560-
return tkl + *(uint8_t *)ext;
561-
case 14:
562-
return tkl + 255 + byteorder_bebuftohs(ext);
563-
case 15:
564-
assert(0);
565-
/* fall-through */
566-
default:
567-
return tkl;
568-
}
555+
return coap_hdr_get_token_len(pkt->hdr);
569556
}
570557

571-
static inline uint8_t *coap_hdr_data_ptr(const coap_hdr_t *hdr);
572-
573558
/**
574559
* @brief Get pointer to a message's token
575560
*
@@ -714,6 +699,65 @@ static inline void coap_hdr_set_type(coap_hdr_t *hdr, unsigned type)
714699
hdr->ver_t_tkl &= ~0x30;
715700
hdr->ver_t_tkl |= type << 4;
716701
}
702+
703+
/**
704+
* @brief Get the token length of a CoAP over UDP (DTLS) packet
705+
* @param[in] hdr CoAP over UDP header
706+
* @return The size of the token in bytes
707+
*
708+
* @warning This API is super goofy. It assumes that the packet is valid
709+
* and will read more than `sizeof(*hdr)` into the data `hdr`
710+
* points to while crossing fingers hard.
711+
*
712+
* @deprecated This function was introduced to keep legacy code alive.
713+
* Introducing new callers should be avoided. In the RX path an
714+
* @ref coap_pkt_t will be available, so that you can call
715+
* @ref coap_get_token instead. In the TX path the token was
716+
* added by us, so we really should know.
717+
*/
718+
static inline size_t coap_hdr_get_token_len(const coap_hdr_t *hdr)
719+
{
720+
const uint8_t *buf = (const void *)hdr;
721+
/* Regarding use unnamed magic numbers 13 and 269:
722+
* - If token length is < 13 it fits into TKL field (4 bit)
723+
* - If token length is < 269 it fits into 8-bit extended TKL field
724+
* - Otherwise token length goes into 16-bit extended TKL field.
725+
*
726+
* (Not using named constants here, as RFC 8974 also has no names for those
727+
* magic numbers.)
728+
*
729+
* See: https://www.rfc-editor.org/rfc/rfc8974#name-extended-token-length-tkl-f
730+
*/
731+
switch (coap_hdr_tkl_ext_len(hdr)) {
732+
case 0:
733+
return hdr->ver_t_tkl & 0xf;
734+
case 1:
735+
return buf[sizeof(coap_hdr_t)] + 13;
736+
case 2:
737+
return byteorder_bebuftohs(buf + sizeof(coap_hdr_t)) + 269;
738+
}
739+
740+
return 0;
741+
}
742+
743+
/**
744+
* @brief Get the header length of a CoAP packet.
745+
*
746+
* @warning This API is super goofy. It assumes that the packet is valid
747+
* and will read more than `sizeof(*hdr)` into the data `hdr`
748+
* points to while crossing fingers hard.
749+
*
750+
* @deprecated This function was introduced to keep legacy code alive.
751+
* Introducing new callers should be avoided. In the RX path an
752+
* @ref coap_pkt_t will be available, so that you can call
753+
* @ref coap_get_total_hdr_len instead. In the TX path the header
754+
* was created by us (e.g. using @ref coap_build_hdr which returns
755+
* the header size), so we really should know already.
756+
*/
757+
static inline size_t coap_hdr_len(const coap_hdr_t *hdr)
758+
{
759+
return sizeof(*hdr) + coap_hdr_tkl_ext_len(hdr) + coap_hdr_get_token_len(hdr);
760+
}
717761
/**@}*/
718762

719763
/**

sys/net/application_layer/gcoap/gcoap.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1454,10 +1454,9 @@ static ssize_t _cache_build_response(nanocoap_cache_entry_t *ce, coap_pkt_t *pdu
14541454

14551455
static void _copy_hdr_from_req_memo(coap_pkt_t *pdu, gcoap_request_memo_t *memo)
14561456
{
1457-
coap_pkt_t req_pdu;
1458-
1459-
req_pdu.hdr = gcoap_request_memo_get_hdr(memo);
1460-
memcpy(pdu->hdr, req_pdu.hdr, coap_get_total_hdr_len(&req_pdu));
1457+
const coap_hdr_t *hdr = gcoap_request_memo_get_hdr(memo);
1458+
size_t hdr_len = coap_hdr_len(hdr);
1459+
memcpy(pdu->hdr, hdr, hdr_len);
14611460
}
14621461

14631462
static void _receive_from_cache_cb(void *ctx)

0 commit comments

Comments
 (0)