[Dnsmasq-discuss] Segfault when no uplink dns server is available
Daniel Danzberger
daniel at dd-wrt.com
Wed Mar 1 15:58:21 UTC 2023
Hi,
the segfault occurs when a custom 'server=/domain.test/#' entry is defined in the config,
but no upstream dns server is available yet.
The full valgrind crash log and config to reproduce the issue are below:
root at lappi:[dnsmasq]:# valgrind --track-origins=yes ./src/dnsmasq --conf-file=/tmp/dnsmasq.conf -k
==683879== Memcheck, a memory error detector
==683879== Copyright (C) 2002-2022, and GNU GPL'd, by Julian Seward et al.
==683879== Using Valgrind-3.19.0 and LibVEX; rerun with -h for copyright info
==683879== Command: ./src/dnsmasq --conf-file=/tmp/dnsmasq.conf -k
==683879==
==683879== Warning: invalid file descriptor 1024 in syscall close()
==683879== Warning: invalid file descriptor 1025 in syscall close()
==683879== Warning: invalid file descriptor 1026 in syscall close()
==683879== Warning: invalid file descriptor 1027 in syscall close()
==683879== Use --log-fd=<number> to select an alternative log fd.
==683879== Warning: invalid file descriptor 1028 in syscall close()
==683879== Warning: invalid file descriptor 1029 in syscall close()
==683879== Warning: invalid file descriptor 1030 in syscall close()
==683879== Invalid read of size 4
==683879== at 0x129BED: forward_query (forward.c:353)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
==683879== by 0x110B38: main (dnsmasq.c:1264)
==683879== Address 0x4a60560 is 16 bytes before a block of size 11 alloc'd
==683879== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
==683879== by 0x11AD60: safe_malloc (util.c:302)
==683879== by 0x11C3CC: opt_malloc (option.c:633)
==683879== by 0x11C3CC: opt_string_alloc (option.c:645)
==683879== by 0x11F03B: one_opt (option.c:2346)
==683879== by 0x125578: read_file (option.c:5381)
==683879== by 0x125A0B: one_file (option.c:5487)
==683879== by 0x126608: read_opts (option.c:5854)
==683879== by 0x10FA0C: main (dnsmasq.c:104)
==683879==
==683879== Invalid write of size 4
==683879== at 0x129BF7: forward_query (forward.c:353)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
==683879== by 0x110B38: main (dnsmasq.c:1264)
==683879== Address 0x4a60560 is 16 bytes before a block of size 11 alloc'd
==683879== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
==683879== by 0x11AD60: safe_malloc (util.c:302)
==683879== by 0x11C3CC: opt_malloc (option.c:633)
==683879== by 0x11C3CC: opt_string_alloc (option.c:645)
==683879== by 0x11F03B: one_opt (option.c:2346)
==683879== by 0x125578: read_file (option.c:5381)
==683879== by 0x125A0B: one_file (option.c:5487)
==683879== by 0x126608: read_opts (option.c:5854)
==683879== by 0x10FA0C: main (dnsmasq.c:104)
==683879==
==683879== Invalid read of size 8
==683879== at 0x129C07: forward_query (forward.c:354)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
==683879== by 0x110B38: main (dnsmasq.c:1264)
==683879== Address 0x4a60558 is 24 bytes before a block of size 11 alloc'd
==683879== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
==683879== by 0x11AD60: safe_malloc (util.c:302)
==683879== by 0x11C3CC: opt_malloc (option.c:633)
==683879== by 0x11C3CC: opt_string_alloc (option.c:645)
==683879== by 0x11F03B: one_opt (option.c:2346)
==683879== by 0x125578: read_file (option.c:5381)
==683879== by 0x125A0B: one_file (option.c:5487)
==683879== by 0x126608: read_opts (option.c:5854)
==683879== by 0x10FA0C: main (dnsmasq.c:104)
==683879==
==683879== Invalid write of size 4
==683879== at 0x129502: forward_query (forward.c:358)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
==683879== by 0x110B38: main (dnsmasq.c:1264)
==683879== Address 0x4a60560 is 16 bytes before a block of size 11 alloc'd
==683879== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
==683879== by 0x11AD60: safe_malloc (util.c:302)
==683879== by 0x11C3CC: opt_malloc (option.c:633)
==683879== by 0x11C3CC: opt_string_alloc (option.c:645)
==683879== by 0x11F03B: one_opt (option.c:2346)
==683879== by 0x125578: read_file (option.c:5381)
==683879== by 0x125A0B: one_file (option.c:5487)
==683879== by 0x126608: read_opts (option.c:5854)
==683879== by 0x10FA0C: main (dnsmasq.c:104)
==683879==
==683879== Invalid write of size 8
==683879== at 0x12950C: forward_query (forward.c:357)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
==683879== by 0x110B38: main (dnsmasq.c:1264)
==683879== Address 0x4a60558 is 24 bytes before a block of size 11 alloc'd
==683879== at 0x48455EF: calloc (vg_replace_malloc.c:1328)
==683879== by 0x11AD60: safe_malloc (util.c:302)
==683879== by 0x11C3CC: opt_malloc (option.c:633)
==683879== by 0x11C3CC: opt_string_alloc (option.c:645)
==683879== by 0x11F03B: one_opt (option.c:2346)
==683879== by 0x125578: read_file (option.c:5381)
==683879== by 0x125A0B: one_file (option.c:5487)
==683879== by 0x126608: read_opts (option.c:5854)
==683879== by 0x10FA0C: main (dnsmasq.c:104)
==683879==
==683879== Invalid read of size 4
==683879== at 0x1289B5: allocate_rfd (forward.c:2563)
==683879== by 0x1291BE: forward_query (forward.c:498)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
==683879== by 0x110B38: main (dnsmasq.c:1264)
==683879== Address 0x3 is not stack'd, malloc'd or (recently) free'd
==683879==
==683879==
==683879== Process terminating with default action of signal 11 (SIGSEGV)
==683879== Access not within mapped region at address 0x3
==683879== at 0x1289B5: allocate_rfd (forward.c:2563)
==683879== by 0x1291BE: forward_query (forward.c:498)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
==683879== by 0x110B38: main (dnsmasq.c:1264)
==683879== If you believe this happened as a result of a stack
==683879== overflow in your program's main thread (unlikely but
==683879== possible), you can try to increase the size of the
==683879== main thread stack using the --main-stacksize= flag.
==683879== The main thread stack size used in this run was 8388608.
==683879==
==683879== HEAP SUMMARY:
==683879== in use at exit: 42,261 bytes in 187 blocks
==683879== total heap usage: 243 allocs, 56 frees, 138,085 bytes allocated
==683879==
==683879== LEAK SUMMARY:
==683879== definitely lost: 0 bytes in 0 blocks
==683879== indirectly lost: 0 bytes in 0 blocks
==683879== possibly lost: 36 bytes in 1 blocks
==683879== still reachable: 42,225 bytes in 186 blocks
==683879== suppressed: 0 bytes in 0 blocks
==683879== Rerun with --leak-check=full to see details of leaked memory
==683879==
==683879== For lists of detected and suppressed errors, rerun with: -s
==683879== ERROR SUMMARY: 6 errors from 6 contexts (suppressed: 0 from 0)
==683879== could not unlink /tmp/vgdb-pipe-from-vgdb-to-683879-by-daniel-on-???
==683879== could not unlink /tmp/vgdb-pipe-to-vgdb-from-683879-by-daniel-on-???
==683879== could not unlink /tmp/vgdb-pipe-shared-mem-vgdb-683879-by-daniel-on-???
Segmentation fault
/tmp/dnsmasq.conf:
--
domain-needed
localise-queries
read-ethers
expand-hosts
bind-dynamic
local-service
edns-packet-max=1232
domain=lan
local=/lan/
server=/sub.domain.test/#
server=/domain.test/8.8.8.8
addn-hosts=/tmp/hosts
resolv-file=/tmp/resolv.conf.d/resolv.conf.auto
stop-dns-rebind
rebind-localhost-ok
conf-dir=/tmp/dnsmasq.d
bogus-priv
--
To trigger the issue, pass a simple dns request to the running dnsmasq instance.
I.e. with: # dig sub.domain.test @localhost
The first invalid memory access happens, when the 'struct server' of the matching domain is accessed here:
--
==683879== Invalid read of size 4
==683879== at 0x129BED: forward_query (forward.c:353)
==683879== by 0x12A756: receive_query (forward.c:1869)
==683879== by 0x12ECEA: check_dns_listeners (dnsmasq.c:1843)
if (!option_bool(OPT_ORDER))
{
if (master->forwardcount++ > FORWARD_TEST ||
difftime(now, master->forwardtime) > FORWARD_TIME ||
master->last_server == -1)
{
master->forwardtime = now;
master->forwardcount = 0;
forward->forwardall = 1;
}
else
start = master->last_server;
}
--
The server struct has been allocated here with only 'size' bytes and not the full length of the server struct.
Which causes the member access beyond 'size' to read/write into unwanted memory.
src/domain-match.c:565
--
if (flags & SERV_6ADDR)
size = sizeof(struct serv_addr6);
else if (flags & SERV_4ADDR)
size = sizeof(struct serv_addr4);
else
size = sizeof(struct serv_local);
if (!(serv = whine_malloc(size)))
{
free(alloc_domain);
return 0;
}
--
--
Regards
Daniel Danzberger
embeDD GmbH, Alter Postplatz 2, CH-6370 Stans
More information about the Dnsmasq-discuss
mailing list