#939846 xymon: xymonnet segfaults (and completely stops working) if any URL to check is IPv6-only

Package:
xymon
Source:
xymon
Description:
monitoring system for systems, networks and applications
Submitter:
Axel Beckert
Date:
2019-12-17 19:12:03 UTC
Severity:
normal
#939846#5
Date:
2019-09-09 12:54:52 UTC
From:
To:
Hi,

it's well-known that as of now no released Xymon version supports IPv6.

What's nevertheless an issue of its own, is that, if even only a single
URL in hosts.cfg only resolves to IPv6 addresses(*), the xymonnet
process crashes as soon as it receives the DNS response.

And since it seems to get this response
inbetween parsing hosts.cfg and conducting any tests, a single URL in
hosts.cfg may cause _all_ network tests to stop and go purple.

(*) In this case it additionally was a ULA, i.e. inside fd::/8 (see
https://en.wikipedia.org/wiki/Unique_local_address) which
    potentially might be relevant.

Backtrace:

[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `xymonnet --report --ping --checkresponse'.
Program terminated with signal SIGABRT, Aborted.
#0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
(gdb) #0  __GI_raise (sig=sig@entry=6) at ../sysdeps/unix/sysv/linux/raise.c:51
#1  0x00007f9569f8242a in __GI_abort () at abort.c:89
#2  0x0000559230ff6645 in sigsegv_handler (signum=<optimized out>) at sig.c:57
#3  <signal handler called>
#4  0x0000559230fe9b03 in dns_simple_callback (arg=0x559231f252e0, status=0, timeout=<optimized out>, hent=0x559231f0bd00) at dns.c:121
#5  0x00007f956b0c90a9 in end_hquery (hquery=0x559231f25320, status=<optimized out>, host=0x559231f0bd00) at ares_gethostbyname.c:227
#6  0x00007f956b0c9443 in host_callback (arg=0x559231f25320, status=<optimized out>, timeouts=<optimized out>, abuf=<optimized out>, alen=<optimized out>)
    at ares_gethostbyname.c:207
#7  0x00007f956b0d1ef9 in end_squery (squery=0x559231f25480, status=<optimized out>, abuf=<optimized out>, alen=<optimized out>) at ares_search.c:203
#8  0x00007f956b0d1fed in search_callback (arg=0x559231f25480, status=<optimized out>, timeouts=<optimized out>, abuf=<optimized out>, alen=<optimized out>)
    at ares_search.c:150
#9  0x00007f956b0d1c1b in qcallback (arg=0x559231f25440, status=<optimized out>, timeouts=<optimized out>, abuf=<optimized out>, alen=<optimized out>)
    at ares_query.c:183
#10 0x00007f956b0d0371 in end_query (channel=channel@entry=0x559231e548b0, query=query@entry=0x559231f27560, status=status@entry=0,
    abuf=abuf@entry=0x7ffce6f53520 "\177J\201\200", alen=110) at ares_process.c:1331
#11 0x00007f956b0d1236 in process_answer (channel=channel@entry=0x559231e548b0, abuf=abuf@entry=0x7ffce6f53520 "\177J\201\200", alen=<optimized out>,
    whichserver=whichserver@entry=0, tcp=tcp@entry=0, now=now@entry=0x7ffce6f54590) at ares_process.c:616
#12 0x00007f956b0d1570 in process_answer (now=0x7ffce6f54590, tcp=0, whichserver=0, alen=<optimized out>, abuf=0x7ffce6f53520 "\177J\201\200",
    channel=0x559231e548b0) at ares_process.c:529
#13 read_udp_packets (channel=channel@entry=0x559231e548b0, read_fds=read_fds@entry=0x7ffce6f54600, read_fd=read_fd@entry=-1, now=now@entry=0x7ffce6f54590)
    at ares_process.c:480
#14 0x00007f956b0d1640 in processfds (channel=channel@entry=0x559231e548b0, read_fds=read_fds@entry=0x7ffce6f54600, read_fd=read_fd@entry=-1,
    write_fds=write_fds@entry=0x7ffce6f54680, write_fd=write_fd@entry=-1) at ares_process.c:127
#15 0x00007f956b0d1bc1 in ares_process (channel=channel@entry=0x559231e548b0, read_fds=read_fds@entry=0x7ffce6f54600,
    write_fds=write_fds@entry=0x7ffce6f54680) at ares_process.c:137
#16 0x0000559230fe9863 in dns_ares_queue_run (channel=0x559231e548b0) at dns.c:172
#17 0x0000559230fdb2bf in main (argc=4, argv=0x7ffce6f558d8) at xymonnet.c:2342
(gdb) quit

Even without IPv6 support, I would expect that xymonnet is more robust
and only issues an error or warning, but does not crash and completely
stop working.

P.S.: This is unrelated to the Xymon stable update published about 1.5
days ago and has been observed on both, Debian 9 Stretch as well as
Debian 10 Buster.

#939846#16
Date:
2019-09-09 13:28:58 UTC
From:
To:
Hi,

I wrote in #939846:

https://bugs.debian.org/939846 and https://bugs.debian.org/867341 are
probably related issues if not even the same issue. (867341: "all
networks tests gone purple and reading xymonnet log, I discovered
buffer overflow")

It's though unclear to me relation to the (working for me) conn6 test
from hobbit-plugins is — which works fine for me (with hostnames,
though).

Nicolas: Can you tell us where exactly in xymonnet the buffer overflow
is? Is it in xymonnet/dns.c? Because that's where I experience the
crashes with IPv6-only URLs on hosts.cfg.

Additionally, I actually also have the issue with the last night
uploaded 4.3.30-1 in Debian Unstable.

		Regards, Axel

#939846#21
Date:
2019-12-17 19:04:02 UTC
From:
To:
Dear Maintainer,
I just tried to reproduce the crash but did not get it.
Maybe some more details of the configuration details of
host.cfg and DNS server setup could help,
because in my test I never reached with my IPv6 config
the faulting instruction.

At least the instruction, at that address where the segfault is received,
leads to the assumption that hent->h_addr_list is not a valid pointer
for some reason.


A workaround could be to check if the DNS result is IPv4.
I guess following could achieve this:
dns.c:119:
-	if (status == ARES_SUCCESS) {
+	if (status == ARES_SUCCESS && hent->h_addrtype == AF_INET && hent->h_addr_list) {


But more insight could maybe give someone experiencing the crash
by forwarding the output of following in the dns_simple_callback frame:

    print *hent
    x/1gx *(hent->h_addr_list)
    x/4ub *(hent->h_addr_list)

And maybe a 'bt full' should contain a part of the UDP response.


Kind regards,
Bernhard



(gdb) disassemble /m dns_simple_callback
Dump of assembler code for function dns_simple_callback:
111     {
   0x0000555555569ab0 <+0>:     push   %r13
   0x0000555555569ab2 <+2>:     push   %r12
   0x0000555555569ab4 <+4>:     mov    %rcx,%r13                                                            # store address of hent into $r13
   0x0000555555569ab7 <+7>:     push   %rbp
   0x0000555555569ab8 <+8>:     push   %rbx
   0x0000555555569ab9 <+9>:     mov    %rdi,%rbx
   0x0000555555569abc <+12>:    mov    %esi,%ebp
   0x0000555555569abe <+14>:    sub    $0x28,%rsp
   0x0000555555569ac5 <+21>:    mov    %fs:0x28,%rax
   0x0000555555569ace <+30>:    mov    %rax,0x18(%rsp)
   0x0000555555569ad3 <+35>:    xor    %eax,%eax

112             struct dnsitem_t *dnsc = (dnsitem_t *)arg;
113             struct timespec etime;
114
115             getntimer(&etime);
   0x0000555555569ac2 <+18>:    mov    %rsp,%rdi
   0x0000555555569ad5 <+37>:    callq  0x55555556c030 <getntimer>

116             tvdiff(&dnsc->resolvetime, &etime, &dnsc->resolvetime);
   0x0000555555569ada <+42>:    lea    0x20(%rbx),%rdi
   0x0000555555569ade <+46>:    mov    %rsp,%rsi
   0x0000555555569ae1 <+49>:    mov    %rdi,%rdx
   0x0000555555569ae4 <+52>:    callq  0x555555578790 <tvdiff>

117             pending_dns_count--;
   0x0000555555569ae9 <+57>:    subl   $0x1,0x2287d8(%rip)        # 0x5555557922c8 <pending_dns_count>

118
119             if (status == ARES_SUCCESS) {
   0x0000555555569af0 <+64>:    test   %ebp,%ebp
   0x0000555555569af2 <+66>:    jne    0x555555569b30 <dns_simple_callback+128>

120                     memcpy(&dnsc->addr, *(hent->h_addr_list), sizeof(dnsc->addr));
   0x0000555555569af4 <+68>:    mov    0x18(%r13),%rax                                                      # store address hent->h_addr_list points to into $rax

121                     dbgprintf("Got DNS result for host %s : %s\n", dnsc->name, inet_ntoa(dnsc->addr));
   0x0000555555569af8 <+72>:    mov    0x228dc2(%rip),%edx        # 0x5555557928c0 <debug>
   0x0000555555569afe <+78>:    mov    (%rax),%rax
   0x0000555555569b01 <+81>:    test   %edx,%edx
=> 0x0000555555569b03 <+83>:    mov    (%rax),%edi                                                          # store address pointed to by hent->h_addr into $edi
   0x0000555555569b08 <+88>:    jne    0x555555569b88 <dns_simple_callback+216>


(gdb) print/x $r13
$27 = 0x5555557bd4d0
(gdb) print hent
$28 = (struct hostent *) 0x5555557bd4d0

(gdb) x/1xg $r13 + 0x18
0x5555557bd4e8: 0x00005555557a8560
(gdb) print hent->h_addr_list
$32 = (char **) 0x5555557a8560

(gdb) x/1xg hent->h_addr_list
0x5555557a8560: 0x00005555557a8220
(gdb) print/x $rax
$33 = 0x5555557a8220

(gdb) x/4ub *(hent->h_addr_list)
0x5555557a8220: 192     168     240     240