ILD

dnsmasq僵尸进程分析
作者:Yuan Jianpeng 邮箱:yuanjp89@163.com
发布时间:2023-9-5 站点:Inside Linux Development

Xrouter平台运行过程中,出现很多dnsmasq的僵尸进程:

# ps w

  191 root      0:00 udhcpc -i eth0 -p /run/net/udhcpc.eth0.pid -s /lib/network

  192 nobody    0:00 dnsmasq -k -C /etc/dnsmasq.conf -C /run/net/dnsmasq.conf -

  196 root      0:17 hostapd -i ap2g /run/net/hostapd-ap2g.conf

  202 root      0:26 hostapd -i ap5g /run/net/hostapd-ap5g.conf

  208 root      0:00 udhcpc6 -i eth0 -p /run/net/udhcpc6.eth0.pid -s /lib/netwo

  234 nobody    0:00 [dnsmasq]

  235 nobody    0:00 [dnsmasq]

  236 nobody    0:00 [dnsmasq]

  239 nobody    0:00 [dnsmasq]

  240 nobody    0:00 [dnsmasq]

  241 nobody    0:00 [dnsmasq]

  242 nobody    0:00 [dnsmasq]

  243 nobody    0:00 [dnsmasq]

  244 nobody    0:00 [dnsmasq]

  245 nobody    0:00 [dnsmasq]

  246 nobody    0:00 [dnsmasq]

  247 nobody    0:00 [dnsmasq]

  248 nobody    0:00 [dnsmasq]


使用procmon工具查看,确实是dnsmasq fork出来的。查看dnsmasq的源码,发现是注册SIGCHLD信号处理函数,在信号处理函数中,给主进程写事件,主进程收到事件后,使用waitpid回收。


经过一番分析后,发现SIGCHLD被block了:

# cat /proc/192/status

SigPnd: 0000000000000000

ShdPnd: 0000000000010000

SigBlk: 0000000000010000

SigIgn: 0000000000001000

SigCgt: 0000000000016a03


可以看到SigBlk,17号信号被block了。

$ kill -l

 1) SIGHUP       2) SIGINT       3) SIGQUIT      4) SIGILL       5) SIGTRAP

 6) SIGABRT      7) SIGBUS       8) SIGFPE       9) SIGKILL     10) SIGUSR1

11) SIGSEGV     12) SIGUSR2     13) SIGPIPE     14) SIGALRM     15) SIGTERM

16) SIGSTKFLT   17) SIGCHLD     18) SIGCONT     19) SIGSTOP     20) SIGTSTP

21) SIGTTIN     22) SIGTTOU     23) SIGURG      24) SIGXCPU     25) SIGXFSZ

26) SIGVTALRM   27) SIGPROF     28) SIGWINCH    29) SIGIO       30) SIGPWR

31) SIGSYS 


继续追踪发现,是event库使用signalfd接收sigchld事件,主动把sigchld给block了。dnsmasq从父亲继承了这个block。

修改如下:

diff --git a/app/platform/libbase/event.c b/app/platform/libbase/event.c

index 0587dce..6e536d9 100644

--- a/app/platform/libbase/event.c

+++ b/app/platform/libbase/event.c

@@ -28,7 +28,10 @@ static int create_signalfd()


        sigemptyset(&sigmask);

        sigaddset(&sigmask, SIGCHLD);

-       sigprocmask(SIG_BLOCK, &sigmask, NULL);

+

+       // don't block SIGCHLD

+       // or child process may not wait child (zoombie proc)

+       // sigprocmask(SIG_BLOCK, &sigmask, NULL);


        return signalfd(-1, &sigmask, SFD_NONBLOCK);

 }


参考

How to read bitmask for the signals

https://access.redhat.com/solutions/3478631


Copyright © linuxdev.cc 2017-2024. Some Rights Reserved.