diff mbox series

[uclibc-ng-devel,v1] libc/inet/resolv: fix per thread rest_state access

Message ID 20211125201825.22354-1-ps.report@gmx.net
State Accepted
Headers show
Series [uclibc-ng-devel,v1] libc/inet/resolv: fix per thread rest_state access | expand

Commit Message

Peter Seiderer Nov. 25, 2021, 8:18 p.m. UTC
- use the provided __res_state() method instead of direct access
  to struct __res_state pointer &_res/*__resp

- change the __UCLIBC_HAS_TLS__ protected __res_state() implementation
  to the one where the comment 'When threaded, _res may be a per-thread
  variable.' indicates this should be used with threads/TLS enabled

Fixes the following segfaults with buildroot raspberrypi3_64_defconfig
(uclibc, -Os, Note: runs fine using the raspberrypi3_defconfig):

  $ /usr/sbin/ntpd -n -d
  1970-01-01T00:01:49 ntpd[249]: INIT: ntpd ntpsec-1.2.0 2021-11-03T20:39:50Z: Starting
  1970-01-01T00:01:49 ntpd[249]: INIT: Command line: /usr/sbin/ntpd -n -d
  1970-01-01T00:01:49 ntpd[249]: INIT: precision = 7.240 usec (-17)
  1970-01-01T00:01:49 ntpd[249]: INIT: successfully locked into RAM
  1970-01-01T00:01:49 ntpd[249]: CONFIG: readconfig: parsing file: /etc/ntp.conf
  1970-01-01T00:01:49 ntpd[249]: CONFIG: restrict nopeer ignored
  1970-01-01T00:01:49 ntpd[249]: INIT: Using SO_TIMESTAMPNS
  1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 0 v6wildcard [::]:123
  1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 1 v4wildcard 0.0.0.0:123
  1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 2 lo 127.0.0.1:123
  1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 3 eth0 172.16.0.30:123
  1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 4 lo [::1]:123
  1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 5 eth0 [fe80::ba27:ebff:fea6:340%2]:123
  1970-01-01T00:01:49 ntpd[249]: IO: Listening on routing socket on fd #22 for interface updates
  1970-01-01T00:01:50 ntpd[249]: SYNC: Found 10 servers, suggest minsane at least 3
  1970-01-01T00:01:50 ntpd[249]: INIT: MRU 10922 entries, 13 hash bits, 65536 bytes
  1970-01-01T00:01:50 ntpd[249]: statistics directory /var/NTP/ does not exist or is unwriteable, error No such file or directory
  1970-01-01T00:01:51 ntpd[249]: DNS: dns_probe: 0.pool.ntp.org, cast_flags:8, flags:101
  Segmentation fault (core dumped)

  $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/ntpsec-1_2_0/build/main/ntpd/ntpd core
  Core was generated by `/usr/sbin/ntpd -n -d'.
  Program terminated with signal SIGSEGV, Segmentation fault.
  (gdb) where
  #0  0x0000007f8ff1f150 in res_sync_func () at libc/inet/resolv.c:3356
  #1  0x0000007f8ff1c468 in __open_nameservers () at libc/inet/resolv.c:949
  #2  0x0000007f8ff1b498 in __dns_lookup (name=0x55943c67f0 "0.pool.ntp.org",
      type=1, outpacket=0x7f8fe91c48, a=0x7f8fe91c08) at libc/inet/resolv.c:1134
  #3  0x0000007f8ff1d744 in __GI_gethostbyname_r (
      name=0x55943c67f0 "0.pool.ntp.org", result_buf=0x7f8fe92628,
      buf=0x7f8fe91d90 "", buflen=992, result=0x7f8fe92670,
      h_errnop=0x7f8fe92668) at libc/inet/resolv.c:1966
  #4  0x0000007f8ff1d9a0 in __GI_gethostbyname2_r (
      name=0x55943c67f0 "0.pool.ntp.org", family=2, result_buf=0x7f8fe92628,
      buf=0x7f8fe91d70 "0.pool.ntp.org", buflen=1024, result=0x7f8fe92670,
      h_errnop=0x7f8fe92668) at libc/inet/resolv.c:2065
  #5  0x0000007f8ff16924 in gaih_inet (name=0x55943c67f0 "0.pool.ntp.org",
      service=0x7f8fe92828, req=0x7f8fe92890, pai=0x7f8fe92838)
      at libc/inet/getaddrinfo.c:596
  #6  0x0000007f8ff17624 in __GI_getaddrinfo (
      name=0x55943c67f0 "0.pool.ntp.org",
      service=0x5582eb8acd "\377H\213D$\bL\211\367H\213\260\270",
      hints=0x7f8fe92890, pai=0x5582ee1bf8) at libc/inet/getaddrinfo.c:957
  #7  0x0000005582ea60f4 in _start ()
  (gdb) p _res
  $1 = {options = 0, nsaddr_list = {{sin_family = 0, sin_port = 0, sin_addr = {
          s_addr = 0}, sin_zero = "\000\000\000\000\000\000\000"}, {
        sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0},
        sin_zero = "\000\000\000\000\000\000\000"}, {sin_family = 0,
        sin_port = 0, sin_addr = {s_addr = 0},
        sin_zero = "\000\000\000\000\000\000\000"}}, dnsrch = {0x0, 0x0, 0x0,
      0x0, 0x0, 0x0, 0x0}, nscount = 0 '\000', ndots = 0 '\000',
    retrans = 0 '\000', retry = 0 '\000', defdname = '\000' <repeats 255 times>,
    nsort = 0 '\000', pfcode = 0, id = 0, res_h_errno = 0, sort_list = {{addr = {
          s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
          s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
          s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
          s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
          s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}}, _u = {
      _ext = {nsaddrs = {0x0, 0x0, 0x0}, nscount = 0 '\000', nstimes = {0, 0,
          0}, nssocks = {0, 0, 0}, nscount6 = 0, nsinit = 0}}}
  (gdb) p &_res
  $2 = (struct __res_state *) 0x7f8ff8fd98 <_res>
  (gdb) p rp
  $3 = (struct __res_state *) 0x7fffffffff

  And the following uclibc code at libc/inet/resolv.c:3356:

  3345 static void res_sync_func(void)
  3346 {
  3347         struct __res_state *rp = &(_res);
  3348         int n;
  3349
  3350         /* If we didn't get malloc failure earlier... */
  3351         if (__nameserver != (void*) &__local_nameserver) {
  3352                 /* TODO:
  3353                  * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
  3354                  */
  3355 #ifdef __UCLIBC_HAS_IPV6__
  3356                 if (__nameservers > rp->_u._ext.nscount)
  3357                         __nameservers = rp->_u._ext.nscount;
  3358                 n = __nameservers;

  The special thing about ntpsec is the DNS lookup in an extra thread
  and/or the call to res_init(), see ntpsec-1_2_0/ntpd/ntp_dns.c:

   69         msyslog(LOG_INFO, "DNS: dns_probe: %s, cast_flags:%x, flags:%x%s",
   70                 hostname, pp->cast_flags, pp->cfg.flags, busy);
   71         if (NULL != active)     /* normally redundant */
   72                 return false;
   73
   74         active = pp;
   75
   76         sigfillset(&block_mask);
   77         pthread_sigmask(SIG_BLOCK, &block_mask, &saved_sig_mask);
   78         rc = pthread_create(&worker, NULL, dns_lookup, pp);

  and

  165 static void* dns_lookup(void* arg)
  166 {
  167         struct peer *pp = (struct peer *) arg;
  168         struct addrinfo hints;
  169
  170 #ifdef HAVE_SECCOMP_H
  171         setup_SIGSYS_trap();      /* enable trap for this thread */
  172 #endif
  173
  174 #ifdef HAVE_RES_INIT
  175         /* Reload DNS servers from /etc/resolv.conf in case DHCP has updated it.
  176          * We only need to do this occasionally, but it's not expensive
  177          * and simpler to do it every time than it is to figure out when
  178          * to do it.
  179          * This res_init() covers NTS too.
  180          */
  181         res_init();
  182 #endif
  183
  184         if (pp->cfg.flags & FLAG_NTS) {
  185 #ifndef DISABLE_NTS
  186                 nts_probe(pp);
  187 #endif
  188         } else {
  189                 ZERO(hints);
  190                 hints.ai_protocol = IPPROTO_UDP;
  191                 hints.ai_socktype = SOCK_DGRAM;
  192                 hints.ai_family = AF(&pp->srcadr);
  193                 gai_rc = getaddrinfo(pp->hostname, NTP_PORTA, &hints, &answer);
  194         }

  $ /usr/lib/uclibc-ng-test/test/inet/tst-res
  Segmentation fault (core dumped)

  $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/uclibc-ng-test-0844445e7358eb10e716155b55b0fb23e88d644a/test/inet/tst-res core
  Core was generated by `/usr/lib/uclibc-ng-test/test/inet/tst-res'.
  Program terminated with signal SIGSEGV, Segmentation fault.
  (gdb) where
  #0  __GI___res_init () at libc/inet/resolv.c:3514
  #1  0x0000005591e507e4 in main (argc=<optimized out>, argv=<optimized out>)
      at tst-res.c:20

Signed-off-by: Peter Seiderer <ps.report@gmx.net>
---
 include/resolv.h   | 2 +-
 libc/inet/resolv.c | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

Comments

Peter Seiderer Nov. 25, 2021, 8:34 p.m. UTC | #1
On Thu, 25 Nov 2021 21:18:25 +0100, Peter Seiderer <ps.report@gmx.net> wrote:

> - use the provided __res_state() method instead of direct access
>   to struct __res_state pointer &_res/*__resp
>
> - change the __UCLIBC_HAS_TLS__ protected __res_state() implementation
>   to the one where the comment 'When threaded, _res may be a per-thread
>   variable.' indicates this should be used with threads/TLS enabled
>
> Fixes the following segfaults with buildroot raspberrypi3_64_defconfig
> (uclibc, -Os, Note: runs fine using the raspberrypi3_defconfig):
>
>   $ /usr/sbin/ntpd -n -d
>   1970-01-01T00:01:49 ntpd[249]: INIT: ntpd ntpsec-1.2.0 2021-11-03T20:39:50Z: Starting
>   1970-01-01T00:01:49 ntpd[249]: INIT: Command line: /usr/sbin/ntpd -n -d
>   1970-01-01T00:01:49 ntpd[249]: INIT: precision = 7.240 usec (-17)
>   1970-01-01T00:01:49 ntpd[249]: INIT: successfully locked into RAM
>   1970-01-01T00:01:49 ntpd[249]: CONFIG: readconfig: parsing file: /etc/ntp.conf
>   1970-01-01T00:01:49 ntpd[249]: CONFIG: restrict nopeer ignored
>   1970-01-01T00:01:49 ntpd[249]: INIT: Using SO_TIMESTAMPNS
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 0 v6wildcard [::]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 1 v4wildcard 0.0.0.0:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 2 lo 127.0.0.1:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 3 eth0 172.16.0.30:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 4 lo [::1]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 5 eth0 [fe80::ba27:ebff:fea6:340%2]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listening on routing socket on fd #22 for interface updates
>   1970-01-01T00:01:50 ntpd[249]: SYNC: Found 10 servers, suggest minsane at least 3
>   1970-01-01T00:01:50 ntpd[249]: INIT: MRU 10922 entries, 13 hash bits, 65536 bytes
>   1970-01-01T00:01:50 ntpd[249]: statistics directory /var/NTP/ does not exist or is unwriteable, error No such file or directory
>   1970-01-01T00:01:51 ntpd[249]: DNS: dns_probe: 0.pool.ntp.org, cast_flags:8, flags:101
>   Segmentation fault (core dumped)
>
>   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/ntpsec-1_2_0/build/main/ntpd/ntpd core
>   Core was generated by `/usr/sbin/ntpd -n -d'.
>   Program terminated with signal SIGSEGV, Segmentation fault.
>   (gdb) where
>   #0  0x0000007f8ff1f150 in res_sync_func () at libc/inet/resolv.c:3356
>   #1  0x0000007f8ff1c468 in __open_nameservers () at libc/inet/resolv.c:949
>   #2  0x0000007f8ff1b498 in __dns_lookup (name=0x55943c67f0 "0.pool.ntp.org",
>       type=1, outpacket=0x7f8fe91c48, a=0x7f8fe91c08) at libc/inet/resolv.c:1134
>   #3  0x0000007f8ff1d744 in __GI_gethostbyname_r (
>       name=0x55943c67f0 "0.pool.ntp.org", result_buf=0x7f8fe92628,
>       buf=0x7f8fe91d90 "", buflen=992, result=0x7f8fe92670,
>       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:1966
>   #4  0x0000007f8ff1d9a0 in __GI_gethostbyname2_r (
>       name=0x55943c67f0 "0.pool.ntp.org", family=2, result_buf=0x7f8fe92628,
>       buf=0x7f8fe91d70 "0.pool.ntp.org", buflen=1024, result=0x7f8fe92670,
>       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:2065
>   #5  0x0000007f8ff16924 in gaih_inet (name=0x55943c67f0 "0.pool.ntp.org",
>       service=0x7f8fe92828, req=0x7f8fe92890, pai=0x7f8fe92838)
>       at libc/inet/getaddrinfo.c:596
>   #6  0x0000007f8ff17624 in __GI_getaddrinfo (
>       name=0x55943c67f0 "0.pool.ntp.org",
>       service=0x5582eb8acd "\377H\213D$\bL\211\367H\213\260\270",
>       hints=0x7f8fe92890, pai=0x5582ee1bf8) at libc/inet/getaddrinfo.c:957
>   #7  0x0000005582ea60f4 in _start ()
>   (gdb) p _res
>   $1 = {options = 0, nsaddr_list = {{sin_family = 0, sin_port = 0, sin_addr = {
>           s_addr = 0}, sin_zero = "\000\000\000\000\000\000\000"}, {
>         sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0},
>         sin_zero = "\000\000\000\000\000\000\000"}, {sin_family = 0,
>         sin_port = 0, sin_addr = {s_addr = 0},
>         sin_zero = "\000\000\000\000\000\000\000"}}, dnsrch = {0x0, 0x0, 0x0,
>       0x0, 0x0, 0x0, 0x0}, nscount = 0 '\000', ndots = 0 '\000',
>     retrans = 0 '\000', retry = 0 '\000', defdname = '\000' <repeats 255 times>,
>     nsort = 0 '\000', pfcode = 0, id = 0, res_h_errno = 0, sort_list = {{addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}}, _u = {
>       _ext = {nsaddrs = {0x0, 0x0, 0x0}, nscount = 0 '\000', nstimes = {0, 0,
>           0}, nssocks = {0, 0, 0}, nscount6 = 0, nsinit = 0}}}
>   (gdb) p &_res
>   $2 = (struct __res_state *) 0x7f8ff8fd98 <_res>
>   (gdb) p rp
>   $3 = (struct __res_state *) 0x7fffffffff
>
>   And the following uclibc code at libc/inet/resolv.c:3356:
>
>   3345 static void res_sync_func(void)
>   3346 {
>   3347         struct __res_state *rp = &(_res);
>   3348         int n;
>   3349
>   3350         /* If we didn't get malloc failure earlier... */
>   3351         if (__nameserver != (void*) &__local_nameserver) {
>   3352                 /* TODO:
>   3353                  * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
>   3354                  */
>   3355 #ifdef __UCLIBC_HAS_IPV6__
>   3356                 if (__nameservers > rp->_u._ext.nscount)
>   3357                         __nameservers = rp->_u._ext.nscount;
>   3358                 n = __nameservers;
>
>   The special thing about ntpsec is the DNS lookup in an extra thread
>   and/or the call to res_init(), see ntpsec-1_2_0/ntpd/ntp_dns.c:
>
>    69         msyslog(LOG_INFO, "DNS: dns_probe: %s, cast_flags:%x, flags:%x%s",
>    70                 hostname, pp->cast_flags, pp->cfg.flags, busy);
>    71         if (NULL != active)     /* normally redundant */
>    72                 return false;
>    73
>    74         active = pp;
>    75
>    76         sigfillset(&block_mask);
>    77         pthread_sigmask(SIG_BLOCK, &block_mask, &saved_sig_mask);
>    78         rc = pthread_create(&worker, NULL, dns_lookup, pp);
>
>   and
>
>   165 static void* dns_lookup(void* arg)
>   166 {
>   167         struct peer *pp = (struct peer *) arg;
>   168         struct addrinfo hints;
>   169
>   170 #ifdef HAVE_SECCOMP_H
>   171         setup_SIGSYS_trap();      /* enable trap for this thread */
>   172 #endif
>   173
>   174 #ifdef HAVE_RES_INIT
>   175         /* Reload DNS servers from /etc/resolv.conf in case DHCP has updated it.
>   176          * We only need to do this occasionally, but it's not expensive
>   177          * and simpler to do it every time than it is to figure out when
>   178          * to do it.
>   179          * This res_init() covers NTS too.
>   180          */
>   181         res_init();
>   182 #endif
>   183
>   184         if (pp->cfg.flags & FLAG_NTS) {
>   185 #ifndef DISABLE_NTS
>   186                 nts_probe(pp);
>   187 #endif
>   188         } else {
>   189                 ZERO(hints);
>   190                 hints.ai_protocol = IPPROTO_UDP;
>   191                 hints.ai_socktype = SOCK_DGRAM;
>   192                 hints.ai_family = AF(&pp->srcadr);
>   193                 gai_rc = getaddrinfo(pp->hostname, NTP_PORTA, &hints, &answer);
>   194         }
>
>   $ /usr/lib/uclibc-ng-test/test/inet/tst-res
>   Segmentation fault (core dumped)
>
>   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/uclibc-ng-test-0844445e7358eb10e716155b55b0fb23e88d644a/test/inet/tst-res core
>   Core was generated by `/usr/lib/uclibc-ng-test/test/inet/tst-res'.
>   Program terminated with signal SIGSEGV, Segmentation fault.
>   (gdb) where
>   #0  __GI___res_init () at libc/inet/resolv.c:3514
>   #1  0x0000005591e507e4 in main (argc=<optimized out>, argv=<optimized out>)
>       at tst-res.c:20
>
> Signed-off-by: Peter Seiderer <ps.report@gmx.net>

Forgot to link to the original buildroot/uclibc-ng error reports:

	https://lore.kernel.org/buildroot/20211028230131.5f50d6e7@gmx.net/
	https://www.mail-archive.com/devel@uclibc-ng.org/msg01085.html

Regards,
Peter

> ---
>  include/resolv.h   | 2 +-
>  libc/inet/resolv.c | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
>
> diff --git a/include/resolv.h b/include/resolv.h
> index 485b8db98..2a82641a4 100644
> --- a/include/resolv.h
> +++ b/include/resolv.h
> @@ -457,7 +457,7 @@ __END_DECLS
>  #    ifndef NOT_IN_libc
>  #     define __resp __libc_resp
>  #    endif
> -#    define _res (*__resp)
> +#    define _res (*__res_state())
>  extern __thread struct __res_state *__resp attribute_tls_model_ie;
>  #   endif
>  #  else
> diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
> index 8bbd7c7cd..cf170fba6 100644
> --- a/libc/inet/resolv.c
> +++ b/libc/inet/resolv.c
> @@ -3344,7 +3344,7 @@ libc_hidden_def(dn_skipname)
>  /* Will be called under __resolv_lock. */
>  static void res_sync_func(void)
>  {
> -	struct __res_state *rp = &(_res);
> +	struct __res_state *rp = __res_state();
>  	int n;
>
>  	/* If we didn't get malloc failure earlier... */
> @@ -3896,7 +3896,7 @@ res_ninit(res_state statp)
>  #endif /* L_res_init */
>
>  #ifdef L_res_state
> -# if defined __UCLIBC_HAS_TLS__
> +# if !defined __UCLIBC_HAS_TLS__
>  struct __res_state *
>  __res_state (void)
>  {
Waldemar Brodkorb Nov. 26, 2021, 2:20 p.m. UTC | #2
Hi Peter,

thanks applied!

best regards
 Waldemar

Peter Seiderer wrote,

> - use the provided __res_state() method instead of direct access
>   to struct __res_state pointer &_res/*__resp
> 
> - change the __UCLIBC_HAS_TLS__ protected __res_state() implementation
>   to the one where the comment 'When threaded, _res may be a per-thread
>   variable.' indicates this should be used with threads/TLS enabled
> 
> Fixes the following segfaults with buildroot raspberrypi3_64_defconfig
> (uclibc, -Os, Note: runs fine using the raspberrypi3_defconfig):
> 
>   $ /usr/sbin/ntpd -n -d
>   1970-01-01T00:01:49 ntpd[249]: INIT: ntpd ntpsec-1.2.0 2021-11-03T20:39:50Z: Starting
>   1970-01-01T00:01:49 ntpd[249]: INIT: Command line: /usr/sbin/ntpd -n -d
>   1970-01-01T00:01:49 ntpd[249]: INIT: precision = 7.240 usec (-17)
>   1970-01-01T00:01:49 ntpd[249]: INIT: successfully locked into RAM
>   1970-01-01T00:01:49 ntpd[249]: CONFIG: readconfig: parsing file: /etc/ntp.conf
>   1970-01-01T00:01:49 ntpd[249]: CONFIG: restrict nopeer ignored
>   1970-01-01T00:01:49 ntpd[249]: INIT: Using SO_TIMESTAMPNS
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 0 v6wildcard [::]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 1 v4wildcard 0.0.0.0:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 2 lo 127.0.0.1:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 3 eth0 172.16.0.30:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 4 lo [::1]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 5 eth0 [fe80::ba27:ebff:fea6:340%2]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listening on routing socket on fd #22 for interface updates
>   1970-01-01T00:01:50 ntpd[249]: SYNC: Found 10 servers, suggest minsane at least 3
>   1970-01-01T00:01:50 ntpd[249]: INIT: MRU 10922 entries, 13 hash bits, 65536 bytes
>   1970-01-01T00:01:50 ntpd[249]: statistics directory /var/NTP/ does not exist or is unwriteable, error No such file or directory
>   1970-01-01T00:01:51 ntpd[249]: DNS: dns_probe: 0.pool.ntp.org, cast_flags:8, flags:101
>   Segmentation fault (core dumped)
> 
>   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/ntpsec-1_2_0/build/main/ntpd/ntpd core
>   Core was generated by `/usr/sbin/ntpd -n -d'.
>   Program terminated with signal SIGSEGV, Segmentation fault.
>   (gdb) where
>   #0  0x0000007f8ff1f150 in res_sync_func () at libc/inet/resolv.c:3356
>   #1  0x0000007f8ff1c468 in __open_nameservers () at libc/inet/resolv.c:949
>   #2  0x0000007f8ff1b498 in __dns_lookup (name=0x55943c67f0 "0.pool.ntp.org",
>       type=1, outpacket=0x7f8fe91c48, a=0x7f8fe91c08) at libc/inet/resolv.c:1134
>   #3  0x0000007f8ff1d744 in __GI_gethostbyname_r (
>       name=0x55943c67f0 "0.pool.ntp.org", result_buf=0x7f8fe92628,
>       buf=0x7f8fe91d90 "", buflen=992, result=0x7f8fe92670,
>       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:1966
>   #4  0x0000007f8ff1d9a0 in __GI_gethostbyname2_r (
>       name=0x55943c67f0 "0.pool.ntp.org", family=2, result_buf=0x7f8fe92628,
>       buf=0x7f8fe91d70 "0.pool.ntp.org", buflen=1024, result=0x7f8fe92670,
>       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:2065
>   #5  0x0000007f8ff16924 in gaih_inet (name=0x55943c67f0 "0.pool.ntp.org",
>       service=0x7f8fe92828, req=0x7f8fe92890, pai=0x7f8fe92838)
>       at libc/inet/getaddrinfo.c:596
>   #6  0x0000007f8ff17624 in __GI_getaddrinfo (
>       name=0x55943c67f0 "0.pool.ntp.org",
>       service=0x5582eb8acd "\377H\213D$\bL\211\367H\213\260\270",
>       hints=0x7f8fe92890, pai=0x5582ee1bf8) at libc/inet/getaddrinfo.c:957
>   #7  0x0000005582ea60f4 in _start ()
>   (gdb) p _res
>   $1 = {options = 0, nsaddr_list = {{sin_family = 0, sin_port = 0, sin_addr = {
>           s_addr = 0}, sin_zero = "\000\000\000\000\000\000\000"}, {
>         sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0},
>         sin_zero = "\000\000\000\000\000\000\000"}, {sin_family = 0,
>         sin_port = 0, sin_addr = {s_addr = 0},
>         sin_zero = "\000\000\000\000\000\000\000"}}, dnsrch = {0x0, 0x0, 0x0,
>       0x0, 0x0, 0x0, 0x0}, nscount = 0 '\000', ndots = 0 '\000',
>     retrans = 0 '\000', retry = 0 '\000', defdname = '\000' <repeats 255 times>,
>     nsort = 0 '\000', pfcode = 0, id = 0, res_h_errno = 0, sort_list = {{addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}}, _u = {
>       _ext = {nsaddrs = {0x0, 0x0, 0x0}, nscount = 0 '\000', nstimes = {0, 0,
>           0}, nssocks = {0, 0, 0}, nscount6 = 0, nsinit = 0}}}
>   (gdb) p &_res
>   $2 = (struct __res_state *) 0x7f8ff8fd98 <_res>
>   (gdb) p rp
>   $3 = (struct __res_state *) 0x7fffffffff
> 
>   And the following uclibc code at libc/inet/resolv.c:3356:
> 
>   3345 static void res_sync_func(void)
>   3346 {
>   3347         struct __res_state *rp = &(_res);
>   3348         int n;
>   3349
>   3350         /* If we didn't get malloc failure earlier... */
>   3351         if (__nameserver != (void*) &__local_nameserver) {
>   3352                 /* TODO:
>   3353                  * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
>   3354                  */
>   3355 #ifdef __UCLIBC_HAS_IPV6__
>   3356                 if (__nameservers > rp->_u._ext.nscount)
>   3357                         __nameservers = rp->_u._ext.nscount;
>   3358                 n = __nameservers;
> 
>   The special thing about ntpsec is the DNS lookup in an extra thread
>   and/or the call to res_init(), see ntpsec-1_2_0/ntpd/ntp_dns.c:
> 
>    69         msyslog(LOG_INFO, "DNS: dns_probe: %s, cast_flags:%x, flags:%x%s",
>    70                 hostname, pp->cast_flags, pp->cfg.flags, busy);
>    71         if (NULL != active)     /* normally redundant */
>    72                 return false;
>    73
>    74         active = pp;
>    75
>    76         sigfillset(&block_mask);
>    77         pthread_sigmask(SIG_BLOCK, &block_mask, &saved_sig_mask);
>    78         rc = pthread_create(&worker, NULL, dns_lookup, pp);
> 
>   and
> 
>   165 static void* dns_lookup(void* arg)
>   166 {
>   167         struct peer *pp = (struct peer *) arg;
>   168         struct addrinfo hints;
>   169
>   170 #ifdef HAVE_SECCOMP_H
>   171         setup_SIGSYS_trap();      /* enable trap for this thread */
>   172 #endif
>   173
>   174 #ifdef HAVE_RES_INIT
>   175         /* Reload DNS servers from /etc/resolv.conf in case DHCP has updated it.
>   176          * We only need to do this occasionally, but it's not expensive
>   177          * and simpler to do it every time than it is to figure out when
>   178          * to do it.
>   179          * This res_init() covers NTS too.
>   180          */
>   181         res_init();
>   182 #endif
>   183
>   184         if (pp->cfg.flags & FLAG_NTS) {
>   185 #ifndef DISABLE_NTS
>   186                 nts_probe(pp);
>   187 #endif
>   188         } else {
>   189                 ZERO(hints);
>   190                 hints.ai_protocol = IPPROTO_UDP;
>   191                 hints.ai_socktype = SOCK_DGRAM;
>   192                 hints.ai_family = AF(&pp->srcadr);
>   193                 gai_rc = getaddrinfo(pp->hostname, NTP_PORTA, &hints, &answer);
>   194         }
> 
>   $ /usr/lib/uclibc-ng-test/test/inet/tst-res
>   Segmentation fault (core dumped)
> 
>   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/uclibc-ng-test-0844445e7358eb10e716155b55b0fb23e88d644a/test/inet/tst-res core
>   Core was generated by `/usr/lib/uclibc-ng-test/test/inet/tst-res'.
>   Program terminated with signal SIGSEGV, Segmentation fault.
>   (gdb) where
>   #0  __GI___res_init () at libc/inet/resolv.c:3514
>   #1  0x0000005591e507e4 in main (argc=<optimized out>, argv=<optimized out>)
>       at tst-res.c:20
> 
> Signed-off-by: Peter Seiderer <ps.report@gmx.net>
> ---
>  include/resolv.h   | 2 +-
>  libc/inet/resolv.c | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/include/resolv.h b/include/resolv.h
> index 485b8db98..2a82641a4 100644
> --- a/include/resolv.h
> +++ b/include/resolv.h
> @@ -457,7 +457,7 @@ __END_DECLS
>  #    ifndef NOT_IN_libc
>  #     define __resp __libc_resp
>  #    endif
> -#    define _res (*__resp)
> +#    define _res (*__res_state())
>  extern __thread struct __res_state *__resp attribute_tls_model_ie;
>  #   endif
>  #  else
> diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
> index 8bbd7c7cd..cf170fba6 100644
> --- a/libc/inet/resolv.c
> +++ b/libc/inet/resolv.c
> @@ -3344,7 +3344,7 @@ libc_hidden_def(dn_skipname)
>  /* Will be called under __resolv_lock. */
>  static void res_sync_func(void)
>  {
> -	struct __res_state *rp = &(_res);
> +	struct __res_state *rp = __res_state();
>  	int n;
>  
>  	/* If we didn't get malloc failure earlier... */
> @@ -3896,7 +3896,7 @@ res_ninit(res_state statp)
>  #endif /* L_res_init */
>  
>  #ifdef L_res_state
> -# if defined __UCLIBC_HAS_TLS__
> +# if !defined __UCLIBC_HAS_TLS__
>  struct __res_state *
>  __res_state (void)
>  {
> -- 
> 2.33.1
> 
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
>
Waldemar Brodkorb Jan. 21, 2022, 10:04 a.m. UTC | #3
Hi Peter,

sorry about coming so late up with a regression.

I get following failure when compiling the defconfig stm32f429_disco_xip_defconfig in buildroot with your patch:

In file included from libc/inet/_res_state.c:8:
libc/inet/resolv.c: In function '__res_state':
libc/inet/resolv.c:3903:15: error: '__resp' undeclared (first use in this function); did you mean '_res'?
 3903 |        return __resp;
      |               ^~~~~~
      |               _res
libc/inet/resolv.c:3903:15: note: each undeclared identifier is reported only once for each function it appears in
libc/inet/resolv.c:3904:1: warning: control reaches end of non-void function [-Wreturn-type]
 3904 | }
      | ^
make[1]: *** [Makerules:368: libc/inet/_res_state.o] Error 1
make[1]: Leaving directory '/home/wbx/buildroot/output/build/uclibc-1.0.39'
make: *** [package/pkg-generic.mk:295: /home/wbx/buildroot/output/build/uclibc-1.0.39/.stamp_built] Error 2

In this case Linuxthreads are used, because the target is noMMU and FLAT binary format. 

Any idea?

best regards
 Waldemar

Peter Seiderer wrote,

> - use the provided __res_state() method instead of direct access
>   to struct __res_state pointer &_res/*__resp
> 
> - change the __UCLIBC_HAS_TLS__ protected __res_state() implementation
>   to the one where the comment 'When threaded, _res may be a per-thread
>   variable.' indicates this should be used with threads/TLS enabled
> 
> Fixes the following segfaults with buildroot raspberrypi3_64_defconfig
> (uclibc, -Os, Note: runs fine using the raspberrypi3_defconfig):
> 
>   $ /usr/sbin/ntpd -n -d
>   1970-01-01T00:01:49 ntpd[249]: INIT: ntpd ntpsec-1.2.0 2021-11-03T20:39:50Z: Starting
>   1970-01-01T00:01:49 ntpd[249]: INIT: Command line: /usr/sbin/ntpd -n -d
>   1970-01-01T00:01:49 ntpd[249]: INIT: precision = 7.240 usec (-17)
>   1970-01-01T00:01:49 ntpd[249]: INIT: successfully locked into RAM
>   1970-01-01T00:01:49 ntpd[249]: CONFIG: readconfig: parsing file: /etc/ntp.conf
>   1970-01-01T00:01:49 ntpd[249]: CONFIG: restrict nopeer ignored
>   1970-01-01T00:01:49 ntpd[249]: INIT: Using SO_TIMESTAMPNS
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 0 v6wildcard [::]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 1 v4wildcard 0.0.0.0:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 2 lo 127.0.0.1:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 3 eth0 172.16.0.30:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 4 lo [::1]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 5 eth0 [fe80::ba27:ebff:fea6:340%2]:123
>   1970-01-01T00:01:49 ntpd[249]: IO: Listening on routing socket on fd #22 for interface updates
>   1970-01-01T00:01:50 ntpd[249]: SYNC: Found 10 servers, suggest minsane at least 3
>   1970-01-01T00:01:50 ntpd[249]: INIT: MRU 10922 entries, 13 hash bits, 65536 bytes
>   1970-01-01T00:01:50 ntpd[249]: statistics directory /var/NTP/ does not exist or is unwriteable, error No such file or directory
>   1970-01-01T00:01:51 ntpd[249]: DNS: dns_probe: 0.pool.ntp.org, cast_flags:8, flags:101
>   Segmentation fault (core dumped)
> 
>   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/ntpsec-1_2_0/build/main/ntpd/ntpd core
>   Core was generated by `/usr/sbin/ntpd -n -d'.
>   Program terminated with signal SIGSEGV, Segmentation fault.
>   (gdb) where
>   #0  0x0000007f8ff1f150 in res_sync_func () at libc/inet/resolv.c:3356
>   #1  0x0000007f8ff1c468 in __open_nameservers () at libc/inet/resolv.c:949
>   #2  0x0000007f8ff1b498 in __dns_lookup (name=0x55943c67f0 "0.pool.ntp.org",
>       type=1, outpacket=0x7f8fe91c48, a=0x7f8fe91c08) at libc/inet/resolv.c:1134
>   #3  0x0000007f8ff1d744 in __GI_gethostbyname_r (
>       name=0x55943c67f0 "0.pool.ntp.org", result_buf=0x7f8fe92628,
>       buf=0x7f8fe91d90 "", buflen=992, result=0x7f8fe92670,
>       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:1966
>   #4  0x0000007f8ff1d9a0 in __GI_gethostbyname2_r (
>       name=0x55943c67f0 "0.pool.ntp.org", family=2, result_buf=0x7f8fe92628,
>       buf=0x7f8fe91d70 "0.pool.ntp.org", buflen=1024, result=0x7f8fe92670,
>       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:2065
>   #5  0x0000007f8ff16924 in gaih_inet (name=0x55943c67f0 "0.pool.ntp.org",
>       service=0x7f8fe92828, req=0x7f8fe92890, pai=0x7f8fe92838)
>       at libc/inet/getaddrinfo.c:596
>   #6  0x0000007f8ff17624 in __GI_getaddrinfo (
>       name=0x55943c67f0 "0.pool.ntp.org",
>       service=0x5582eb8acd "\377H\213D$\bL\211\367H\213\260\270",
>       hints=0x7f8fe92890, pai=0x5582ee1bf8) at libc/inet/getaddrinfo.c:957
>   #7  0x0000005582ea60f4 in _start ()
>   (gdb) p _res
>   $1 = {options = 0, nsaddr_list = {{sin_family = 0, sin_port = 0, sin_addr = {
>           s_addr = 0}, sin_zero = "\000\000\000\000\000\000\000"}, {
>         sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0},
>         sin_zero = "\000\000\000\000\000\000\000"}, {sin_family = 0,
>         sin_port = 0, sin_addr = {s_addr = 0},
>         sin_zero = "\000\000\000\000\000\000\000"}}, dnsrch = {0x0, 0x0, 0x0,
>       0x0, 0x0, 0x0, 0x0}, nscount = 0 '\000', ndots = 0 '\000',
>     retrans = 0 '\000', retry = 0 '\000', defdname = '\000' <repeats 255 times>,
>     nsort = 0 '\000', pfcode = 0, id = 0, res_h_errno = 0, sort_list = {{addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
>           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}}, _u = {
>       _ext = {nsaddrs = {0x0, 0x0, 0x0}, nscount = 0 '\000', nstimes = {0, 0,
>           0}, nssocks = {0, 0, 0}, nscount6 = 0, nsinit = 0}}}
>   (gdb) p &_res
>   $2 = (struct __res_state *) 0x7f8ff8fd98 <_res>
>   (gdb) p rp
>   $3 = (struct __res_state *) 0x7fffffffff
> 
>   And the following uclibc code at libc/inet/resolv.c:3356:
> 
>   3345 static void res_sync_func(void)
>   3346 {
>   3347         struct __res_state *rp = &(_res);
>   3348         int n;
>   3349
>   3350         /* If we didn't get malloc failure earlier... */
>   3351         if (__nameserver != (void*) &__local_nameserver) {
>   3352                 /* TODO:
>   3353                  * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
>   3354                  */
>   3355 #ifdef __UCLIBC_HAS_IPV6__
>   3356                 if (__nameservers > rp->_u._ext.nscount)
>   3357                         __nameservers = rp->_u._ext.nscount;
>   3358                 n = __nameservers;
> 
>   The special thing about ntpsec is the DNS lookup in an extra thread
>   and/or the call to res_init(), see ntpsec-1_2_0/ntpd/ntp_dns.c:
> 
>    69         msyslog(LOG_INFO, "DNS: dns_probe: %s, cast_flags:%x, flags:%x%s",
>    70                 hostname, pp->cast_flags, pp->cfg.flags, busy);
>    71         if (NULL != active)     /* normally redundant */
>    72                 return false;
>    73
>    74         active = pp;
>    75
>    76         sigfillset(&block_mask);
>    77         pthread_sigmask(SIG_BLOCK, &block_mask, &saved_sig_mask);
>    78         rc = pthread_create(&worker, NULL, dns_lookup, pp);
> 
>   and
> 
>   165 static void* dns_lookup(void* arg)
>   166 {
>   167         struct peer *pp = (struct peer *) arg;
>   168         struct addrinfo hints;
>   169
>   170 #ifdef HAVE_SECCOMP_H
>   171         setup_SIGSYS_trap();      /* enable trap for this thread */
>   172 #endif
>   173
>   174 #ifdef HAVE_RES_INIT
>   175         /* Reload DNS servers from /etc/resolv.conf in case DHCP has updated it.
>   176          * We only need to do this occasionally, but it's not expensive
>   177          * and simpler to do it every time than it is to figure out when
>   178          * to do it.
>   179          * This res_init() covers NTS too.
>   180          */
>   181         res_init();
>   182 #endif
>   183
>   184         if (pp->cfg.flags & FLAG_NTS) {
>   185 #ifndef DISABLE_NTS
>   186                 nts_probe(pp);
>   187 #endif
>   188         } else {
>   189                 ZERO(hints);
>   190                 hints.ai_protocol = IPPROTO_UDP;
>   191                 hints.ai_socktype = SOCK_DGRAM;
>   192                 hints.ai_family = AF(&pp->srcadr);
>   193                 gai_rc = getaddrinfo(pp->hostname, NTP_PORTA, &hints, &answer);
>   194         }
> 
>   $ /usr/lib/uclibc-ng-test/test/inet/tst-res
>   Segmentation fault (core dumped)
> 
>   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/uclibc-ng-test-0844445e7358eb10e716155b55b0fb23e88d644a/test/inet/tst-res core
>   Core was generated by `/usr/lib/uclibc-ng-test/test/inet/tst-res'.
>   Program terminated with signal SIGSEGV, Segmentation fault.
>   (gdb) where
>   #0  __GI___res_init () at libc/inet/resolv.c:3514
>   #1  0x0000005591e507e4 in main (argc=<optimized out>, argv=<optimized out>)
>       at tst-res.c:20
> 
> Signed-off-by: Peter Seiderer <ps.report@gmx.net>
> ---
>  include/resolv.h   | 2 +-
>  libc/inet/resolv.c | 4 ++--
>  2 files changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/include/resolv.h b/include/resolv.h
> index 485b8db98..2a82641a4 100644
> --- a/include/resolv.h
> +++ b/include/resolv.h
> @@ -457,7 +457,7 @@ __END_DECLS
>  #    ifndef NOT_IN_libc
>  #     define __resp __libc_resp
>  #    endif
> -#    define _res (*__resp)
> +#    define _res (*__res_state())
>  extern __thread struct __res_state *__resp attribute_tls_model_ie;
>  #   endif
>  #  else
> diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
> index 8bbd7c7cd..cf170fba6 100644
> --- a/libc/inet/resolv.c
> +++ b/libc/inet/resolv.c
> @@ -3344,7 +3344,7 @@ libc_hidden_def(dn_skipname)
>  /* Will be called under __resolv_lock. */
>  static void res_sync_func(void)
>  {
> -	struct __res_state *rp = &(_res);
> +	struct __res_state *rp = __res_state();
>  	int n;
>  
>  	/* If we didn't get malloc failure earlier... */
> @@ -3896,7 +3896,7 @@ res_ninit(res_state statp)
>  #endif /* L_res_init */
>  
>  #ifdef L_res_state
> -# if defined __UCLIBC_HAS_TLS__
> +# if !defined __UCLIBC_HAS_TLS__
>  struct __res_state *
>  __res_state (void)
>  {
> -- 
> 2.33.1
> 
> _______________________________________________
> devel mailing list -- devel@uclibc-ng.org
> To unsubscribe send an email to devel-leave@uclibc-ng.org
>
Peter Seiderer Jan. 21, 2022, 10:54 a.m. UTC | #4
Hello Waldemar,

On Fri, 21 Jan 2022 11:04:57 +0100, Waldemar Brodkorb <wbx@uclibc-ng.org> wrote:

> Hi Peter,
>
> sorry about coming so late up with a regression.

No problem...

>
> I get following failure when compiling the defconfig stm32f429_disco_xip_defconfig in buildroot with your patch:
>
> In file included from libc/inet/_res_state.c:8:
> libc/inet/resolv.c: In function '__res_state':
> libc/inet/resolv.c:3903:15: error: '__resp' undeclared (first use in this function); did you mean '_res'?
>  3903 |        return __resp;
>       |               ^~~~~~
>       |               _res
> libc/inet/resolv.c:3903:15: note: each undeclared identifier is reported only once for each function it appears in
> libc/inet/resolv.c:3904:1: warning: control reaches end of non-void function [-Wreturn-type]
>  3904 | }
>       | ^
> make[1]: *** [Makerules:368: libc/inet/_res_state.o] Error 1
> make[1]: Leaving directory '/home/wbx/buildroot/output/build/uclibc-1.0.39'
> make: *** [package/pkg-generic.mk:295: /home/wbx/buildroot/output/build/uclibc-1.0.39/.stamp_built] Error 2
>
> In this case Linuxthreads are used, because the target is noMMU and FLAT binary format.
>
> Any idea?

No...not yet, but will take a look at it ;-)

Regards,
Peter

>
> best regards
>  Waldemar
>
> Peter Seiderer wrote,
>
> > - use the provided __res_state() method instead of direct access
> >   to struct __res_state pointer &_res/*__resp
> >
> > - change the __UCLIBC_HAS_TLS__ protected __res_state() implementation
> >   to the one where the comment 'When threaded, _res may be a per-thread
> >   variable.' indicates this should be used with threads/TLS enabled
> >
> > Fixes the following segfaults with buildroot raspberrypi3_64_defconfig
> > (uclibc, -Os, Note: runs fine using the raspberrypi3_defconfig):
> >
> >   $ /usr/sbin/ntpd -n -d
> >   1970-01-01T00:01:49 ntpd[249]: INIT: ntpd ntpsec-1.2.0 2021-11-03T20:39:50Z: Starting
> >   1970-01-01T00:01:49 ntpd[249]: INIT: Command line: /usr/sbin/ntpd -n -d
> >   1970-01-01T00:01:49 ntpd[249]: INIT: precision = 7.240 usec (-17)
> >   1970-01-01T00:01:49 ntpd[249]: INIT: successfully locked into RAM
> >   1970-01-01T00:01:49 ntpd[249]: CONFIG: readconfig: parsing file: /etc/ntp.conf
> >   1970-01-01T00:01:49 ntpd[249]: CONFIG: restrict nopeer ignored
> >   1970-01-01T00:01:49 ntpd[249]: INIT: Using SO_TIMESTAMPNS
> >   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 0 v6wildcard [::]:123
> >   1970-01-01T00:01:49 ntpd[249]: IO: Listen and drop on 1 v4wildcard 0.0.0.0:123
> >   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 2 lo 127.0.0.1:123
> >   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 3 eth0 172.16.0.30:123
> >   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 4 lo [::1]:123
> >   1970-01-01T00:01:49 ntpd[249]: IO: Listen normally on 5 eth0 [fe80::ba27:ebff:fea6:340%2]:123
> >   1970-01-01T00:01:49 ntpd[249]: IO: Listening on routing socket on fd #22 for interface updates
> >   1970-01-01T00:01:50 ntpd[249]: SYNC: Found 10 servers, suggest minsane at least 3
> >   1970-01-01T00:01:50 ntpd[249]: INIT: MRU 10922 entries, 13 hash bits, 65536 bytes
> >   1970-01-01T00:01:50 ntpd[249]: statistics directory /var/NTP/ does not exist or is unwriteable, error No such file or directory
> >   1970-01-01T00:01:51 ntpd[249]: DNS: dns_probe: 0.pool.ntp.org, cast_flags:8, flags:101
> >   Segmentation fault (core dumped)
> >
> >   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/ntpsec-1_2_0/build/main/ntpd/ntpd core
> >   Core was generated by `/usr/sbin/ntpd -n -d'.
> >   Program terminated with signal SIGSEGV, Segmentation fault.
> >   (gdb) where
> >   #0  0x0000007f8ff1f150 in res_sync_func () at libc/inet/resolv.c:3356
> >   #1  0x0000007f8ff1c468 in __open_nameservers () at libc/inet/resolv.c:949
> >   #2  0x0000007f8ff1b498 in __dns_lookup (name=0x55943c67f0 "0.pool.ntp.org",
> >       type=1, outpacket=0x7f8fe91c48, a=0x7f8fe91c08) at libc/inet/resolv.c:1134
> >   #3  0x0000007f8ff1d744 in __GI_gethostbyname_r (
> >       name=0x55943c67f0 "0.pool.ntp.org", result_buf=0x7f8fe92628,
> >       buf=0x7f8fe91d90 "", buflen=992, result=0x7f8fe92670,
> >       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:1966
> >   #4  0x0000007f8ff1d9a0 in __GI_gethostbyname2_r (
> >       name=0x55943c67f0 "0.pool.ntp.org", family=2, result_buf=0x7f8fe92628,
> >       buf=0x7f8fe91d70 "0.pool.ntp.org", buflen=1024, result=0x7f8fe92670,
> >       h_errnop=0x7f8fe92668) at libc/inet/resolv.c:2065
> >   #5  0x0000007f8ff16924 in gaih_inet (name=0x55943c67f0 "0.pool.ntp.org",
> >       service=0x7f8fe92828, req=0x7f8fe92890, pai=0x7f8fe92838)
> >       at libc/inet/getaddrinfo.c:596
> >   #6  0x0000007f8ff17624 in __GI_getaddrinfo (
> >       name=0x55943c67f0 "0.pool.ntp.org",
> >       service=0x5582eb8acd "\377H\213D$\bL\211\367H\213\260\270",
> >       hints=0x7f8fe92890, pai=0x5582ee1bf8) at libc/inet/getaddrinfo.c:957
> >   #7  0x0000005582ea60f4 in _start ()
> >   (gdb) p _res
> >   $1 = {options = 0, nsaddr_list = {{sin_family = 0, sin_port = 0, sin_addr = {
> >           s_addr = 0}, sin_zero = "\000\000\000\000\000\000\000"}, {
> >         sin_family = 0, sin_port = 0, sin_addr = {s_addr = 0},
> >         sin_zero = "\000\000\000\000\000\000\000"}, {sin_family = 0,
> >         sin_port = 0, sin_addr = {s_addr = 0},
> >         sin_zero = "\000\000\000\000\000\000\000"}}, dnsrch = {0x0, 0x0, 0x0,
> >       0x0, 0x0, 0x0, 0x0}, nscount = 0 '\000', ndots = 0 '\000',
> >     retrans = 0 '\000', retry = 0 '\000', defdname = '\000' <repeats 255 times>,
> >     nsort = 0 '\000', pfcode = 0, id = 0, res_h_errno = 0, sort_list = {{addr = {
> >           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
> >           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
> >           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
> >           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}, {addr = {
> >           s_addr = 0}, mask = 0}, {addr = {s_addr = 0}, mask = 0}}, _u = {
> >       _ext = {nsaddrs = {0x0, 0x0, 0x0}, nscount = 0 '\000', nstimes = {0, 0,
> >           0}, nssocks = {0, 0, 0}, nscount6 = 0, nsinit = 0}}}
> >   (gdb) p &_res
> >   $2 = (struct __res_state *) 0x7f8ff8fd98 <_res>
> >   (gdb) p rp
> >   $3 = (struct __res_state *) 0x7fffffffff
> >
> >   And the following uclibc code at libc/inet/resolv.c:3356:
> >
> >   3345 static void res_sync_func(void)
> >   3346 {
> >   3347         struct __res_state *rp = &(_res);
> >   3348         int n;
> >   3349
> >   3350         /* If we didn't get malloc failure earlier... */
> >   3351         if (__nameserver != (void*) &__local_nameserver) {
> >   3352                 /* TODO:
> >   3353                  * if (__nameservers < rp->nscount) - try to grow __nameserver[]?
> >   3354                  */
> >   3355 #ifdef __UCLIBC_HAS_IPV6__
> >   3356                 if (__nameservers > rp->_u._ext.nscount)
> >   3357                         __nameservers = rp->_u._ext.nscount;
> >   3358                 n = __nameservers;
> >
> >   The special thing about ntpsec is the DNS lookup in an extra thread
> >   and/or the call to res_init(), see ntpsec-1_2_0/ntpd/ntp_dns.c:
> >
> >    69         msyslog(LOG_INFO, "DNS: dns_probe: %s, cast_flags:%x, flags:%x%s",
> >    70                 hostname, pp->cast_flags, pp->cfg.flags, busy);
> >    71         if (NULL != active)     /* normally redundant */
> >    72                 return false;
> >    73
> >    74         active = pp;
> >    75
> >    76         sigfillset(&block_mask);
> >    77         pthread_sigmask(SIG_BLOCK, &block_mask, &saved_sig_mask);
> >    78         rc = pthread_create(&worker, NULL, dns_lookup, pp);
> >
> >   and
> >
> >   165 static void* dns_lookup(void* arg)
> >   166 {
> >   167         struct peer *pp = (struct peer *) arg;
> >   168         struct addrinfo hints;
> >   169
> >   170 #ifdef HAVE_SECCOMP_H
> >   171         setup_SIGSYS_trap();      /* enable trap for this thread */
> >   172 #endif
> >   173
> >   174 #ifdef HAVE_RES_INIT
> >   175         /* Reload DNS servers from /etc/resolv.conf in case DHCP has updated it.
> >   176          * We only need to do this occasionally, but it's not expensive
> >   177          * and simpler to do it every time than it is to figure out when
> >   178          * to do it.
> >   179          * This res_init() covers NTS too.
> >   180          */
> >   181         res_init();
> >   182 #endif
> >   183
> >   184         if (pp->cfg.flags & FLAG_NTS) {
> >   185 #ifndef DISABLE_NTS
> >   186                 nts_probe(pp);
> >   187 #endif
> >   188         } else {
> >   189                 ZERO(hints);
> >   190                 hints.ai_protocol = IPPROTO_UDP;
> >   191                 hints.ai_socktype = SOCK_DGRAM;
> >   192                 hints.ai_family = AF(&pp->srcadr);
> >   193                 gai_rc = getaddrinfo(pp->hostname, NTP_PORTA, &hints, &answer);
> >   194         }
> >
> >   $ /usr/lib/uclibc-ng-test/test/inet/tst-res
> >   Segmentation fault (core dumped)
> >
> >   $ ./host/bin/aarch64-buildroot-linux-uclibc-gdb ./build/uclibc-ng-test-0844445e7358eb10e716155b55b0fb23e88d644a/test/inet/tst-res core
> >   Core was generated by `/usr/lib/uclibc-ng-test/test/inet/tst-res'.
> >   Program terminated with signal SIGSEGV, Segmentation fault.
> >   (gdb) where
> >   #0  __GI___res_init () at libc/inet/resolv.c:3514
> >   #1  0x0000005591e507e4 in main (argc=<optimized out>, argv=<optimized out>)
> >       at tst-res.c:20
> >
> > Signed-off-by: Peter Seiderer <ps.report@gmx.net>
> > ---
> >  include/resolv.h   | 2 +-
> >  libc/inet/resolv.c | 4 ++--
> >  2 files changed, 3 insertions(+), 3 deletions(-)
> >
> > diff --git a/include/resolv.h b/include/resolv.h
> > index 485b8db98..2a82641a4 100644
> > --- a/include/resolv.h
> > +++ b/include/resolv.h
> > @@ -457,7 +457,7 @@ __END_DECLS
> >  #    ifndef NOT_IN_libc
> >  #     define __resp __libc_resp
> >  #    endif
> > -#    define _res (*__resp)
> > +#    define _res (*__res_state())
> >  extern __thread struct __res_state *__resp attribute_tls_model_ie;
> >  #   endif
> >  #  else
> > diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
> > index 8bbd7c7cd..cf170fba6 100644
> > --- a/libc/inet/resolv.c
> > +++ b/libc/inet/resolv.c
> > @@ -3344,7 +3344,7 @@ libc_hidden_def(dn_skipname)
> >  /* Will be called under __resolv_lock. */
> >  static void res_sync_func(void)
> >  {
> > -	struct __res_state *rp = &(_res);
> > +	struct __res_state *rp = __res_state();
> >  	int n;
> >
> >  	/* If we didn't get malloc failure earlier... */
> > @@ -3896,7 +3896,7 @@ res_ninit(res_state statp)
> >  #endif /* L_res_init */
> >
> >  #ifdef L_res_state
> > -# if defined __UCLIBC_HAS_TLS__
> > +# if !defined __UCLIBC_HAS_TLS__
> >  struct __res_state *
> >  __res_state (void)
> >  {
> > --
> > 2.33.1
> >
> > _______________________________________________
> > devel mailing list -- devel@uclibc-ng.org
> > To unsubscribe send an email to devel-leave@uclibc-ng.org
> >
diff mbox series

Patch

diff --git a/include/resolv.h b/include/resolv.h
index 485b8db98..2a82641a4 100644
--- a/include/resolv.h
+++ b/include/resolv.h
@@ -457,7 +457,7 @@  __END_DECLS
 #    ifndef NOT_IN_libc
 #     define __resp __libc_resp
 #    endif
-#    define _res (*__resp)
+#    define _res (*__res_state())
 extern __thread struct __res_state *__resp attribute_tls_model_ie;
 #   endif
 #  else
diff --git a/libc/inet/resolv.c b/libc/inet/resolv.c
index 8bbd7c7cd..cf170fba6 100644
--- a/libc/inet/resolv.c
+++ b/libc/inet/resolv.c
@@ -3344,7 +3344,7 @@  libc_hidden_def(dn_skipname)
 /* Will be called under __resolv_lock. */
 static void res_sync_func(void)
 {
-	struct __res_state *rp = &(_res);
+	struct __res_state *rp = __res_state();
 	int n;
 
 	/* If we didn't get malloc failure earlier... */
@@ -3896,7 +3896,7 @@  res_ninit(res_state statp)
 #endif /* L_res_init */
 
 #ifdef L_res_state
-# if defined __UCLIBC_HAS_TLS__
+# if !defined __UCLIBC_HAS_TLS__
 struct __res_state *
 __res_state (void)
 {