为什么挂在服务器的“sshd”两端打开的SSH命令等待输出?

为什么挂在服务器的“sshd”两端打开的SSH命令等待输出?,第1张

概述为什么挂在服务器的“sshd”两端打开的SSH命令等待输出

这是在StackOverflow而不是SuperUser / ServerFault,因为它与系统调用和 *** 作系统的交互是由sshd执行的,而不是我使用 SSH的问题(虽然这也是值得赞赏的:p)。

语境:

我通过SSH调用了一系列复杂的脚本,例如ssh user@host -- /my/command 。 远程命令会执行很多复杂的分支和执行 *** 作,并最终导致在远程主机上运行后台进程。 偶尔(我正在慢慢发疯,试图找出可靠的复制条件), ssh命令将永远不会返回到客户端shell的控制。 在这些情况下,我可以进入目标主机,看到一个sshd: user@notty进程,没有孩子无限期悬挂。

解决这个问题不是这个问题的关键。 这个问题是关于sshd进程在做什么的 。

如果我有一个过程,我克隆它,PID是一样的吗?

fork()的function

为什么从孩子getppID()返回1

共享内存不与C中的进程共享

当一个进程分叉时会发生什么?

SSH实现为OpenSSH,版本为5.3p1-112.el6_7。

问题:

如果我发现其中一个卡住了sshd s并对其进行了strace ,我可以看到它在两个句柄上进行select,例如select(12,[3 6],[],NulL,NulL或类似的。 handle是连接到SSH客户端的TCP套接字,另一个是pipe道, 另一端只在同一个sshd进程中打开,如果我使用这个SuperUser问题的答案通过IDsearchpipe道,包含对该pipe道的引用的进程是相同的进程, lsof证实了这一点:pipe道的读和写端都在同一进程中打开,例如(对于pipe道788422703和sshd PID 22744):

sshd 22744 user 6r FIFO 0,8 0t0 788422703 pipe sshd 22744 user 7w FIFO 0,8 0t0 788422703 pipe

问题:

什么是SSH等待? 如果pipe道没有连接到任何东西,也没有subprocess,我无法想象它可能会发生什么事件。

什么是“循环”pipe道/它代表什么? 我唯一的理论是,如果STDIN没有提供给SSH客户端,目标主机sshd打开一个虚拟的STDINpipe道,所以它的一些内部的子pipe理代码可以更加统一? 但是这似乎很脆弱。

SSH如何进入这种情况?

我试过的东西/附加信息:

起初,我认为这是一个守护进程的处理漏洞。 可以通过发出一个命令来自己创build一个等待的无子sshd进程,例如ssh user@host -- 'sleep 60 &' ; sshd将等待stream被closures到守护进程; 不仅仅是直接孩子的出口。 由于有问题的脚本最终导致(在进程树中)在一个正在启动的守护进程中,守护进程最初似乎有可能持有一个句柄。 但是,这似乎并不成立 – 以sleep 60 &命令为例,与守护进程通信的sshd进程持有并select了四个打开的pipe道,而不仅仅是两个,并且至less有两个pipe道从sshd到守护进程,不循环。 除非有一种跟踪/指向pipe道的方法,我不知道(有可能 – 例如,我不知道如何dup文件句柄进入close()信号量等待或pipe道),我不知道认为pipe道对自己的情况代表了一个等待守护进程的情况。

sshd周期性地在TCP socket / ssh连接本身上接收通信,这个连接在select s中被唤醒以进行短暂的通信(在此期间, strace显示它阻塞了SIGCHLD),然后返回等待相同的FD。

我可能受到这种竞争条件的影响(SIGCHLD在内核使pipe道中的数据可用之前交付)。 然而,这似乎不太可能,既考虑到了这种情况出现的速度,而且在目标主机上运行的进程都是Perl脚本,并且Perl运行时在closures时closures并刷新打开的文件描述符 。

用C在linux的后台启动一个进程

LD_PRELOADed库和subprocess

正确的方法来使用fork()和wait()

如何testing调用过程是否是分叉

为什么FT_Read()在subprocess中失败,但在父进程中工作?

看来你正在描述通知管道。 OpenSSH sshd主循环调用select()来等待,直到它有事情要做。 正在轮询的文件描述符包括到客户端的TCP连接以及任何用于服务活动通道的描述符。

当接收到SIGCHLD信号时,sshd希望能够中断select()调用。 为此,sshd为SIGCHLD安装信号处理程序,并创建一个管道。 当收到SIGCHLD信号时,信号处理程序将一个字节写入管道。 管道的读取端包含在由select()轮询的文件描述符列表中。 写入管道的行为将导致select()调用返回并显示通知管道是可读的。

所有的代码都在serverloop.c :

/* * we write to this pipe if a SIGCHLD is caught in order to avoID * the race between select() and child_terminated */ static int notify_pipe[2]; static voID notify_setup(voID) { if (pipe(notify_pipe) < 0) { error("pipe(notify_pipe) Failed %s",strerror(errno)); } else if ((fcntl(notify_pipe[0],F_SETFD,1) == -1) || (fcntl(notify_pipe[1],1) == -1)) { error("fcntl(notify_pipe,F_SETFD) Failed %s",strerror(errno)); close(notify_pipe[0]); close(notify_pipe[1]); } else { set_nonblock(notify_pipe[0]); set_nonblock(notify_pipe[1]); return; } notify_pipe[0] = -1; /* read end */ notify_pipe[1] = -1; /* write end */ } static voID notify_parent(voID) { if (notify_pipe[1] != -1) write(notify_pipe[1],"",1); } [...] /*ARGSUSED*/ static voID sigchld_handler(int sig) { int save_errno = errno; child_terminated = 1; #ifndef _UNICOS mysignal(SIGCHLD,sigchld_handler); #endif notify_parent(); errno = save_errno; }

设置和执行select调用的代码位于另一个名为wait_until_can_do_something()函数中。 这是相当长的,所以我不会在这里包括它。 OpenSSH是开源的, 这个页面描述了如何下载源代码。

总结

以上是内存溢出为你收集整理的为什么挂在服务器的“sshd”两端打开的SSH命令等待输出?全部内容,希望文章能够帮你解决为什么挂在服务器的“sshd”两端打开的SSH命令等待输出?所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1254572.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-07
下一篇 2022-06-07

发表评论

登录后才能评论

评论列表(0条)

保存