Fix double-free in blockdata_expand().

If blockdata_expand() fails, it frees the existing block chain
and returns zero. Each call to blockdata_expand() checks for the zero return,
and calls blockdata_free() as part of its clean-up, resulting in
a double-free and crash.

Thanks to fallrig for finding this.
This commit is contained in:
Simon Kelley committed 2026-06-09 22:11:21 +01:00
1 parent 3ff66da573
commit c310853907
2 files changed
+11 -25

No files matched your search

+1 -1
View File
@@ -132,7 +132,7 @@ int blockdata_expand(struct blockdata *block, size_t oldlen, char *data, size_t
/* find size of current final block */
for (b = block; oldlen > KEYBLOCK_LEN && b; b = b->next, oldlen -= KEYBLOCK_LEN);
/* chain to short for length, something is broken */
/* chain too short for length, something is broken */
if (oldlen > KEYBLOCK_LEN)
{
blockdata_free(block);
+10 -24
View File
@@ -585,11 +585,8 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
{
len = to_wire(daemon->workspacename);
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, daemon->workspacename, len))
{
blockdata_free(addr.rrblock.rrdata);
return 0;
}
return 0;
addr.rrblock.datalen += len;
}
}
@@ -607,11 +604,8 @@ static int find_soa(struct dns_header *header, size_t qlen, char *name, int *sub
int secflag = 0;
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p, 20))
{
blockdata_free(addr.rrblock.rrdata);
return 0;
}
return 0;
addr.rrblock.datalen += 20;
#ifdef HAVE_DNSSEC
@@ -942,10 +936,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
{
/* Copy the rest of the RR and end. */
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, endrr - p1))
{
blockdata_free(addr.rrblock.rrdata);
return 0;
}
return 0;
addr.rrblock.datalen += endrr - p1;
}
else if (desc == 0)
@@ -962,11 +954,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
len = to_wire(name);
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, name, len))
{
blockdata_free(addr.rrblock.rrdata);
return 0;
}
return 0;
addr.rrblock.datalen += len;
}
else
@@ -976,11 +965,8 @@ int extract_addresses(struct dns_header *header, size_t qlen, char *name, time_t
desc = endrr - p1;
if (!blockdata_expand(addr.rrblock.rrdata, addr.rrblock.datalen, (char *)p1, desc))
{
blockdata_free(addr.rrblock.rrdata);
return 0;
}
return 0;
addr.rrblock.datalen += desc;
p1 += desc;
}