Hey. I've noticed the following behavior and wondered whether it's possibly a bug or why it behaves like this: When having a SSH connection, than it seems there may be two sshd processes for that, one running as root the other as the user. As far as I know this is because of privilege separation, like e.g.: ??sshd(2931)???sshd(10174)???bash(10180) ? ??sshd(10000)???sshd(10050,someuser)???sleep(10051) When sending INT, TERM, QUIT or HUB to the 2nd process (10050), the first one always exits with and error, and the remote command gets a HUP when RequestTTY=yes|force or nothing when it's =no. When sending INT, TERM, QUIT or HUB to the 1st process (10000), than the second get the same (sent by the 1st) except for the case of QUIT. Plus the same behavior with the remote command (here sleep) as above, depending on RequestTTY (but of course, not working in the QUIT case, as the 2nd process doesn't get that). Is there any reason why it passes on all these signals but not QUIT? Or is the perhaps a bug? Thanks, Philippe
On Tue, 27 Dec 2022, Philippe Cerfon wrote:> Hey. > > I've noticed the following behavior and wondered whether it's possibly > a bug or why it behaves like this: > > When having a SSH connection, than it seems there may be two sshd > processes for that, one running as root the other as the user. As far > as I know this is because of privilege separation, like e.g.: > ??sshd(2931)???sshd(10174)???bash(10180) > ? ??sshd(10000)???sshd(10050,someuser)???sleep(10051) > > > When sending INT, TERM, QUIT or HUB to the 2nd process (10050), the > first one always exits with and error, and the remote command gets a > HUP when RequestTTY=yes|force or nothing when it's =no. > > When sending INT, TERM, QUIT or HUB to the 1st process (10000), than > the second get the same (sent by the 1st) except for the case of QUIT. > Plus the same behavior with the remote command (here sleep) as above, > depending on RequestTTY (but of course, not working in the QUIT case, > as the 2nd process doesn't get that). > > Is there any reason why it passes on all these signals but not QUIT? > Or is the perhaps a bug?It's because the monitor process doesn't explicitly handle SIGQUIT. Try this: diff --git a/monitor.c b/monitor.c index 93d122e..ea44873 100644 --- a/monitor.c +++ b/monitor.c @@ -328,6 +328,7 @@ monitor_child_postauth(struct ssh *ssh, struct monitor *pmonitor) ssh_signal(SIGHUP, &monitor_child_handler); ssh_signal(SIGTERM, &monitor_child_handler); ssh_signal(SIGINT, &monitor_child_handler); + ssh_signal(SIGQUIT, &monitor_child_handler); mon_dispatch = mon_dispatch_postauth20;
Philippe Cerfon wrote:> When having a SSH connection, than it seems there may be two sshd > processes for that, one running as root the other as the user. As far > as I know this is because of privilege separation, like e.g.: > ??sshd(2931)???sshd(10174)???bash(10180) > ? ??sshd(10000)???sshd(10050,someuser)???sleep(10051) > > When sending INT, TERM, QUIT or HUB to the 1st process (10000), than > the second get the same (sent by the 1st) except for the case of QUIT. > Plus the same behavior with the remote command (here sleep) as above, > depending on RequestTTY (but of course, not working in the QUIT case, > as the 2nd process doesn't get that). > > Is there any reason why it passes on all these signals but not QUIT? > Or is the perhaps a bug?I don't know the original author's intent with sshd but the main purpose of the SIGQUIT is to cause the process to dump a core image for debugging. The core image can then be used to debug the state of the program. For example if the program appeared to be stuck in an infinite loop then the core image would allow one to deduce this mapping the program state back to the program source and allow inspecting the value of variables at the time. The traditional name for core was "core". For the most part these days we set it to be "core.$$" types of names with the process ID in the file name so that multiple processes would have uniquely named core files. But on a traditional "core" type of system then the last one dumped would be the one still left on the file system. Does it really make sense to pass along SIGQUIT such that instead of one core file from the program you are targeting with SIGQUIT to get a debugging core that there would be a chain of core files from each of the programs where the signal was forwarded to? That doesn't feel like it makes sense to me. How would that be useful? Bob P.S. Note that most systems now have the core ulimit set to disable writing core dumps to the file system. Because these were often left due to program bugs that only the developer with source could debug but that the user did not care about. Meaning that today in order to obtain a core file these days one must enable the ulimit value of it first.