我最近遇到一个问题,我的 sshd 反复死机,我做了以下检查。
从
/var/log/message
,我可以看到 sshd 不断重新启动Apr 23 12:05:39 host1 systemd: Stopping OpenSSH server daemon... Apr 23 12:05:39 host1 systemd: Stopped OpenSSH server daemon. Apr 23 12:05:39 host1 systemd: Starting OpenSSH server daemon... Apr 23 12:05:39 host1 systemd: Started OpenSSH server daemon.
从
/var/log/secure
,我发现sshd有时会收到singal 15Apr 23 11:32:52 host1 sshd[105049]: Received signal 15; terminating. Apr 23 11:32:52 host1 sshd[111278]: Server listening on 0.0.0.0 port 36000. Apr 23 11:32:52 host1 sshd[111278]: Received signal 15; terminating. Apr 23 11:32:52 host1 sshd[111306]: Server listening on 0.0.0.0 port 36000.
我查了一下
sshd -t
,没有语法错误为了检查谁正在向 sshd 发送信号 15,我尝试了以下操作,下次应该如何尝试?
[root@host1 /sys/kernel/debug/tracing/events/signal/signal_deliver]# echo 1 > /sys/kernel/debug/tracing/events/signal/enable [root@host1 /sys/kernel/debug/tracing/events/signal/signal_deliver]# echo "sig == 15" > /sys/kernel/debug/tracing/events/signal/filter
答案1
没有通用的 Unix 方法可以做到这一点。信号本身不携带该信息。这取决于实际的操作系统。因此,正如您已经意识到的那样,您需要使用内核跟踪来找出 Linux 上的这一问题。
您决定的跟踪点可能不是最佳的 - 您正在观察信号的传递位置,而不是信号的起源位置!因此,signal_deliver
您可能想要跟踪kill
系统调用的入口(因为我们知道谁发送信号)和它的出口(因为我们知道它是否实际上已被传递),而不是跟踪系统调用的入口。
虽然那做听起来很复杂,但有一个工具已经可以做到这一点:
该bpftrace
实用程序附带了很多示例。我不知道您的 Linux 发行版,但是当我安装该bpftrace
软件包时,/usr/share/bpftrace/tools 包含很多很好的跟踪实用程序。
根据您的情况,您需要做什么(如果您已经这样做root
,请删除sudo
):
cd /usr/share/bpftrace/tools # or whichever place these tools have been installed to
sudo ./killsnoop
假设你想要仅有的观看信号 15,您将需要像这样修改脚本:
#!/usr/bin/bpftrace
/*
* signoop Trace who issues signal 15 to whom
* Base on Brendan Gregg's killsnoop, "Trace signals issued by the kill() syscall",
* USAGE: sigsnoop.bt
* Copyright 2018 Netflix, Inc.
* Copyright 2023 Marcus Müller
* Licensed under the Apache License, Version 2.0 (the "License")
*
* 07-Sep-2018 Brendan Gregg Created this.
* 23-Apr-2023 Marcus Müller made it worse :)
*/
BEGIN
{
printf("Tracing signal 15... Hit Ctrl-C to end.\n");
printf("%-9s %-6s %-16s %-4s %-6s %s\n", "TIME", "PID", "COMM", "SIG",
"TPID", "RESULT");
}
tracepoint:syscalls:sys_enter_kill
{
/* here's the relevant part: filter by sig */
if (args->sig == 15) {
@tpid[tid] = args->pid;
@tsig[tid] = args->sig;
}
}
tracepoint:syscalls:sys_exit_kill
/@tpid[tid]/
{
time("%H:%M:%S ");
printf("%-6d %-16s %-4d %-6d %d\n", pid, comm, @tsig[tid], @tpid[tid],
args->ret);
delete(@tpid[tid]);
delete(@tsig[tid]);
}
将其另存为sigsnoop.bt
,授予它任何人都可以执行的权限 ( chmod 755 sigsnoop.bt
),并以 root 身份运行它 ( sudo ./signsnoop.bt
)
答案2
另一种选择是使用系统水龙头。您可以利用signal.send
探测。
例如,要监视发送到进程名称的信号 15 sshd
:
$ stap -e 'probe begin { print("Starting monitoring...\n")}
probe signal.send {
if (sig == 15 && pid_name == "sshd")
printf ("%s(%d) sent signal 15 to %s(%d)\n", execname(), pid(), pid_name, sig_pid)
}'
输出将类似于:
Starting monitoring...
bash(22405) sent signal 15 to sshd(15261)
您甚至可以检查发送信号的进程的命令行
$ stap -e 'probe begin { print("Starting monitoring...\n")}
probe signal.send {
if (sig == 15 && pid_name == "sshd")
printf ("%s(%d) (cmdline: \"%s\") sent signal 15 to %s(%d)\n", execname(), pid(), cmdline_str(), pid_name, sig_pid)
}'
Starting monitoring...
kill(20811) (cmdline: "/usr/bin/kill -15 20809") sent signal 15 to sshd(20809)
您可以在需要时添加更多信息。看看还有哪些水龙头组由 提供systemtap
。
答案3
感谢大家的热心帮助。
我终于发现有一个脚本调用了
service sshd restart
多次重复导致了问题。通过注释掉该声明,sshd
不再有任何问题了。