Compare commits

...
6 Commits
Author SHA1 Message Date
Matthias Andree 3ff66da573 Fix two typos in v2.93 CHANGELOG 2026-06-04 12:47:22 +01:00
Simon Kelley d823d8e9cd Fix OOB-read crash in get_rdata().
get_rdata() contains another instance of a crash caused by
a false value of RDLEN in a resource-record.

An RR containing name which is longer than the rdlen of the RR can
get get_rdata into a state where it calculates the length of the data
following the name as a negative number which is then promoted
to a very large positive number, and causing SIGSEGV.

This can be triggered by crafted packets from malicous DNS servers,
but only when DNSSEC validation is enabled. The attack packets do not
have to be correctly DNSSEC signed.

Thanks to Tristan G. for spotting this problem.

Also fix error handling for RRs with a fixed size fields in the specification
where the rrsize indicates that there are zero bytes in that position.
2026-06-04 12:47:18 +01:00
Simon Kelley 2c78b6db6c Better code to make human-friendly tokens for pointers in log-malloc.
It turns out that subtracting NULL from a pointer to turn it into
an integer is not a good idea, because subtracting a NULL pointer
is undefined behaviour in C.

The correct way to do this is simply to cast the pointer to
uintptr_t. The only fly in this ointment is that the C standard
does not mandate support for uintptr_t.  In practice, I doubt
anyone is running dnsmasq on the long-dead architectures where
this might be a problem.

Thanks to Matthias Andree for the heads-up.
2026-06-02 13:00:18 +01:00
Simon Kelley 4bf46ceb37 Add the ability to bail before EOF to get_line_alloc();
If we stop reading a file before getting to the end, get_line_alloc()
will not clean up the memory it allocated. Give get_line_alloc()
the ability to do a forced cleanup by calling it with a NULL file,
and use that ability where we stop reading a file early.

Also clear the state variables when we free the memory, to
pre-empt use-after-free.
2026-06-02 00:22:05 +01:00
Simon Kelley 7d42376a3a Fix get_line_alloc()
Assigning the result of getc() to a char makes comparing it to EOF
unreliable, at the very least. You're never too old to make newbie
mistakes.

Thanks to Sebastian Gottschall  for spotting this.
2026-06-01 22:56:23 +01:00
Simon Kelley 08cc209e7a Add --log-debug to man page. 2026-06-01 22:45:49 +01:00
5 changed files with 34 additions and 22 deletions

No files matched your search

+2 -2
View File
@@ -1,6 +1,6 @@
version 2.93
Fix a corner-case in DNSSEC validation with wildcards. If we have
a wildcard record *.example.com and recieve a query for
a wildcard record *.example.com and receive a query for
a.example.com then that's OK, but we have to check that there isn't
an actual a.example.com record. The corner case is when we get a
query for *.example.com in that case the non-existence check
@@ -19,7 +19,7 @@ version 2.93
(eg rivcoed.org) will still fail. Thanks to Petr Menšík
for the bug report.
Fix DNSSEC fail with CNAME replies to DS queries. As CNAME reply
Fix DNSSEC fail with CNAME replies to DS queries. A CNAME reply
to a DNSSEC query was confusing the validation logic. It now
accepts a signed CNAME reply to a DS query as proof that no DS
exists at the domain. This fixes the DS/zone break detection logic.
+3
View File
@@ -154,6 +154,9 @@ allows the log file to be rotated without stopping dnsmasq.
.B --log-debug
Enable extra logging intended for debugging rather than information.
.TP
.B --log-malloc
Enable logging of memory allocation and release, for debugging.
.TP
.B --log-async[=<lines>]
Enable asynchronous logging and optionally set the limit on the
number of lines
+17 -13
View File
@@ -177,7 +177,7 @@ static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state
if ((state->c = state->end - state->ip) != 0)
{
state->op = state->ip;
state->ip = state->end;;
state->ip = state->end;
}
else
return 0;
@@ -189,24 +189,28 @@ static int get_rdata(struct dns_header *header, size_t plen, struct rdata_state
if (d == (u16)0)
{
/* domain-name, canonicalise */
int len;
/* If the name is malformed, or runs beyond the end of the RR, abort.
under no circumstances should state->ip be beyond state->end since
that will cause the run-out code above to turn the negative
calculted length into a very large postive value for state->c
and overrun the buffer. */
if (!extract_name(header, plen, &state->ip, state->buff, EXTR_NAME_EXTRACT, 0) ||
(len = to_wire(state->buff)) == 0)
continue;
state->c = len;
state->ip > state->end)
return 0;
/* to_wire() always returns length > 0 */
state->c = to_wire(state->buff);
state->op = (unsigned char *)state->buff;
}
else
{
/* plain data preceding a domain-name, don't run off the end of the data */
if ((state->end - state->ip) < d)
d = state->end - state->ip;
if (d == 0)
continue;
/* Plain data preceding a domain-name.
Handle short RR, if there are no bytes left, return finished. */
if ((state->end - state->ip) < d &&
(d = state->end - state->ip) == 0)
return 0;
state->op = state->ip;
state->c = d;
state->ip += d;
+5 -1
View File
@@ -6270,7 +6270,11 @@ void read_opts(int argc, char **argv, char *compile_opts)
if ((token = strtok(NULL, " \t\n\r")) &&
(daemon->domain_suffix = canonicalise_opt(token)))
break;
{
/* We don't call get_line_alloc() until it returns false and frees the automatically */
get_line_alloc(NULL, &line, &linesz);
break;
}
}
fclose(f);
+7 -6
View File
@@ -947,7 +947,7 @@ int kernel_version(void)
}
#endif
#define hash_ptr(x) (((unsigned int)(((char *)(x)) - ((char *)NULL))) & 0xffffff)
#define hash_ptr(x) (((uintptr_t)(x)) & 0xffffff)
void *whine_malloc_real(const char *func, unsigned int line, size_t size)
{
@@ -1038,16 +1038,15 @@ void free_real(const char *func, unsigned int line, void *ptr)
}
/* get lines from f, expand buffer as required. Buffer is freed when
EOF reached and we return zero. */
EOF reached and we return zero. Buffer also freed if f == NULL. */
int get_line_alloc(FILE *f, char **buffp, size_t *sizep)
{
char c;
size_t cnt = 0;
char *buff = *buffp;
while (1) {
c = getc(f);
while (1) {
int c = f ? getc(f) : EOF;
if (cnt == *sizep)
{
void *new;
@@ -1081,6 +1080,8 @@ int get_line_alloc(FILE *f, char **buffp, size_t *sizep)
return 1;
free(buff);
*buffp = NULL;
*sizep = 0;
return 0;
}