Dirmngr - high cpu usage - 100%

NIIBE Yutaka gniibe at fsij.org
Thu Apr 3 03:23:27 CEST 2025


Hello,

Lukas | GPGTools wrote:
> dirmngr of a self-compiled version of gnupg 2.4.7 on macOS 15.4 shows a constantly cpu usage of 99-100%.
> From the spindump (attached) it appears that the problem is somehow related to DNS `dns_res_check` for example.
> The same behavior could not be observed with gnupg 2.2.x.
>
> What is the best way to debug what is going wrong?

I don't know how to debug on macOS, so, I describe about the symptom and
the code.

IIUC, the issue is in/around dirmngr/dns.c (USE_LIBDNS option at compile
time), which does name resolving directly to DNS.

I think that it is an option for macOS not to use this code.  I'd
recomment simply using the standard system name resolver, by no
USE_LIBDNS option at compile time, or dirmngr runtime option of
--standard-resolver.

I checked the commit log of dirmngr/dns.c, but I can't find any
meaningful changes between gnupg 2.2.x and gnupg 2.4.7 for this kind of
problem.


That's being said, I think that direct problems are the default
behavior of dirmngr/dns.c:

 - default configuration reading /etc/resolv.conf, /etc/nsswitch.conf
 - default dns server (INADDR_ANY -> INADDR_LOOPBACK)
 - handling an error of connect(2)

That is, the buggy behavior would be: when no /etc/resolv.conf, DNS
server 0.0.0.0 -> 127.0.0.1 then, if no nameserver running on the
machine, it loops forever calling connect(2).

The code in question (for me) is the following:

==========================
diff --git a/dirmngr/dns.c b/dirmngr/dns.c
index e0eb33244..129502ce7 100644
--- a/dirmngr/dns.c
+++ b/dirmngr/dns.c
@@ -7749,6 +7749,10 @@ retry:
 		error = dns_connect(so->udp, (struct sockaddr *)&so->remote, dns_sa_len(&so->remote));
 		dns_trace_sys_connect(so->trace, so->udp, SOCK_DGRAM, (struct sockaddr *)&so->remote, error);
 
+#if 0
+/* This code is questionable; It seemed that it was based on OS
+   specific old behavior (not relevant these days) and/or confusion
+   reading man pages of irrelevant section.  */
 		/* Linux returns EINVAL when address was bound to
 		   localhost and it's external IP address now.  */
 		if (error == EINVAL) {
@@ -7761,6 +7765,7 @@ retry:
 			/* Error for previous socket operation may
 			   be reserved(?) asynchronously. */
 			goto udp_connect_retry;
+#endif
 
 		if (error)
 			goto error;
==========================

The description of ECONNREFUSED can be found in the udp(7) page (for
socket(2)) for Linux kernel.  But it's not for connect(2).

ECONNREFUSED can be returned by connect(2) on POSIX system.  Retrying
(by goto udp_connect_retry) is wrong in the code.
-- 



More information about the Gnupg-devel mailing list