mirror of
https://github.com/NLnetLabs/unbound.git
synced 2026-08-17 21:25:50 +02:00
- Fix bounds check in packed_rr_to_string, it checked the (#1488)
assembled rr length against the output string length dest_len, instead of against the size of the rr buffer it writes into. Callers in cachedump.c and remote.c pass a dest_len larger than that buffer. - Unit test for packed_rr_to_string.
This commit is contained in:
@@ -1,3 +1,11 @@
|
||||
6 August 2026: Alex Khanin
|
||||
- Fix bounds check in packed_rr_to_string, it checked the
|
||||
assembled rr length against the output string length
|
||||
dest_len, instead of against the size of the rr buffer it
|
||||
writes into. Callers in cachedump.c and remote.c pass a
|
||||
dest_len larger than that buffer.
|
||||
- Unit test for packed_rr_to_string.
|
||||
|
||||
6 August 2026: Wouter
|
||||
- Fix #1485: the list_forwards command omits port numbers.
|
||||
The list_forwards and list_stubs commands for
|
||||
|
||||
@@ -1337,6 +1337,89 @@ static void mesh_test(void)
|
||||
free(c1);
|
||||
}
|
||||
|
||||
#include "util/data/packed_rrset.h"
|
||||
#include "sldns/sbuffer.h"
|
||||
/** packed_rrset unit tests */
|
||||
static void packed_rrset_test(void)
|
||||
{
|
||||
/* packed_rr_to_string assembles the dname, type, class, ttl and
|
||||
* rdata of one rr into a buffer of 65535 bytes. Check that it
|
||||
* refuses an rr that does not fit in there, also when the caller
|
||||
* passes a dest_len that is larger than that, like the callers in
|
||||
* daemon/cachedump.c and daemon/remote.c do. Without the check it
|
||||
* writes past the end of the assembly buffer. */
|
||||
uint8_t smalldname[] = "\003www\007example\003com";
|
||||
uint8_t smallrdata[] = {0, 4, 1, 2, 3, 4};
|
||||
uint8_t maxdname[LDNS_MAX_DOMAINLEN];
|
||||
struct ub_packed_rrset_key rrk;
|
||||
struct packed_rrset_data d;
|
||||
uint8_t* rr_data[1];
|
||||
size_t rr_len[1];
|
||||
time_t rr_ttl[1];
|
||||
size_t dest_len = 65535*4+2048; /* the size daemon/cachedump.c uses */
|
||||
char* dest = (char*)malloc(dest_len);
|
||||
int i;
|
||||
|
||||
unit_show_func("util/data/packed_rrset.c", "packed_rr_to_string");
|
||||
if(!dest) fatal_exit("out of memory");
|
||||
memset(&rrk, 0, sizeof(rrk));
|
||||
memset(&d, 0, sizeof(d));
|
||||
rrk.entry.data = &d;
|
||||
rrk.rk.rrset_class = htons(LDNS_RR_CLASS_IN);
|
||||
d.count = 1;
|
||||
d.rr_len = rr_len;
|
||||
d.rr_ttl = rr_ttl;
|
||||
d.rr_data = rr_data;
|
||||
rr_ttl[0] = 3600;
|
||||
|
||||
/* an ordinary rr is printed, also with the large dest_len */
|
||||
rrk.rk.dname = smalldname;
|
||||
rrk.rk.dname_len = sizeof(smalldname);
|
||||
rrk.rk.type = htons(LDNS_RR_TYPE_A);
|
||||
rr_data[0] = smallrdata;
|
||||
rr_len[0] = sizeof(smallrdata);
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
|
||||
unit_assert(strstr(dest, "1.2.3.4") != NULL);
|
||||
|
||||
/* a dname of the maximum length, 127 labels of one character */
|
||||
for(i=0; i<127; i++) {
|
||||
maxdname[i*2] = 1;
|
||||
maxdname[i*2+1] = (uint8_t)'a';
|
||||
}
|
||||
maxdname[254] = 0;
|
||||
rrk.rk.dname = maxdname;
|
||||
rrk.rk.dname_len = sizeof(maxdname);
|
||||
rrk.rk.type = htons(LDNS_RR_TYPE_TXT);
|
||||
|
||||
/* 255+2+2+4+65272 is exactly 65535, that still fits */
|
||||
rr_len[0] = 65535 - 255 - 8;
|
||||
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
|
||||
if(!rr_data[0]) fatal_exit("out of memory");
|
||||
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 1);
|
||||
free(rr_data[0]);
|
||||
|
||||
/* one more byte of rdata does not fit and must be refused */
|
||||
rr_len[0] = 65535 - 255 - 8 + 1;
|
||||
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
|
||||
if(!rr_data[0]) fatal_exit("out of memory");
|
||||
sldns_write_uint16(rr_data[0], (uint16_t)(rr_len[0]-2));
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
|
||||
unit_assert(dest[0] == 0);
|
||||
free(rr_data[0]);
|
||||
|
||||
/* the largest rdata an rr can hold, well over the buffer */
|
||||
rr_len[0] = 2 + 65535;
|
||||
rr_data[0] = (uint8_t*)calloc(1, rr_len[0]);
|
||||
if(!rr_data[0]) fatal_exit("out of memory");
|
||||
sldns_write_uint16(rr_data[0], 65535);
|
||||
unit_assert(packed_rr_to_string(&rrk, 0, 0, dest, dest_len) == 0);
|
||||
unit_assert(dest[0] == 0);
|
||||
free(rr_data[0]);
|
||||
|
||||
free(dest);
|
||||
}
|
||||
|
||||
void unit_show_func(const char* file, const char* func)
|
||||
{
|
||||
printf("test %s:%s\n", file, func);
|
||||
@@ -1409,6 +1492,7 @@ main(int argc, char* argv[])
|
||||
zonemd_test();
|
||||
tcpreuse_test();
|
||||
msgparse_test();
|
||||
packed_rrset_test();
|
||||
edns_ede_answer_encode_test();
|
||||
localzone_test();
|
||||
mesh_test();
|
||||
|
||||
@@ -280,7 +280,9 @@ int packed_rr_to_string(struct ub_packed_rrset_key* rrset, size_t i,
|
||||
size_t rlen = rrset->rk.dname_len + 2 + 2 + 4 + d->rr_len[i];
|
||||
time_t adjust = 0;
|
||||
log_assert(dest_len > 0 && dest);
|
||||
if(rlen > dest_len) {
|
||||
/* rlen is the length written into rr, dest_len bounds the output
|
||||
* string; check both, callers can pass a dest_len over sizeof(rr). */
|
||||
if(rlen > dest_len || rlen > sizeof(rr)) {
|
||||
dest[0] = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user