Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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
# ##############################################################################
Expand Down
15 changes: 7 additions & 8 deletions mdns.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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++);
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand All @@ -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);
Expand Down
29 changes: 29 additions & 0 deletions tests/record_parse_bounds.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Reject a near-SIZE_MAX offset instead of wrapping past the bounds check.

#define MDNS_IMPLEMENTATION
#include "mdns.h"

#include <stdint.h>

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;
}