diff --git a/CMakeLists.txt b/CMakeLists.txt index 50f1f05..48079ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -32,6 +32,13 @@ if(MDNS_BUILD_EXAMPLE) target_link_libraries(${PROJECT_NAME}_example ${PROJECT_NAME}) endif() +include(CTest) +if(BUILD_TESTING) + add_executable(${PROJECT_NAME}_record_parse_bounds_test tests/record_parse_bounds.c) + target_link_libraries(${PROJECT_NAME}_record_parse_bounds_test ${PROJECT_NAME}) + add_test(NAME ${PROJECT_NAME}_record_parse_bounds COMMAND ${PROJECT_NAME}_record_parse_bounds_test) +endif() + # ############################################################################## # install # ############################################################################## diff --git a/mdns.h b/mdns.h index d0794bf..bf3e65a 100644 --- a/mdns.h +++ b/mdns.h @@ -1504,7 +1504,7 @@ static inline mdns_string_t mdns_record_parse_ptr(const void* buffer, size_t size, size_t offset, size_t length, char* strbuffer, size_t capacity) { // PTR record is just a string - if ((size >= offset + length) && (length >= 2)) + if ((offset <= size && length <= size - offset) && (length >= 2)) return mdns_string_extract(buffer, size, &offset, strbuffer, capacity); mdns_string_t empty = {0, 0}; return empty; @@ -1521,7 +1521,7 @@ mdns_record_parse_srv(const void* buffer, size_t size, size_t offset, size_t len // 2 bytes network-order unsigned weight // 2 bytes network-order unsigned port // string: discovery (domain) name, minimum 2 bytes when compressed - if ((size >= offset + length) && (length >= 8)) { + if ((offset <= size && length <= size - offset) && (length >= 8)) { const uint16_t* recorddata = (const uint16_t*)MDNS_POINTER_OFFSET_CONST(buffer, offset); srv.priority = mdns_ntohs(recorddata++); srv.weight = mdns_ntohs(recorddata++); @@ -1540,7 +1540,7 @@ mdns_record_parse_a(const void* buffer, size_t size, size_t offset, size_t lengt #ifdef __APPLE__ addr->sin_len = sizeof(struct sockaddr_in); #endif - if ((size >= offset + length) && (length == 4)) + if ((offset <= size && length <= size - offset) && (length == 4)) memcpy(&addr->sin_addr.s_addr, MDNS_POINTER_OFFSET(buffer, offset), 4); return addr; } @@ -1553,7 +1553,7 @@ mdns_record_parse_aaaa(const void* buffer, size_t size, size_t offset, size_t le #ifdef __APPLE__ addr->sin6_len = sizeof(struct sockaddr_in6); #endif - if ((size >= offset + length) && (length == 16)) + if ((offset <= size && length <= size - offset) && (length == 16)) memcpy(&addr->sin6_addr, MDNS_POINTER_OFFSET(buffer, offset), 16); return addr; } @@ -1563,10 +1563,9 @@ mdns_record_parse_txt(const void* buffer, size_t size, size_t offset, size_t len mdns_record_txt_t* records, size_t capacity) { size_t parsed = 0; const char* strdata; - size_t end = offset + length; - - if (size < end) - end = size; + size_t end = size; + if (offset <= size && length <= size - offset) + end = offset + length; while ((offset < end) && (parsed < capacity)) { strdata = (const char*)MDNS_POINTER_OFFSET(buffer, offset); diff --git a/tests/record_parse_bounds.c b/tests/record_parse_bounds.c new file mode 100644 index 0000000..7667002 --- /dev/null +++ b/tests/record_parse_bounds.c @@ -0,0 +1,29 @@ +// Reject a near-SIZE_MAX offset instead of wrapping past the bounds check. + +#define MDNS_IMPLEMENTATION +#include "mdns.h" + +#include + +int main(void) { + uint8_t buffer[16] = {0}; + char strbuffer[16] = {0}; + struct sockaddr_in addr4; + struct sockaddr_in6 addr6; + mdns_record_txt_t txtrec[1]; + + mdns_string_t ptr = + mdns_record_parse_ptr(buffer, sizeof(buffer), (size_t)0 - 2, 2, strbuffer, sizeof(strbuffer)); + mdns_record_srv_t srv = + mdns_record_parse_srv(buffer, sizeof(buffer), (size_t)0 - 8, 8, strbuffer, sizeof(strbuffer)); + struct sockaddr_in* a = + mdns_record_parse_a(buffer, sizeof(buffer), (size_t)0 - 4, 4, &addr4); + struct sockaddr_in6* aaaa = + mdns_record_parse_aaaa(buffer, sizeof(buffer), (size_t)0 - 16, 16, &addr6); + size_t txt = + mdns_record_parse_txt(buffer, sizeof(buffer), (size_t)0 - 4, 4, txtrec, 1); + + if (ptr.length || srv.port || a->sin_addr.s_addr || aaaa->sin6_addr.s6_addr[0] || txt) + return 1; + return 0; +}