On 5/27/24 04:17, Damien Miller wrote: > On Fri, 24 May 2024, Donald Buczek wrote: > >> Hi, >> >> I've created a tool which utilizes sshd to enable users to get an interactive >> session on a Linux compute cluster. The tool submits a wrapper into the >> cluster. This wrapper creates the listen socket on a dynamic port number, >> accepts a connection on that socket and then calls sshd in inetd mode with >> '-i'. Everything works fine and as intended. >> >> However, there is one nuisance: I've noticed that sshd always terminates with >> exit status 255 even if the interactive session is closed normally. Because of >> this I can't just exec() sshd from the wrapper as its last step, but need to >> fork sshd, wait for it, ignore its exit status and exit the wrapper with exit >> status 0 to communicate a normal exit to the cluster scheduler. This could >> cover real and unexpected errors. >> >> I've used gdbserver to attach to the sshd process, so I can tell that the exit >> status of the main (the "privileged" process?) of sshd originates in >> mm_request_receive from the EPIPE errno check: >> >> void >> mm_request_receive(int sock, struct sshbuf *m) >> { >> u_char buf[4], *p = NULL; >> u_int msg_len; >> int r; >> >> debug3_f("entering"); >> >> if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) { >> if (errno == EPIPE) >> cleanup_exit(255); >> fatal_f("read: %s", strerror(errno)); >> } >> >> Questions: >> >> - Is this the expected exit point of `sshd -i` ? >> - If so, is there a reason to return a failure exit status? > > No, it's probably that nobody has checked it before. This might help: > > > diff --git a/packet.c b/packet.c > index beb214f99..7d02379bd 100644 > --- a/packet.c > +++ b/packet.c > @@ -1909,7 +1909,8 @@ sshpkt_vfatal(struct ssh *ssh, int r, const char *fmt, va_list ap) > ssh->state->server_side ? "from" : "to", remote_id); > case SSH_ERR_DISCONNECTED: > ssh_packet_clear_keys(ssh); > - logdie("Disconnected from %s", remote_id); > + logit("Disconnected from %s", remote_id); > + cleanup_exit(0); > case SSH_ERR_SYSTEM_ERROR: > if (errno == ECONNRESET) { > ssh_packet_clear_keys(ssh); Thanks, I've tested this patch, but it doesn't seem to fix the problem. Isn't the process doing the ssh protocol the unprivileged one and we have the exist status from the parent (the privileged one)? I'm not really into it. As described, the failure exit status is from EPIPE received by mm_request_receive. Here's my call stack on exit: (gdb) where #0 __GI__exit (status=255) at ../sysdeps/unix/sysv/linux/_exit.c:27 #1 0x0000555555566afa in cleanup_exit (i=255) at sshd.c:2424 #2 0x0000555555592822 in mm_request_receive (sock=8, m=0x55555566f0f0) at monitor_wrap.c:154 #3 0x000055555558cf72 in monitor_read (ssh=0x55555566cf50, pmonitor=0x55555566ee10, ent=0x5555556589e0 <mon_dispatch_postauth20>, pent=0x0) at monitor.c:507 #4 0x000055555558c8c8 in monitor_child_postauth (ssh=0x55555566cf50, pmonitor=0x55555566ee10) at monitor.c:413 #5 0x00005555555605a1 in privsep_postauth (ssh=0x55555566cf50, authctxt=0x55555566ea20) at sshd.c:563 #6 0x00005555555662c3 in main (ac=7, av=0x55555565e2c0) at sshd.c:2266 (gdb) frame 2 #2 0x0000555555592822 in mm_request_receive (sock=8, m=0x55555566f0f0) at monitor_wrap.c:154 154 cleanup_exit(255); (gdb) list 154 149 150 debug3_f("entering"); 151 152 if (atomicio(read, sock, buf, sizeof(buf)) != sizeof(buf)) { 153 if (errno == EPIPE) 154 cleanup_exit(255); 155 fatal_f("read: %s", strerror(errno)); 156 } 157 msg_len = PEEK_U32(buf); 158 if (msg_len > 256 * 1024) (gdb) -- Donald Buczek buczek@xxxxxxxxxxxxx Tel: +49 30 8413 1433 _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev